Skip to content

Commit 0a0ec83

Browse files
committed
Adding tests that verify the recover callbacks and improving the two previous tests with asserts on the session id.
1 parent f8c20d7 commit 0a0ec83

4 files changed

Lines changed: 81 additions & 5 deletions

File tree

domain-models-runtime/src/main/java/org/folio/rest/persist/PostgresClient.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,11 @@ public static void closeAllClients() {
508508
PG_POOLS_READER.clear();
509509
}
510510

511+
public static void clearConnectionCache() {
512+
CACHED_CONNECTION_MANAGER.closeAllConnectionsInCache();
513+
CACHED_CONNECTION_MANAGER.clearCache();
514+
}
515+
511516

512517
private void init() throws Exception {
513518

domain-models-runtime/src/main/java/org/folio/rest/persist/cache/CachedConnectionManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ public void clearCache() {
3939
LOG.debug("Cleared connection cache");
4040
}
4141

42+
public void closeAllConnectionsInCache() {
43+
connectionCache.closeAll();
44+
}
45+
4246
public void removeFromCache(CachedPgConnection connection) {
4347
connectionCache.remove(connection);
4448
}

domain-models-runtime/src/main/java/org/folio/rest/persist/cache/ConnectionCache.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ public void clear() {
102102
}
103103
}
104104

105+
public void closeAll() {
106+
synchronized (cache) {
107+
for (CachedPgConnection conn : cache) {
108+
conn.getWrappedConnection().close();
109+
}
110+
}
111+
}
112+
105113
public int size() {
106114
synchronized (cache) {
107115
return cache.size();

domain-models-runtime/src/test/java/org/folio/rest/persist/cache/CachedConnectionManagerIT.java

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import io.vertx.ext.unit.TestContext;
44
import io.vertx.ext.unit.junit.VertxUnitRunner;
5-
import io.vertx.pgclient.PgConnection;
65
import io.vertx.pgclient.impl.PgConnectionImpl;
76
import org.folio.postgres.testing.PostgresTesterContainer;
87
import org.folio.rest.impl.TenantAPI;
@@ -11,6 +10,7 @@
1110
import org.folio.rest.persist.PostgresClientHelper;
1211
import org.folio.rest.tools.utils.VertxUtils;
1312
import org.junit.AfterClass;
13+
import org.junit.Before;
1414
import org.junit.BeforeClass;
1515
import org.junit.Test;
1616
import org.junit.runner.RunWith;
@@ -32,41 +32,48 @@ public static void afterClass() {
3232
PostgresClientHelper.setSharedPgPool(false);
3333
}
3434

35+
@Before
36+
public void beforeEach() {
37+
PostgresClientHelper.setSharedPgPool(true);
38+
PostgresClient.clearConnectionCache();
39+
}
40+
3541
@Test
3642
public void shouldNotCreateNestedWrappers(TestContext context) {
37-
PostgresClientHelper.setSharedPgPool(true);
3843
tenantPost(new TenantAPI(), context, null, "tenant1");
3944
tenantPost(new TenantAPI(), context, null, "tenant2");
4045

4146
var async = context.async();
4247
var pgClient1 = PostgresClient.getInstance(vertx, "tenant1");
4348
pgClient1.getConnection().onComplete(context.asyncAssertSuccess(conn1 -> {
49+
var originalSessionId = ((CachedPgConnection) conn1).getSessionId();
4450
// Closing the connection returns it to the cache so it can be recycled.
4551
conn1.close();
4652

4753
var pgClient2 = PostgresClient.getInstance(vertx, "tenant2");
4854
pgClient2.getConnection().onComplete(context.asyncAssertSuccess(conn2 -> {
4955
var recycledCached = (CachedPgConnection) conn2;
5056

57+
assertEquals(originalSessionId, recycledCached.getSessionId());
5158
// Should still wrap the REAL connection, not the cached one
5259
assertEquals(PgConnectionImpl.class, recycledCached.getWrappedConnection().getClass());
5360
assertNotEquals(CachedPgConnection.class, recycledCached.getWrappedConnection().getClass());
5461

55-
async.complete();
62+
conn2.close().onComplete(context.asyncAssertSuccess(v -> async.complete()));
5663
}));
5764
}));
5865
}
5966

6067
@Test
6168
public void shouldUpdateConnectionMetadataAfterConnectionSucceeds(TestContext context) {
62-
PostgresClientHelper.setSharedPgPool(true);
6369
tenantPost(new TenantAPI(), context, null, "tenant1");
6470
tenantPost(new TenantAPI(), context, null, "tenant2");
6571

6672
var async = context.async();
6773
var pgClient1 = PostgresClient.getInstance(vertx, "tenant1");
6874
pgClient1.getConnection().onComplete(context.asyncAssertSuccess(conn1 -> {
6975
var recycledCached1 = (CachedPgConnection) conn1;
76+
var originalSessionId = recycledCached1.getSessionId();
7077

7178
assertEquals("tenant1", recycledCached1.getTenantId());
7279
assertEquals("tenant1_raml_module_builder", recycledCached1.getSchemaName());
@@ -82,10 +89,62 @@ public void shouldUpdateConnectionMetadataAfterConnectionSucceeds(TestContext co
8289
pgClient2.getConnection().onComplete(context.asyncAssertSuccess(conn2 -> {
8390
var recycledCached2 = (CachedPgConnection) conn2;
8491

92+
assertEquals(originalSessionId, recycledCached2.getSessionId());
8593
assertEquals("tenant2", recycledCached2.getTenantId());
8694
assertEquals("tenant2_raml_module_builder", recycledCached2.getSchemaName());
8795

88-
async.complete();
96+
conn2.close().onComplete(context.asyncAssertSuccess(v -> async.complete()));
97+
}));
98+
}));
99+
}
100+
101+
@Test
102+
public void shouldRecoverOnSetRoleFailure(TestContext context) {
103+
tenantPost(new TenantAPI(), context, null, "tenant1");
104+
105+
var async = context.async();
106+
var pgClient1 = PostgresClient.getInstance(vertx, "tenant1");
107+
pgClient1.getConnection().onComplete(context.asyncAssertSuccess(conn1 -> {
108+
var cachedConn = (CachedPgConnection) conn1;
109+
var originalSessionId = cachedConn.getSessionId();
110+
111+
// Closing the connection returns it to the cache so it can be recycled.
112+
conn1.close();
113+
114+
// Try to get a connection for a tenant that does not exist. This will cause the SET ROLE to fail.
115+
var pgClient2 = PostgresClient.getInstance(vertx, "nonexistent");
116+
pgClient2.getConnection().onComplete(context.asyncAssertFailure(failure -> {
117+
// After the failure, the connection should have been returned to the cache with its original tenant.
118+
// Let's try to get it again for the original tenant.
119+
pgClient1.getConnection().onComplete(context.asyncAssertSuccess(conn3 -> {
120+
var cachedConn3 = (CachedPgConnection) conn3;
121+
122+
// The connection should be the same one we got before.
123+
assertEquals(originalSessionId, cachedConn3.getSessionId());
124+
assertEquals("tenant1", cachedConn3.getTenantId());
125+
assertEquals("tenant1_raml_module_builder", cachedConn3.getSchemaName());
126+
127+
conn3.close().onComplete(context.asyncAssertSuccess(v -> async.complete()));
128+
}));
129+
}));
130+
}));
131+
}
132+
133+
@Test
134+
public void shouldRecoverOnSetRoleFailureForNewConnection(TestContext context) {
135+
tenantPost(new TenantAPI(), context, null, "diku");
136+
137+
var async = context.async();
138+
// Try to get a connection for a tenant that does not exist. This will cause the SET ROLE to fail.
139+
var pgClient1 = PostgresClient.getInstance(vertx, "nonexistent");
140+
pgClient1.getConnection().onComplete(context.asyncAssertFailure(failure -> {
141+
// After the failure, the underlying connection should have been closed and returned to the pool.
142+
// Let's try to get a connection for a valid tenant to prove the pool is healthy.
143+
var pgClient2 = PostgresClient.getInstance(vertx, "diku");
144+
pgClient2.getConnection().onComplete(context.asyncAssertSuccess(conn -> {
145+
// The connection should be a valid one.
146+
assertEquals("diku", ((CachedPgConnection) conn).getTenantId());
147+
conn.close().onComplete(context.asyncAssertSuccess(v -> async.complete()));
89148
}));
90149
}));
91150
}

0 commit comments

Comments
 (0)