feat: reuse PostgreSQL container across tests#3018
feat: reuse PostgreSQL container across tests#3018
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughReplace per-test Postgres containers with a shared Docker Postgres instance and per-test databases; add a DockerClient wrapper and tests; introduce DB readiness and replica-sync helpers; initialize Goose migrations at package init; and adjust Postgres ping backoff construction. Changes
Sequence Diagram(s)sequenceDiagram
participant Test as Test code
participant Fixture as Postgres fixture
participant DockerClient as testutils.DockerClient
participant DockerEngine as Docker daemon
participant Postgres as Postgres container
participant DB as Per-test database
Test->>Fixture: RunPostgresTestContainer(t)
Fixture->>DockerClient: FindRunningContainer(name, image)
DockerClient->>DockerEngine: List/Inspect containers
alt container found
DockerEngine-->>DockerClient: InspectResponse
else not found
DockerClient->>DockerEngine: Pull image
DockerClient->>DockerEngine: Create & Start container
DockerEngine-->>DockerClient: InspectResponse
end
DockerClient-->>Fixture: host, port
Fixture->>Postgres: ExecCommand(createdb per-test DB)
Fixture->>DB: waitForDatabase(uri)
Fixture->>DB: waitForMigrationVersion(uri)
alt replica requested
Fixture->>DockerClient: RunContainer(replica)
Fixture->>Postgres: waitForPostgresReplicaSync(replicaURI)
end
Test->>Fixture: cleanup per-test DB (DROP DATABASE)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3018 +/- ##
==========================================
- Coverage 90.90% 90.81% -0.08%
==========================================
Files 193 194 +1
Lines 21348 21449 +101
==========================================
+ Hits 19404 19477 +73
- Misses 1287 1305 +18
- Partials 657 667 +10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
34f9d0c to
94793b9
Compare
94793b9 to
f691653
Compare
There was a problem hiding this comment.
Pull request overview
This PR improves test infrastructure performance by reusing a single PostgreSQL container across tests instead of creating new containers for each test invocation. The implementation uses per-test databases within the shared container to maintain isolation, achieving approximately 30% reduction in test execution time for PostgreSQL tests.
Changes:
- Added
DockerClientwrapper utility intestutilsfor managing Docker containers and images - Refactored PostgreSQL test fixture to implement container reuse with per-test database isolation
- Added
waitForDatabasehelper function to handle database readiness checks - Updated test container invocation from method-based to function-based approach
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/testutils/dockerclient.go | New Docker client wrapper with container/image management utilities |
| pkg/testutils/dockerclient_test.go | Comprehensive tests for Docker client functionality |
| pkg/testfixtures/storage/postgres.go | Refactored to reuse containers and maintain per-test database isolation |
| pkg/testfixtures/storage/readiness.go | New helper for database connectivity checks with backoff retry |
| pkg/testfixtures/storage/storage.go | Updated postgres container invocation to use new function-based API |
| pkg/storage/postgres/postgres.go | Minor refactoring of backoff policy initialization |
| CHANGELOG.md | Documented performance improvement in unreleased section |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
pkg/testfixtures/storage/postgres.go (2)
130-138: Template database readiness depends on bootstrap completion.The
waitForDatabaseon Line 131 only verifies TCP connectivity topostgresTemplateDB, but doesn't guarantee that migrations have completed. If a parallel test process finds the container mid-bootstrap (after container start but beforegoose.Upcompletes at Line 222), thecreatedbwill succeed but the template may lack schema, causing subsequent migration version checks to fail.Consider having the bootstrap process create a sentinel (e.g., a marker table or file) after migrations complete, and have consumers wait for that sentinel.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/testfixtures/storage/postgres.go` around lines 130 - 138, The current readiness check uses waitForDatabase(...) which only verifies TCP/connectivity to postgresTemplateDB before running createdb; instead add a post-bootstrap sentinel (e.g., a marker table or file) created after migrations complete in the bootstrap path (where goose.Up runs) and replace or augment the waitForDatabase call in this setup flow with a new waitForTemplateReady (or waitForSentinel) call that polls the sentinel via the same connection URI (use testCont.GetConnectionURI(true)) before running container.ExecOptions createdb; ensure the bootstrap code that runs goose.Up creates the sentinel and the test fixture uses that sentinel check so createdb only proceeds after migrations finish.
112-117: Potential race condition when multiple test binaries run in parallel.When multiple test processes (e.g., different packages running with
go test ./...) execute simultaneously, they may all observe "not found" fromFindRunningContainerand attempt to bootstrap containers concurrently. While each container gets a unique ULID suffix preventing name collisions, this defeats the container reuse goal and wastes resources.Consider adding a file-based lock or using Docker's container creation idempotently by catching "container already exists" errors and retrying the find operation.
💡 Suggested approach
dockerCont, found, err := docker.FindRunningContainer(t.Context(), "^"+postgresContainerPrefix, postgresImage) require.NoError(t, err, "find running postgres container") if !found { - dockerCont = bootstrapPostgresContainer(t, docker) + dockerCont, err = bootstrapPostgresContainerWithRetry(t, docker) + require.NoError(t, err, "bootstrap postgres container") }Where
bootstrapPostgresContainerWithRetrycatches "container name conflict" errors and re-checks for an existing container.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/testfixtures/storage/postgres.go` around lines 112 - 117, The current logic using docker.FindRunningContainer and bootstrapPostgresContainer can race when multiple test processes see "not found" and all attempt to create containers; update the flow by introducing a retry-or-lock around container creation: implement a wrapper (e.g., bootstrapPostgresContainerWithRetry) that first tries docker.FindRunningContainer(t.Context(), "^"+postgresContainerPrefix, postgresImage), and if not found attempts bootstrapPostgresContainer but catches Docker "container already exists" / name conflict errors, then re-runs FindRunningContainer (with a short backoff) before failing; alternatively use a simple file-based lock around the create path to ensure only one process calls bootstrapPostgresContainer at a time—apply this change where dockerCont is set so container creation becomes idempotent and concurrent test runs reuse an existing container.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@pkg/testfixtures/storage/postgres.go`:
- Around line 130-138: The current readiness check uses waitForDatabase(...)
which only verifies TCP/connectivity to postgresTemplateDB before running
createdb; instead add a post-bootstrap sentinel (e.g., a marker table or file)
created after migrations complete in the bootstrap path (where goose.Up runs)
and replace or augment the waitForDatabase call in this setup flow with a new
waitForTemplateReady (or waitForSentinel) call that polls the sentinel via the
same connection URI (use testCont.GetConnectionURI(true)) before running
container.ExecOptions createdb; ensure the bootstrap code that runs goose.Up
creates the sentinel and the test fixture uses that sentinel check so createdb
only proceeds after migrations finish.
- Around line 112-117: The current logic using docker.FindRunningContainer and
bootstrapPostgresContainer can race when multiple test processes see "not found"
and all attempt to create containers; update the flow by introducing a
retry-or-lock around container creation: implement a wrapper (e.g.,
bootstrapPostgresContainerWithRetry) that first tries
docker.FindRunningContainer(t.Context(), "^"+postgresContainerPrefix,
postgresImage), and if not found attempts bootstrapPostgresContainer but catches
Docker "container already exists" / name conflict errors, then re-runs
FindRunningContainer (with a short backoff) before failing; alternatively use a
simple file-based lock around the create path to ensure only one process calls
bootstrapPostgresContainer at a time—apply this change where dockerCont is set
so container creation becomes idempotent and concurrent test runs reuse an
existing container.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9b94326f-2d30-4e55-84ee-1f1edab733ff
📒 Files selected for processing (7)
CHANGELOG.mdpkg/storage/postgres/postgres.gopkg/testfixtures/storage/postgres.gopkg/testfixtures/storage/readiness.gopkg/testfixtures/storage/storage.gopkg/testutils/dockerclient.gopkg/testutils/dockerclient_test.go
f691653 to
7c35a5d
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
pkg/testfixtures/storage/postgres.go (2)
228-234: Consider passing DockerClient as parameter instead of creating a new one.A new
DockerClientis created for each replica, though the caller already has one. This is minor for test code but could be cleaner.♻️ Optional: Pass existing client
-func runPostgresReplica(t testing.TB, primary *postgresTestContainer) *postgresReplicaContainer { - docker, err := testutils.NewDockerClient() - require.NoError(t, err) - - t.Cleanup(func() { - docker.Close() - }) +func runPostgresReplica(t testing.TB, docker *testutils.DockerClient, primary *postgresTestContainer) *postgresReplicaContainer {Then update
CreateSecondaryto pass the client.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/testfixtures/storage/postgres.go` around lines 228 - 234, runPostgresReplica creates a new DockerClient via testutils.NewDockerClient for each replica even though the caller already has one; change runPostgresReplica to accept a DockerClient parameter and reuse it instead of calling testutils.NewDockerClient, and update CreateSecondary (and any call sites constructing postgresReplicaContainer) to accept and forward that DockerClient so the same client instance is reused when creating postgresReplicaContainer/secondary replicas.
352-360: Usesql.NullString.Validfor clearer NULL handling.The
pg_last_wal_receive_lsn()function returns NULL when the replica hasn't received any WAL. While checkingString == ""works becausesql.NullStringsetsStringto empty whenValidis false, it's more semantically correct to check!Valid.♻️ Clearer NULL check
- if replicaLSN.String == "" { + if !replicaLSN.Valid || replicaLSN.String == "" { return fmt.Errorf("replica has not received any WAL yet") } - t.Logf("Replica is synchronized and receiving WAL at LSN: %s", replicaLSN.String) + t.Logf("Replica is synchronized and receiving WAL at LSN: %s", replicaLSN.String)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/testfixtures/storage/postgres.go` around lines 352 - 360, Replace the empty-string check on the sql.NullString with a semantic NULL check: after scanning into replicaLSN (the sql.NullString returned from db.QueryRow("SELECT pg_last_wal_receive_lsn()").Scan(&replicaLSN)), use replicaLSN.Valid (i.e., if !replicaLSN.Valid) to detect the NULL/absence of WAL instead of comparing replicaLSN.String == ""; keep the same error message and return path when the value is not valid.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/testutils/dockerclient_test.go`:
- Line 67: Rename the test function TestContainerLifecycle_PoolAndExec to
TestContainerLifecycle_PullAndExec to fix the typo; update the function
declaration and any references or test invocations that use
TestContainerLifecycle_PoolAndExec so they point to
TestContainerLifecycle_PullAndExec (search for the symbol
TestContainerLifecycle_PoolAndExec and replace it accordingly).
---
Nitpick comments:
In `@pkg/testfixtures/storage/postgres.go`:
- Around line 228-234: runPostgresReplica creates a new DockerClient via
testutils.NewDockerClient for each replica even though the caller already has
one; change runPostgresReplica to accept a DockerClient parameter and reuse it
instead of calling testutils.NewDockerClient, and update CreateSecondary (and
any call sites constructing postgresReplicaContainer) to accept and forward that
DockerClient so the same client instance is reused when creating
postgresReplicaContainer/secondary replicas.
- Around line 352-360: Replace the empty-string check on the sql.NullString with
a semantic NULL check: after scanning into replicaLSN (the sql.NullString
returned from db.QueryRow("SELECT
pg_last_wal_receive_lsn()").Scan(&replicaLSN)), use replicaLSN.Valid (i.e., if
!replicaLSN.Valid) to detect the NULL/absence of WAL instead of comparing
replicaLSN.String == ""; keep the same error message and return path when the
value is not valid.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4fc21e6a-ce00-4fdd-9528-59c9559ac583
📒 Files selected for processing (7)
CHANGELOG.mdpkg/storage/postgres/postgres.gopkg/testfixtures/storage/postgres.gopkg/testfixtures/storage/readiness.gopkg/testfixtures/storage/storage.gopkg/testutils/dockerclient.gopkg/testutils/dockerclient_test.go
✅ Files skipped from review due to trivial changes (3)
- pkg/testfixtures/storage/storage.go
- CHANGELOG.md
- pkg/storage/postgres/postgres.go
🚧 Files skipped from review as they are similar to previous changes (2)
- pkg/testfixtures/storage/readiness.go
- pkg/testutils/dockerclient.go
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/testfixtures/storage/storage.go`:
- Around line 89-92: The goose.CollectMigrations call returns an error that is
currently returned raw; update the error return to wrap the original error with
context using fmt.Errorf so callers know which migrationDir failed (e.g., return
0, fmt.Errorf("collecting migrations from %s: %w", migrationDir, err)). Import
fmt if necessary and update the return in the block that calls
goose.CollectMigrations to use the %w verb.
In `@pkg/testutils/dockerclient.go`:
- Around line 33-36: The Close method on DockerClient currently returns the raw
error from d.client.Close(), losing context; update DockerClient.Close to call
d.client.Close(), check the returned error, and if non-nil wrap it using
fmt.Errorf with %w (for example: fmt.Errorf("DockerClient.Close: %w", err))
before returning so callers receive contextualized errors. Ensure fmt is
imported if not already.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5f30c4f1-b639-4593-b1a1-7f432898a82a
📒 Files selected for processing (9)
CHANGELOG.mdpkg/storage/postgres/postgres.gopkg/testfixtures/storage/postgres.gopkg/testfixtures/storage/readiness.gopkg/testfixtures/storage/sqlite.gopkg/testfixtures/storage/storage.gopkg/testutils/dockerclient.gopkg/testutils/dockerclient_test.gotests/tests.go
💤 Files with no reviewable changes (1)
- pkg/testfixtures/storage/sqlite.go
✅ Files skipped from review due to trivial changes (3)
- CHANGELOG.md
- pkg/storage/postgres/postgres.go
- pkg/testutils/dockerclient_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
- tests/tests.go
- pkg/testfixtures/storage/readiness.go
- pkg/testfixtures/storage/postgres.go
d2016c7 to
643f2ca
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (3)
pkg/testfixtures/storage/storage.go (1)
13-16: Consider removing redundant Goose setup in mysql.go.The
init()centralizes Goose configuration, butpkg/testfixtures/storage/mysql.gostill callsgoose.SetLogger()at line 140 andgoose.SetBaseFS()at line 158, which override this global state. While functionally harmless (they set the same values), removing the redundant calls would improve consistency.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/testfixtures/storage/storage.go` around lines 13 - 16, Remove the redundant Goose setup in mysql.go by deleting the extra calls to goose.SetLogger(...) and goose.SetBaseFS(...) so the global initialization in init() within storage.go is the single source of truth; locate and remove the goose.SetLogger invocation (around the call in mysql.go) and the goose.SetBaseFS invocation (the later call in mysql.go) so they no longer override the central init() configuration.pkg/testfixtures/storage/postgres.go (1)
126-126: Consider sanitizing the database name for SQL safety.The database name is constructed using
postgresDBPrefix + ulid.Make().String(). While ULIDs are alphanumeric and safe, theDROP DATABASEstatement at line 145 uses string interpolation withfmt.Sprintf. If the prefix or format ever changes, this could become an injection risk.The current implementation is safe because ULID characters are
[0-9A-Z], but consider usingpq.QuoteIdentifieror similar for defense-in-depth.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/testfixtures/storage/postgres.go` at line 126, The database name is built as postgresDBPrefix + ulid.Make().String() and later interpolated into a DROP DATABASE string using fmt.Sprintf, so update the code to quote/sanitize the identifier before interpolation: import and use pq.QuoteIdentifier (or an equivalent identifier-quoting helper) to wrap the composed database name when constructing any SQL that embeds it (e.g., the DROP DATABASE fmt.Sprintf call and any other ad-hoc SQL), and keep the original composed name for internal tracking; reference postgresDBPrefix, ulid.Make().String(), and the DROP DATABASE fmt.Sprintf usage to locate where to apply pq.QuoteIdentifier.pkg/testutils/dockerclient.go (1)
119-122: Port readiness timeout may be too aggressive compared to other test infrastructure timeouts.The 5-second
MaxElapsedTimehere is significantly shorter thanwaitForDatabase(30s) andwaitForMigrationVersion(1 minute) inpkg/testfixtures/storage/readiness.go. While Docker port binding is typically a fast local operation, slow CI environments may hit this limit. Consider either increasing the timeout or documenting why Docker port binding requires a shorter window than database/migration operations.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/testutils/dockerclient.go` around lines 119 - 122, The current backoff policy created by backoff.NewExponentialBackOff sets MaxElapsedTime to 5*time.Second via the backoffPolicy variable which is much shorter than other test readiness timeouts (waitForDatabase 30s and waitForMigrationVersion 1m); update the MaxElapsedTime to a longer duration (e.g., 30*time.Second) or make it configurable so Docker port readiness aligns with CI flakiness expectations, and adjust the call site that uses backoffPolicy accordingly to use the new value or configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@pkg/testfixtures/storage/postgres.go`:
- Line 126: The database name is built as postgresDBPrefix +
ulid.Make().String() and later interpolated into a DROP DATABASE string using
fmt.Sprintf, so update the code to quote/sanitize the identifier before
interpolation: import and use pq.QuoteIdentifier (or an equivalent
identifier-quoting helper) to wrap the composed database name when constructing
any SQL that embeds it (e.g., the DROP DATABASE fmt.Sprintf call and any other
ad-hoc SQL), and keep the original composed name for internal tracking;
reference postgresDBPrefix, ulid.Make().String(), and the DROP DATABASE
fmt.Sprintf usage to locate where to apply pq.QuoteIdentifier.
In `@pkg/testfixtures/storage/storage.go`:
- Around line 13-16: Remove the redundant Goose setup in mysql.go by deleting
the extra calls to goose.SetLogger(...) and goose.SetBaseFS(...) so the global
initialization in init() within storage.go is the single source of truth; locate
and remove the goose.SetLogger invocation (around the call in mysql.go) and the
goose.SetBaseFS invocation (the later call in mysql.go) so they no longer
override the central init() configuration.
In `@pkg/testutils/dockerclient.go`:
- Around line 119-122: The current backoff policy created by
backoff.NewExponentialBackOff sets MaxElapsedTime to 5*time.Second via the
backoffPolicy variable which is much shorter than other test readiness timeouts
(waitForDatabase 30s and waitForMigrationVersion 1m); update the MaxElapsedTime
to a longer duration (e.g., 30*time.Second) or make it configurable so Docker
port readiness aligns with CI flakiness expectations, and adjust the call site
that uses backoffPolicy accordingly to use the new value or configuration.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9a079362-728c-4784-8717-b967aa26299d
📒 Files selected for processing (9)
CHANGELOG.mdpkg/storage/postgres/postgres.gopkg/testfixtures/storage/postgres.gopkg/testfixtures/storage/readiness.gopkg/testfixtures/storage/sqlite.gopkg/testfixtures/storage/storage.gopkg/testutils/dockerclient.gopkg/testutils/dockerclient_test.gotests/tests.go
💤 Files with no reviewable changes (1)
- pkg/testfixtures/storage/sqlite.go
✅ Files skipped from review due to trivial changes (2)
- pkg/storage/postgres/postgres.go
- CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/tests.go
- pkg/testfixtures/storage/readiness.go
643f2ca to
d3893db
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
pkg/testutils/dockerclient_test.go (1)
101-135: Assert the actualContainerListfilters in these cases.These
FindRunningContainertests only validate method/path, so they still go green if the request is built with the wrongname/ancestor/statusfilters. Since the shared-container lookup depends on those arguments, I'd add a per-step assertion hook and validate the serialized request in the/containers/jsoncases.🧪 Minimal hook to let mock steps validate request details
type dockerMockStep struct { Method string Path string Body []byte Error string + Assert func(*testing.T, *http.Request) } @@ if !strings.HasSuffix(r.URL.Path, step.Path) { t.Fatalf("unexpected path %s", r.URL.Path) } + if step.Assert != nil { + step.Assert(t, r) + } if step.Body != nil { _, _ = w.Write(step.Body) returnAlso applies to: 360-374
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/testutils/dockerclient_test.go` around lines 101 - 135, The tests for TestFindRunningContainer_Fail call FindRunningContainer but only assert HTTP method/path; add a validation hook to the docker mock (via dockerMockStep or newDockerClientMock) so that when a step with Path "/containers/json" is invoked it decodes the actual request query/body into the Docker ContainerList filters and asserts the expected name, ancestor (alpineImage) and status filters are present; update the three subtests ("not_found", "list_containers", "inspect_container") to supply that assertion hook for the /containers/json step (and mirror the same change in the other failing test range referenced) so the mock fails if the request is built with wrong filters while leaving existing method/path checks intact and keeping FindRunningContainer, newDockerClientMock and dockerMockStep usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/testfixtures/storage/readiness.go`:
- Around line 26-27: The retry uses db.Ping which has no deadline; change the
retry body to call db.PingContext with a per-attempt context timeout (e.g., 2s)
so each attempt fails fast. Replace the backoff.Retry(db.Ping, backoffPolicy)
call with a closure that creates a context via context.WithTimeout, defers
cancel, calls db.PingContext(ctx) and returns that error to Retry (keep
backoffPolicy unchanged). Ensure imports include context if missing.
---
Nitpick comments:
In `@pkg/testutils/dockerclient_test.go`:
- Around line 101-135: The tests for TestFindRunningContainer_Fail call
FindRunningContainer but only assert HTTP method/path; add a validation hook to
the docker mock (via dockerMockStep or newDockerClientMock) so that when a step
with Path "/containers/json" is invoked it decodes the actual request query/body
into the Docker ContainerList filters and asserts the expected name, ancestor
(alpineImage) and status filters are present; update the three subtests
("not_found", "list_containers", "inspect_container") to supply that assertion
hook for the /containers/json step (and mirror the same change in the other
failing test range referenced) so the mock fails if the request is built with
wrong filters while leaving existing method/path checks intact and keeping
FindRunningContainer, newDockerClientMock and dockerMockStep usage.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: da476513-1b26-4015-8f43-bd37ddcf3a14
📒 Files selected for processing (9)
CHANGELOG.mdpkg/storage/postgres/postgres.gopkg/testfixtures/storage/postgres.gopkg/testfixtures/storage/readiness.gopkg/testfixtures/storage/sqlite.gopkg/testfixtures/storage/storage.gopkg/testutils/dockerclient.gopkg/testutils/dockerclient_test.gotests/tests.go
💤 Files with no reviewable changes (1)
- pkg/testfixtures/storage/sqlite.go
✅ Files skipped from review due to trivial changes (2)
- pkg/storage/postgres/postgres.go
- CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (2)
- pkg/testfixtures/storage/postgres.go
- pkg/testfixtures/storage/storage.go
d3893db to
b47e59f
Compare
77a9b65 to
5fd16dd
Compare
Added an improved Docker client in testutils, used by the PostgreSQL fixture and ready for MySQL reuse. Updated the PostgreSQL test fixture to reuse a single container while isolating tests via per-test databases, reducing storage/postgres/postgres_test.go execution time by ~30%.
8e1f771 to
ebaf7d5
Compare
ebaf7d5 to
0a2dfd6
Compare
This reverts commit 0a2dfd6
Description
What problem is being solved?
The
RunDatastoreTestContainerstorage fixture currently creates a new container on each invocation, which can result in more than 10 containers being started during a single test run per storage. Each container initialization involves startup and running migrations, increasing execution time and resource usage in CI. This added overhead can negatively impact overall test performance.How is it being solved?
I started with
PostgreSQLby updating its test fixture to reuse a single container across tests, while maintaining isolation through per-test databases. This significantly reduces the overhead of container creation and migration execution.As a result, the execution time of
storage/postgres/postgres_test.godecreased by ~30%:github.com/openfga/openfga/pkg/storage/postgres 159.219sgithub.com/openfga/openfga/pkg/storage/postgres 108.411sWarning
The current implementation does not remove the
PostgreSQLcontainer after tests complete. Instead, it is cleaned up along with theCIworker. As an improvement, this cleanup step could be added to themake testcommand.What changes are made to solve it?
Dockerclient intestutils, used by thePostgreSQLfixture and ready forMySQLreuse.References
followup #2912
Review Checklist
mainSummary by CodeRabbit