From 9df7c6c1aa78e90ec084a66f5b4901d86c579387 Mon Sep 17 00:00:00 2001 From: Sakshi Sharma <57200045+SakshiS-harma@users.noreply.github.com> Date: Sun, 14 Mar 2021 11:27:16 -0700 Subject: [PATCH] Added integration tests for schema compare (#14479) * Added integration tests for schema compare * Addressed comments * Revert beforeEach change * Addressed comments and reverted table creation change * Removed cancelCompare test and addressed a comment * Increase test timeout from 5 to 10mins --- .../src/test/schemaCompare.test.ts | 209 +++++++++++++++++- .../integration-tests/src/test/utils.ts | 2 +- 2 files changed, 202 insertions(+), 9 deletions(-) diff --git a/extensions/integration-tests/src/test/schemaCompare.test.ts b/extensions/integration-tests/src/test/schemaCompare.test.ts index dea121fdd3..04429783be 100644 --- a/extensions/integration-tests/src/test/schemaCompare.test.ts +++ b/extensions/integration-tests/src/test/schemaCompare.test.ts @@ -22,8 +22,9 @@ const dacpac2: string = path.join(__dirname, '..', '..', 'testData', 'Database2. const includeExcludeSourceDacpac: string = path.join(__dirname, '..', '..', 'testData', 'SchemaCompareIncludeExcludeSource.dacpac'); const includeExcludeTargetDacpac: string = path.join(__dirname, '..', '..', 'testData', 'SchemaCompareIncludeExcludeTarget.dacpac'); const SERVER_CONNECTION_TIMEOUT: number = 3000; -const retryCount = 24; // 2 minutes +const retryCount = 12; // 1 minute const folderPath = path.join(os.tmpdir(), 'SchemaCompareTest'); +const testTimeout = 10 * 60 * 1000; // 10 minutes suite('Schema compare integration test suite @DacFx@', () => { suiteSetup(async function () { @@ -39,8 +40,9 @@ suite('Schema compare integration test suite @DacFx@', () => { dacfxService = ((await vscode.extensions.getExtension(mssql.extension.name).activate() as mssql.IExtension)).dacFx; console.log(`Start schema compare tests`); }); + test('Schema compare dacpac to dacpac comparison and scmp', async function () { - this.timeout(5 * 60 * 1000); + this.timeout(testTimeout); assert(schemaCompareService, 'Schema Compare Service Provider is not available'); const now = new Date(); const operationId = 'testOperationId_' + now.getTime().toString(); @@ -82,8 +84,9 @@ suite('Schema compare integration test suite @DacFx@', () => { assert(openScmpResult.sourceEndpointInfo.packageFilePath === source.packageFilePath, `Expected: source packageFilePath to be ${source.packageFilePath}, Actual: ${openScmpResult.sourceEndpointInfo.packageFilePath}`); assert(openScmpResult.targetEndpointInfo.packageFilePath === target.packageFilePath, `Expected: target packageFilePath to be ${target.packageFilePath}, Actual: ${openScmpResult.targetEndpointInfo.packageFilePath}`); }); + test('Schema compare database to database comparison, script generation, and scmp @UNSTABLE@', async function () { - this.timeout(5 * 60 * 1000); + this.timeout(testTimeout); let server = await getStandaloneServer(); const ownerUri = await getConnectionUri(server); const now = new Date(); @@ -154,8 +157,9 @@ suite('Schema compare integration test suite @DacFx@', () => { await utils.tryDeleteDB(server, targetDB, ownerUri); } }); + test('Schema compare dacpac to database comparison, script generation, and scmp @UNSTABLE@', async function () { - this.timeout(5 * 60 * 1000); + this.timeout(testTimeout); let server = await getStandaloneServer(); const ownerUri = await getConnectionUri(server); const now = new Date(); @@ -214,8 +218,9 @@ suite('Schema compare integration test suite @DacFx@', () => { await utils.tryDeleteDB(server, targetDB, ownerUri); } }); + test('Schema compare dacpac to dacpac comparison with include exclude', async function () { - this.timeout(5 * 60 * 1000); + this.timeout(testTimeout); assert(schemaCompareService, 'Schema Compare Service Provider is not available'); const operationId = 'testOperationId_' + new Date().getTime().toString(); @@ -270,6 +275,194 @@ suite('Schema compare integration test suite @DacFx@', () => { const excludeResult3 = await schemaCompareService.schemaCompareIncludeExcludeNode(operationId, t2Difference, false, azdata.TaskExecutionMode.execute); assertIncludeExcludeResult(excludeResult3, true, 0, 0); }); + + test('Schema compare dacpac to database comparison with publishing some changes and then compare again', async function () { + this.timeout(testTimeout); + const server = await getStandaloneServer(); + const ownerUri = await getConnectionUri(server); + const now = new Date().getTime().toString(); + const operationId = 'testOperationId_' + now; + const targetDB: string = 'ads_schemaCompare_targetDB_' + now; + + try { + assert(dacfxService, 'DacFx Service Provider is not available'); + let result = await dacfxService.deployDacpac(dacpac1, targetDB, true, ownerUri, azdata.TaskExecutionMode.execute); + + assert(result.success === true, 'Deploy database 2 (target) should succeed'); + + const source: mssql.SchemaCompareEndpointInfo = { + endpointType: mssql.SchemaCompareEndpointType.Dacpac, + packageFilePath: dacpac2, + serverDisplayName: '', + serverName: '', + databaseName: '', + ownerUri: ownerUri, + connectionDetails: undefined + }; + const target: mssql.SchemaCompareEndpointInfo = { + endpointType: mssql.SchemaCompareEndpointType.Database, + packageFilePath: '', + serverDisplayName: '', + serverName: server.serverName, + databaseName: targetDB, + ownerUri: ownerUri, + connectionDetails: undefined + }; + + assert(schemaCompareService, 'Schema Compare Service Provider is not available'); + + const schemaCompareResult = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, null); + assertSchemaCompareResult(schemaCompareResult, operationId, 4); + + //try to exclude the difference of function Function1 and it should not fail + let function1Difference = schemaCompareResult.differences.find(e => e.sourceValue && e.sourceValue[1] === 'Function1' && e.name === 'SqlInlineTableValuedFunction'); + assert(function1Difference !== undefined, 'The difference function Function1 should be found. Should not be undefined'); + + //by default all changes are included while publishing, hence excluding Function1 + const includeResult = await schemaCompareService.schemaCompareIncludeExcludeNode(operationId, function1Difference, false, azdata.TaskExecutionMode.execute); + assertIncludeExcludeResult(includeResult, true, 0, 0); + + //publish the updated changes. Function1 should not be added to the target database + const publishChangesResult = await schemaCompareService.schemaComparePublishChanges(schemaCompareResult.operationId, server.serverName, targetDB, azdata.TaskExecutionMode.execute); + assert(publishChangesResult.success === true, 'Publish changes should complete successfully. But it failed.'); + + //verify table Table3 is added + const dbConnectionId = await utils.connectToServer({ + serverName: server.serverName, + database: targetDB, + userName: server.userName, + password: server.password, + authenticationTypeName: server.authenticationTypeName, + providerName: server.providerName + }); + const dbConnectionOwnerUri = await azdata.connection.getUriForConnection(dbConnectionId); + await utils.assertTableCreationResult('dbo', 'Table3', dbConnectionOwnerUri, retryCount); + + //verify only one difference exist now + let schemaCompareResult2 = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, null); + assertSchemaCompareResult(schemaCompareResult2, operationId, 1); + + //verify the one difference is of Function1 + function1Difference = schemaCompareResult2.differences.find(e => e.sourceValue && e.sourceValue[1] === 'Function1' && e.name === 'SqlInlineTableValuedFunction'); + assert(function1Difference !== undefined, 'The difference function Function1 should be found. Should not be undefined'); + } + finally { + await utils.tryDeleteDB(server, targetDB, ownerUri); + } + }); + + test('Schema compare dacpac to database comparison with publishing all changes and then compare again', async function () { + this.timeout(testTimeout); + const server = await getStandaloneServer(); + const ownerUri = await getConnectionUri(server); + const now = new Date().getTime().toString(); + const operationId = 'testOperationId_' + now; + const targetDB: string = 'ads_schemaCompare_targetDB_' + now; + + try { + assert(dacfxService, 'DacFx Service Provider is not available'); + let result = await dacfxService.deployDacpac(dacpac1, targetDB, true, ownerUri, azdata.TaskExecutionMode.execute); + + assert(result.success === true, 'Deploy database 2 (target) should succeed'); + + const source: mssql.SchemaCompareEndpointInfo = { + endpointType: mssql.SchemaCompareEndpointType.Dacpac, + packageFilePath: dacpac2, + serverDisplayName: '', + serverName: '', + databaseName: '', + ownerUri: ownerUri, + connectionDetails: undefined + }; + const target: mssql.SchemaCompareEndpointInfo = { + endpointType: mssql.SchemaCompareEndpointType.Database, + packageFilePath: '', + serverDisplayName: '', + serverName: server.serverName, + databaseName: targetDB, + ownerUri: ownerUri, + connectionDetails: undefined + }; + + assert(schemaCompareService, 'Schema Compare Service Provider is not available'); + + const schemaCompareResult = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, null); + assertSchemaCompareResult(schemaCompareResult, operationId, 4); + + //publish all the changes + const publishChangesResult = await schemaCompareService.schemaComparePublishChanges(schemaCompareResult.operationId, server.serverName, targetDB, azdata.TaskExecutionMode.execute); + assert(publishChangesResult.success === true, 'Publish changes should complete successfully. But it failed.'); + + //verify table Table3 is added + const dbConnectionId = await utils.connectToServer({ + serverName: server.serverName, + database: targetDB, + userName: server.userName, + password: server.password, + authenticationTypeName: server.authenticationTypeName, + providerName: server.providerName + }); + const dbConnectionOwnerUri = await azdata.connection.getUriForConnection(dbConnectionId); + await utils.assertTableCreationResult('dbo', 'Table3', dbConnectionOwnerUri, retryCount); + + //verify no differences exist now + const schemaCompareResult2 = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, null); + assertSchemaCompareResult(schemaCompareResult2, operationId, 0, true); + } + finally { + await utils.tryDeleteDB(server, targetDB, ownerUri); + } + }); + + test('Schema compare dacpac to database comparison with non-default deployment options', async function () { + this.timeout(testTimeout); + let server = await getStandaloneServer(); + const ownerUri = await getConnectionUri(server); + const now = new Date().getTime().toString(); + const operationId = 'testOperationId_' + now; + const targetDB: string = 'ads_schemaCompare_targetDB_' + now; + + try { + assert(dacfxService, 'DacFx Service Provider is not available'); + let result = await dacfxService.deployDacpac(dacpac1, targetDB, true, ownerUri, azdata.TaskExecutionMode.execute); + + assert(result.success === true, 'Deploy database 2 (target) should succeed'); + + const source: mssql.SchemaCompareEndpointInfo = { + endpointType: mssql.SchemaCompareEndpointType.Dacpac, + packageFilePath: dacpac2, + serverDisplayName: '', + serverName: '', + databaseName: '', + ownerUri: ownerUri, + connectionDetails: undefined + }; + const target: mssql.SchemaCompareEndpointInfo = { + endpointType: mssql.SchemaCompareEndpointType.Database, + packageFilePath: '', + serverDisplayName: '', + serverName: server.serverName, + databaseName: targetDB, + ownerUri: ownerUri, + connectionDetails: undefined + }; + + assert(schemaCompareService, 'Schema Compare Service Provider is not available'); + + const deploymentOptionsResult = await schemaCompareService.schemaCompareGetDefaultOptions(); + let deploymentOptions = deploymentOptionsResult.defaultDeploymentOptions; + deploymentOptions.excludeObjectTypes.push(mssql.SchemaObjectType.TableValuedFunctions); + const schemaCompareResult = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, deploymentOptions); + assertSchemaCompareResult(schemaCompareResult, operationId, 3); + + //Function1 difference of index shouldn't be included in difference + const function1Difference = schemaCompareResult.differences.find(e => e.sourceValue && e.sourceValue[1] === 'Function1' && e.name === 'SqlInlineTableValuedFunction'); + assert(function1Difference === undefined, 'The difference for function Function1 should be undefined'); + } + finally { + await utils.tryDeleteDB(server, targetDB, ownerUri); + } + }); }); async function getConnectionUri(server: TestServerProfile): Promise { @@ -297,10 +490,10 @@ function assertIncludeExcludeResult(result: mssql.SchemaCompareIncludeExcludeRes } } -function assertSchemaCompareResult(schemaCompareResult: mssql.SchemaCompareResult, operationId: string, expectedDifferenceCount: number): void { - assert(schemaCompareResult.areEqual === false, `Expected: the schemas are not to be equal Actual: Equal`); +function assertSchemaCompareResult(schemaCompareResult: mssql.SchemaCompareResult, operationId: string, expectedDifferenceCount: number, expectedIfEqual: boolean = false): void { + assert(schemaCompareResult.areEqual === expectedIfEqual, `Expected: the schemas equivalency to be ${expectedIfEqual} Actual: ${schemaCompareResult.areEqual}`); assert(schemaCompareResult.errorMessage === null, `Expected: there should be no error. Actual Error message: "${schemaCompareResult.errorMessage}"`); - assert(schemaCompareResult.success === true, `Expected: success in schema compare, Actual: Failure`); + assert(schemaCompareResult.success === true, `Expected: success in schema compare. Actual: Failure`); assert(schemaCompareResult.differences.length === expectedDifferenceCount, `Expected: ${expectedDifferenceCount} differences. Actual differences: "${schemaCompareResult.differences.length}"`); assert(schemaCompareResult.operationId === operationId, `Operation Id Expected to be same as passed. Expected : ${operationId}, Actual ${schemaCompareResult.operationId}`); } diff --git a/extensions/integration-tests/src/test/utils.ts b/extensions/integration-tests/src/test/utils.ts index e23d30686c..1e774e0413 100644 --- a/extensions/integration-tests/src/test/utils.ts +++ b/extensions/integration-tests/src/test/utils.ts @@ -146,7 +146,7 @@ export async function deleteDB(server: TestServerProfile, dbName: string, ownerU */ export async function tryDeleteDB(server: TestServerProfile, dbName: string, ownerUri: string): Promise { try { - deleteDB(server, dbName, ownerUri); + await deleteDB(server, dbName, ownerUri); return true; } catch (err) { console.warn(err);