package examples_test
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/exec"
"github.com/testcontainers/testcontainers-go/wait"
)
// TestGenericNginx demonstrates using a generic container with nginx
func TestGenericNginx(t *testing.T) {
ctx := context.Background()
// Start nginx container
nginxContainer, err := testcontainers.Run(
ctx,
"nginx:alpine",
testcontainers.WithExposedPorts("80/tcp"),
testcontainers.WithWaitStrategy(
wait.ForListeningPort("80/tcp").WithStartupTimeout(30*time.Second),
),
)
testcontainers.CleanupContainer(t, nginxContainer)
require.NoError(t, err)
// Get endpoint
endpoint, err := nginxContainer.Endpoint(ctx, "http")
require.NoError(t, err)
// Test the nginx default page
resp, err := http.Get(endpoint)
require.NoError(t, err)
defer resp.Body.Close()
require.Equal(t, http.StatusOK, resp.StatusCode)
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Contains(t, string(body), "Welcome to nginx")
t.Log("Successfully accessed nginx container")
}
// TestGenericContainerWithCustomHTML demonstrates serving custom content with nginx
func TestGenericContainerWithCustomHTML(t *testing.T) {
ctx := context.Background()
customHTML := `
Test Page
Hello from Testcontainers!
`
// Start nginx with custom HTML
nginxContainer, err := testcontainers.Run(
ctx,
"nginx:alpine",
testcontainers.WithExposedPorts("80/tcp"),
testcontainers.WithFiles(testcontainers.ContainerFile{
Reader: strings.NewReader(customHTML),
ContainerFilePath: "/usr/share/nginx/html/index.html",
FileMode: 0o644,
}),
testcontainers.WithWaitStrategy(
wait.ForListeningPort("80/tcp"),
),
)
testcontainers.CleanupContainer(t, nginxContainer)
require.NoError(t, err)
endpoint, err := nginxContainer.Endpoint(ctx, "http")
require.NoError(t, err)
resp, err := http.Get(endpoint)
require.NoError(t, err)
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Contains(t, string(body), "Hello from Testcontainers!")
t.Log("Successfully served custom HTML from nginx")
}
// TestGenericContainerWithEnv demonstrates using environment variables
func TestGenericContainerWithEnv(t *testing.T) {
ctx := context.Background()
// Start alpine container that echoes an environment variable
alpineContainer, err := testcontainers.Run(
ctx,
"alpine:latest",
testcontainers.WithEnv(map[string]string{
"MY_VAR": "test_value",
"ANOTHER_VAR": "another_value",
}),
testcontainers.WithCmd("sleep", "300"),
)
testcontainers.CleanupContainer(t, alpineContainer)
require.NoError(t, err)
// Execute command to read environment variable
exitCode, reader, err := alpineContainer.Exec(ctx, []string{"sh", "-c", "echo $MY_VAR"}, exec.Multiplexed())
require.NoError(t, err)
require.Equal(t, 0, exitCode)
output, err := io.ReadAll(reader)
require.NoError(t, err)
require.Contains(t, string(output), "test_value")
t.Log("Successfully used environment variables in container")
}
// TestGenericContainerWithCommand demonstrates running a custom command
func TestGenericContainerWithCommand(t *testing.T) {
ctx := context.Background()
// Start alpine with a custom command that creates a file
alpineContainer, err := testcontainers.Run(
ctx,
"alpine:latest",
testcontainers.WithCmd("sh", "-c", "echo 'Hello' > /tmp/hello.txt && sleep 300"),
)
testcontainers.CleanupContainer(t, alpineContainer)
require.NoError(t, err)
// Give it a moment to create the file
time.Sleep(1 * time.Second)
// Read the file we created
exitCode, reader, err := alpineContainer.Exec(ctx, []string{"cat", "/tmp/hello.txt"}, exec.Multiplexed())
require.NoError(t, err)
require.Equal(t, 0, exitCode)
output, err := io.ReadAll(reader)
require.NoError(t, err)
require.Contains(t, string(output), "Hello")
t.Log("Successfully ran custom command in container")
}
// TestGenericContainerWithLabels demonstrates using labels
func TestGenericContainerWithLabels(t *testing.T) {
ctx := context.Background()
alpineContainer, err := testcontainers.Run(
ctx,
"alpine:latest",
testcontainers.WithLabels(map[string]string{
"app": "testapp",
"environment": "test",
"version": "1.0",
}),
testcontainers.WithCmd("sleep", "300"),
)
testcontainers.CleanupContainer(t, alpineContainer)
require.NoError(t, err)
// Inspect container to verify labels
inspect, err := alpineContainer.Inspect(ctx)
require.NoError(t, err)
require.Equal(t, "testapp", inspect.Config.Labels["app"])
require.Equal(t, "test", inspect.Config.Labels["environment"])
require.Equal(t, "1.0", inspect.Config.Labels["version"])
t.Log("Successfully set and verified container labels")
}
// TestGenericContainerWithTmpfs demonstrates using temporary filesystems
func TestGenericContainerWithTmpfs(t *testing.T) {
ctx := context.Background()
alpineContainer, err := testcontainers.Run(
ctx,
"alpine:latest",
testcontainers.WithTmpfs(map[string]string{
"/tmp": "rw,size=100m",
}),
testcontainers.WithCmd("sleep", "300"),
)
testcontainers.CleanupContainer(t, alpineContainer)
require.NoError(t, err)
// Verify tmpfs is mounted
exitCode, reader, err := alpineContainer.Exec(ctx, []string{"mount"}, exec.Multiplexed())
require.NoError(t, err)
require.Equal(t, 0, exitCode)
output, err := io.ReadAll(reader)
require.NoError(t, err)
require.Contains(t, string(output), "tmpfs on /tmp")
t.Log("Successfully mounted tmpfs in container")
}
// TestGenericContainerLogs demonstrates accessing container logs
func TestGenericContainerLogs(t *testing.T) {
ctx := context.Background()
// Start container that produces logs
alpineContainer, err := testcontainers.Run(
ctx,
"alpine:latest",
testcontainers.WithCmd("sh", "-c", "echo 'Starting...'; sleep 1; echo 'Running...'; sleep 300"),
)
testcontainers.CleanupContainer(t, alpineContainer)
require.NoError(t, err)
// Wait a moment for logs to be written
time.Sleep(2 * time.Second)
// Read logs
logs, err := alpineContainer.Logs(ctx)
require.NoError(t, err)
defer logs.Close()
logContent, err := io.ReadAll(logs)
require.NoError(t, err)
logStr := string(logContent)
require.Contains(t, logStr, "Starting...")
require.Contains(t, logStr, "Running...")
t.Log("Successfully read container logs")
}
// TestGenericContainerExec demonstrates executing commands in a running container
func TestGenericContainerExec(t *testing.T) {
ctx := context.Background()
alpineContainer, err := testcontainers.Run(
ctx,
"alpine:latest",
testcontainers.WithCmd("sleep", "300"),
)
testcontainers.CleanupContainer(t, alpineContainer)
require.NoError(t, err)
// Execute multiple commands
tests := []struct {
name string
cmd []string
expected string
}{
{
name: "echo",
cmd: []string{"echo", "hello world"},
expected: "hello world",
},
{
name: "pwd",
cmd: []string{"pwd"},
expected: "/",
},
{
name: "uname",
cmd: []string{"uname", "-s"},
expected: "Linux",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
exitCode, reader, err := alpineContainer.Exec(ctx, tt.cmd, exec.Multiplexed())
require.NoError(t, err)
require.Equal(t, 0, exitCode)
output, err := io.ReadAll(reader)
require.NoError(t, err)
require.Contains(t, string(output), tt.expected)
})
}
t.Log("Successfully executed multiple commands")
}
// TestGenericContainerHTTPWait demonstrates waiting for an HTTP endpoint
func TestGenericContainerHTTPWait(t *testing.T) {
ctx := context.Background()
nginxContainer, err := testcontainers.Run(
ctx,
"nginx:alpine",
testcontainers.WithExposedPorts("80/tcp"),
testcontainers.WithWaitStrategy(
wait.ForListeningPort("80/tcp"),
wait.ForHTTP("/").
WithPort("80/tcp").
WithStatusCodeMatcher(func(status int) bool {
return status == http.StatusOK
}).
WithStartupTimeout(30*time.Second),
),
)
testcontainers.CleanupContainer(t, nginxContainer)
require.NoError(t, err)
endpoint, err := nginxContainer.Endpoint(ctx, "http")
require.NoError(t, err)
// Container is already ready because wait strategy succeeded
resp, err := http.Get(endpoint)
require.NoError(t, err)
defer resp.Body.Close()
require.Equal(t, http.StatusOK, resp.StatusCode)
t.Log("HTTP wait strategy worked correctly")
}
// TestGenericContainerLogWait demonstrates waiting for a log message
func TestGenericContainerLogWait(t *testing.T) {
ctx := context.Background()
alpineContainer, err := testcontainers.Run(
ctx,
"alpine:latest",
testcontainers.WithCmd(
"sh", "-c",
"echo 'Initializing...'; sleep 2; echo 'Ready!'; sleep 300",
),
testcontainers.WithWaitStrategy(
wait.ForLog("Ready!").WithStartupTimeout(10*time.Second),
),
)
testcontainers.CleanupContainer(t, alpineContainer)
require.NoError(t, err)
// If we got here, the "Ready!" message was logged
t.Log("Container became ready after logging expected message")
}
// TestGenericContainerPortInfo demonstrates getting port information
func TestGenericContainerPortInfo(t *testing.T) {
ctx := context.Background()
nginxContainer, err := testcontainers.Run(
ctx,
"nginx:alpine",
testcontainers.WithExposedPorts("80/tcp", "443/tcp"),
testcontainers.WithWaitStrategy(wait.ForListeningPort("80/tcp")),
)
testcontainers.CleanupContainer(t, nginxContainer)
require.NoError(t, err)
// Method 1: Get mapped port
port80, err := nginxContainer.MappedPort(ctx, "80/tcp")
require.NoError(t, err)
t.Logf("Port 80 is mapped to: %s", port80.Port())
// Method 2: Get host
host, err := nginxContainer.Host(ctx)
require.NoError(t, err)
t.Logf("Container host: %s", host)
// Method 3: Get endpoint
endpoint, err := nginxContainer.Endpoint(ctx, "http")
require.NoError(t, err)
t.Logf("HTTP endpoint: %s", endpoint)
// Method 4: Get all ports
ports, err := nginxContainer.Ports(ctx)
require.NoError(t, err)
t.Logf("All ports: %v", ports)
// Verify we can access port 80
resp, err := http.Get(fmt.Sprintf("http://%s:%s", host, port80.Port()))
require.NoError(t, err)
defer resp.Body.Close()
require.Equal(t, http.StatusOK, resp.StatusCode)
t.Log("Successfully retrieved and used port information")
}