or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdindex.mdjdbc-url-pattern.mdpostgresql-container.mdpostgresql-variants.mdr2dbc-support.md
tile.json

postgresql-container.mddocs/

PostgreSQL Container

The PostgreSQLContainer class provides full lifecycle management for PostgreSQL database containers in Java integration tests. It automatically handles container startup, port mapping, connection management, and cleanup.

Complete API Reference

PostgreSQLContainer Class

Main container class for managing PostgreSQL instances in Docker containers.

/**
 * Testcontainers implementation for PostgreSQL.
 * Supported images: postgres, pgvector/pgvector
 * Exposed ports: 5432
 *
 * @param <SELF> Self-referential generic type for fluent API
 */
public class PostgreSQLContainer<SELF extends PostgreSQLContainer<SELF>>
    extends JdbcDatabaseContainer<SELF> {

    // Constants
    public static final String NAME = "postgresql";
    public static final String IMAGE = "postgres";
    public static final String DEFAULT_TAG = "9.6.12";
    public static final Integer POSTGRESQL_PORT = 5432;

    /**
     * Create a PostgreSQL container with the default image (postgres:9.6.12)
     * @deprecated Use PostgreSQLContainer(String) or PostgreSQLContainer(DockerImageName) instead
     */
    @Deprecated
    public PostgreSQLContainer();

    /**
     * Create a PostgreSQL container with a specific Docker image name
     * @param dockerImageName Full Docker image name (e.g., "postgres:15")
     * @throws IllegalArgumentException if dockerImageName is null or empty
     */
    public PostgreSQLContainer(String dockerImageName);

    /**
     * Create a PostgreSQL container with a DockerImageName object
     * @param dockerImageName DockerImageName instance
     * @throws IllegalArgumentException if dockerImageName is null
     */
    public PostgreSQLContainer(DockerImageName dockerImageName);
}

Usage Examples:

import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.utility.DockerImageName;

// Using default image (deprecated)
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>();

// Using specific version
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");

// Using DockerImageName for better validation
DockerImageName imageName = DockerImageName.parse("postgres:15");
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(imageName);

// Using pgvector variant
PostgreSQLContainer<?> pgvector = new PostgreSQLContainer<>("pgvector/pgvector:pg16");

// Using PostGIS image with compatibility check
DockerImageName postgisImage = DockerImageName
    .parse("postgis/postgis:16-3.4")
    .asCompatibleSubstituteFor("postgres");
PostgreSQLContainer<?> postgis = new PostgreSQLContainer<>(postgisImage);

Error Handling for Image Names:

// Validate image name before use
try {
    DockerImageName imageName = DockerImageName.parse("postgres:15")
        .asCompatibleSubstituteFor("postgres");
    PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(imageName);
} catch (IllegalArgumentException e) {
    // Handle invalid image name
    System.err.println("Invalid Docker image: " + e.getMessage());
    throw e;
}

// Handle null image name
try {
    PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>((String) null);
} catch (IllegalArgumentException e) {
    // Image name cannot be null
}

// Handle empty image name
try {
    PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("");
} catch (IllegalArgumentException e) {
    // Image name cannot be empty
}

Connection Information Methods

Methods for retrieving database connection details after the container has started. These methods are only valid after start() has been called.

/**
 * Get the PostgreSQL JDBC driver class name
 * @return "org.postgresql.Driver"
 * @throws IllegalStateException if container is not started
 */
public String getDriverClassName();

/**
 * Get the JDBC connection URL for the running PostgreSQL container
 * Includes host, mapped port, database name, and any URL parameters
 * @return JDBC URL in format: jdbc:postgresql://host:port/database?params
 * @throws IllegalStateException if container is not started
 */
public String getJdbcUrl();

/**
 * Get the configured database name
 * @return Database name (default: "test")
 */
public String getDatabaseName();

/**
 * Get the configured username
 * @return Username (default: "test")
 */
public String getUsername();

/**
 * Get the configured password
 * @return Password (default: "test")
 */
public String getPassword();

/**
 * Get the test query string used to verify database connectivity
 * @return "SELECT 1"
 */
public String getTestQueryString();

Usage Examples:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();

    // Get connection details
    String jdbcUrl = postgres.getJdbcUrl();
    // Example: "jdbc:postgresql://localhost:54321/test?loggerLevel=OFF"

    String username = postgres.getUsername();  // "test"
    String password = postgres.getPassword();  // "test"
    String database = postgres.getDatabaseName();  // "test"
    String driver = postgres.getDriverClassName();  // "org.postgresql.Driver"
    String testQuery = postgres.getTestQueryString();  // "SELECT 1"

    // Use with JDBC
    try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
        // Execute test query
        try (Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(testQuery)) {
            rs.next();
            int result = rs.getInt(1);  // result is 1
        }
    }
}

Validating Connection Information:

try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();
    
    // Verify connection details are available
    assert postgres.getJdbcUrl() != null && !postgres.getJdbcUrl().isEmpty();
    assert postgres.getUsername() != null && !postgres.getUsername().isEmpty();
    assert postgres.getPassword() != null && !postgres.getPassword().isEmpty();
    assert postgres.getDatabaseName() != null && !postgres.getDatabaseName().isEmpty();
    assert postgres.getDriverClassName().equals("org.postgresql.Driver");
    assert postgres.getTestQueryString().equals("SELECT 1");
    
    // Test connection
    try (Connection conn = DriverManager.getConnection(
            postgres.getJdbcUrl(),
            postgres.getUsername(),
            postgres.getPassword())) {
        assert conn.isValid(5);  // Verify connection is valid
        
        // Verify database name
        assert conn.getCatalog().equals(postgres.getDatabaseName());
    }
}

// Error: Calling getJdbcUrl() before start()
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");
try {
    String url = postgres.getJdbcUrl();  // Throws IllegalStateException
} catch (IllegalStateException e) {
    // Container must be started first
}

Configuration Methods

Fluent API methods for configuring the PostgreSQL container before starting it. All methods return SELF for method chaining.

/**
 * Configure the database name to create on container startup
 * @param databaseName Database name (must not be null)
 * @return this for method chaining
 * @throws IllegalArgumentException if databaseName is null
 */
public SELF withDatabaseName(String databaseName);

/**
 * Configure the username for database access
 * @param username Username (must not be null)
 * @return this for method chaining
 * @throws IllegalArgumentException if username is null
 */
public SELF withUsername(String username);

/**
 * Configure the password for database access
 * @param password Password (must not be null)
 * @return this for method chaining
 * @throws IllegalArgumentException if password is null
 */
public SELF withPassword(String password);

Usage Examples:

PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
    .withDatabaseName("myapp")
    .withUsername("appuser")
    .withPassword("secret123");

postgres.start();

String jdbcUrl = postgres.getJdbcUrl();
// "jdbc:postgresql://localhost:54321/myapp?loggerLevel=OFF"

// Verify configuration
assert postgres.getDatabaseName().equals("myapp");
assert postgres.getUsername().equals("appuser");
assert postgres.getPassword().equals("secret123");

Configuration Validation:

// Validate configuration before starting
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
    .withDatabaseName("myapp")
    .withUsername("appuser")
    .withPassword("secret123");

// Verify configuration is set
assert "myapp".equals(postgres.getDatabaseName());
assert "appuser".equals(postgres.getUsername());
assert "secret123".equals(postgres.getPassword());

postgres.start();

// Verify configuration was applied
assert "myapp".equals(postgres.getDatabaseName());
assert "myapp".equals(postgres.getDatabaseName());  // Still accessible after start

// Error: null database name
try {
    postgres.withDatabaseName(null);
} catch (IllegalArgumentException e) {
    // Database name cannot be null
}

Inherited Lifecycle Methods

Methods inherited from JdbcDatabaseContainer and GenericContainer for managing container lifecycle.

/**
 * Start the PostgreSQL container
 * Pulls the Docker image if needed, creates and starts the container,
 * waits for PostgreSQL to be ready, and sets up port mappings
 * @throws ContainerLaunchException if container fails to start
 * @throws TimeoutException if container startup exceeds timeout
 */
public void start();

/**
 * Stop the PostgreSQL container
 * Stops and removes the container, freeing resources
 */
public void stop();

/**
 * Check if the container is currently running
 * @return true if container is running, false otherwise
 */
public boolean isRunning();

/**
 * Check if the container has been created
 * @return true if container has been created, false otherwise
 */
public boolean isCreated();

/**
 * Close the container (same as stop())
 * Implements AutoCloseable for try-with-resources
 */
public void close();

Usage Examples:

// Manual lifecycle management
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");
postgres.start();
try {
    // Use the database
    String jdbcUrl = postgres.getJdbcUrl();
    assert postgres.isRunning();
    assert postgres.isCreated();
    // ...
} finally {
    postgres.stop();
    assert !postgres.isRunning();
}

// Automatic lifecycle with try-with-resources (recommended)
try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();
    // Container automatically stopped when exiting try block
}

// Error: Starting already started container
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");
postgres.start();
try {
    postgres.start();  // May throw IllegalStateException or be a no-op
} catch (IllegalStateException e) {
    // Container already started
}

Error Handling During Startup:

PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");

try {
    postgres.start();
} catch (ContainerLaunchException e) {
    // Container failed to start
    System.err.println("Failed to start container: " + e.getMessage());
    System.err.println("Container logs: " + postgres.getLogs());
    
    // Check common issues
    if (e.getMessage().contains("timeout")) {
        System.err.println("Consider increasing startup timeout");
    } else if (e.getMessage().contains("image")) {
        System.err.println("Check Docker image availability");
    } else if (e.getMessage().contains("port")) {
        System.err.println("Port conflict detected");
    }
    
    throw e;
} catch (TimeoutException e) {
    // Startup timeout exceeded
    System.err.println("Container startup timeout: " + e.getMessage());
    System.err.println("Consider increasing withStartupTimeoutSeconds()");
    throw e;
} catch (Exception e) {
    // Other errors
    System.err.println("Unexpected error: " + e.getMessage());
    throw e;
}

Verifying Container State:

try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    // Before start
    assert !postgres.isRunning();
    assert !postgres.isCreated();
    
    postgres.start();
    
    // After start
    assert postgres.isRunning() : "Container should be running";
    assert postgres.isCreated() : "Container should be created";
    
    // Verify container is healthy
    try (Connection conn = DriverManager.getConnection(
            postgres.getJdbcUrl(),
            postgres.getUsername(),
            postgres.getPassword())) {
        assert conn.isValid(5) : "Connection should be valid";
    }
    
    postgres.stop();
    
    // After stop
    assert !postgres.isRunning();
}

Inherited Port and Network Methods

Methods for accessing container port and network information.

/**
 * Get the list of ports exposed by this container
 * @return List containing POSTGRESQL_PORT (5432)
 * @throws IllegalStateException if container is not started
 */
public List<Integer> getExposedPorts();

/**
 * Get the set of port numbers used for liveness checks
 * @return Set containing the mapped PostgreSQL port
 * @throws IllegalStateException if container is not started
 */
public Set<Integer> getLivenessCheckPortNumbers();

/**
 * Get the host port mapped to the container's PostgreSQL port
 * @param originalPort Container port (typically POSTGRESQL_PORT)
 * @return Host port number
 * @throws IllegalStateException if container is not started
 * @throws IllegalArgumentException if originalPort is not exposed
 */
public Integer getMappedPort(int originalPort);

/**
 * Get the container host address
 * @return Host address (typically "localhost" or Docker host IP)
 * @throws IllegalStateException if container is not started
 */
public String getHost();

/**
 * Get the container ID
 * @return Docker container ID
 * @throws IllegalStateException if container is not started
 */
public String getContainerId();

/**
 * Get the container name
 * @return Docker container name
 * @throws IllegalStateException if container is not started
 */
public String getContainerName();

Usage Examples:

try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();

    // Get exposed ports
    List<Integer> exposedPorts = postgres.getExposedPorts();
    // [5432]
    assert exposedPorts.contains(PostgreSQLContainer.POSTGRESQL_PORT);

    // Get mapped port
    Integer mappedPort = postgres.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT);
    // e.g., 54321 (dynamically assigned)
    assert mappedPort != null;
    assert mappedPort > 1024 && mappedPort < 65536;

    // Get host
    String host = postgres.getHost();
    // "localhost" or Docker host IP
    assert host != null && !host.isEmpty();

    // Get container ID
    String containerId = postgres.getContainerId();
    assert containerId != null && !containerId.isEmpty();

    // Get container name
    String containerName = postgres.getContainerName();
    assert containerName != null && !containerName.isEmpty();

    // Build connection URL manually
    String url = String.format(
        "jdbc:postgresql://%s:%d/%s",
        host,
        mappedPort,
        postgres.getDatabaseName()
    );
    assert url.equals(postgres.getJdbcUrl());
}

Port Validation:

try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();
    
    // Verify port mapping
    Integer mappedPort = postgres.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT);
    assert mappedPort != null : "Port should be mapped";
    assert mappedPort > 1024 : "Port should be above privileged range";
    assert mappedPort < 65536 : "Port should be valid";
    
    // Verify port is accessible
    try (Socket socket = new Socket(postgres.getHost(), mappedPort)) {
        assert socket.isConnected() : "Port should be accessible";
    }
    
    // Error: Requesting unmapped port
    try {
        postgres.getMappedPort(8080);  // Port 8080 is not exposed
    } catch (IllegalArgumentException e) {
        // Port not exposed
    }
}

Inherited Container Information Methods

Methods for accessing container logs, executing commands, and getting container metadata.

/**
 * Get all container logs as a string
 * @return Container logs
 * @throws IllegalStateException if container is not started
 */
public String getLogs();

/**
 * Get container logs filtered by output type
 * @param outputType Output type filter (STDOUT, STDERR, or END)
 * @return Filtered container logs
 * @throws IllegalStateException if container is not started
 */
public String getLogs(OutputFrame.OutputType outputType);

/**
 * Execute a command in the running container
 * @param command Command and arguments to execute
 * @return Execution result with exit code, stdout, and stderr
 * @throws IllegalStateException if container is not started
 * @throws UnsupportedOperationException if container doesn't support exec
 */
public ExecResult execInContainer(String... command);

/**
 * Execute a command in the running container as a specific user
 * @param user User to execute command as
 * @param command Command and arguments to execute
 * @return Execution result with exit code, stdout, and stderr
 * @throws IllegalStateException if container is not started
 */
public ExecResult execInContainer(String user, String... command);

/**
 * Execute a command in the running container with timeout
 * @param timeout Maximum time to wait for command completion
 * @param command Command and arguments to execute
 * @return Execution result with exit code, stdout, and stderr
 * @throws IllegalStateException if container is not started
 * @throws TimeoutException if command execution exceeds timeout
 */
public ExecResult execInContainer(Duration timeout, String... command);

/**
 * Get the Docker image name used by this container
 * @return Docker image name
 */
public String getDockerImageName();

Usage Examples:

try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();
    
    // Get all logs
    String logs = postgres.getLogs();
    assert logs != null;
    assert logs.contains("database system is ready");
    
    // Get filtered logs
    String stdout = postgres.getLogs(OutputFrame.OutputType.STDOUT);
    String stderr = postgres.getLogs(OutputFrame.OutputType.STDERR);
    
    // Execute command in container
    ExecResult result = postgres.execInContainer("psql", "-U", "test", "-d", "test", "-c", "SELECT version()");
    assert result.getExitCode() == 0;
    assert result.getStdout().contains("PostgreSQL");
    
    // Execute as specific user
    ExecResult result2 = postgres.execInContainer("postgres", "psql", "-c", "SELECT 1");
    assert result2.getExitCode() == 0;
    
    // Execute with timeout
    ExecResult result3 = postgres.execInContainer(
        Duration.ofSeconds(10),
        "psql", "-U", "test", "-d", "test", "-c", "SELECT pg_sleep(5)"
    );
    assert result3.getExitCode() == 0;
    
    // Get Docker image name
    String imageName = postgres.getDockerImageName();
    assert imageName.equals("postgres:15");
}

Default Behavior

Default Configuration Values

When not explicitly configured, the PostgreSQL container uses these defaults:

  • Database Name: "test"
  • Username: "test"
  • Password: "test"
  • Port: 5432 (container port, mapped to random host port)
  • Default Image: postgres:9.6.12 (when using deprecated no-arg constructor)
  • Startup Timeout: 60 seconds
  • Connection Timeout: 120 seconds (inherited from base class)

Default Command

The container starts PostgreSQL with the following command:

postgres -c fsync=off

The fsync=off option disables filesystem synchronization for better performance in test environments. This is safe for testing but should never be used in production.

Customizing the command:

// Override default command
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
    .withCommand("postgres -c fsync=off -c synchronous_commit=off");

// Reset to default
PostgreSQLContainer<?> postgres2 = new PostgreSQLContainer<>("postgres:15")
    .withCommand("postgres -c max_connections=200")
    .withCommand();  // Reset to default

Wait Strategy

The container waits for PostgreSQL to be ready by monitoring log output for the message:

database system is ready to accept connections

This message must appear twice (startup and recovery completion), with a timeout of 60 seconds.

Custom Wait Strategy:

import org.testcontainers.containers.wait.strategy.Wait;
import java.time.Duration;

PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
    .waitingFor(Wait.forLogMessage(".*database system is ready to accept connections.*", 2)
        .withStartupTimeout(Duration.ofSeconds(120)));

// Custom wait with health check
PostgreSQLContainer<?> postgres2 = new PostgreSQLContainer<>("postgres:15")
    .waitingFor(Wait.forHealthcheck()
        .withStartupTimeout(Duration.ofSeconds(180)));

Automatic Configuration

The container automatically:

  • Sets POSTGRES_DB environment variable to the configured database name
  • Sets POSTGRES_USER environment variable to the configured username
  • Sets POSTGRES_PASSWORD environment variable to the configured password
  • Adds loggerLevel=OFF to JDBC URL to reduce PostgreSQL driver logging noise
  • Maps container port 5432 to a random available host port
  • Waits for PostgreSQL to be ready before start() returns

Complete Example

import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.utility.DockerImageName;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class DatabaseTest {
    public void testDatabaseOperations() throws Exception {
        // Create container with custom configuration
        DockerImageName image = DockerImageName.parse("postgres:15");
        try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(image)
                .withDatabaseName("testdb")
                .withUsername("testuser")
                .withPassword("testpass")) {

            // Start container
            postgres.start();

            // Get connection details
            String jdbcUrl = postgres.getJdbcUrl();
            String username = postgres.getUsername();
            String password = postgres.getPassword();

            // Connect to database
            try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
                // Create table
                try (Statement stmt = conn.createStatement()) {
                    stmt.execute("CREATE TABLE users (id SERIAL PRIMARY KEY, name VARCHAR(100))");
                    stmt.execute("INSERT INTO users (name) VALUES ('Alice'), ('Bob')");
                }

                // Query data
                try (Statement stmt = conn.createStatement();
                     ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM users")) {
                    rs.next();
                    int count = rs.getInt(1);
                    // count is 2
                }
            }
        } // Container automatically stopped and removed
    }
}

Resource Management

Proper Cleanup

Always use try-with-resources to ensure containers are properly cleaned up:

// Correct: Automatic cleanup
try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();
    // Use container
} // Container automatically stopped

// Incorrect: May leak resources
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");
postgres.start();
// If exception occurs before stop(), container may not be cleaned up
postgres.stop();

Container State Checking

try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();
    
    // Check container state
    if (!postgres.isRunning()) {
        throw new IllegalStateException("Container is not running");
    }
    
    // Verify container is ready
    try (Connection conn = DriverManager.getConnection(
            postgres.getJdbcUrl(),
            postgres.getUsername(),
            postgres.getPassword())) {
        // Container is ready
    }
}

Troubleshooting

Container Won't Start

PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");

try {
    postgres.start();
} catch (Exception e) {
    // Get diagnostic information
    System.err.println("Error: " + e.getMessage());
    System.err.println("Container ID: " + postgres.getContainerId());
    System.err.println("Container logs:");
    System.err.println(postgres.getLogs());
    
    // Check Docker availability
    // Check disk space
    // Check port availability
}

Connection Failures

try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();
    
    // Verify connection details
    String jdbcUrl = postgres.getJdbcUrl();
    System.out.println("JDBC URL: " + jdbcUrl);
    System.out.println("Host: " + postgres.getHost());
    System.out.println("Port: " + postgres.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT));
    
    // Test connection with retry
    int maxRetries = 3;
    for (int i = 0; i < maxRetries; i++) {
        try (Connection conn = DriverManager.getConnection(
                jdbcUrl,
                postgres.getUsername(),
                postgres.getPassword())) {
            // Connection successful
            break;
        } catch (SQLException e) {
            if (i == maxRetries - 1) {
                System.err.println("Connection failed after " + maxRetries + " attempts");
                System.err.println("Container logs: " + postgres.getLogs());
                throw e;
            }
            Thread.sleep(1000);  // Wait before retry
        }
    }
}

Debugging Container Issues

try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")) {
    postgres.start();
    
    // Get container information
    System.out.println("Container ID: " + postgres.getContainerId());
    System.out.println("Container name: " + postgres.getContainerName());
    System.out.println("Docker image: " + postgres.getDockerImageName());
    System.out.println("Container logs (last 100 lines):");
    System.out.println(postgres.getLogs());
    
    // Get network information
    System.out.println("Host: " + postgres.getHost());
    System.out.println("Mapped port: " + postgres.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT));
    
    // Execute diagnostic commands
    ExecResult version = postgres.execInContainer("psql", "-U", "test", "-d", "test", "-c", "SELECT version()");
    System.out.println("PostgreSQL version: " + version.getStdout());
}