From 8cdb5b36a9cd74225f8855de7cf8dae8b6624575 Mon Sep 17 00:00:00 2001 From: Kim Santiago <31145923+kisantia@users.noreply.github.com> Date: Tue, 7 Jan 2020 10:05:36 -0800 Subject: [PATCH] Add test for schema compare include exclude (#8765) * add test for schema compare include exclude * combine a few checks * small fixes * add testData folder to whtiespace check exclusion list * addressing comments * fix testData path in gulpfile.hygiene.js * move change up a couple lines --- build/gulpfile.hygiene.js | 1 + .../integration-tests/src/dacpac.test.ts | 3 - .../src/schemaCompare.test.ts | 105 +++++++++++++++--- .../SchemaCompareIncludeExcludeSource.dacpac | Bin 0 -> 3471 bytes .../SchemaCompareIncludeExcludeTarget.dacpac | Bin 0 -> 3488 bytes 5 files changed, 91 insertions(+), 18 deletions(-) create mode 100644 extensions/integration-tests/testData/SchemaCompareIncludeExcludeSource.dacpac create mode 100644 extensions/integration-tests/testData/SchemaCompareIncludeExcludeTarget.dacpac diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 1941239ce4..9abf539025 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -103,6 +103,7 @@ const indentationFilter = [ '!extensions/admin-tool-ext-win/ssmsmin/**', '!extensions/resource-deployment/notebooks/**', '!extensions/mssql/notebooks/**', + '!extensions/integration-tests/testData/**', '!extensions/big-data-cluster/src/bigDataCluster/controller/apiGenerated.ts', '!extensions/big-data-cluster/src/bigDataCluster/controller/clusterApiGenerated2.ts' ]; diff --git a/extensions/integration-tests/src/dacpac.test.ts b/extensions/integration-tests/src/dacpac.test.ts index 2ef99bd3fe..fb03095dad 100644 --- a/extensions/integration-tests/src/dacpac.test.ts +++ b/extensions/integration-tests/src/dacpac.test.ts @@ -69,9 +69,6 @@ if (isTestSetupCompleted()) { } }); - // Disabling due to intermittent failure with error Editor is not connected - // Tracking bug https://github.com/microsoft/azuredatastudio/issues/7323 - const bacpac1: string = path.join(__dirname, '..', 'testData', 'Database1.bacpac'); test('Import and export bacpac', async function () { const server = await getStandaloneServer(); diff --git a/extensions/integration-tests/src/schemaCompare.test.ts b/extensions/integration-tests/src/schemaCompare.test.ts index 83fa799b4d..2df8d10954 100644 --- a/extensions/integration-tests/src/schemaCompare.test.ts +++ b/extensions/integration-tests/src/schemaCompare.test.ts @@ -19,8 +19,10 @@ import { stressify } from 'adstest'; let schemaCompareService: mssql.ISchemaCompareService; let dacfxService: mssql.IDacFxService; let schemaCompareTester: SchemaCompareTester; -const dacpac1: string = path.join(__dirname, '../testData/Database1.dacpac'); -const dacpac2: string = path.join(__dirname, '../testData/Database2.dacpac'); +const dacpac1: string = path.join(__dirname, '..','testData', 'Database1.dacpac'); +const dacpac2: string = path.join(__dirname, '..', 'testData', 'Database2.dacpac'); +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 folderPath = path.join(os.tmpdir(), 'SchemaCompareTest'); @@ -47,10 +49,12 @@ if (isTestSetupCompleted()) { test('Schema compare database to database comparison, script generation, and scmp', async function () { await schemaCompareTester.SchemaCompareDatabaseToDatabase(); }); - // TODO: figure out why this is failing with Error: This editor is not connected to a database Parameter name: OwnerUri - // test('Schema compare dacpac to database comparison, script generation, and scmp', async function () { - // await schemaCompareTester.SchemaCompareDacpacToDatabase(); - // }); + test('Schema compare dacpac to database comparison, script generation, and scmp', async function () { + await schemaCompareTester.SchemaCompareDacpacToDatabase(); + }); + test('Schema compare dacpac to dacpac comparison with include exclude', async function () { + await schemaCompareTester.SchemaCompareIncludeExcludeDacpacToDacpac(); + }); }); } @@ -83,7 +87,7 @@ class SchemaCompareTester { }; let schemaCompareResult = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, null); - this.assertSchemaCompareResult(schemaCompareResult, operationId); + this.assertSchemaCompareResult(schemaCompareResult, operationId, 4); // save to scmp const filepath = path.join(folderPath, `ads_schemaCompare_${now.getTime().toString()}.scmp`); @@ -126,8 +130,8 @@ class SchemaCompareTester { assert(result1.success === true, 'Deploy source database should succeed'); assert(result2.success === true, 'Deploy target database should succeed'); - utils.assertDatabaseCreationResult(sourceDB, ownerUri, retryCount); - utils.assertDatabaseCreationResult(targetDB, ownerUri, retryCount); + await utils.assertDatabaseCreationResult(sourceDB, ownerUri, retryCount); + await utils.assertDatabaseCreationResult(targetDB, ownerUri, retryCount); assert(schemaCompareService, 'Schema Compare Service Provider is not available'); @@ -151,7 +155,7 @@ class SchemaCompareTester { }; let schemaCompareResult = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, null); - this.assertSchemaCompareResult(schemaCompareResult, operationId); + this.assertSchemaCompareResult(schemaCompareResult, operationId, 4); let status = await schemaCompareService.schemaCompareGenerateScript(schemaCompareResult.operationId, server.serverName, targetDB, azdata.TaskExecutionMode.script); @@ -160,7 +164,7 @@ class SchemaCompareTester { await this.assertScriptGenerationResult(status, target.serverName, target.databaseName); // save to scmp - const filepath = path.join(folderPath,`ads_schemaCompare_${now.getTime().toString()}.scmp`); + const filepath = path.join(folderPath, `ads_schemaCompare_${now.getTime().toString()}.scmp`); if (!fs.existsSync(folderPath)) { fs.mkdirSync(folderPath); } @@ -226,7 +230,7 @@ class SchemaCompareTester { assert(schemaCompareService, 'Schema Compare Service Provider is not available'); let schemaCompareResult = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, null); - this.assertSchemaCompareResult(schemaCompareResult, operationId); + this.assertSchemaCompareResult(schemaCompareResult, operationId, 4); let status = await schemaCompareService.schemaCompareGenerateScript(schemaCompareResult.operationId, server.serverName, targetDB, azdata.TaskExecutionMode.script); await this.assertScriptGenerationResult(status, target.serverName, target.databaseName); @@ -251,18 +255,89 @@ class SchemaCompareTester { } } - private assertSchemaCompareResult(schemaCompareResult: mssql.SchemaCompareResult, operationId: string): void { + @stressify({ dop: SchemaCompareTester.ParallelCount }) + async SchemaCompareIncludeExcludeDacpacToDacpac(): Promise { + assert(schemaCompareService, 'Schema Compare Service Provider is not available'); + const operationId = 'testOperationId_' + new Date().getTime().toString(); + + let source: mssql.SchemaCompareEndpointInfo = { + endpointType: mssql.SchemaCompareEndpointType.Dacpac, + packageFilePath: includeExcludeSourceDacpac, + serverDisplayName: '', + serverName: '', + databaseName: '', + ownerUri: '', + connectionDetails: undefined + }; + let target: mssql.SchemaCompareEndpointInfo = { + endpointType: mssql.SchemaCompareEndpointType.Dacpac, + packageFilePath: includeExcludeTargetDacpac, + serverDisplayName: '', + serverName: '', + databaseName: '', + ownerUri: '', + connectionDetails: undefined + }; + + const deploymentOptionsResult = await schemaCompareService.schemaCompareGetDefaultOptions(); + let deploymentOptions = deploymentOptionsResult.defaultDeploymentOptions; + const schemaCompareResult = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, deploymentOptions); + this.assertSchemaCompareResult(schemaCompareResult, operationId, 5); + + // try to exclude table t2 and it should fail because a dependency is still included + const t2Difference = schemaCompareResult.differences.find(e => e.sourceValue && e.sourceValue[1] === 't2' && e.name === 'SqlTable'); + assert(t2Difference !== undefined, 'The difference Table t2 should be found. Should not be undefined'); + const excludeResult = await schemaCompareService.schemaCompareIncludeExcludeNode(operationId, t2Difference, false, azdata.TaskExecutionMode.execute); + this.assertIncludeExcludeResult(excludeResult, false, 1, 0); + assert(excludeResult.blockingDependencies[0].sourceValue[1] === 'v1', `Blocking dependency should be view v1. Actual: ${excludeResult.blockingDependencies[0].sourceValue[1]}`); + + // Exclude the view v1 that t2 was a dependency for and it should succeed and t2 should also be excluded + const v1Difference = schemaCompareResult.differences.find(e => e.sourceValue && e.sourceValue[1] === 'v1' && e.name === 'SqlView'); + assert(v1Difference !== undefined, 'The difference View v1 should be found. Should not be undefined'); + const excludeResult2 = await schemaCompareService.schemaCompareIncludeExcludeNode(operationId, v1Difference, false, azdata.TaskExecutionMode.execute); + this.assertIncludeExcludeResult(excludeResult2, true, 0, 1); + assert(excludeResult2.affectedDependencies[0].sourceValue[1] === 't2', `Table t2 should be the affected dependency. Actual: ${excludeResult2.affectedDependencies[0].sourceValue[1]}`); + assert(excludeResult2.affectedDependencies[0].included === false, 'Table t2 should be excluded as a result of excluding v1. Actual: true'); + + // including the view v1 should also include the table t2 + const includeResult = await schemaCompareService.schemaCompareIncludeExcludeNode(operationId, v1Difference, true, azdata.TaskExecutionMode.execute); + this.assertIncludeExcludeResult(includeResult, true, 0, 1); + assert(includeResult.affectedDependencies[0].sourceValue[1] === 't2', `Table t2 should be the affected dependency. Actual: ${includeResult.affectedDependencies[0].sourceValue[1]}`); + assert(includeResult.affectedDependencies[0].included === true, 'Table t2 should be included as a result of including v1. Actual: false'); + + // excluding views from the comparison should make it so t2 can be excluded + deploymentOptions.excludeObjectTypes.push(mssql.SchemaObjectType.Views); + await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, deploymentOptions); + const excludeResult3 = await schemaCompareService.schemaCompareIncludeExcludeNode(operationId, t2Difference, false, azdata.TaskExecutionMode.execute); + this.assertIncludeExcludeResult(excludeResult3, true, 0, 0); + } + + private assertIncludeExcludeResult(result: mssql.SchemaCompareIncludeExcludeResult, expectedSuccess: boolean, expectedBlockingDependenciesLength: number, expectedAffectedDependenciesLength: number): void { + assert(result.success === expectedSuccess, `Operation success should have been ${expectedSuccess}. Actual: ${result.success}`); + if (result.blockingDependencies) { + assert(result.blockingDependencies.length === expectedBlockingDependenciesLength, `Expected ${expectedBlockingDependenciesLength} blocking dependencies. Actual: ${result.blockingDependencies}`); + } else if (expectedBlockingDependenciesLength !== 0) { + throw new Error(`ExpectedBlockingDependencies length was ${expectedBlockingDependenciesLength} but blockingDependencies was undefined`); + } + if (result.affectedDependencies) { + assert(result.affectedDependencies.length === expectedAffectedDependenciesLength, `Expected ${expectedAffectedDependenciesLength} affected dependencies. Actual: ${result.affectedDependencies}`); + } else if (expectedAffectedDependenciesLength !== 0) { + throw new Error(`ExpectedAffectedDependencies length was ${expectedAffectedDependenciesLength} but affectedDependencies was undefined`); + } + } + + private assertSchemaCompareResult(schemaCompareResult: mssql.SchemaCompareResult, operationId: string, expectedDifferenceCount: number): void { assert(schemaCompareResult.areEqual === false, `Expected: the schemas are not to be equal Actual: Equal`); 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.differences.length === 4, `Expected: 4 differences. Actual differences: "${schemaCompareResult.differences.length}"`); + 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}`); } private async assertScriptGenerationResult(resultstatus: azdata.ResultStatus, server: string, database: string): Promise { // TODO add more validation assert(resultstatus.success === true, `Expected: success true Actual: "${resultstatus.success}" Error Message: "${resultstatus.errorMessage}`); - const taskService = await azdata.dataprotocol.getProvider('MSSQL', azdata.DataProviderType.TaskServicesProvider); + const taskService = azdata.dataprotocol.getProvider('MSSQL', azdata.DataProviderType.TaskServicesProvider); const tasks = await taskService.getAllTasks({ listActiveTasksOnly: true }); let foundTask: azdata.TaskInfo; tasks.tasks.forEach(t => { diff --git a/extensions/integration-tests/testData/SchemaCompareIncludeExcludeSource.dacpac b/extensions/integration-tests/testData/SchemaCompareIncludeExcludeSource.dacpac new file mode 100644 index 0000000000000000000000000000000000000000..311a269bdeb3b45dfd8cb4ed3ca7a99826fc0a3d GIT binary patch literal 3471 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 AI{*Lx literal 0 HcmV?d00001