Skip to content

Commit 0272d07

Browse files
authored
fix: share single CockroachDB testcontainer across reconciliation persistence tests (#1254)
* fix: share single CockroachDB testcontainer across reconciliation persistence tests Each test was spinning up its own CockroachDB container (~12s each), causing the 51-test suite to exceed the default 10-minute timeout. Introduces TestMain to create one shared container with table truncation between tests for data isolation. Reduces suite runtime from 600s+ to ~14s. * fix: use flag.Parse and testing.Short for short-mode detection in TestMain Replaces brittle manual os.Args parsing with the standard flag.Parse() + testing.Short() pattern, correctly handling all boolean flag forms. --------- Co-authored-by: Ben Coombs <bjcoombs@users.noreply.github.com>
1 parent 1a53bb5 commit 0272d07

3 files changed

Lines changed: 244 additions & 165 deletions

File tree

services/reconciliation/adapters/persistence/dispute_repository_test.go

Lines changed: 4 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -3,153 +3,26 @@ package persistence_test
33
import (
44
"context"
55
"fmt"
6-
"os"
76
"testing"
87

98
"github.com/google/uuid"
109
"github.com/meridianhub/meridian/services/reconciliation/adapters/persistence"
1110
"github.com/meridianhub/meridian/services/reconciliation/domain"
1211
"github.com/meridianhub/meridian/shared/platform/tenant"
13-
"github.com/meridianhub/meridian/shared/platform/testdb"
1412
"github.com/stretchr/testify/assert"
1513
"github.com/stretchr/testify/require"
1614
"gorm.io/gorm"
1715
)
1816

1917
func setupTestDB(t *testing.T) (*gorm.DB, func()) {
2018
t.Helper()
21-
if os.Getenv("INTEGRATION_TEST") == "" && testing.Short() {
22-
t.Skip("Skipping integration test (set INTEGRATION_TEST=1 or remove -short)")
19+
if sharedDB == nil {
20+
t.Skip("Skipping integration test (shared DB not initialized)")
2321
}
2422

25-
db, cleanup := testdb.SetupCockroachDB(t, nil)
23+
truncateAllTables(t, sharedDB)
2624

27-
// Create tenant schema and tables
28-
tid := tenant.TenantID("test-tenant-01")
29-
schemaName := tid.SchemaName()
30-
quoted := fmt.Sprintf("%q", schemaName)
31-
32-
err := db.Exec("CREATE SCHEMA IF NOT EXISTS " + quoted).Error
33-
require.NoError(t, err)
34-
35-
// Run migrations in the tenant schema
36-
migrationSQL := `
37-
SET search_path TO ` + quoted + `, public;
38-
39-
CREATE TABLE IF NOT EXISTS "settlement_run" (
40-
"id" uuid NOT NULL DEFAULT gen_random_uuid(),
41-
"created_at" timestamptz NOT NULL DEFAULT now(),
42-
"updated_at" timestamptz NOT NULL DEFAULT now(),
43-
"run_id" uuid NOT NULL,
44-
"account_id" character varying(34) NOT NULL,
45-
"scope" character varying(20) NOT NULL DEFAULT 'ACCOUNT',
46-
"settlement_type" character varying(20) NOT NULL DEFAULT 'DAILY',
47-
"status" character varying(20) NOT NULL DEFAULT 'PENDING',
48-
"period_start" timestamptz NOT NULL,
49-
"period_end" timestamptz NOT NULL,
50-
"initiated_by" character varying(100) NOT NULL,
51-
"completed_at" timestamptz NULL,
52-
"variance_count" integer NOT NULL DEFAULT 0,
53-
"failure_reason" text NULL,
54-
"last_completed_phase" character varying(30) NULL,
55-
"attributes" jsonb NULL,
56-
"version" bigint NOT NULL DEFAULT 1,
57-
PRIMARY KEY ("id")
58-
);
59-
CREATE UNIQUE INDEX IF NOT EXISTS "idx_sr_run_id" ON "settlement_run" ("run_id");
60-
61-
CREATE TABLE IF NOT EXISTS "settlement_snapshot" (
62-
"id" uuid NOT NULL DEFAULT gen_random_uuid(),
63-
"created_at" timestamptz NOT NULL DEFAULT now(),
64-
"snapshot_id" uuid NOT NULL,
65-
"run_id" uuid NOT NULL REFERENCES "settlement_run" ("id") ON DELETE CASCADE,
66-
"account_id" character varying(34) NOT NULL,
67-
"instrument_code" character varying(20) NOT NULL,
68-
"expected_balance" decimal(38, 18) NOT NULL,
69-
"actual_balance" decimal(38, 18) NOT NULL,
70-
"variance_amount" decimal(38, 18) NOT NULL,
71-
"source_system" character varying(100) NOT NULL,
72-
"attributes" jsonb NULL,
73-
"captured_at" timestamptz NOT NULL,
74-
PRIMARY KEY ("id")
75-
);
76-
CREATE UNIQUE INDEX IF NOT EXISTS "idx_ss_snap_id" ON "settlement_snapshot" ("snapshot_id");
77-
78-
CREATE TABLE IF NOT EXISTS "variance" (
79-
"id" uuid NOT NULL DEFAULT gen_random_uuid(),
80-
"created_at" timestamptz NOT NULL DEFAULT now(),
81-
"updated_at" timestamptz NOT NULL DEFAULT now(),
82-
"variance_id" uuid NOT NULL,
83-
"run_id" uuid NOT NULL REFERENCES "settlement_run" ("id") ON DELETE CASCADE,
84-
"snapshot_id" uuid NOT NULL REFERENCES "settlement_snapshot" ("id") ON DELETE CASCADE,
85-
"account_id" character varying(34) NOT NULL,
86-
"instrument_code" character varying(20) NOT NULL,
87-
"expected_amount" decimal(38, 18) NOT NULL,
88-
"actual_amount" decimal(38, 18) NOT NULL,
89-
"variance_amount" decimal(38, 18) NOT NULL,
90-
"value_delta" decimal(38, 18) NOT NULL DEFAULT 0,
91-
"currency" character varying(10) NOT NULL DEFAULT '',
92-
"reason" character varying(30) NOT NULL,
93-
"status" character varying(20) NOT NULL DEFAULT 'OPEN',
94-
"resolution_note" text NULL,
95-
"resolved_by" character varying(100) NULL,
96-
"resolved_at" timestamptz NULL,
97-
"attributes" jsonb NULL,
98-
PRIMARY KEY ("id")
99-
);
100-
CREATE UNIQUE INDEX IF NOT EXISTS "idx_v_var_id" ON "variance" ("variance_id");
101-
102-
CREATE TABLE IF NOT EXISTS "dispute" (
103-
"id" uuid NOT NULL DEFAULT gen_random_uuid(),
104-
"created_at" timestamptz NOT NULL DEFAULT now(),
105-
"updated_at" timestamptz NOT NULL DEFAULT now(),
106-
"dispute_id" uuid NOT NULL,
107-
"variance_id" uuid NOT NULL,
108-
"run_id" uuid NOT NULL,
109-
"account_id" character varying(34) NOT NULL,
110-
"status" character varying(20) NOT NULL DEFAULT 'OPEN',
111-
"reason" text NOT NULL,
112-
"resolution" text NULL,
113-
"raised_by" character varying(100) NOT NULL,
114-
"resolved_by" character varying(100) NULL,
115-
"resolved_at" timestamptz NULL,
116-
"attributes" jsonb NULL,
117-
PRIMARY KEY ("id")
118-
);
119-
CREATE UNIQUE INDEX IF NOT EXISTS "idx_d_disp_id" ON "dispute" ("dispute_id");
120-
121-
CREATE TABLE IF NOT EXISTS "balance_assertion" (
122-
"id" uuid NOT NULL DEFAULT gen_random_uuid(),
123-
"created_at" timestamptz NOT NULL DEFAULT now(),
124-
"updated_at" timestamptz NOT NULL DEFAULT now(),
125-
"assertion_id" uuid NOT NULL,
126-
"run_id" uuid NULL,
127-
"account_id" character varying(34) NOT NULL,
128-
"instrument_code" character varying(20) NOT NULL,
129-
"expression" text NOT NULL,
130-
"expected_balance" decimal(38, 18) NOT NULL,
131-
"actual_balance" decimal(38, 18) NOT NULL DEFAULT 0,
132-
"status" character varying(20) NOT NULL DEFAULT 'PENDING',
133-
"failure_reason" text NULL,
134-
"override_reason" text NULL,
135-
"attributes" jsonb NULL,
136-
"metadata" jsonb NULL,
137-
"asserted_at" timestamptz NULL,
138-
"version" bigint NOT NULL DEFAULT 1,
139-
PRIMARY KEY ("id")
140-
);
141-
CREATE UNIQUE INDEX IF NOT EXISTS "idx_ba_assertion_id" ON "balance_assertion" ("assertion_id");
142-
CREATE INDEX IF NOT EXISTS "idx_ba_run_id" ON "balance_assertion" ("run_id");
143-
CREATE INDEX IF NOT EXISTS "idx_ba_account_id" ON "balance_assertion" ("account_id");
144-
CREATE INDEX IF NOT EXISTS "idx_ba_instrument_code" ON "balance_assertion" ("instrument_code");
145-
CREATE INDEX IF NOT EXISTS "idx_ba_status" ON "balance_assertion" ("status");
146-
147-
SET search_path TO public;
148-
`
149-
err = db.Exec(migrationSQL).Error
150-
require.NoError(t, err)
151-
152-
return db, cleanup
25+
return sharedDB, func() { /* container lifecycle managed by TestMain */ }
15326
}
15427

15528
func tenantCtx() context.Context {

services/reconciliation/adapters/persistence/imbalance_trend_repository_test.go

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,24 @@
11
package persistence_test
22

33
import (
4-
"fmt"
54
"sync"
65
"testing"
76
"time"
87

98
"github.com/google/uuid"
109
"github.com/meridianhub/meridian/services/reconciliation/adapters/persistence"
1110
"github.com/meridianhub/meridian/services/reconciliation/domain"
12-
"github.com/meridianhub/meridian/shared/platform/tenant"
1311
"github.com/shopspring/decimal"
1412
"github.com/stretchr/testify/assert"
1513
"github.com/stretchr/testify/require"
1614
)
1715

18-
// setupImbalanceTrendDB creates a test database with the imbalance_trend table.
16+
// setupImbalanceTrendDB returns a repository backed by the shared test database.
17+
// The imbalance_trend table is created once in TestMain.
1918
func setupImbalanceTrendDB(t *testing.T) (*persistence.ImbalanceTrendRepository, func()) {
2019
t.Helper()
2120
db, cleanup := setupTestDB(t)
2221

23-
tid := tenant.TenantID("test-tenant-01")
24-
quoted := fmt.Sprintf("%q", tid.SchemaName())
25-
26-
migrationSQL := fmt.Sprintf(`
27-
SET search_path TO %s, public;
28-
29-
CREATE TABLE IF NOT EXISTS "imbalance_trend" (
30-
"id" uuid NOT NULL DEFAULT gen_random_uuid(),
31-
"created_at" timestamptz NOT NULL DEFAULT now(),
32-
"updated_at" timestamptz NOT NULL DEFAULT now(),
33-
"trend_id" uuid NOT NULL,
34-
"instrument_code" character varying(20) NOT NULL,
35-
"first_detected_at" timestamptz NOT NULL,
36-
"last_detected_at" timestamptz NOT NULL,
37-
"consecutive_days" integer NOT NULL DEFAULT 0,
38-
"total_occurrences" integer NOT NULL DEFAULT 0,
39-
"last_imbalance_amount" decimal(38, 18) NOT NULL,
40-
"last_assertion_id" uuid NULL,
41-
"resolved_at" timestamptz NULL,
42-
"metadata" jsonb NULL,
43-
PRIMARY KEY ("id")
44-
);
45-
CREATE UNIQUE INDEX IF NOT EXISTS "idx_it_trend_id" ON "imbalance_trend" ("trend_id");
46-
CREATE UNIQUE INDEX IF NOT EXISTS "idx_it_instrument_code" ON "imbalance_trend" ("instrument_code");
47-
48-
SET search_path TO public;
49-
`, quoted)
50-
51-
err := db.Exec(migrationSQL).Error
52-
require.NoError(t, err)
53-
5422
repo := persistence.NewImbalanceTrendRepository(db)
5523
return repo, cleanup
5624
}

0 commit comments

Comments
 (0)