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 0000000000..311a269bde Binary files /dev/null and b/extensions/integration-tests/testData/SchemaCompareIncludeExcludeSource.dacpac differ diff --git a/extensions/integration-tests/testData/SchemaCompareIncludeExcludeTarget.dacpac b/extensions/integration-tests/testData/SchemaCompareIncludeExcludeTarget.dacpac new file mode 100644 index 0000000000..018dd5cdbe Binary files /dev/null and b/extensions/integration-tests/testData/SchemaCompareIncludeExcludeTarget.dacpac differ