Skip to content

Commit 1aaaff2

Browse files
committed
test: fastest response strategy, connect time and execute time integration tests
1 parent 6f71019 commit 1aaaff2

File tree

3 files changed

+337
-1
lines changed

3 files changed

+337
-1
lines changed

docs/using-the-nodejs-wrapper/using-plugins/UsingTheFastestResponseStrategyPlugin.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ await client.connect();
3838

3939
The Host Response Time Monitor measures the host response time in a separate monitoring task. If the monitoring task has not been called for a response time for 10 minutes, the task is stopped. When the topology changes, the new hosts will be added to monitoring.
4040

41-
The host response time monitoring task creates new database connections. By default, it uses the same set of connection parameters provided for the main connection, but you can customize these connections with the `frt-` prefix, as in the following example:
41+
The host response time monitoring task creates new database connections. By default, it uses the same set of connection parameters provided for the main connection, but you can customize these connections with the `frt_` prefix, as in the following example:
4242

4343
```ts
4444
const client = new AwsMySQLClient({
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License").
5+
You may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { TestEnvironment } from "./utils/test_environment";
18+
import { DriverHelper } from "./utils/driver_helper";
19+
import { AuroraTestUtility } from "./utils/aurora_test_utility";
20+
import { ProxyHelper } from "./utils/proxy_helper";
21+
import { logger } from "../../../../common/logutils";
22+
import { TestEnvironmentFeatures } from "./utils/test_environment_features";
23+
import { features, instanceCount } from "./config";
24+
import { PluginManager } from "../../../../common/lib";
25+
import { RdsHostListProvider } from "../../../../common/lib/host_list_provider/rds_host_list_provider";
26+
import { PluginService } from "../../../../common/lib/plugin_service";
27+
import { ConnectTimePlugin } from "../../../../common/lib/plugins/connect_time_plugin";
28+
import { ExecuteTimePlugin } from "../../../../common/lib/plugins/execute_time_plugin";
29+
import { getTimeInNanos } from "../../../../common/lib/utils/utils";
30+
31+
const itIf =
32+
!features.includes(TestEnvironmentFeatures.PERFORMANCE) &&
33+
features.includes(TestEnvironmentFeatures.IAM) &&
34+
!features.includes(TestEnvironmentFeatures.RUN_AUTOSCALING_TESTS_ONLY) &&
35+
instanceCount >= 2
36+
? it
37+
: it.skip;
38+
39+
let env: TestEnvironment;
40+
let driver;
41+
let initClientFunc: (props: any) => any;
42+
let client: any;
43+
let auroraTestUtility: AuroraTestUtility;
44+
45+
async function initConfig(host: string, port: number, connectToProxy: boolean, plugins: string): Promise<any> {
46+
let config: any = {
47+
user: env.databaseInfo.username,
48+
host: host,
49+
database: env.databaseInfo.defaultDbName,
50+
password: env.databaseInfo.password,
51+
port: port,
52+
plugins: plugins,
53+
enableTelemetry: true,
54+
telemetryTracesBackend: "OTLP",
55+
telemetryMetricsBackend: "OTLP"
56+
};
57+
config = DriverHelper.addDriverSpecificConfiguration(config, env.engine);
58+
return config;
59+
}
60+
61+
describe("aurora connect and execute time plugin", () => {
62+
beforeEach(async () => {
63+
logger.info(`Test started: ${expect.getState().currentTestName}`);
64+
env = await TestEnvironment.getCurrent();
65+
auroraTestUtility = new AuroraTestUtility(env.region);
66+
67+
driver = DriverHelper.getDriverForDatabaseEngine(env.engine);
68+
initClientFunc = DriverHelper.getClient(driver);
69+
await ProxyHelper.enableAllConnectivity();
70+
client = null;
71+
await TestEnvironment.verifyClusterStatus();
72+
await TestEnvironment.verifyAllInstancesHasRightState("available");
73+
await TestEnvironment.verifyAllInstancesUp();
74+
75+
RdsHostListProvider.clearAll();
76+
PluginService.clearHostAvailabilityCache();
77+
}, 1320000);
78+
79+
afterEach(async () => {
80+
if (client !== null) {
81+
try {
82+
await client.end();
83+
} catch (error) {
84+
// pass
85+
}
86+
}
87+
await PluginManager.releaseResources();
88+
logger.info(`Test finished: ${expect.getState().currentTestName}`);
89+
}, 1320000);
90+
91+
itIf(
92+
"test connect time",
93+
async () => {
94+
const writerConfig = await initConfig(
95+
env.proxyDatabaseInfo.writerInstanceEndpoint,
96+
env.proxyDatabaseInfo.instanceEndpointPort,
97+
true,
98+
"connectTime"
99+
);
100+
client = initClientFunc(writerConfig);
101+
const startTime = Number(getTimeInNanos());
102+
expect(Number(ConnectTimePlugin.getTotalConnectTime())).toBe(0);
103+
await client.connect();
104+
const connectTime = ConnectTimePlugin.getTotalConnectTime();
105+
const elapsedTime = Number(getTimeInNanos()) - startTime;
106+
expect(Number(connectTime)).toBeGreaterThan(0);
107+
expect(elapsedTime).toBeGreaterThan(connectTime);
108+
},
109+
1320000
110+
);
111+
112+
itIf(
113+
"test execute time",
114+
async () => {
115+
const writerConfig = await initConfig(
116+
env.proxyDatabaseInfo.writerInstanceEndpoint,
117+
env.proxyDatabaseInfo.instanceEndpointPort,
118+
true,
119+
"executeTime"
120+
);
121+
client = initClientFunc(writerConfig);
122+
await client.connect();
123+
const startTime = Number(getTimeInNanos());
124+
const executePluginStartTime = Number(ExecuteTimePlugin.getTotalExecuteTime());
125+
await auroraTestUtility.queryInstanceId(client);
126+
const elapsedTime = Number(getTimeInNanos()) - startTime;
127+
const executeTime = Number(ExecuteTimePlugin.getTotalExecuteTime()) - executePluginStartTime;
128+
expect(executeTime).toBeGreaterThan(executePluginStartTime);
129+
expect(elapsedTime).toBeGreaterThan(executeTime);
130+
},
131+
1320000
132+
);
133+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License").
5+
You may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { TestEnvironment } from "./utils/test_environment";
18+
import { DriverHelper } from "./utils/driver_helper";
19+
import { AuroraTestUtility } from "./utils/aurora_test_utility";
20+
import { FailoverSuccessError } from "../../../../common/lib/utils/errors";
21+
import { ProxyHelper } from "./utils/proxy_helper";
22+
import { logger } from "../../../../common/logutils";
23+
import { TestEnvironmentFeatures } from "./utils/test_environment_features";
24+
import { features, instanceCount } from "./config";
25+
import { InternalPooledConnectionProvider } from "../../../../common/lib/internal_pooled_connection_provider";
26+
import { PluginManager } from "../../../../common/lib";
27+
import { RdsHostListProvider } from "../../../../common/lib/host_list_provider/rds_host_list_provider";
28+
import { PluginService } from "../../../../common/lib/plugin_service";
29+
import { AwsPoolConfig } from "../../../../common/lib/aws_pool_config";
30+
31+
const itIf =
32+
!features.includes(TestEnvironmentFeatures.PERFORMANCE) &&
33+
features.includes(TestEnvironmentFeatures.IAM) &&
34+
!features.includes(TestEnvironmentFeatures.RUN_AUTOSCALING_TESTS_ONLY) &&
35+
instanceCount >= 2
36+
? it
37+
: it.skip;
38+
const itIfMinThreeInstance = instanceCount >= 3 ? itIf : it.skip;
39+
40+
let env: TestEnvironment;
41+
let driver;
42+
let initClientFunc: (props: any) => any;
43+
let client: any;
44+
let secondaryClient: any;
45+
let auroraTestUtility: AuroraTestUtility;
46+
let provider: InternalPooledConnectionProvider | null;
47+
48+
async function initConfig(host: string, port: number, connectToProxy: boolean, plugins: string): Promise<any> {
49+
let config: any = {
50+
user: env.databaseInfo.username,
51+
host: host,
52+
database: env.databaseInfo.defaultDbName,
53+
password: env.databaseInfo.password,
54+
port: port,
55+
plugins: plugins,
56+
enableTelemetry: true,
57+
telemetryTracesBackend: "OTLP",
58+
telemetryMetricsBackend: "OTLP",
59+
readerHostSelectorStrategy: "fastestResponse"
60+
};
61+
62+
if (connectToProxy) {
63+
config["clusterInstanceHostPattern"] = "?." + env.proxyDatabaseInfo.instanceEndpointSuffix;
64+
}
65+
config = DriverHelper.addDriverSpecificConfiguration(config, env.engine);
66+
return config;
67+
}
68+
69+
async function initDefaultConfig(host: string, port: number, connectToProxy: boolean): Promise<any> {
70+
return await initConfig(host, port, connectToProxy, "readWriteSplitting,fastestResponseStrategy");
71+
}
72+
73+
async function initConfigWithFailover(host: string, port: number, connectToProxy: boolean): Promise<any> {
74+
const config: any = await initConfig(host, port, connectToProxy, "readWriteSplitting,failover,fastestResponseStrategy");
75+
config["failoverTimeoutMs"] = 400000;
76+
return config;
77+
}
78+
79+
describe("aurora fastest response strategy", () => {
80+
beforeEach(async () => {
81+
logger.info(`Test started: ${expect.getState().currentTestName}`);
82+
env = await TestEnvironment.getCurrent();
83+
auroraTestUtility = new AuroraTestUtility(env.region);
84+
85+
driver = DriverHelper.getDriverForDatabaseEngine(env.engine);
86+
initClientFunc = DriverHelper.getClient(driver);
87+
await ProxyHelper.enableAllConnectivity();
88+
client = null;
89+
secondaryClient = null;
90+
provider = null;
91+
await TestEnvironment.verifyClusterStatus();
92+
await TestEnvironment.verifyAllInstancesHasRightState("available");
93+
await TestEnvironment.verifyAllInstancesUp();
94+
95+
RdsHostListProvider.clearAll();
96+
PluginService.clearHostAvailabilityCache();
97+
}, 1320000);
98+
99+
afterEach(async () => {
100+
if (client !== null) {
101+
try {
102+
await client.end();
103+
} catch (error) {
104+
// pass
105+
}
106+
}
107+
108+
if (secondaryClient !== null) {
109+
try {
110+
await secondaryClient.end();
111+
} catch (error) {
112+
// pass
113+
}
114+
}
115+
await PluginManager.releaseResources();
116+
logger.info(`Test finished: ${expect.getState().currentTestName}`);
117+
}, 1320000);
118+
119+
itIfMinThreeInstance(
120+
"test failover to new reader use cached connection",
121+
async () => {
122+
// Connect to writer instance
123+
const writerConfig = await initConfigWithFailover(
124+
env.proxyDatabaseInfo.writerInstanceEndpoint,
125+
env.proxyDatabaseInfo.instanceEndpointPort,
126+
true
127+
);
128+
writerConfig["failoverMode"] = "reader-or-writer";
129+
client = initClientFunc(writerConfig);
130+
131+
await client.connect();
132+
const initialWriterId = await auroraTestUtility.queryInstanceId(client);
133+
expect(await auroraTestUtility.isDbInstanceWriter(initialWriterId)).toStrictEqual(true);
134+
135+
await client.setReadOnly(true);
136+
137+
const readerConnectionId = await auroraTestUtility.queryInstanceId(client);
138+
expect(readerConnectionId).not.toBe(initialWriterId);
139+
// Get a reader instance
140+
let otherReaderId;
141+
for (const host of env.proxyDatabaseInfo.instances) {
142+
if (host.instanceId && host.instanceId !== readerConnectionId && host.instanceId !== initialWriterId) {
143+
otherReaderId = host.instanceId;
144+
break;
145+
}
146+
}
147+
148+
if (!otherReaderId) {
149+
throw new Error("Could not find a reader instance");
150+
}
151+
// Kill all instances except one other reader
152+
for (const host of env.proxyDatabaseInfo.instances) {
153+
if (host.instanceId && host.instanceId !== otherReaderId) {
154+
await ProxyHelper.disableConnectivity(env.engine, host.instanceId);
155+
}
156+
}
157+
await expect(async () => {
158+
await auroraTestUtility.queryInstanceId(client);
159+
}).rejects.toThrow(FailoverSuccessError);
160+
161+
const currentReaderId0 = await auroraTestUtility.queryInstanceId(client);
162+
163+
expect(currentReaderId0).toStrictEqual(otherReaderId);
164+
expect(currentReaderId0).not.toBe(readerConnectionId);
165+
166+
await ProxyHelper.enableAllConnectivity();
167+
await client.setReadOnly(false);
168+
169+
const currentId = await auroraTestUtility.queryInstanceId(client);
170+
expect(currentId).toStrictEqual(initialWriterId);
171+
// Connect using cached fastest connection.
172+
await client.setReadOnly(true);
173+
174+
const currentReaderId2 = await auroraTestUtility.queryInstanceId(client);
175+
expect(currentReaderId2).toStrictEqual(otherReaderId);
176+
},
177+
1320000
178+
);
179+
180+
itIf(
181+
"test secondary client use fastest connection",
182+
async () => {
183+
const config = await initDefaultConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, false);
184+
185+
client = initClientFunc(config);
186+
secondaryClient = initClientFunc(config);
187+
188+
await client.connect();
189+
await client.setReadOnly(true);
190+
const currentReaderId0 = await auroraTestUtility.queryInstanceId(client);
191+
await client.end();
192+
await secondaryClient.connect();
193+
194+
// Connect using cached fastest connection.
195+
await secondaryClient.setReadOnly(true);
196+
const currentReaderId1 = await auroraTestUtility.queryInstanceId(secondaryClient);
197+
198+
expect(currentReaderId1).toStrictEqual(currentReaderId0);
199+
expect(client).not.toBe(secondaryClient);
200+
},
201+
1000000
202+
);
203+
});

0 commit comments

Comments
 (0)