|
| 1 | +package postgresqlretriever_test |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "testing" |
| 6 | + "time" |
| 7 | + |
| 8 | + "github.com/stretchr/testify/assert" |
| 9 | + "github.com/testcontainers/testcontainers-go" |
| 10 | + "github.com/testcontainers/testcontainers-go/wait" |
| 11 | + rr "github.com/thomaspoignant/go-feature-flag/retriever/postgresqlretriever" |
| 12 | +) |
| 13 | + |
| 14 | +func TestGetPool_MultipleURIsAndReuse(t *testing.T) { |
| 15 | + ctx := context.Background() |
| 16 | + |
| 17 | + // Setup Container |
| 18 | + req := testcontainers.ContainerRequest{ |
| 19 | + Image: "postgres:15-alpine", |
| 20 | + ExposedPorts: []string{"5432/tcp"}, |
| 21 | + Env: map[string]string{"POSTGRES_PASSWORD": "password"}, |
| 22 | + // This waits until the log says the system is ready, preventing connection errors |
| 23 | + WaitingFor: wait.ForAll( |
| 24 | + wait.ForLog("database system is ready to accept connections").WithStartupTimeout(10*time.Second), |
| 25 | + wait.ForListeningPort("5432/tcp").WithStartupTimeout(10*time.Second), |
| 26 | + ), |
| 27 | + } |
| 28 | + |
| 29 | + pg, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ |
| 30 | + ContainerRequest: req, |
| 31 | + Started: true, |
| 32 | + }) |
| 33 | + assert.NoError(t, err) |
| 34 | + defer pg.Terminate(ctx) |
| 35 | + |
| 36 | + endpoint, err := pg.Endpoint(ctx, "") |
| 37 | + assert.NoError(t, err) |
| 38 | + baseURI := "postgres://postgres:password@" + endpoint + "/postgres?sslmode=disable" |
| 39 | + |
| 40 | + // Different URIs |
| 41 | + uri1 := baseURI + "&application_name=A" |
| 42 | + uri2 := baseURI + "&application_name=B" |
| 43 | + |
| 44 | + // First Calls (RefCount = 1) |
| 45 | + pool1a, err := rr.GetPool(ctx, uri1) |
| 46 | + assert.NoError(t, err) |
| 47 | + assert.NotNil(t, pool1a) |
| 48 | + |
| 49 | + pool2a, err := rr.GetPool(ctx, uri2) |
| 50 | + assert.NoError(t, err) |
| 51 | + assert.NotNil(t, pool2a) |
| 52 | + |
| 53 | + // Verify distinct pools |
| 54 | + assert.NotEqual(t, pool1a, pool2a) |
| 55 | + |
| 56 | + // Reuse Logic (RefCount = 2 for URI1) |
| 57 | + pool1b, err := rr.GetPool(ctx, uri1) |
| 58 | + assert.NoError(t, err) |
| 59 | + assert.Equal(t, pool1a, pool1b, "Should return exact same pool instance") |
| 60 | + |
| 61 | + // Release Logic |
| 62 | + // URI1 RefCount: 2 -> 1 |
| 63 | + rr.ReleasePool(ctx, uri1) |
| 64 | + |
| 65 | + // URI1 RefCount: 1 -> 0 (Closed & Removed) |
| 66 | + rr.ReleasePool(ctx, uri1) |
| 67 | + |
| 68 | + // Recreation Logic |
| 69 | + // URI1 should now create a NEW pool |
| 70 | + pool1c, err := rr.GetPool(ctx, uri1) |
| 71 | + assert.NoError(t, err) |
| 72 | + assert.NotEqual(t, pool1a, pool1c, "Should be a new pool instance after full release") |
| 73 | + |
| 74 | + // Cleanup new pool |
| 75 | + rr.ReleasePool(ctx, uri1) |
| 76 | + |
| 77 | + // URI2 Cleanup verification |
| 78 | + rr.ReleasePool(ctx, uri2) // RefCount -> 0 |
| 79 | + |
| 80 | + pool2b, err := rr.GetPool(ctx, uri2) |
| 81 | + assert.NoError(t, err) |
| 82 | + assert.NotEqual(t, pool2a, pool2b, "URI2 should be recreated") |
| 83 | + |
| 84 | + rr.ReleasePool(ctx, uri2) |
| 85 | +} |
0 commit comments