Documentation ¶
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func LoadScenario ¶
func LoadScenario(ctx context.Context, db ExecerContext, filename string) error
LoadScenario reads a YAML "scenario" file and uses it to populate the given db. Top-level keys in the YAML are treated as table names having repeated rows, where keys on each row are column names. For example:
users: - id: 1 name: Alice email: alice@example.com - id: 2 name: Bob email: bob@example.com posts: - user_id: 1 title: Hello, world! - user_id: 2 title: Goodbye, world! is_draft: true
The above would populate the users and posts tables. Fields that are missing from the YAML are left out of the INSERT statement, and so are populated with the default value for that column.
func RunMigrations ¶
func RunMigrations(ctx context.Context, db ExecerContext, migrationDir string) error
RunMigrations reads all of the files matching *.up.sql in migrationDir and executes them in lexicographical order against the provided db. A typical convention is to use a numeric prefix for each new migration, e.g.:
001_create_users.up.sql 002_create_posts.up.sql 003_create_comments.up.sql
Note that this function does not check whether the migration has already been run. Its primary purpose is to initialize a test database.
Types ¶
type ExecerContext ¶
type ExecerContext interface {
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
}
ExecerContext is an interface used by MustExecContext and LoadFileContext
type Option ¶ added in v1.0.6
type Option func(*PostgresContainerConfig)
PostgresContainerConfig setter
func WithDBName ¶ added in v1.0.6
WithDBName sets the DBName field of the PostgresContainerConfig
func WithDBPassword ¶ added in v1.0.6
WithDBPassword sets the DBPassword field of the PostgresContainerConfig
func WithDBUser ¶ added in v1.0.6
WithDBUser sets the DBUser field of the PostgresContainerConfig
func WithSSLMode ¶ added in v1.0.6
WithSSLMode sets the SSLMode field of the PostgresContainerConfig
func WithTimeZone ¶ added in v1.0.6
WithTimeZone sets the TimeZone field of the PostgresContainerConfig
type PostgresContainer ¶
type PostgresContainer struct {
// contains filtered or unexported fields
}
PostgresContainer is a Docker container running Postgres. It can be used to cheaply start a throwaway Postgres instance for testing.
Example ¶
ctx := context.Background() // Create a new container container, err := StartPostgresContainer(ctx, "15") if err != nil { log.Fatalf("could not start container: %v", err) } defer container.Shutdown(ctx) // Get the connection string connStr := container.ConnectionString() db, err := sql.Open("pgx", connStr) if err != nil { container.Shutdown(ctx) log.Fatalf("could not open connection: %v", err) } if err := db.Ping(); err != nil { container.Shutdown(ctx) log.Fatalf("could not ping database: %v", err) } // Do something with the database row := db.QueryRowContext(ctx, "SELECT 2024") var result int if err := row.Scan(&result); err != nil { container.Shutdown(ctx) log.Fatalf("could not scan row: %v", err) } fmt.Println(result)
Output: 2024
func StartPostgresContainer ¶
func StartPostgresContainer( ctx context.Context, version string, options ...Option, ) (*PostgresContainer, error)
StartPostgresContainer starts a new Postgres Docker container. The version parameter is the tagged version of Postgres image to use, e.g. to use postgres:12 pass "12". Creation involes a few steps:
1. Pull the image if it isn't already cached locally 2. Start the container 3. Wait for Postgres to be healthy
Once created the container will be immediately usable. It should be stopped with the Shutdown method. The container will bind to a randomly available host port, and random password. The SQL connection string can be obtained with the ConnectionString method.
Container startup and shutdown together can take a few seconds (longer when the image has not yet been pulled.) This is generally too slow to initiate in each unit test so it's advisable to do setup and teardown once for a whole suite of tests. TestMain is one way to do this, however because of Golang issue 37206 1, panics in tests will immediately exit the process without giving you the opportunity to Shutdown, which results in orphaned containers lying around.
Another approach is to write a single test that starts and stops the container and then run sub-tests within there. The testify 2 suite package provides a good way to structure these kinds of tests:
type ExampleTestSuite struct { suite.Suite } func (s *ExampleTestSuite) TestExample() { // test something } func TestExampleTestSuite(t *testing.T) { pg, _ := sqltestutil.StartPostgresContainer(context.Background(), "12") defer pg.Shutdown(ctx) suite.Run(t, &ExampleTestSuite{}) }
func (*PostgresContainer) ConnectionString ¶
func (c *PostgresContainer) ConnectionString() string
ConnectionString returns a connection URL string that can be used to connect to the running Postgres container.
func (*PostgresContainer) ID ¶
func (c *PostgresContainer) ID() string
ID returns the Docker container ID of the running Postgres container.
type PostgresContainerConfig ¶ added in v1.0.6
type PostgresContainerConfig struct { // DBName is to set POSTGRES_DB environment variable DBName string // DBUser is to set POSTGRES_USER environment variable DBUser string // DBPassword is to set POSTGRES_PASSWORD environment variable DBPassword string // TimeZone is to set TZ environment variable. It's also used to set timezone query parameter in the connection string TimeZone string // SSLMode is to set sslmode query parameter in the connection string SSLMode string }
PostgresContainerConfig is a configuration struct for PostgresContainer. It's used to pass configuration options to the StartPostgresContainer
type Suite ¶
type Suite struct { suite.Suite // Context is a required field for constructing a Suite, and is used for // database operations within a suite. It's public because it's convenient to // have access to it in tests. context.Context // DriverName is a required field for constructing a Suite, and is used to // connect to the underlying SQL database. DriverName string // DataSourceName is a required field for constructing a Suite, and is used to // connect to the underlying SQL database. DataSourceName string // contains filtered or unexported fields }
Suite is a testify suite 1 that provides a database connection for running tests against a SQL database. For each test that is run, a new transaction is started, and then rolled back at the end of the test so that each test can operate on a clean slate. Here's an example of how to use it:
type ExampleTestSuite struct { sqltestutil.Suite } func (s *ExampleTestSuite) TestExample() { _, err := s.Tx().Exec("INSERT INTO foo (bar) VALUES (?)", "baz") s.Assert().NoError(err) } func TestExampleTestSuite(t *testing.T) { suite.Run(t, &ExampleTestSuite{ Suite: sqltestutil.Suite{ Context: context.Background(), DriverName: "pgx", DataSourceName: "postgres://localhost:5432/example", }, }) }
func (*Suite) SetupSuite ¶
func (s *Suite) SetupSuite()
func (*Suite) TearDownSuite ¶
func (s *Suite) TearDownSuite()
func (*Suite) TearDownTest ¶
func (s *Suite) TearDownTest()