diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index 52594b28..c18d481e 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -5,6 +5,7 @@ on: push: branches: - main + - refactor/update-read-only paths-ignore: - "**/*.md" - "**/*.jpg" diff --git a/common/lib/plugin_service.ts b/common/lib/plugin_service.ts index 528a26bf..f038b306 100644 --- a/common/lib/plugin_service.ts +++ b/common/lib/plugin_service.ts @@ -386,8 +386,8 @@ export class PluginService implements ErrorHandler, HostListProviderService { async abortCurrentClient(): Promise { if (this._currentClient.targetClient) { await this._currentClient.targetClient.abort(); - // this.setInTransaction(false); - // this.getSessionStateService().reset(); + this.setInTransaction(false); + this.getSessionStateService().reset(); } } diff --git a/common/lib/utils/sql_method_utils.ts b/common/lib/utils/sql_method_utils.ts index 4a5eded7..b61ab4da 100644 --- a/common/lib/utils/sql_method_utils.ts +++ b/common/lib/utils/sql_method_utils.ts @@ -47,7 +47,7 @@ export class SqlMethodUtils { } static doesSetAutoCommit(statements: string[], dialect: DatabaseDialect): boolean | undefined { - let autoCommit; + let autoCommit = undefined; for (const statement of statements) { const cleanStatement = statement .toLowerCase() @@ -60,7 +60,7 @@ export class SqlMethodUtils { } static doesSetCatalog(statements: string[], dialect: DatabaseDialect): string | undefined { - let catalog; + let catalog = undefined; for (const statement of statements) { const cleanStatement = statement .toLowerCase() @@ -73,7 +73,7 @@ export class SqlMethodUtils { } static doesSetSchema(statements: string[], dialect: DatabaseDialect): string | undefined { - let schema; + let schema = undefined; for (const statement of statements) { const cleanStatement = statement .toLowerCase() @@ -86,7 +86,7 @@ export class SqlMethodUtils { } static doesSetTransactionIsolation(statements: string[], dialect: DatabaseDialect): TransactionIsolationLevel | undefined { - let transactionIsolation; + let transactionIsolation = undefined; for (const statement of statements) { const cleanStatement = statement .toLowerCase() diff --git a/mysql/lib/dialect/mysql_database_dialect.ts b/mysql/lib/dialect/mysql_database_dialect.ts index bb352e35..755a66f1 100644 --- a/mysql/lib/dialect/mysql_database_dialect.ts +++ b/mysql/lib/dialect/mysql_database_dialect.ts @@ -17,9 +17,7 @@ import { DatabaseDialect, DatabaseType } from "../../../common/lib/database_dialect/database_dialect"; import { HostListProviderService } from "../../../common/lib/host_list_provider_service"; import { HostListProvider } from "../../../common/lib/host_list_provider/host_list_provider"; -import { - ConnectionStringHostListProvider -} from "../../../common/lib/host_list_provider/connection_string_host_list_provider"; +import { ConnectionStringHostListProvider } from "../../../common/lib/host_list_provider/connection_string_host_list_provider"; import { AwsWrapperError, UnsupportedMethodError } from "../../../common/lib/utils/errors"; import { DatabaseDialectCodes } from "../../../common/lib/database_dialect/database_dialect_codes"; import { TransactionIsolationLevel } from "../../../common/lib/utils/transaction_isolation_level"; @@ -34,7 +32,7 @@ import { Messages } from "../../../common/lib/utils/messages"; export class MySQLDatabaseDialect implements DatabaseDialect { protected dialectName: string = this.constructor.name; protected defaultPort: number = 3306; - + getDefaultPort(): number { return this.defaultPort; } diff --git a/tests/integration/container/tests/aurora_failover.test.ts b/tests/integration/container/tests/aurora_failover.test.ts index edd187f4..a787b57a 100644 --- a/tests/integration/container/tests/aurora_failover.test.ts +++ b/tests/integration/container/tests/aurora_failover.test.ts @@ -100,77 +100,77 @@ describe("aurora failover", () => { logger.info(`Test finished: ${expect.getState().currentTestName}`); }, 1320000); - // itIf( - // "fails from writer to new writer on connection invocation", - // async () => { - // const config = await initDefaultConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, false); - // client = initClientFunc(config); - // - // await client.connect(); - // - // const initialWriterId = await auroraTestUtility.queryInstanceId(client); - // expect(await auroraTestUtility.isDbInstanceWriter(initialWriterId)).toStrictEqual(true); - // - // // Crash instance 1 and nominate a new writer - // await auroraTestUtility.failoverClusterAndWaitUntilWriterChanged(); - // - // await expect(async () => { - // await auroraTestUtility.queryInstanceId(client); - // }).rejects.toThrow(FailoverSuccessError); - // - // // Assert that we are connected to the new writer after failover happens - // const currentConnectionId = await auroraTestUtility.queryInstanceId(client); - // expect(await auroraTestUtility.isDbInstanceWriter(currentConnectionId)).toBe(true); - // expect(currentConnectionId).not.toBe(initialWriterId); - // }, - // 1320000 - // ); - // - // itIf( - // "writer fails within transaction", - // async () => { - // const config = await initDefaultConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, false); - // client = initClientFunc(config); - // - // await client.connect(); - // const initialWriterId = await auroraTestUtility.queryInstanceId(client); - // expect(await auroraTestUtility.isDbInstanceWriter(initialWriterId)).toStrictEqual(true); - // - // await DriverHelper.executeQuery(env.engine, client, "DROP TABLE IF EXISTS test3_3"); - // await DriverHelper.executeQuery(env.engine, client, "CREATE TABLE test3_3 (id int not null primary key, test3_3_field varchar(255) not null)"); - // - // await DriverHelper.executeQuery(env.engine, client, "START TRANSACTION"); // start transaction - // await DriverHelper.executeQuery(env.engine, client, "INSERT INTO test3_3 VALUES (1, 'test field string 1')"); - // - // // Crash instance 1 and nominate a new writer - // await auroraTestUtility.failoverClusterAndWaitUntilWriterChanged(); - // - // await expect(async () => { - // await DriverHelper.executeQuery(env.engine, client, "INSERT INTO test3_3 VALUES (2, 'test field string 2')"); - // }).rejects.toThrow(TransactionResolutionUnknownError); - // - // // Attempt to query the instance id. - // const currentConnectionId = await auroraTestUtility.queryInstanceId(client); - // - // // Assert that we are connected to the new writer after failover happens. - // expect(await auroraTestUtility.isDbInstanceWriter(currentConnectionId)).toBe(true); - // - // const nextClusterWriterId = await auroraTestUtility.getClusterWriterInstanceId(); - // expect(currentConnectionId).toBe(nextClusterWriterId); - // expect(initialWriterId).not.toBe(nextClusterWriterId); - // - // // Assert that NO row has been inserted to the table. - // const result = await DriverHelper.executeQuery(env.engine, client, "SELECT count(*) from test3_3"); - // if (env.engine === DatabaseEngine.PG) { - // expect((result as QueryResult).rows[0]["count"]).toBe("0"); - // } else if (env.engine === DatabaseEngine.MYSQL) { - // expect(JSON.parse(JSON.stringify(result))[0][0]["count(*)"]).toBe(0); - // } - // - // await DriverHelper.executeQuery(env.engine, client, "DROP TABLE IF EXISTS test3_3"); - // }, - // 2000000 - // ); + itIf( + "fails from writer to new writer on connection invocation", + async () => { + const config = await initDefaultConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, false); + client = initClientFunc(config); + + await client.connect(); + + const initialWriterId = await auroraTestUtility.queryInstanceId(client); + expect(await auroraTestUtility.isDbInstanceWriter(initialWriterId)).toStrictEqual(true); + + // Crash instance 1 and nominate a new writer + await auroraTestUtility.failoverClusterAndWaitUntilWriterChanged(); + + await expect(async () => { + await auroraTestUtility.queryInstanceId(client); + }).rejects.toThrow(FailoverSuccessError); + + // Assert that we are connected to the new writer after failover happens + const currentConnectionId = await auroraTestUtility.queryInstanceId(client); + expect(await auroraTestUtility.isDbInstanceWriter(currentConnectionId)).toBe(true); + expect(currentConnectionId).not.toBe(initialWriterId); + }, + 1320000 + ); + + itIf( + "writer fails within transaction", + async () => { + const config = await initDefaultConfig(env.databaseInfo.writerInstanceEndpoint, env.databaseInfo.instanceEndpointPort, false); + client = initClientFunc(config); + + await client.connect(); + const initialWriterId = await auroraTestUtility.queryInstanceId(client); + expect(await auroraTestUtility.isDbInstanceWriter(initialWriterId)).toStrictEqual(true); + + await DriverHelper.executeQuery(env.engine, client, "DROP TABLE IF EXISTS test3_3"); + await DriverHelper.executeQuery(env.engine, client, "CREATE TABLE test3_3 (id int not null primary key, test3_3_field varchar(255) not null)"); + + await DriverHelper.executeQuery(env.engine, client, "START TRANSACTION"); // start transaction + await DriverHelper.executeQuery(env.engine, client, "INSERT INTO test3_3 VALUES (1, 'test field string 1')"); + + // Crash instance 1 and nominate a new writer + await auroraTestUtility.failoverClusterAndWaitUntilWriterChanged(); + + await expect(async () => { + await DriverHelper.executeQuery(env.engine, client, "INSERT INTO test3_3 VALUES (2, 'test field string 2')"); + }).rejects.toThrow(TransactionResolutionUnknownError); + + // Attempt to query the instance id. + const currentConnectionId = await auroraTestUtility.queryInstanceId(client); + + // Assert that we are connected to the new writer after failover happens. + expect(await auroraTestUtility.isDbInstanceWriter(currentConnectionId)).toBe(true); + + const nextClusterWriterId = await auroraTestUtility.getClusterWriterInstanceId(); + expect(currentConnectionId).toBe(nextClusterWriterId); + expect(initialWriterId).not.toBe(nextClusterWriterId); + + // Assert that NO row has been inserted to the table. + const result = await DriverHelper.executeQuery(env.engine, client, "SELECT count(*) from test3_3"); + if (env.engine === DatabaseEngine.PG) { + expect((result as QueryResult).rows[0]["count"]).toBe("0"); + } else if (env.engine === DatabaseEngine.MYSQL) { + expect(JSON.parse(JSON.stringify(result))[0][0]["count(*)"]).toBe(0); + } + + await DriverHelper.executeQuery(env.engine, client, "DROP TABLE IF EXISTS test3_3"); + }, + 2000000 + ); itIf( "fails from writer and transfers session state", diff --git a/tests/plugin_manager_benchmarks.ts b/tests/plugin_manager_benchmarks.ts index cb318e4c..6fd09a29 100644 --- a/tests/plugin_manager_benchmarks.ts +++ b/tests/plugin_manager_benchmarks.ts @@ -283,7 +283,7 @@ suite( }), add("initHostProviderWith10Plugins", async () => { - const pluginManagerWithPlugins = await initPluginManagerWithPlugins(10, instance(mockPluginService), propsWithPlugins);; + const pluginManagerWithPlugins = await initPluginManagerWithPlugins(10, instance(mockPluginService), propsWithPlugins); return async () => await pluginManagerWithPlugins.initHostProvider( new HostInfoBuilder({ hostAvailabilityStrategy: new SimpleHostAvailabilityStrategy() }).withHost("host").build(), @@ -325,7 +325,7 @@ suite( }), add("notifyConnectionChangedWith10Plugins", async () => { - const pluginManagerWithPlugins = await initPluginManagerWithPlugins(10, instance(mockPluginService), propsWithPlugins);; + const pluginManagerWithPlugins = await initPluginManagerWithPlugins(10, instance(mockPluginService), propsWithPlugins); return async () => await pluginManagerWithPlugins.notifyConnectionChanged(new Set([HostChangeOptions.INITIAL_CONNECTION]), null); }),