diff --git a/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj b/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj index f6041472..cad3b3d7 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj +++ b/src/Microsoft.SqlTools.ServiceLayer/Microsoft.SqlTools.ServiceLayer.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/DeploymentOptions.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/DeploymentOptions.cs index 5feeb904..f65d6ee5 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/DeploymentOptions.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/DeploymentOptions.cs @@ -116,6 +116,10 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts public int CommandTimeout { get; set; } = 120; + public int LongRunningCommandTimeout { get; set; } = 0; + + public int DatabaseLockTimeout { get; set; } = 60; + public bool BlockWhenDriftDetected { get; set; } public bool BlockOnPossibleDataLoss { get; set; } @@ -176,6 +180,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts public bool IgnoreColumnOrder { get; set; } + public string AdditionalDeploymentContributorPaths { get; set; } = string.Empty; + public ObjectType[] DoNotDropObjectTypes { get; set; } = null; public ObjectType[] ExcludeObjectTypes { get; set; } = @@ -185,7 +191,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts ObjectType.LinkedServerLogins, ObjectType.Endpoints, ObjectType.ErrorMessages, - ObjectType.Filegroups, + ObjectType.Files, ObjectType.Logins, ObjectType.LinkedServers, ObjectType.Credentials, diff --git a/test/Microsoft.SqlTools.ManagedBatchParser.IntegrationTests/Microsoft.SqlTools.ManagedBatchParser.IntegrationTests.csproj b/test/Microsoft.SqlTools.ManagedBatchParser.IntegrationTests/Microsoft.SqlTools.ManagedBatchParser.IntegrationTests.csproj index 2245ff18..d3c45d01 100644 --- a/test/Microsoft.SqlTools.ManagedBatchParser.IntegrationTests/Microsoft.SqlTools.ManagedBatchParser.IntegrationTests.csproj +++ b/test/Microsoft.SqlTools.ManagedBatchParser.IntegrationTests/Microsoft.SqlTools.ManagedBatchParser.IntegrationTests.csproj @@ -35,7 +35,7 @@ - + diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj index 13d79d60..6a18af3f 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Microsoft.SqlTools.ServiceLayer.IntegrationTests.csproj @@ -36,7 +36,7 @@ - + diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs index 36486151..4df6823a 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs @@ -85,6 +85,7 @@ END ObjectType.Endpoints, ObjectType.ErrorMessages, ObjectType.Filegroups, + ObjectType.Files, ObjectType.Logins, ObjectType.LinkedServers, ObjectType.Credentials, diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs index 983d936f..d3323e78 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs @@ -45,6 +45,23 @@ CREATE TABLE [dbo].[table3] [col1] INT NULL, )"; + private const string CreateKey = @"CREATE COLUMN MASTER KEY [CMK_Auto1] +WITH ( + KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE', + KEY_PATH = N'CurrentUser/my/1234' +); +CREATE COLUMN ENCRYPTION KEY [CEK_Auto1] +WITH VALUES +( + COLUMN_MASTER_KEY = [CMK_Auto1], + ALGORITHM = N'RSA_OAEP', + ENCRYPTED_VALUE = 0x0000 +);"; + + private const string CreateFileGroup = @"ALTER DATABASE {0} + ADD FILEGROUP [MyFileGroup] CONTAINS MEMORY_OPTIMIZED_DATA; + GO"; + /// /// Verify the schema compare request comparing two dacpacs /// @@ -653,7 +670,7 @@ CREATE TABLE [dbo].[table3] await SchemaCompareService.Instance.HandleSchemaCompareOpenScmpRequest(openScmpParams, openScmpRequestContext.Object); await SchemaCompareService.Instance.CurrentSchemaCompareTask; - SchemaCompareTestUtils.VerifyAndCleanup(scmpFilePath); + SchemaCompareTestUtils.VerifyAndCleanup(scmpFilePath); } finally { @@ -712,6 +729,81 @@ CREATE TABLE [dbo].[table3] } } + /// + /// test to verify recent dacfx bugs + /// does not need all combinations of db and dacpacs + /// + [Fact] + public async void SchemaCompareCEKAndFilegoupTest() + { + var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects(); + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, CreateKey, "SchemaCompareSource"); + sourceDb.RunQuery(string.Format(CreateFileGroup, sourceDb.DatabaseName)); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); + + try + { + SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo(); + SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo(); + + sourceInfo.EndpointType = SchemaCompareEndpointType.Database; + sourceInfo.DatabaseName = sourceDb.DatabaseName; + targetInfo.EndpointType = SchemaCompareEndpointType.Database; + targetInfo.DatabaseName = targetDb.DatabaseName; + DeploymentOptions options = new DeploymentOptions(); + + // ensure that files are excluded seperate from filegroups + Assert.True(options.ExcludeObjectTypes.Contains(SqlServer.Dac.ObjectType.Files)); + Assert.False(options.ExcludeObjectTypes.Contains(SqlServer.Dac.ObjectType.Filegroups)); + + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo, + DeploymentOptions = options + }; + + SchemaCompareOperation schemaCompareOperation = new SchemaCompareOperation(schemaCompareParams, result.ConnectionInfo, result.ConnectionInfo); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + + // validate CEK script + var cek = schemaCompareOperation.ComparisonResult.Differences.First(x => x.Name == "SqlColumnEncryptionKey"); + Assert.NotNull(cek); + Assert.True(cek.SourceObject != null, "CEK obect is null"); + Assert.True(cek.SourceObject.Name.ToString() == "[CEK_Auto1]", string.Format("CEK object name incorrect. Expected {0}, Actual {1}", "CEK_Auto1", cek.SourceObject.Name.ToString())); + Assert.True(CreateKey.Contains(cek.SourceObject.GetScript().Trim()), string.Format("Expected script : {0}, Actual Script {1}", cek.SourceObject.GetScript(), CreateKey)); + + // validate CMK script + var cmk = schemaCompareOperation.ComparisonResult.Differences.First(x => x.Name == "SqlColumnMasterKey"); + Assert.NotNull(cmk); + Assert.True(cmk.SourceObject != null, "CMK obect is null"); + Assert.True(cmk.SourceObject.Name.ToString() == "[CMK_Auto1]", string.Format("CMK object name incorrect. Expected {0}, Actual {1}", "CEK_Auto1", cmk.SourceObject.Name.ToString())); + Assert.True(CreateKey.Contains(cmk.SourceObject.GetScript().Trim()), string.Format("Expected script : {0}, Actual Script {1}", cmk.SourceObject.GetScript(), CreateKey)); + + // validate filegroup's presence + var filegroup = schemaCompareOperation.ComparisonResult.Differences.First(x => x.Name == "SqlFilegroup"); + Assert.NotNull(filegroup); + Assert.True(filegroup.SourceObject != null, "File group obect is null"); + + // validate file's absense + bool filepresent = schemaCompareOperation.ComparisonResult.Differences.Any(x => x.Name == "SqlFile"); + Assert.False(filepresent, "SqlFile should not be present"); + var objectsWithFileInName = schemaCompareOperation.ComparisonResult.Differences.Where(x => x.Name.Contains("File")); + Assert.True(1 == objectsWithFileInName.Count(), string.Format("Only one File/Filegroup object was to be found, but found {0}", objectsWithFileInName.Count())); + } + finally + { + // cleanup + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + + } + private void ValidateSchemaCompareWithExcludeIncludeResults(SchemaCompareOperation schemaCompareOperation) { schemaCompareOperation.Execute(TaskExecutionMode.Execute); diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs index 2cc59e94..69ef1cc7 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs @@ -89,7 +89,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare System.Reflection.PropertyInfo[] deploymentOptionsProperties = deploymentOptions.GetType().GetProperties(); System.Reflection.PropertyInfo[] dacDeployProperties = dacDeployOptions.GetType().GetProperties(); - // Note that DatabaseSpecification and sql cmd variables list is not present in Sqltools service - its not settable and is not used by ADS options. + // Note that DatabaseSpecification and sql cmd variables list is not present in Sqltools service - its not settable with checkbox and is not used by ADS options. // They are not present in SSDT as well // TODO : update this test if the above options are added later Assert.True(deploymentOptionsProperties.Length == dacDeployProperties.Length - 2, $"Number of properties is not same Deployment options : {deploymentOptionsProperties.Length} DacFx options : {dacDeployProperties.Length}");