Skip to content

Commit 829ebcf

Browse files
committed
test: add unit tests
1 parent 68d9bdb commit 829ebcf

File tree

8 files changed

+177
-160
lines changed

8 files changed

+177
-160
lines changed

wrapper/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,11 @@ tasks.register<Test>("test-all-mysql-aurora") {
315315
systemProperty("test-no-performance", "true")
316316
systemProperty("test-no-pg-driver", "true")
317317
systemProperty("test-no-pg-engine", "true")
318+
systemProperty("test-no-mariadb-driver", "true")
319+
systemProperty("test-no-mariadb-engine", "true")
320+
systemProperty("test-no-iam", "true")
321+
systemProperty("test-no-hikari", "true")
322+
systemProperty("test-no-secrets-manager", "true")
318323
}
319324
}
320325

wrapper/src/main/java/software/amazon/jdbc/PluginServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ public void updateDialect(final @NonNull Connection connection) throws SQLExcept
495495
@Override
496496
public HostSpec identifyConnection(Connection connection) throws SQLException {
497497
if (!(this.getDialect() instanceof TopologyAwareDatabaseCluster)) {
498-
return this.getCurrentHostSpec();
498+
return null;
499499
}
500500

501501
return this.hostListProvider.identifyConnection(connection);

wrapper/src/main/java/software/amazon/jdbc/plugin/AuroraConnectionTrackerPlugin.java

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,9 @@
3030
import software.amazon.jdbc.JdbcCallable;
3131
import software.amazon.jdbc.NodeChangeOptions;
3232
import software.amazon.jdbc.PluginService;
33-
import software.amazon.jdbc.dialect.TopologyAwareDatabaseCluster;
34-
import software.amazon.jdbc.hostlistprovider.AuroraHostListProvider;
3533
import software.amazon.jdbc.plugin.failover.FailoverSQLException;
34+
import software.amazon.jdbc.util.RdsUrlType;
3635
import software.amazon.jdbc.util.RdsUtils;
37-
import software.amazon.jdbc.util.StringUtils;
3836
import software.amazon.jdbc.util.SubscribedMethodHelper;
3937

4038
public class AuroraConnectionTrackerPlugin extends AbstractConnectionPlugin {
@@ -93,7 +91,11 @@ public Connection connectInternal(
9391
: hostSpec;
9492

9593
if (conn != null) {
96-
this.pluginService.fillAliases(conn, hostSpec);
94+
final RdsUrlType type = this.rdsHelper.identifyRdsType(hostSpec.getHost());
95+
if (type.isRdsCluster()) {
96+
hostSpec.resetAliases();
97+
this.pluginService.fillAliases(conn, hostSpec);
98+
}
9799
}
98100

99101
tracker.populateOpenedConnectionQueue(currentHostSpec, conn);
@@ -108,16 +110,6 @@ public Connection forceConnect(String driverProtocol, HostSpec hostSpec, Propert
108110
return connectInternal(hostSpec, forceConnectFunc);
109111
}
110112

111-
private String getInstanceEndpointPattern(final String url) {
112-
if (StringUtils.isNullOrEmpty(this.clusterInstanceTemplate)) {
113-
this.clusterInstanceTemplate = AuroraHostListProvider.CLUSTER_INSTANCE_HOST_PATTERN.getString(this.props) == null
114-
? rdsHelper.getRdsInstanceHostPattern(url)
115-
: AuroraHostListProvider.CLUSTER_INSTANCE_HOST_PATTERN.getString(this.props);
116-
}
117-
118-
return this.clusterInstanceTemplate;
119-
}
120-
121113
@Override
122114
public <T, E extends Exception> T execute(final Class<T> resultClass, final Class<E> exceptionClass,
123115
final Object methodInvokeOn, final String methodName, final JdbcCallable<T, E> jdbcMethodFunc,
@@ -148,29 +140,6 @@ public void notifyNodeListChanged(final Map<String, EnumSet<NodeChangeOptions>>
148140
}
149141

150142
private boolean isRoleChanged(final EnumSet<NodeChangeOptions> changes) {
151-
return changes.contains(NodeChangeOptions.PROMOTED_TO_WRITER)
152-
|| changes.contains(NodeChangeOptions.PROMOTED_TO_READER);
153-
}
154-
155-
public String getInstanceEndpoint(final Connection conn, final HostSpec host) {
156-
String instanceName = "?";
157-
158-
if (!(this.pluginService.getDialect() instanceof TopologyAwareDatabaseCluster)) {
159-
return instanceName;
160-
}
161-
final TopologyAwareDatabaseCluster topologyAwareDialect =
162-
(TopologyAwareDatabaseCluster) this.pluginService.getDialect();
163-
164-
try (final Statement stmt = conn.createStatement();
165-
final ResultSet resultSet = stmt.executeQuery(topologyAwareDialect.getNodeIdQuery())) {
166-
if (resultSet.next()) {
167-
instanceName = resultSet.getString(1);
168-
}
169-
String instanceEndpoint = getInstanceEndpointPattern(host.getHost());
170-
instanceEndpoint = host.isPortSpecified() ? instanceEndpoint + ":" + host.getPort() : instanceEndpoint;
171-
return instanceEndpoint.replace("?", instanceName);
172-
} catch (final SQLException e) {
173-
return instanceName;
174-
}
143+
return changes.contains(NodeChangeOptions.PROMOTED_TO_READER);
175144
}
176145
}

wrapper/src/test/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,5 @@ tasks.register<Test>("in-container") {
8686

8787
// modify below filter to select specific integration tests
8888
// see https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/testing/TestFilter.html
89-
filter.includeTestsMatching("integration.refactored.container.tests.*")
89+
filter.includeTestsMatching("integration.refactored.container.tests.AuroraFailoverTest.testServerFailoverWithIdleConnections")
9090
}

wrapper/src/test/java/software/amazon/jdbc/PluginServiceImplTests.java

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616

1717
package software.amazon.jdbc;
1818

19+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
1920
import static org.junit.jupiter.api.Assertions.assertEquals;
2021
import static org.junit.jupiter.api.Assertions.assertFalse;
2122
import static org.junit.jupiter.api.Assertions.assertNotEquals;
2223
import static org.junit.jupiter.api.Assertions.assertNull;
2324
import static org.junit.jupiter.api.Assertions.assertTrue;
2425
import static org.mockito.ArgumentMatchers.any;
26+
import static org.mockito.ArgumentMatchers.eq;
2527
import static org.mockito.Mockito.doNothing;
2628
import static org.mockito.Mockito.never;
2729
import static org.mockito.Mockito.spy;
@@ -30,7 +32,9 @@
3032
import static org.mockito.Mockito.when;
3133

3234
import java.sql.Connection;
35+
import java.sql.ResultSet;
3336
import java.sql.SQLException;
37+
import java.sql.Statement;
3438
import java.util.ArrayList;
3539
import java.util.Arrays;
3640
import java.util.Collections;
@@ -40,15 +44,21 @@
4044
import java.util.Map;
4145
import java.util.Properties;
4246
import java.util.Set;
47+
import java.util.stream.Stream;
4348
import org.junit.jupiter.api.AfterEach;
4449
import org.junit.jupiter.api.BeforeEach;
4550
import org.junit.jupiter.api.Test;
51+
import org.junit.jupiter.params.ParameterizedTest;
52+
import org.junit.jupiter.params.provider.Arguments;
53+
import org.junit.jupiter.params.provider.MethodSource;
4654
import org.mockito.ArgumentCaptor;
4755
import org.mockito.Captor;
4856
import org.mockito.Mock;
49-
import org.mockito.Mockito;
5057
import org.mockito.MockitoAnnotations;
58+
import software.amazon.jdbc.dialect.AuroraPgDialect;
59+
import software.amazon.jdbc.dialect.Dialect;
5160
import software.amazon.jdbc.dialect.DialectManager;
61+
import software.amazon.jdbc.dialect.MysqlDialect;
5262
import software.amazon.jdbc.exceptions.ExceptionManager;
5363

5464
public class PluginServiceImplTests {
@@ -63,6 +73,8 @@ public class PluginServiceImplTests {
6373
@Mock Connection oldConnection;
6474
@Mock HostListProvider hostListProvider;
6575
@Mock DialectManager dialectManager;
76+
@Mock Statement statement;
77+
@Mock ResultSet resultSet;
6678

6779
@Captor ArgumentCaptor<EnumSet<NodeChangeOptions>> argumentChanges;
6880
@Captor ArgumentCaptor<Map<String, EnumSet<NodeChangeOptions>>> argumentChangesMap;
@@ -72,6 +84,8 @@ public class PluginServiceImplTests {
7284
void setUp() throws SQLException {
7385
closeable = MockitoAnnotations.openMocks(this);
7486
when(oldConnection.isClosed()).thenReturn(false);
87+
when(newConnection.createStatement()).thenReturn(statement);
88+
when(statement.executeQuery(any())).thenReturn(resultSet);
7589
PluginServiceImpl.hostAvailabilityExpiringCache.clear();
7690
}
7791

@@ -580,4 +594,73 @@ void testForceRefreshHostList_withCachedHostAvailability() throws SQLException {
580594
target.forceRefreshHostList(newConnection);
581595
assertEquals(expectedHostSpecs2, newHostSpecs);
582596
}
597+
598+
@Test
599+
void testIdentifyConnectionWithNoAliases() throws SQLException {
600+
PluginServiceImpl target = spy(
601+
new PluginServiceImpl(
602+
pluginManager, new ExceptionManager(), PROPERTIES, URL, DRIVER_PROTOCOL, dialectManager));
603+
when(target.getHostListProvider()).thenReturn(hostListProvider);
604+
605+
when(target.getDialect()).thenReturn(new MysqlDialect());
606+
assertNull(target.identifyConnection(newConnection));
607+
}
608+
609+
@Test
610+
void testIdentifyConnectionWithAliases() throws SQLException {
611+
final HostSpec expected = new HostSpec("test");
612+
PluginServiceImpl target = spy(
613+
new PluginServiceImpl(
614+
pluginManager, new ExceptionManager(), PROPERTIES, URL, DRIVER_PROTOCOL, dialectManager));
615+
target.hostListProvider = hostListProvider;
616+
when(target.getHostListProvider()).thenReturn(hostListProvider);
617+
when(hostListProvider.identifyConnection(eq(newConnection))).thenReturn(expected);
618+
619+
when(target.getDialect()).thenReturn(new AuroraPgDialect());
620+
final HostSpec actual = target.identifyConnection(newConnection);
621+
verify(target, never()).getCurrentHostSpec();
622+
verify(hostListProvider).identifyConnection(newConnection);
623+
assertEquals(expected, actual);
624+
}
625+
626+
@Test
627+
void testFillAliasesNonEmptyAliases() throws SQLException {
628+
final HostSpec oneAlias = new HostSpec("foo");
629+
oneAlias.addAlias(oneAlias.asAlias());
630+
631+
PluginServiceImpl target = spy(
632+
new PluginServiceImpl(
633+
pluginManager, new ExceptionManager(), PROPERTIES, URL, DRIVER_PROTOCOL, dialectManager));
634+
635+
assertEquals(1, oneAlias.getAliases().size());
636+
target.fillAliases(newConnection, oneAlias);
637+
// Fill aliases should return directly and no additional aliases should be added.
638+
assertEquals(1, oneAlias.getAliases().size());
639+
}
640+
641+
@ParameterizedTest
642+
@MethodSource("fillAliasesDialects")
643+
void testFillAliasesWithInstanceEndpoint(Dialect dialect, String[] expectedInstanceAliases) throws SQLException {
644+
final HostSpec empty = new HostSpec("foo");
645+
PluginServiceImpl target = spy(
646+
new PluginServiceImpl(
647+
pluginManager, new ExceptionManager(), PROPERTIES, URL, DRIVER_PROTOCOL, dialectManager));
648+
target.hostListProvider = hostListProvider;
649+
when(target.getDialect()).thenReturn(dialect);
650+
when(resultSet.next()).thenReturn(true, false); // Result set contains 1 row.
651+
when(resultSet.getString(eq(1))).thenReturn("ip");
652+
when(hostListProvider.identifyConnection(eq(newConnection))).thenReturn(new HostSpec("instance"));
653+
654+
target.fillAliases(newConnection, empty);
655+
656+
final String[] aliases = empty.getAliases().toArray(new String[] {});
657+
assertArrayEquals(expectedInstanceAliases, aliases);
658+
}
659+
660+
private static Stream<Arguments> fillAliasesDialects() {
661+
return Stream.of(
662+
Arguments.of(new AuroraPgDialect(), new String[]{"instance", "foo", "ip"}),
663+
Arguments.of(new MysqlDialect(), new String[]{"foo", "ip"})
664+
);
665+
}
583666
}

wrapper/src/test/java/software/amazon/jdbc/hostlistprovider/AuroraHostListProviderTest.java

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ void setUp() throws SQLException {
9292
when(mockConnection.createStatement()).thenReturn(mockStatement);
9393
when(mockStatement.executeQuery(queryCaptor.capture())).thenReturn(mockResultSet);
9494
when(mockHostListProviderService.getDialect()).thenReturn(mockTopologyAwareDialect);
95+
when(((TopologyAwareDatabaseCluster) mockTopologyAwareDialect).getNodeIdQuery()).thenReturn("nodeIdQuery");
9596
}
9697

9798
@AfterEach
@@ -105,7 +106,7 @@ private AuroraHostListProvider getAuroraHostListProvider(String protocol,
105106
AuroraHostListProvider provider = new AuroraHostListProvider(
106107
protocol, mockHostListProviderService, new Properties(), originalUrl);
107108
provider.init();
108-
//provider.clusterId = "cluster-id";
109+
// provider.clusterId = "cluster-id";
109110
return provider;
110111
}
111112

@@ -378,7 +379,7 @@ void testTopologyCache_AcceptSuggestion() throws SQLException {
378379
List<HostSpec> topologyProvider1 = provider1.refresh(Mockito.mock(Connection.class));
379380
assertEquals(topologyClusterA, topologyProvider1);
380381

381-
//AuroraHostListProvider.logCache();
382+
// AuroraHostListProvider.logCache();
382383

383384
AuroraHostListProvider provider2 = Mockito.spy(
384385
getAuroraHostListProvider("jdbc:something://", mockHostListProviderService,
@@ -397,14 +398,84 @@ void testTopologyCache_AcceptSuggestion() throws SQLException {
397398
assertEquals("cluster-a.cluster-xyz.us-east-2.rds.amazonaws.com/",
398399
AuroraHostListProvider.suggestedPrimaryClusterIdCache.get(provider1.clusterId));
399400

400-
//AuroraHostListProvider.logCache();
401+
// AuroraHostListProvider.logCache();
401402

402403
topologyProvider1 = provider1.forceRefresh(Mockito.mock(Connection.class));
403404
assertEquals(topologyClusterA, topologyProvider1);
404405
assertEquals(provider1.clusterId, provider2.clusterId);
405406
assertTrue(provider1.isPrimaryClusterId);
406407
assertTrue(provider2.isPrimaryClusterId);
407408

408-
//AuroraHostListProvider.logCache();
409+
// AuroraHostListProvider.logCache();
410+
}
411+
412+
@Test
413+
void testIdentifyConnectionWithInvalidNodeIdQuery() throws SQLException {
414+
auroraHostListProvider = Mockito.spy(getAuroraHostListProvider(
415+
"jdbc:someprotocol://",
416+
mockHostListProviderService,
417+
"jdbc:someprotocol://url"));
418+
419+
when(mockResultSet.next()).thenReturn(false);
420+
assertThrows(SQLException.class, () -> auroraHostListProvider.identifyConnection(mockConnection));
421+
422+
when(mockConnection.createStatement()).thenThrow(new SQLException("exception"));
423+
assertThrows(SQLException.class, () -> auroraHostListProvider.identifyConnection(mockConnection));
424+
}
425+
426+
@Test
427+
void testIdentifyConnectionNullTopology() throws SQLException {
428+
auroraHostListProvider = Mockito.spy(getAuroraHostListProvider(
429+
"jdbc:someprotocol://",
430+
mockHostListProviderService,
431+
"jdbc:someprotocol://url"));
432+
auroraHostListProvider.clusterInstanceTemplate = new HostSpec("?.pattern");
433+
434+
when(mockResultSet.next()).thenReturn(true);
435+
when(mockResultSet.getString(eq(1))).thenReturn("instance-1");
436+
when(auroraHostListProvider.refresh(eq(mockConnection))).thenReturn(null);
437+
438+
final HostSpec actual = auroraHostListProvider.identifyConnection(mockConnection);
439+
440+
assertEquals("instance-1.pattern", actual.getHost());
441+
assertEquals("instance-1", actual.getHostId());
442+
}
443+
444+
@Test
445+
void testIdentifyConnectionHostNotInTopology() throws SQLException {
446+
final List<HostSpec> cachedTopology = Collections.singletonList(
447+
new HostSpec("instance-a-1.xyz.us-east-2.rds.amazonaws.com", HostSpec.NO_PORT, HostRole.WRITER));
448+
449+
auroraHostListProvider = Mockito.spy(getAuroraHostListProvider(
450+
"jdbc:someprotocol://",
451+
mockHostListProviderService,
452+
"jdbc:someprotocol://url"));
453+
when(mockResultSet.next()).thenReturn(true);
454+
when(mockResultSet.getString(eq(1))).thenReturn("instance-1");
455+
when(auroraHostListProvider.refresh(eq(mockConnection))).thenReturn(cachedTopology);
456+
457+
assertNull(auroraHostListProvider.identifyConnection(mockConnection));
458+
}
459+
460+
@Test
461+
void testIdentifyConnectionHostInTopology() throws SQLException {
462+
final HostSpec expectedHost = new HostSpec(
463+
"instance-a-1.xyz.us-east-2.rds.amazonaws.com",
464+
HostSpec.NO_PORT,
465+
HostRole.WRITER);
466+
expectedHost.setHostId("instance-a-1");
467+
final List<HostSpec> cachedTopology = Collections.singletonList(expectedHost);
468+
469+
auroraHostListProvider = Mockito.spy(getAuroraHostListProvider(
470+
"jdbc:someprotocol://",
471+
mockHostListProviderService,
472+
"jdbc:someprotocol://url"));
473+
when(mockResultSet.next()).thenReturn(true);
474+
when(mockResultSet.getString(eq(1))).thenReturn("instance-a-1");
475+
when(auroraHostListProvider.refresh(eq(mockConnection))).thenReturn(cachedTopology);
476+
477+
final HostSpec actual = auroraHostListProvider.identifyConnection(mockConnection);
478+
assertEquals("instance-a-1.xyz.us-east-2.rds.amazonaws.com", actual.getHost());
479+
assertEquals("instance-a-1", actual.getHostId());
409480
}
410481
}

0 commit comments

Comments
 (0)