### Basic Test Example Source: https://github.com/home-operations/containers/blob/main/_autodocs/README.md A basic test that retrieves a test image and verifies a command succeeds within the container. ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func TestMyImage(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") testhelpers.TestCommandSucceeds(t, image, nil, "/app/validate") } ``` -------------------------------- ### Install testhelpers Module Source: https://github.com/home-operations/containers/blob/main/_autodocs/README.md Add the testhelpers module to your Go project to use its testing utilities. ```go import "github.com/home-operations/containers/testhelpers" ``` -------------------------------- ### Run Individual Test Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Demonstrates how to run a single test file for a specific application within the container project. Includes an example of the expected output. ```bash cd /workspace/home/containers/apps/home-assistant go test -v ``` ```text === RUN Test --- PASS: Test (3.45s) PASS ok github.com/home-operations/containers/apps/home-assistant 3.456s ``` -------------------------------- ### Configure Paths and URLs via Environment Variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Use environment variables to specify configuration paths and URLs for the container. Examples include CONFIG_FILE, DATABASE_URL, and LOG_DIR. ```go config := &testhelpers.ContainerConfig{ Env: map[string]string{ "CONFIG_FILE": "/etc/app/config.yml", "DATABASE_URL": "postgres://localhost/testdb", "LOG_DIR": "/var/log/app", }, } ``` -------------------------------- ### Check Docker and Testcontainers-Go Dependencies Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md Verify that Docker is running and testcontainers-go is correctly installed and configured by running the `check-docker` command. ```bash go run github.com/testcontainers/testcontainers-go/cmd/check-docker@latest ``` -------------------------------- ### Run Tests with Custom Image Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Example of running tests for a specific application while overriding the default image with a custom one from a registry. ```bash TEST_IMAGE=my-registry/my-app:custom go test -v ./apps/my-app/ ``` -------------------------------- ### Test Container Configurability Source: https://github.com/home-operations/containers/blob/main/_autodocs/README.md Verifies that a container's configuration, such as environment variables, is correctly applied. This example checks for the presence of a file indicating debug mode is enabled. ```go func TestConfigurability(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/app:rolling") config := &testhelpers.ContainerConfig{ Env: map[string]string{ "ENABLE_DEBUG": "true", }, } testhelpers.TestFileExists(t, image, "/app/.debug-mode-enabled", config) } ``` -------------------------------- ### Test Container Image Startup Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Verify that a container image starts and exits cleanly. This snippet uses GetTestImage to retrieve the image and TestCommandSucceeds to check for a successful command execution. ```go func TestImageStartup(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/app:rolling") // The test passes if the container starts and exits cleanly testhelpers.TestCommandSucceeds(t, image, nil, "true") } ``` -------------------------------- ### Get Test Image Reference Source: https://github.com/home-operations/containers/blob/main/_autodocs/INDEX.md Retrieves a reference for a test image. Use this to specify the container image for your tests. ```go image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") ``` -------------------------------- ### Configure Numeric Values via Environment Variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Set numeric values as strings in environment variables for the container. Examples include PORT, MAX_WORKERS, and TIMEOUT_SECONDS. ```go config := &testhelpers.ContainerConfig{ Env: map[string]string{ "PORT": "8080", "MAX_WORKERS": "4", "TIMEOUT_SECONDS": "30", }, } ``` -------------------------------- ### Verify Image Signature with cosign Source: https://github.com/home-operations/containers/blob/main/README.md Use this command with cosign to verify the image's provenance. This command requires cosign to be installed and configured. ```sh cosign verify-attestation --new-bundle-format --type slsaprovenance1 \ --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ --certificate-identity-regexp "^https://github.com/home-operations/containers/.github/workflows/app-builder.yaml@refs/heads/main" \ ghcr.io/home-operations/${APP}:${TAG} ``` -------------------------------- ### Configure Boolean-like Flags via Environment Variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Use environment variables to pass boolean-like flags to the container. Example includes DEBUG and ENABLE_API. ```go config := &testhelpers.ContainerConfig{ Env: map[string]string{ "DEBUG": "true", "ENABLE_API": "false", }, } ``` -------------------------------- ### Define ContainerConfig with a single environment variable Source: https://github.com/home-operations/containers/blob/main/_autodocs/types.md Use ContainerConfig to set environment variables for a container. This example sets the DEBUG variable. ```go config := &testhelpers.ContainerConfig{ Env: map[string]string{ "DEBUG": "true", }, } testhelpers.TestCommandSucceeds(t, image, config, "/app/check-config.sh") ``` -------------------------------- ### Test HTTP Endpoint with Configuration Source: https://github.com/home-operations/containers/blob/main/_autodocs/INDEX.md Tests an HTTP endpoint with custom container configuration, including environment variables. This allows for more complex test setups. ```go config := &testhelpers.ContainerConfig{ Env: map[string]string{ "DEBUG": "true", }, } testhelpers.TestHTTPEndpoint(t, image, httpConfig, config) ``` -------------------------------- ### Passing Arguments to Containers in Kubernetes Source: https://github.com/home-operations/containers/blob/main/README.md Example of how to pass command-line arguments to a container within a Kubernetes deployment. This is useful for applications that do not support configuration via environment variables. ```yaml args: - --port - "8080" ``` -------------------------------- ### Configure HTTP Test Path (Default) Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md When the Path field in HTTPTestConfig is empty, it defaults to '/'. This example shows how to explicitly set an empty path, which results in the default being used. ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", Path: "", // Will use "/" } ``` -------------------------------- ### Verify Image Signature with gh attestation Source: https://github.com/home-operations/containers/blob/main/README.md Use this command to verify that a container image was built by GitHub CI. Ensure you have the 'gh' CLI installed and authenticated. ```sh gh attestation verify --repo home-operations/containers oci://ghcr.io/home-operations/${APP}:${TAG} ``` -------------------------------- ### Define HTTPTestConfig with default path and status code Source: https://github.com/home-operations/containers/blob/main/_autodocs/types.md Configure basic HTTP endpoint testing using HTTPTestConfig. This example specifies the port and relies on default values for path and status code. ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", } testhelpers.TestHTTPEndpoint(t, image, httpConfig, nil) ``` -------------------------------- ### Get Test Image from Environment Variable Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Retrieves the container image URI to test. It prioritizes the TEST_IMAGE environment variable and falls back to a provided default image if the variable is not set. ```go package main import ( test_helpers "github.com/home-operations/containers/testhelpers" "testing" ) func Test(t *testing.T) { image := test_helpers.GetTestImage("ghcr.io/home-operations/busybox:rolling") // image will be "ghcr.io/home-operations/busybox:rolling" // unless TEST_IMAGE environment variable is set } ``` -------------------------------- ### Get Test Image with TEST_IMAGE Override Source: https://github.com/home-operations/containers/blob/main/_autodocs/README.md Illustrates the behavior of `testhelpers.GetTestImage()`. It returns the specified image path unless the TEST_IMAGE environment variable is set, in which case it returns the value of TEST_IMAGE. ```go image := testhelpers.GetTestImage("ghcr.io/home-operations/busybox:rolling") // Returns "ghcr.io/home-operations/busybox:rolling" // unless TEST_IMAGE environment variable is set ``` -------------------------------- ### Test TuDuDi with Full Configuration Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Tests a TuDuDi service container with required authentication and session configuration. Ensures the container starts correctly and the HTTP health endpoint is accessible. ```go package main import ( test "testing" "github.com/home-operations/containers/testhelpers" ) func Test(t *test.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/tududi:rolling") testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "3002", Path: "/api/health", StatusCode: 200, }, &testhelpers.ContainerConfig{ Env: map[string]string{ "TUDUDI_USER_EMAIL": "test@example.com", "TUDUDI_USER_PASSWORD": "testpassword123", "TUDUDI_SESSION_SECRET": "test-session-secret-32chars!!", }, }) } ``` -------------------------------- ### Configure HTTP Test Path (Custom) Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Specify a custom HTTP path for testing endpoints using the Path field in HTTPTestConfig. Examples include '/health', '/api/v1/status', and '/metrics'. ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", Path: "/health", } ``` ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "3000", Path: "/api/v1/status", } ``` ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "9000", Path: "/metrics", } ``` -------------------------------- ### Kubernetes Deployment for Rootless Containers Source: https://github.com/home-operations/containers/blob/main/README.md Example Kubernetes Deployment manifest for running a container as a non-root user. It includes security context settings for privilege escalation, capabilities, and read-only root filesystem. Note the fsGroup and fsGroupChangePolicy require CSI support. ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: home-assistant # ... spec: # ... template: # ... spec: containers: - name: home-assistant image: ghcr.io/home-operations/home-assistant:2025.5.1 securityContext: # May require mounting in additional dirs as emptyDir allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: true volumeMounts: - name: tmp mountPath: /tmp # ... securityContext: runAsUser: 1000 runAsGroup: 1000 fsGroup: 65534 # (Requires CSI support) fsGroupChangePolicy: OnRootMismatch # (Requires CSI support) volumes: - name: tmp emptyDir: {} # ... # ... ``` -------------------------------- ### Test Container Environment Variable Validation Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Validate container behavior with specific environment variables set. This example uses ContainerConfig to define environment variables and TestFileExists to check for a file's presence. ```go func TestWithFeatureFlags(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") config := &testhelpers.ContainerConfig{ Env: map[string]string{ "ENABLE_FEATURE_X": "true", }, } testhelpers.TestFileExists(t, image, "/var/feature-x-marker", config) } ``` -------------------------------- ### Docker Compose Configuration for Rootless Containers Source: https://github.com/home-operations/containers/blob/main/README.md Example of configuring a service in Docker Compose to run a container as a non-root user. Ensure data volume permissions match the specified user and group. ```yaml services: home-assistant: image: ghcr.io/home-operations/home-assistant:2025.5.1 container_name: home-assistant user: 1000:1000 # The data volume permissions must match this user:group read_only: true # May require mounting in additional dirs as tmpfs tmpfs: - /tmp:rw # ... ``` -------------------------------- ### Get Test Image with Runtime Override Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md The GetTestImage function retrieves the Docker image name, respecting the TEST_IMAGE environment variable if set. Otherwise, it returns the default image. ```go image := testhelpers.GetTestImage("ghcr.io/home-operations/busybox:rolling") // Returns "ghcr.io/home-operations/busybox:rolling" unless TEST_IMAGE is set ``` -------------------------------- ### Command Validation Test Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md Tests the execution of a specific command within a container. Verifies that the container starts, the specified binary exists, and the command exits with a zero status code. Ideal for validating application startup scripts or utility commands. ```go testhelpers.TestCommandSucceeds(t, image, nil, "/app/my-app", "--version") ``` -------------------------------- ### Test HTTP Endpoint in a Container Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md The `TestHTTPEndpoint` function tests a given HTTP endpoint within a container. It configures the container, starts it, waits for the endpoint to be ready, and performs the HTTP request. ```go func TestHTTPEndpoint(ctx context.Context, req *http.Request, config ContainerConfig, waitStrategy testcontainers.WaitStrategy) error { image := GetTestImage() container, err := testcontainers.GenericContainerStart(ctx, testcontainers.GenericContainerRequest{ Image: image, ContainerConfig: testcontainers.ContainerConfig{ Env: config.Env, Networks: config.Networks, }, Reuse: true, }) if err != nil { return fmt.Errorf("failed to start container: %w", err) } defer container.Terminate(ctx) endpoint := container.Endpoint url := fmt.Sprintf("%s%s", endpoint, req.URL.Path) if waitStrategy != nil { if err := container.Start(ctx); err != nil { return fmt.Errorf("failed to start container: %w", err) } if err := waitStrategy.WaitUntilReady(ctx, container); err != nil { return fmt.Errorf("wait strategy failed: %w", err) } } newReq, err := http.NewRequestWithContext(ctx, req.Method, url, req.Body) if err != nil { return fmt.Errorf("failed to create request: %w", err) } newReq.Header = req.Header client := &http.Client{} resp, err := client.Do(newReq) if err != nil { return fmt.Errorf("failed to execute request: %w", err) } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 300 { return fmt.Errorf("unexpected status code: %d", resp.StatusCode) } return nil } ``` -------------------------------- ### Testing Multiple Configurations with Table-Driven Tests Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Demonstrates how to test a command with multiple configurations by iterating through a slice of test cases, each defining different environment variables. ```go func TestMultipleConfigs(t *testing.T) { testCases := []struct { name string env map[string]string }{ { name: "default config", env: map[string]string{}, }, { name: "debug enabled", env: map[string]string{ "DEBUG": "true", }, }, { name: "custom log level", env: map[string]string{ "LOG_LEVEL": "debug", }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { config := &testhelpers.ContainerConfig{ Env: tc.env, } testhelpers.TestCommandSucceeds(t, image, config, "validate-config") }) } } ``` -------------------------------- ### Test File Existence with No Configuration Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Demonstrates how to check for file existence without providing additional configuration by passing `nil` for optional parameters. ```go testhelpers.TestFileExists(t, image, "/etc/app.conf", nil) ``` -------------------------------- ### Use GetTestImage for Testable Images Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Illustrates the recommended practice of using `testhelpers.GetTestImage` to allow for `TEST_IMAGE` environment variable overrides, contrasting it with hardcoded image strings. ```go // ✅ Good - allows TEST_IMAGE override image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") // ❌ Avoid - hardcoded image, no override capability image := "ghcr.io/home-operations/my-app:rolling" ``` -------------------------------- ### Use Default HTTP Timeout Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Configure the startup timeout for the HTTP wait strategy. A zero value uses the testcontainers library default. ```go import "time" // Use library default (0 value means use default) httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", Timeout: 0, } ``` -------------------------------- ### Comprehensive Multi-Aspect Testing Pattern Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Demonstrates a pattern for comprehensive container testing, including binary existence, command execution, HTTP endpoint accessibility, and configuration-driven behavior. ```go package main import ( test "testing" "github.com/home-operations/containers/testhelpers" ) func Test(t *test.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") t run("binary exists", func(t *test.T) { testhelpers.TestFileExists(t, image, "/usr/local/bin/my-app", nil) }) t run("version command works", func(t *test.T) { testhelpers.TestCommandSucceeds(t, image, nil, "/usr/local/bin/my-app", "--version") }) t run("http endpoint accessible", func(t *test.T) { testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8080", Path: "/api/health", StatusCode: 200, }, nil) }) t run("with custom config", func(t *test.T) { testhelpers.TestFileExists(t, image, "/etc/my-app/.configured", &testhelpers.ContainerConfig{ Env: map[string]string{ "CONFIGURE_ON_START": "true", }, }) }) } ``` -------------------------------- ### Test Busybox Command List Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Verifies the Busybox binary and its available commands by executing the --list command. Checks for container startup, binary presence, and successful command execution. ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func Test(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/busybox:rolling") testhelpers.TestCommandSucceeds(t, image, nil, "/bin/busybox", "--list") } ``` -------------------------------- ### Minimal HTTP Test Configuration Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Sets up a minimal HTTP test by providing only the required port in the `HTTPTestConfig`. ```go testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8080", }, nil) ``` -------------------------------- ### Test Application Version Command Source: https://github.com/home-operations/containers/blob/main/_autodocs/README.md Verifies that a command to display the application version executes successfully within the container. ```go func TestApplicationVersionCommand(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/app:rolling") // Verify version command works testhelpers.TestCommandSucceeds(t, image, nil, "/app/main", "--version") } ``` -------------------------------- ### Include Required Environment Variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Ensure necessary environment variables are provided for the container. Missing configurations can lead to test failures. ```go // ✅ Good - provides necessary environment variables testhelpers.TestHTTPEndpoint(t, image, httpConfig, &testhelpers.ContainerConfig{ Env: map[string]string{ "DELUGE_BIN": "deluge-web", }, }) // ❌ Avoid - missing required config, test will fail testhelpers.TestHTTPEndpoint(t, image, httpConfig, nil) ``` -------------------------------- ### Test File Existence Source: https://github.com/home-operations/containers/blob/main/_autodocs/INDEX.md Verifies if a file exists within the container. Provide the image, file path, and an optional configuration object. ```go testhelpers.TestFileExists(t, image, "/app/config.yml", nil) ``` -------------------------------- ### Test with Environment Variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/README.md Verifies the existence of a file within a container after setting custom environment variables for the container's configuration. ```go func TestWithConfig(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") config := &testhelpers.ContainerConfig{ Env: map[string]string{ "DEBUG": "true", "LOG_LEVEL": "info", }, } testhelpers.TestFileExists(t, image, "/etc/app/config.yml", config) } ``` -------------------------------- ### Configuration Testing with Environment Variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md Tests a containerized service with specific environment variables set. Verifies that the container accepts environment variables and that the service behaves correctly with the provided configuration. Useful for testing application settings and behavior under different configurations. ```go testhelpers.TestHTTPEndpoint(t, image, httpConfig, &testhelpers.ContainerConfig{ Env: map[string]string{ "KEY": "value", }, }) ``` -------------------------------- ### Use Default Container Configuration Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Pass nil for ContainerConfig when no specific environment variables or configurations are needed for the container. ```go testhelpers.TestCommandSucceeds(t, image, nil, "validate") ``` -------------------------------- ### Run All App Tests Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Command to execute all tests for applications within the 'apps' directory of the containers repository. ```bash cd /workspace/home/containers go test -v ./apps/... ``` -------------------------------- ### Test Actual Service Behavior Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Highlights the best practice of testing meaningful service behavior, such as HTTP endpoints, rather than trivial command executions. ```go // ✅ Good - tests the actual service behavior testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8080", Path: "/api/health", }, nil) // ❌ Avoid - testing nothing meaningful testhelpers.TestCommandSucceeds(t, image, nil, "echo", "hello") ``` -------------------------------- ### Test Kopia Backup Tool Version Command Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Verifies the Kopia backup tool binary by running its version command. Checks for container startup, binary presence, and successful execution of the --version command. ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func Test(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/kopia:rolling") testhelpers.TestCommandSucceeds(t, image, nil, "/usr/local/bin/kopia", "--version") } ``` -------------------------------- ### Configure Container with Environment Variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Create a ContainerConfig struct to set environment variables within the container. This is useful for enabling debug modes or setting log levels. ```go config := &testhelpers.ContainerConfig{ Env: map[string]string{ "DEBUG": "true", "LOG_LEVEL": "info", }, } testhelpers.TestCommandSucceeds(t, image, config, "validate") ``` -------------------------------- ### Complete HTTP Test Configuration Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Configures a comprehensive HTTP test including port, path, status code, timeout, and container environment variables. ```go testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8080", Path: "/api/health", StatusCode: 200, Timeout: 30 * time.Second, }, &testhelpers.ContainerConfig{ Env: map[string]string{ "DEBUG": "true", "LOG_LEVEL": "info", }, }) ``` -------------------------------- ### Specific Endpoint Test Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md Tests a specific HTTP endpoint within a containerized service. Verifies that the container starts, the port is listening, and a given path returns the expected HTTP status code. Useful for testing API health checks or specific resource endpoints. ```go testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8080", Path: "/api/health", StatusCode: 200, }, nil) ``` -------------------------------- ### Run Tests in Parallel Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md Tests can be run in parallel using the `-parallel` flag with `go test`. Ensure different port numbers are used for each parallel test. ```bash go test -parallel ``` -------------------------------- ### Define HTTPTestConfig with a custom startup timeout Source: https://github.com/home-operations/containers/blob/main/_autodocs/types.md Set a custom startup timeout for the HTTP wait strategy in HTTPTestConfig. This overrides the default testcontainers library timeout. ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", Path: "/health", StatusCode: 200, Timeout: 30 * time.Second, } testhelpers.TestHTTPEndpoint(t, image, httpConfig, nil) ``` -------------------------------- ### Test ESPHome Web Interface Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Tests the ESPHome dashboard by verifying container startup, service binding to port 6052, and a 200 response on the default path. ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func Test(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/esphome:rolling") testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "6052", }, nil) } ``` -------------------------------- ### Test File Existence in Container Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Verifies if a specific file exists within a container. It runs the `test -f` command and cleans up the container automatically. Use this to ensure configuration files or binaries are present. ```go func TestFileExists(t *testing.T, image string, filePath string, config *ContainerConfig) ``` ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func TestConfigFileExists(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") testhelpers.TestFileExists(t, image, "/etc/my-app/config.yml", nil) } ``` ```go func TestBinaryExecutable(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") // Verify the main application binary exists testhelpers.TestFileExists(t, image, "/usr/local/bin/my-app", nil) } ``` -------------------------------- ### Run Tests with Verbose Logging Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Shows how to enable verbose logging during test execution by setting the TEST_LOGLEVEL environment variable, alongside overriding the test image. ```bash TEST_LOGLEVEL=debug TEST_IMAGE=localhost:5000/home-assistant:dev go test -v ./apps/home-assistant/ ``` -------------------------------- ### Test Command Success Source: https://github.com/home-operations/containers/blob/main/_autodocs/INDEX.md Checks if a command executes successfully within the container. Provide the image, command, and any arguments. ```go testhelpers.TestCommandSucceeds(t, image, nil, "/app/validate", "--strict") ``` -------------------------------- ### Test Deluge HTTP Endpoint with Environment Configuration Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Tests the Deluge HTTP endpoint with a specific environment variable (DELUGE_BIN=deluge-web) to configure its behavior. Verifies container startup, correct binary execution, service binding, and a 200 response. ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func Test(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/deluge:rolling") t.Run("HTTP endpoint test", func(t *testing.T) { testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8112", }, &testhelpers.ContainerConfig{ Env: map[string]string{ "DELUGE_BIN": "deluge-web", }, }, ) }) } ``` -------------------------------- ### Pass nil ContainerConfig when no configuration is needed Source: https://github.com/home-operations/containers/blob/main/_autodocs/types.md When no specific environment variables or configurations are required for a container test, pass nil for the ContainerConfig parameter. ```go testhelpers.TestFileExists(t, image, "/etc/app/config.yml", nil) ``` -------------------------------- ### Define ContainerConfig with multiple environment variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/types.md Configure multiple environment variables for a container using ContainerConfig. This is useful for setting up application modes, logging levels, or worker counts. ```go config := &testhelpers.ContainerConfig{ Env: map[string]string{ "LOG_LEVEL": "debug", "APP_MODE": "test", "MAX_WORKERS": "4", }, } testhelpers.TestHTTPEndpoint(t, image, httpConfig, config) ``` -------------------------------- ### Test HTTP endpoint with environment variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/types.md Combine HTTPTestConfig with ContainerConfig to test an HTTP endpoint while also setting environment variables for the container. This allows for dynamic configuration during testing. ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", Path: "/api/v1/status", } config := &testhelpers.ContainerConfig{ Env: map[string]string{ "LOG_LEVEL": "debug", "API_PORT": "8080", }, } testhelpers.TestHTTPEndpoint(t, image, httpConfig, config) ``` -------------------------------- ### Apply Container Configuration Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md The `applyContainerConfig` function applies a `ContainerConfig` to a testcontainers `Container` object, setting up necessary configurations. ```go func applyContainerConfig(ctx context.Context, container *testcontainers.GenericContainer, config ContainerConfig) error { if config.Env != nil { container.WithEnv(config.Env) } if config.Networks != nil { container.WithNetwork(config.Networks...) } return nil } ``` -------------------------------- ### View Container Logs During Test Execution Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md Enable verbose test output with `go test -v` to view container logs prefixed with `[stdout]` or `[stderr]`. ```bash go test -v -run TestName ``` -------------------------------- ### Override Default Container Image for Testing Source: https://github.com/home-operations/containers/blob/main/_autodocs/README.md Demonstrates how to override the default container image used for testing by setting the TEST_IMAGE environment variable. This allows testing with custom images without code changes. ```bash TEST_IMAGE=custom-registry/my-app:custom-tag go test ./apps/my-app/ ``` -------------------------------- ### Configure Complex String Values via Environment Variables Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Pass complex string values, including JSON and multiline strings, using environment variables. Ensure proper escaping for special characters. ```go config := &testhelpers.ContainerConfig{ Env: map[string]string{ "CUSTOM_JSON": `{"key":"value","nested":{"data":123}}`, "MULTILINE": "line1\nline2\nline3", }, } ``` -------------------------------- ### Test File Existence in Container Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md Tests if a specified file exists within a container. This is achieved by executing a 'test -f ' command inside the container. ```Go func TestFileExists(t *testing.T, image string, filePath string, config *ContainerConfig) { TestCommandSucceeds(t, image, config, "test", "-f", filePath) } ``` -------------------------------- ### Use Meaningful Port Numbers Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Utilize the actual service port defined in the Dockerfile for accurate testing. Using incorrect ports can lead to false negatives. ```go // ✅ Good - uses actual service port from Dockerfile testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8123", // Home Assistant's default port }, nil) // ❌ Avoid - using wrong port testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8080", // Wrong port! }, nil) ``` -------------------------------- ### Set Default HTTP Status Code Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Configure the expected HTTP response status code. A zero value defaults to 200. ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", StatusCode: 0, // Will use 200 } ``` -------------------------------- ### Test Multi-Step Container Validation Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Perform multiple validations on a container image, such as checking file existence, command execution, and HTTP endpoints. This snippet composes several test helper functions. ```go func TestAppImage(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") // Verify structure testhelpers.TestFileExists(t, image, "/app/config.json", nil) // Verify binary works testhelpers.TestCommandSucceeds(t, image, nil, "/app/my-app", "--version") // Verify HTTP endpoint testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8080", Path: "/health", StatusCode: 200, }, nil) } ``` -------------------------------- ### Test Plex Media Server API Endpoint Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Tests a specific Plex API endpoint, verifying container startup, service binding to port 32400, and accessibility of the /web/index.html path. ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func Test(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/plex:rolling") testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "32400", Path: "/web/index.html", }, nil) } ``` -------------------------------- ### Environment-Driven Test Configuration Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Configures a test to run with specific environment variables set within the container, useful for feature flags or dynamic settings. ```go func TestWithFeatureFlag(t *testing.T) { config := &testhelpers.ContainerConfig{ Env: map[string]string{ "ENABLE_FEATURE_X": "true", }, } testhelpers.TestFileExists(t, image, "/etc/feature-x.marker", config) } ``` -------------------------------- ### Test HTTP Endpoint Source: https://github.com/home-operations/containers/blob/main/_autodocs/INDEX.md Tests an HTTP endpoint within a container. Specify the port, path, and optionally provide a configuration object. ```go testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8080", Path: "/health", }, nil) ``` -------------------------------- ### Set Custom HTTP Status Codes Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Configure common alternative HTTP status codes for testing various responses. ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", StatusCode: 201, // Created } ``` ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", StatusCode: 202, // Accepted } ``` ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", StatusCode: 204, // No Content } ``` ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", StatusCode: 301, // Moved Permanently } ``` ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", StatusCode: 404, // Not Found (if testing error handling) } ``` ```go httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", StatusCode: 500, // Internal Server Error (if testing error handling) } ``` -------------------------------- ### Log Consumer Implementation Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md Implements the testcontainers log consumer interface to forward container logs to test output. Ensures all container output appears in test logs for easier debugging. ```go type tLogConsumer struct{ t *testing.T } func (c *tLogConsumer) Accept(l testcontainers.Log) { c.t.Logf("[%s] %s", l.LogType, l.Content) } ``` -------------------------------- ### Test Command Execution Success in Container Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Ensures a command runs successfully inside a container with an exit code of 0. This is useful for verifying scripts or application startup. The function automatically manages container cleanup. ```go func TestCommandSucceeds(t *testing.T, image string, config *ContainerConfig, entrypoint string, args ...string) ``` ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func TestBusyboxVersion(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/busybox:rolling") testhelpers.TestCommandSucceeds(t, image, nil, "/bin/busybox", "--list") } ``` ```go func TestPythonScript(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/python-app:rolling") testhelpers.TestCommandSucceeds(t, image, nil, "python", "-m", "compileall", "/app") } ``` ```go func TestCommandWithEnv(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") config := &testhelpers.ContainerConfig{ Env: map[string]string{ "APP_MODE": "test", "DEBUG": "true", }, } testhelpers.TestCommandSucceeds(t, image, config, "/app/validate-config.sh") } ``` -------------------------------- ### Set Environment Variables for Container Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md The Env field in ContainerConfig accepts a map of string key-value pairs for environment variables. Keys are case-sensitive names, and values are their string representations. ```go Env: map[string]string{ "VARIABLE_NAME": "value", "ANOTHER_VAR": "another_value", } ``` -------------------------------- ### Set Custom HTTP Timeout Source: https://github.com/home-operations/containers/blob/main/_autodocs/configuration.md Configure custom timeout values for the HTTP wait strategy using `time.Duration`. ```go import "time" httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", Timeout: 10 * time.Second, } ``` ```go import "time" httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", Timeout: 30 * time.Second, } ``` ```go import "time" httpConfig := testhelpers.HTTPTestConfig{ Port: "8080", Timeout: 5 * time.Minute, } ``` -------------------------------- ### Test Home Assistant HTTP Endpoint Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md Tests if the Home Assistant HTTP API is accessible on the default port 8123. Verifies container startup, service binding, and a 200 response on the default path. ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func Test(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/home-assistant:rolling") testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8123", }, nil) } ``` -------------------------------- ### GetTestImage Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Returns the container image to test, either from the TEST_IMAGE environment variable or falls back to a provided default image. ```APIDOC ## GetTestImage ### Description Returns the container image to test, either from the `TEST_IMAGE` environment variable or falls back to a provided default image. ### Function Signature ```go func GetTestImage(defaultImage string) string ``` ### Parameters #### Path Parameters - **defaultImage** (string) - Required - Default image URI to use if TEST_IMAGE environment variable is not set ### Returns - **string** - The image URI from TEST_IMAGE env var or the provided default ### Usage Example ```go package main import ( t "testing" "github.com/home-operations/containers/testhelpers" ) func Test(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/busybox:rolling") // image will be "ghcr.io/home-operations/busybox:rolling" // unless TEST_IMAGE environment variable is set } ``` ``` -------------------------------- ### Test Command Execution in a Container Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md The `TestCommandSucceeds` function executes a specified command within the container and asserts that it exits with a zero status code, indicating success. ```go func TestCommandSucceeds(ctx context.Context, cmd testcontainers.ContainerCommand, config ContainerConfig) error { image := GetTestImage() container, err := testcontainers.GenericContainerStart(ctx, testcontainers.GenericContainerRequest{ Image: image, ContainerConfig: testcontainers.ContainerConfig{ Env: config.Env, Networks: config.Networks, }, Reuse: true, }) if err != nil { return fmt.Errorf("failed to start container: %w", err) } defer container.Terminate(ctx) _, err = container.Exec(ctx, cmd) if err != nil { return fmt.Errorf("command failed: %w", err) } return assertExitZero(ctx, container) } ``` -------------------------------- ### TestFileExists Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Tests that a specific file exists inside the container. It runs the `test -f` command and asserts that the file is present. The container is automatically cleaned up after the test. ```APIDOC ## TestFileExists ### Description Tests that a specific file exists inside the container. It runs the `test -f` command and asserts that the file is present. The container is automatically cleaned up after the test. ### Function Signature ```go func TestFileExists(t *testing.T, image string, filePath string, config *ContainerConfig) ``` ### Parameters #### Path Parameters - **t** (*testing.T) - Required - The testing context. - **image** (string) - Required - Container image URI to test. - **filePath** (string) - Required - Absolute path to the file inside the container. - **config** (*ContainerConfig) - Optional - Optional container configuration. ### Return Type None. The function asserts internally and fails the test if the file does not exist. ### Usage Example ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func TestConfigFileExists(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") testhelpers.TestFileExists(t, image, "/etc/my-app/config.yml", nil) } ``` ``` -------------------------------- ### Assert Container Exits with Zero Status Source: https://github.com/home-operations/containers/blob/main/_autodocs/module-reference.md The `assertExitZero` function checks if a container has exited successfully with a status code of zero. It logs an error if the exit code is non-zero. ```go func assertExitZero(ctx context.Context, container *testcontainers.GenericContainer) error { exitCode, err := container.Exec(ctx, testcontainers.ContainerCommand{Path: "true"}) if err != nil { return fmt.Errorf("failed to execute command: %w", err) } if exitCode != 0 { return fmt.Errorf("container exited with non-zero status: %d", exitCode) } return nil } ``` -------------------------------- ### Validate Container Structure Source: https://github.com/home-operations/containers/blob/main/_autodocs/README.md Checks for the presence of critical files within a container image, such as executables and configuration files. ```go func TestImageStructure(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/app:rolling") // Verify important files exist testhelpers.TestFileExists(t, image, "/app/main", nil) testhelpers.TestFileExists(t, image, "/etc/app/config.yaml", nil) } ``` -------------------------------- ### Test Specific API Paths Source: https://github.com/home-operations/containers/blob/main/_autodocs/examples.md When available, test specific API endpoints or health check paths for more meaningful validation. Testing the root path may work but is less informative. ```go // ✅ Good - tests a real API endpoint testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "32400", Path: "/web/index.html", }, nil) // ✅ Also good - tests the health check endpoint testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "3002", Path: "/api/health", StatusCode: 200, }, nil) // ⚠️ Works but less meaningful - just tests root testhelpers.TestHTTPEndpoint(t, image, testhelpers.HTTPTestConfig{ Port: "8080", }, nil) ``` -------------------------------- ### TestCommandSucceeds Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Tests that a command runs successfully inside the container with an exit code of 0. It sets the entrypoint, passes arguments, and validates the exit status. The container is automatically cleaned up after the test. ```APIDOC ## TestCommandSucceeds ### Description Tests that a command runs successfully inside the container with an exit code of 0. It sets the entrypoint, passes arguments, and validates the exit status. The container is automatically cleaned up after the test. ### Function Signature ```go func TestCommandSucceeds(t *testing.T, image string, config *ContainerConfig, entrypoint string, args ...string) ``` ### Parameters #### Path Parameters - **t** (*testing.T) - Required - The testing context. - **image** (string) - Required - Container image URI to test. - **config** (*ContainerConfig) - Optional - Optional container configuration. - **entrypoint** (string) - Required - Command or binary to execute. - **args** (...string) - Optional - Command arguments. ### Return Type None. The function asserts internally and fails the test if the command exits with a non-zero code. ### Usage Example ```go package main import ( testing "github.com/home-operations/containers/testhelpers" ) func TestBusyboxVersion(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/busybox:rolling") testhelpers.TestCommandSucceeds(t, image, nil, "/bin/busybox", "--list") } ``` ``` -------------------------------- ### TestHTTPEndpoint Source: https://github.com/home-operations/containers/blob/main/_autodocs/api-reference/testhelpers.md Tests that an HTTP endpoint in a container is accessible and returns the expected status code. Automatically handles container startup, port exposure, and cleanup. ```APIDOC ## TestHTTPEndpoint ### Description Tests that an HTTP endpoint in a container is accessible and returns the expected status code. Automatically handles container startup, port exposure, and cleanup. ### Function Signature ```go func TestHTTPEndpoint(t *testing.T, image string, httpConfig HTTPTestConfig, containerConfig *ContainerConfig) ``` ### Parameters #### Path Parameters - **t** (*testing.T) - Required - The testing context (from `func Test(t *testing.T)`) - **image** (string) - Required - Container image URI to test - **httpConfig** (HTTPTestConfig) - Required - HTTP endpoint configuration (port, path, expected status code) - **containerConfig** (*ContainerConfig) - Optional - Optional container configuration (environment variables, etc.) ### Return Type None. The function asserts internally and fails the test if the HTTP endpoint is not accessible or returns an unexpected status code. ### HTTPTestConfig Fields #### Request Body - **Port** (string) - Required - Container port number (e.g., "8080") - **Path** (string) - Optional - HTTP path to test (e.g., "/health") - **StatusCode** (int) - Optional - Expected HTTP status code - **Timeout** (time.Duration) - Optional - Startup timeout for HTTP wait strategy ### Usage Example ```go package main import ( t "testing" t "time" "github.com/home-operations/containers/testhelpers" ) func TestHomeAssistantHTTP(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/home-assistant:rolling") httpConfig := testhelpers.HTTPTestConfig{ Port: "8123", Path: "/api/", StatusCode: 200, Timeout: 30 * time.Second, } testhelpers.TestHTTPEndpoint(t, image, httpConfig, nil) } ``` ### Usage Example with Container Config ```go func TestWithEnvironment(t *testing.T) { image := testhelpers.GetTestImage("ghcr.io/home-operations/my-app:rolling") httpConfig := testhelpers.HTTPTestConfig{ Port: "3000", Path: "/health", } containerConfig := &testhelpers.ContainerConfig{ Env: map[string]string{ "DEBUG": "true", "LOG_LEVEL": "info", }, } testhelpers.TestHTTPEndpoint(t, image, httpConfig, containerConfig) } ``` ### Behavior - Creates a container from the provided image - Exposes the specified port - Waits for the port to be listening - Waits for the HTTP endpoint to respond with the expected status code - Automatically cleans up the container after the test - Logs all container output for debugging test failures ```