From 9e143362933e45f507f0156b7b4442560cab41dc Mon Sep 17 00:00:00 2001
From: udeeshagautam <46980425+udeeshagautam@users.noreply.github.com>
Date: Thu, 18 Apr 2019 12:52:10 -0700
Subject: [PATCH] Feature/schemacompare options (#798)
* Initial working code for schema compare options
* Removing the unnecessary default value attribute
* Cleaning up tests
* Taking PR comments
* Taking name change for Schema Compare Options --> Deployment Options
* Remove parent to avoid circular reference (to avoid issues with serialization)
---
.../Contracts/DeploymentOptions.cs | 222 ++++++++++
.../Contracts/SchemaCompareRequest.cs | 5 +
.../SchemaCompare/SchemaCompareOperation.cs | 47 +-
.../SchemaCompareServiceOptionsTests.cs | 400 ++++++++++++++++++
.../SchemaCompareServiceTests.cs | 82 +---
.../SchemaCompare/SchemaCompareTestUtils.cs | 57 +++
6 files changed, 741 insertions(+), 72 deletions(-)
create mode 100644 src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/DeploymentOptions.cs
create mode 100644 test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs
create mode 100644 test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/DeploymentOptions.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/DeploymentOptions.cs
new file mode 100644
index 00000000..59cb3b94
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/DeploymentOptions.cs
@@ -0,0 +1,222 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlServer.Dac;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+
+namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
+{
+ ///
+ /// Class to define deployment options.
+ /// Keeping the order and defaults same as DacFx
+ /// The default values here should also match the default values in ADS UX
+ ///
+ public class DeploymentOptions
+ {
+ public bool IgnoreTableOptions { get; set; }
+
+ public bool IgnoreSemicolonBetweenStatements { get; set; }
+
+ public bool IgnoreRouteLifetime { get; set; }
+
+ public bool IgnoreRoleMembership { get; set; }
+
+ public bool IgnoreQuotedIdentifiers { get; set; }
+
+ public bool IgnorePermissions { get; set; }
+
+ public bool IgnorePartitionSchemes { get; set; }
+
+ public bool IgnoreObjectPlacementOnPartitionScheme { get; set; }
+
+ public bool IgnoreNotForReplication { get; set; }
+
+ public bool IgnoreLoginSids { get; set; }
+
+ public bool IgnoreLockHintsOnIndexes { get; set; }
+
+ public bool IgnoreKeywordCasing { get; set; }
+
+ public bool IgnoreIndexPadding { get; set; }
+
+ public bool IgnoreIndexOptions { get; set; }
+
+ public bool IgnoreIncrement { get; set; }
+
+ public bool IgnoreIdentitySeed { get; set; }
+
+ public bool IgnoreUserSettingsObjects { get; set; }
+
+ public bool IgnoreFullTextCatalogFilePath { get; set; }
+
+ public bool IgnoreWhitespace { get; set; }
+
+ public bool IgnoreWithNocheckOnForeignKeys { get; set; }
+
+ public bool VerifyCollationCompatibility { get; set; }
+
+ public bool UnmodifiableObjectWarnings { get; set; }
+
+ public bool TreatVerificationErrorsAsWarnings { get; set; }
+
+ public bool ScriptRefreshModule { get; set; }
+
+ public bool ScriptNewConstraintValidation { get; set; }
+
+ public bool ScriptFileSize { get; set; }
+
+ public bool ScriptDeployStateChecks { get; set; }
+
+ public bool ScriptDatabaseOptions { get; set; }
+
+ public bool ScriptDatabaseCompatibility { get; set; }
+
+ public bool ScriptDatabaseCollation { get; set; }
+
+ public bool RunDeploymentPlanExecutors { get; set; }
+
+ public bool RegisterDataTierApplication { get; set; }
+
+ public bool PopulateFilesOnFileGroups { get; set; }
+
+ public bool NoAlterStatementsToChangeClrTypes { get; set; }
+
+ public bool IncludeTransactionalScripts { get; set; }
+
+ public bool IncludeCompositeObjects { get; set; }
+
+ public bool AllowUnsafeRowLevelSecurityDataMovement { get; set; }
+
+ public bool IgnoreWithNocheckOnCheckConstraints { get; set; }
+
+ public bool IgnoreFillFactor { get; set; }
+
+ public bool IgnoreFileSize { get; set; }
+
+ public bool IgnoreFilegroupPlacement { get; set; }
+
+ public bool DoNotAlterReplicatedObjects { get; set; }
+
+ public bool DoNotAlterChangeDataCaptureObjects { get; set; }
+
+ public bool DisableAndReenableDdlTriggers { get; set; }
+
+ public bool DeployDatabaseInSingleUserMode { get; set; }
+
+ public bool CreateNewDatabase { get; set; }
+
+ public bool CompareUsingTargetCollation { get; set; }
+
+ public bool CommentOutSetVarDeclarations { get; set; }
+
+ public int CommandTimeout { get; set; } = 120;
+
+ public bool BlockWhenDriftDetected { get; set; }
+
+ public bool BlockOnPossibleDataLoss { get; set; }
+
+ public bool BackupDatabaseBeforeChanges { get; set; }
+
+ public bool AllowIncompatiblePlatform { get; set; }
+
+ public bool AllowDropBlockingAssemblies { get; set; }
+
+ public string AdditionalDeploymentContributorArguments { get; set; }
+
+ public string AdditionalDeploymentContributors { get; set; }
+
+ public bool DropConstraintsNotInSource { get; set; }
+
+ public bool DropDmlTriggersNotInSource { get; set; }
+
+ public bool DropExtendedPropertiesNotInSource { get; set; }
+
+ public bool DropIndexesNotInSource { get; set; }
+
+ public bool IgnoreFileAndLogFilePath { get; set; }
+
+ public bool IgnoreExtendedProperties { get; set; }
+
+ public bool IgnoreDmlTriggerState { get; set; }
+
+ public bool IgnoreDmlTriggerOrder { get; set; }
+
+ public bool IgnoreDefaultSchema { get; set; }
+
+ public bool IgnoreDdlTriggerState { get; set; }
+
+ public bool IgnoreDdlTriggerOrder { get; set; }
+
+ public bool IgnoreCryptographicProviderFilePath { get; set; }
+
+ public bool VerifyDeployment { get; set; }
+
+ public bool IgnoreComments { get; set; }
+
+ public bool IgnoreColumnCollation { get; set; }
+
+ public bool IgnoreAuthorizer { get; set; }
+
+ public bool IgnoreAnsiNulls { get; set; }
+
+ public bool GenerateSmartDefaults { get; set; }
+
+ public bool DropStatisticsNotInSource { get; set; }
+
+ public bool DropRoleMembersNotInSource { get; set; }
+
+ public bool DropPermissionsNotInSource { get; set; }
+
+ public bool DropObjectsNotInSource { get; set; }
+
+ public bool IgnoreColumnOrder { get; set; }
+
+ public ObjectType[] DoNotDropObjectTypes { get; set; } = null;
+
+ public ObjectType[] ExcludeObjectTypes { get; set; } =
+ {
+ ObjectType.ServerTriggers,
+ ObjectType.Routes,
+ ObjectType.LinkedServerLogins,
+ ObjectType.Endpoints,
+ ObjectType.ErrorMessages,
+ ObjectType.Filegroups,
+ ObjectType.Logins,
+ ObjectType.LinkedServers,
+ ObjectType.Credentials,
+ ObjectType.DatabaseScopedCredentials,
+ ObjectType.DatabaseEncryptionKeys,
+ ObjectType.MasterKeys,
+ ObjectType.DatabaseAuditSpecifications,
+ ObjectType.Audits,
+ ObjectType.ServerAuditSpecifications,
+ ObjectType.CryptographicProviders,
+ ObjectType.ServerRoles,
+ ObjectType.EventSessions,
+ ObjectType.DatabaseOptions,
+ ObjectType.EventNotifications,
+ ObjectType.ServerRoleMembership,
+ ObjectType.AssemblyFiles,
+ };
+
+ public DeploymentOptions()
+ {
+ DacDeployOptions options = new DacDeployOptions();
+ System.Reflection.PropertyInfo[] deploymentOptionsProperties = this.GetType().GetProperties();
+
+ foreach (var deployOptionsProp in deploymentOptionsProperties)
+ {
+ var prop = options.GetType().GetProperty(deployOptionsProp.Name);
+ if (prop != null)
+ {
+ deployOptionsProp.SetValue(this, prop.GetValue(options));
+ }
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareRequest.cs
index 0cd43561..4203f127 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareRequest.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareRequest.cs
@@ -58,6 +58,11 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts
/// Executation mode for the operation. Default is execution
///
public TaskExecutionMode TaskExecutionMode { get; set; }
+
+ ///
+ /// gets or sets the deployment options for schema compare
+ ///
+ public DeploymentOptions DeploymentOptions { get; set; }
}
///
diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOperation.cs
index 61b043c7..1de38af5 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOperation.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOperation.cs
@@ -2,6 +2,7 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
+using Microsoft.SqlServer.Dac;
using Microsoft.SqlServer.Dac.Compare;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts;
@@ -40,6 +41,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
public List Differences;
+ public DacDeployOptions DefaultOptions;
+
public SchemaCompareOperation(SchemaCompareParams parameters, ConnectionInfo sourceConnInfo, ConnectionInfo targetConnInfo)
{
Validate.IsNotNull("parameters", parameters);
@@ -86,10 +89,16 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
SchemaCompareEndpoint targetEndpoint = CreateSchemaCompareEndpoint(this.Parameters.TargetEndpointInfo, this.TargetConnectionString);
SchemaComparison comparison = new SchemaComparison(sourceEndpoint, targetEndpoint);
+
+ if (this.Parameters.DeploymentOptions != null)
+ {
+ comparison.Options = this.CreateSchemaCompareOptions(this.Parameters.DeploymentOptions);
+ }
+
this.ComparisonResult = comparison.Compare();
// try one more time if it didn't work the first time
- if(!this.ComparisonResult.IsValid)
+ if (!this.ComparisonResult.IsValid)
{
this.ComparisonResult = comparison.Compare();
}
@@ -109,6 +118,22 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
}
}
+ private DacDeployOptions CreateSchemaCompareOptions(DeploymentOptions deploymentOptions)
+ {
+ System.Reflection.PropertyInfo[] deploymentOptionsProperties = deploymentOptions.GetType().GetProperties();
+
+ DacDeployOptions dacOptions = new DacDeployOptions();
+ foreach (var deployOptionsProp in deploymentOptionsProperties)
+ {
+ var prop = dacOptions.GetType().GetProperty(deployOptionsProp.Name);
+ if (prop != null)
+ {
+ prop.SetValue(dacOptions, deployOptionsProp.GetValue(deploymentOptions));
+ }
+ }
+ return dacOptions;
+ }
+
private DiffEntry CreateDiffEntry(SchemaDifference difference, DiffEntry parent)
{
DiffEntry diffEntry = new DiffEntry();
@@ -141,7 +166,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
diffEntry.TargetScript = RemoveExcessWhitespace(targetScript);
}
}
-
+
diffEntry.Children = new List();
foreach (SchemaDifference child in difference.Children)
@@ -157,17 +182,17 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare
switch (endpointInfo.EndpointType)
{
case SchemaCompareEndpointType.Dacpac:
- {
- return new SchemaCompareDacpacEndpoint(endpointInfo.PackageFilePath);
- }
+ {
+ return new SchemaCompareDacpacEndpoint(endpointInfo.PackageFilePath);
+ }
case SchemaCompareEndpointType.Database:
- {
- return new SchemaCompareDatabaseEndpoint(connectionString);
- }
+ {
+ return new SchemaCompareDatabaseEndpoint(connectionString);
+ }
default:
- {
- return null;
- }
+ {
+ return null;
+ }
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs
new file mode 100644
index 00000000..6f2bd153
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs
@@ -0,0 +1,400 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+using Microsoft.SqlTools.Hosting.Protocol;
+using Microsoft.SqlTools.ServiceLayer.DacFx;
+using Microsoft.SqlTools.ServiceLayer.DacFx.Contracts;
+using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
+using Microsoft.SqlTools.ServiceLayer.SchemaCompare;
+using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts;
+using Microsoft.SqlTools.ServiceLayer.TaskServices;
+using Microsoft.SqlTools.ServiceLayer.Test.Common;
+using Microsoft.SqlServer.Dac;
+using Moq;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare
+{
+ ///
+ /// Group of tests to test non-default options and included items for schema comapre
+ /// Note - adding it to new class for easy findability
+ ///
+ public class SchemaCompareServiceOptionsTests
+ {
+ private const string Source1 = @"CREATE TABLE [dbo].[table1]
+(
+ [ID] INT NOT NULL PRIMARY KEY,
+ [Date] DATE NOT NULL,
+)";
+ private const string Target1 = @"CREATE TABLE [dbo].[table1]
+(
+ [Date] DATE NOT NULL,
+ [ID] INT NOT NULL PRIMARY KEY,
+)";
+
+ private const string Source2 = @"
+CREATE FUNCTION [dbo].[Function1]
+(
+ @param1 int,
+ @param2 char(5)
+)
+RETURNS @returntable TABLE
+(
+ c1 int,
+ c2 char(5)
+)
+AS
+BEGIN
+ INSERT @returntable
+ SELECT @param1, @param2
+ RETURN
+END"
+;
+ private const string Target2 = @"CREATE FUNCTION [dbo].[Function1]
+(
+ @param1 int,
+ @param2 char(5)
+)
+RETURNS @returntable TABLE
+(
+ x1 int,
+ x2 char(5)
+)
+AS
+BEGIN
+ INSERT @returntable
+ SELECT @param1, @param2
+ RETURN
+END
+";
+ private DeploymentOptions GetIgnoreColumnOptions()
+ {
+ var options = new DeploymentOptions();
+ options.IgnoreColumnOrder = true;
+ return options;
+ }
+
+ private DeploymentOptions GetExcludeTableValuedFunctionOptions()
+ {
+ var options = new DeploymentOptions();
+ options.ExcludeObjectTypes = new ObjectType[]{
+ ObjectType.ServerTriggers,
+ ObjectType.Routes,
+ ObjectType.LinkedServerLogins,
+ ObjectType.Endpoints,
+ ObjectType.ErrorMessages,
+ ObjectType.Filegroups,
+ ObjectType.Logins,
+ ObjectType.LinkedServers,
+ ObjectType.Credentials,
+ ObjectType.DatabaseScopedCredentials,
+ ObjectType.DatabaseEncryptionKeys,
+ ObjectType.MasterKeys,
+ ObjectType.DatabaseAuditSpecifications,
+ ObjectType.Audits,
+ ObjectType.ServerAuditSpecifications,
+ ObjectType.CryptographicProviders,
+ ObjectType.ServerRoles,
+ ObjectType.EventSessions,
+ ObjectType.DatabaseOptions,
+ ObjectType.EventNotifications,
+ ObjectType.ServerRoleMembership,
+ ObjectType.AssemblyFiles,
+ ObjectType.TableValuedFunctions, //added Functions to excluded types
+ };
+ return options;
+ }
+
+ private async Task>> SendAndValidateSchemaCompareRequestDacpacToDacpacWithOptions(string sourceScript, string targetScript, DeploymentOptions nodiffOption, DeploymentOptions shouldDiffOption)
+ {
+
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
+ var schemaCompareRequestContext = new Mock>();
+ schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
+
+ // create dacpacs from databases
+ SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, sourceScript, "SchemaCompareSource");
+ SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, targetScript, "SchemaCompareTarget");
+ try
+ {
+ string sourceDacpacFilePath = SchemaCompareTestUtils.CreateDacpac(sourceDb);
+ string targetDacpacFilePath = SchemaCompareTestUtils.CreateDacpac(targetDb);
+
+ SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo();
+ SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo();
+
+ sourceInfo.EndpointType = SchemaCompareEndpointType.Dacpac;
+ sourceInfo.PackageFilePath = sourceDacpacFilePath;
+ targetInfo.EndpointType = SchemaCompareEndpointType.Dacpac;
+ targetInfo.PackageFilePath = targetDacpacFilePath;
+
+ var schemaCompareParams1 = new SchemaCompareParams
+ {
+ SourceEndpointInfo = sourceInfo,
+ TargetEndpointInfo = targetInfo,
+ DeploymentOptions = nodiffOption
+ };
+
+ SchemaCompareOperation schemaCompareOperation1 = new SchemaCompareOperation(schemaCompareParams1, null, null);
+ schemaCompareOperation1.Execute(TaskExecutionMode.Execute);
+ Assert.True(schemaCompareOperation1.ComparisonResult.IsEqual);
+
+ var schemaCompareParams2 = new SchemaCompareParams
+ {
+ SourceEndpointInfo = sourceInfo,
+ TargetEndpointInfo = targetInfo,
+ DeploymentOptions = shouldDiffOption,
+ };
+
+ SchemaCompareOperation schemaCompareOperation2 = new SchemaCompareOperation(schemaCompareParams2, null, null);
+ schemaCompareOperation2.Execute(TaskExecutionMode.Execute);
+ Assert.False(schemaCompareOperation2.ComparisonResult.IsEqual);
+ Assert.NotNull(schemaCompareOperation2.ComparisonResult.Differences);
+
+ // cleanup
+ SchemaCompareTestUtils.VerifyAndCleanup(sourceDacpacFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(targetDacpacFilePath);
+ }
+ finally
+ {
+ sourceDb.Cleanup();
+ targetDb.Cleanup();
+ }
+
+ return schemaCompareRequestContext;
+ }
+
+ private async Task>> SendAndValidateSchemaCompareRequestDatabaseToDatabaseWithOptions(string sourceScript, string targetScript, DeploymentOptions nodiffOption, DeploymentOptions shouldDiffOption)
+ {
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
+ var schemaCompareRequestContext = new Mock>();
+ schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
+
+ SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, sourceScript, "SchemaCompareSource");
+ SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, targetScript, "SchemaCompareTarget");
+ string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest");
+ Directory.CreateDirectory(folderPath);
+
+ 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;
+
+ var schemaCompareParams1 = new SchemaCompareParams
+ {
+ SourceEndpointInfo = sourceInfo,
+ TargetEndpointInfo = targetInfo,
+ DeploymentOptions = nodiffOption
+ };
+
+ SchemaCompareOperation schemaCompareOperation1 = new SchemaCompareOperation(schemaCompareParams1, result.ConnectionInfo, result.ConnectionInfo);
+ schemaCompareOperation1.Execute(TaskExecutionMode.Execute);
+
+ Assert.True(schemaCompareOperation1.ComparisonResult.IsValid);
+ Assert.True(schemaCompareOperation1.ComparisonResult.IsEqual);
+ Assert.NotNull(schemaCompareOperation1.ComparisonResult.Differences);
+
+ var schemaCompareParams2 = new SchemaCompareParams
+ {
+ SourceEndpointInfo = sourceInfo,
+ TargetEndpointInfo = targetInfo,
+ DeploymentOptions = shouldDiffOption,
+ };
+
+ SchemaCompareOperation schemaCompareOperation2 = new SchemaCompareOperation(schemaCompareParams2, result.ConnectionInfo, result.ConnectionInfo);
+ schemaCompareOperation2.Execute(TaskExecutionMode.Execute);
+ Assert.False(schemaCompareOperation2.ComparisonResult.IsEqual);
+ Assert.NotNull(schemaCompareOperation2.ComparisonResult.Differences);
+ }
+ finally
+ {
+ // cleanup
+ sourceDb.Cleanup();
+ targetDb.Cleanup();
+ }
+ return schemaCompareRequestContext;
+ }
+
+ private async Task>> SendAndValidateSchemaCompareGenerateScriptRequestDacpacToDatabaseWithOptions(string sourceScript, string targetScript, DeploymentOptions nodiffOption, DeploymentOptions shouldDiffOption)
+ {
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
+ var schemaCompareRequestContext = new Mock>();
+ schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
+
+ SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, sourceScript, "SchemaCompareSource");
+ SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, targetScript, "SchemaCompareTarget");
+ string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest");
+ Directory.CreateDirectory(folderPath);
+
+ try
+ {
+ string sourceDacpacFilePath = SchemaCompareTestUtils.CreateDacpac(sourceDb);
+
+ SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo();
+ SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo();
+
+ sourceInfo.EndpointType = SchemaCompareEndpointType.Dacpac;
+ sourceInfo.PackageFilePath = sourceDacpacFilePath;
+ targetInfo.EndpointType = SchemaCompareEndpointType.Database;
+ targetInfo.DatabaseName = targetDb.DatabaseName;
+
+ var schemaCompareParams1 = new SchemaCompareParams
+ {
+ SourceEndpointInfo = sourceInfo,
+ TargetEndpointInfo = targetInfo,
+ DeploymentOptions = nodiffOption,
+ };
+
+ SchemaCompareOperation schemaCompareOperation1 = new SchemaCompareOperation(schemaCompareParams1, result.ConnectionInfo, result.ConnectionInfo);
+ schemaCompareOperation1.Execute(TaskExecutionMode.Execute);
+
+ Assert.True(schemaCompareOperation1.ComparisonResult.IsValid);
+ Assert.True(schemaCompareOperation1.ComparisonResult.IsEqual);
+ Assert.NotNull(schemaCompareOperation1.ComparisonResult.Differences);
+
+ // generate script
+ var generateScriptParams1 = new SchemaCompareGenerateScriptParams
+ {
+ TargetDatabaseName = targetDb.DatabaseName,
+ OperationId = schemaCompareOperation1.OperationId,
+ ScriptFilePath = Path.Combine(folderPath, string.Concat(sourceDb.DatabaseName, "_", "Update.publish1.sql"))
+ };
+
+ SchemaCompareGenerateScriptOperation generateScriptOperation1 = new SchemaCompareGenerateScriptOperation(generateScriptParams1, schemaCompareOperation1.ComparisonResult);
+ generateScriptOperation1.Execute(TaskExecutionMode.Execute);
+
+ // validate script
+ var filePath1 = Path.Combine(folderPath, string.Concat(sourceDb.DatabaseName, "_", "Update.publish1.sql"));
+ Assert.True(File.Exists(filePath1) && string.IsNullOrEmpty(File.ReadAllText(filePath1)), "Should not be any differences");
+
+ var schemaCompareParams2 = new SchemaCompareParams
+ {
+ SourceEndpointInfo = sourceInfo,
+ TargetEndpointInfo = targetInfo,
+ DeploymentOptions = shouldDiffOption,
+ };
+
+ SchemaCompareOperation schemaCompareOperation2 = new SchemaCompareOperation(schemaCompareParams2, result.ConnectionInfo, result.ConnectionInfo);
+ schemaCompareOperation2.Execute(TaskExecutionMode.Execute);
+
+ Assert.True(schemaCompareOperation2.ComparisonResult.IsValid);
+ Assert.False(schemaCompareOperation2.ComparisonResult.IsEqual);
+ Assert.NotNull(schemaCompareOperation2.ComparisonResult.Differences);
+
+ // generate script
+ var generateScriptParams2 = new SchemaCompareGenerateScriptParams
+ {
+ TargetDatabaseName = targetDb.DatabaseName,
+ OperationId = schemaCompareOperation1.OperationId,
+ ScriptFilePath = Path.Combine(folderPath, string.Concat(sourceDb.DatabaseName, "_", "Update.publish2.sql"))
+ };
+
+ SchemaCompareGenerateScriptOperation generateScriptOperation2 = new SchemaCompareGenerateScriptOperation(generateScriptParams2, schemaCompareOperation2.ComparisonResult);
+ generateScriptOperation2.Execute(TaskExecutionMode.Execute);
+
+ // validate script
+ var filePath2 = Path.Combine(folderPath, string.Concat(sourceDb.DatabaseName, "_", "Update.publish2.sql"));
+ Assert.True(File.Exists(filePath2) && !string.IsNullOrEmpty(File.ReadAllText(filePath2)), "Should have differences differences");
+
+ // cleanup
+ SchemaCompareTestUtils.VerifyAndCleanup(generateScriptParams1.ScriptFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(generateScriptParams2.ScriptFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(sourceDacpacFilePath);
+ }
+ finally
+ {
+ sourceDb.Cleanup();
+ targetDb.Cleanup();
+ }
+ return schemaCompareRequestContext;
+ }
+
+ ///
+ /// Verify the schema compare request comparing two dacpacs with and without ignore column option
+ ///
+ [Fact]
+ public async void SchemaCompareDacpacToDacpacOptions()
+ {
+ Assert.NotNull(await SendAndValidateSchemaCompareRequestDacpacToDacpacWithOptions(Source1, Target1, GetIgnoreColumnOptions(), new DeploymentOptions()));
+ }
+
+ ///
+ /// Verify the schema compare request comparing two dacpacs with and excluding table valued functions
+ ///
+ [Fact]
+ public async void SchemaCompareDacpacToDacpacObjectTypes()
+ {
+ Assert.NotNull(await SendAndValidateSchemaCompareRequestDacpacToDacpacWithOptions(Source2, Target2, GetExcludeTableValuedFunctionOptions(), new DeploymentOptions()));
+ }
+
+ ///
+ /// Verify the schema compare request comparing two databases with and without ignore column option
+ ///
+ [Fact]
+ public async void SchemaCompareDatabaseToDatabaseOptions()
+ {
+ Assert.NotNull(await SendAndValidateSchemaCompareRequestDatabaseToDatabaseWithOptions(Source1, Target1, GetIgnoreColumnOptions(), new DeploymentOptions()));
+ }
+
+ ///
+ /// Verify the schema compare request comparing two databases with and excluding table valued functions
+ ///
+ [Fact]
+ public async void SchemaCompareDatabaseToDatabaseObjectTypes()
+ {
+ Assert.NotNull(await SendAndValidateSchemaCompareRequestDatabaseToDatabaseWithOptions(Source2, Target2, GetExcludeTableValuedFunctionOptions(), new DeploymentOptions()));
+ }
+
+ ///
+ /// Verify the schema compare script generation comparing dacpac and db with and without ignore column option
+ ///
+ [Fact]
+ public async void SchemaCompareGenerateScriptDacpacToDatabaseOptions()
+ {
+ Assert.NotNull(await SendAndValidateSchemaCompareGenerateScriptRequestDacpacToDatabaseWithOptions(Source1, Target1, GetIgnoreColumnOptions(), new DeploymentOptions()));
+ }
+
+ ///
+ /// Verify the schema compare script generation comparing dacpac and db with and excluding table valued function
+ ///
+ [Fact]
+ public async void SchemaCompareGenerateScriptDacpacToDatabaseObjectTypes()
+ {
+ Assert.NotNull(await SendAndValidateSchemaCompareGenerateScriptRequestDacpacToDatabaseWithOptions(Source2, Target2, GetExcludeTableValuedFunctionOptions(), new DeploymentOptions()));
+ }
+
+ ///
+ /// Verify the schema compare script generation comparing dacpac and db with and excluding table valued function
+ ///
+ [Fact]
+ public void ValidateSchemaCompareOptionsDefault()
+ {
+ DeploymentOptions deployOptions = new DeploymentOptions();
+ DacDeployOptions dacOptions = new DacDeployOptions();
+
+ System.Reflection.PropertyInfo[] deploymentOptionsProperties = deployOptions.GetType().GetProperties();
+ System.Reflection.PropertyInfo[] ddProperties = dacOptions.GetType().GetProperties();
+
+ foreach (var deployOptionsProp in deploymentOptionsProperties)
+ {
+ var dacProp = dacOptions.GetType().GetProperty(deployOptionsProp.Name);
+ Assert.True(dacProp != null, $"DacDeploy property not present for {deployOptionsProp.Name}");
+
+ var deployOptionsValue = deployOptionsProp.GetValue(deployOptions);
+ var dacValue = dacProp.GetValue(dacOptions);
+
+ Assert.True((deployOptionsValue == null && dacValue == null) || deployOptionsValue.Equals(dacValue), $"DacFx DacDeploy property not equal to Tools Service DeploymentOptions for { deployOptionsProp.Name}, SchemaCompareOptions value: {deployOptionsValue} and DacDeployOptions value: {dacValue} ");
+ }
+ }
+
+ }
+}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs
index 6643a8fb..baa0b71b 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs
@@ -43,16 +43,10 @@ CREATE TABLE [dbo].[table3]
[col1] INT NULL,
)";
- private LiveConnectionHelper.TestConnectionResult GetLiveAutoCompleteTestObjects()
- {
- var result = LiveConnectionHelper.InitLiveConnectionInfo();
- return result;
- }
-
private async Task>> SendAndValidateSchemaCompareRequestDacpacToDacpac()
{
- var result = GetLiveAutoCompleteTestObjects();
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
var schemaCompareRequestContext = new Mock>();
schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
@@ -61,8 +55,8 @@ CREATE TABLE [dbo].[table3]
SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget");
try
{
- string sourceDacpacFilePath = CreateDacpac(sourceDb);
- string targetDacpacFilePath = CreateDacpac(targetDb);
+ string sourceDacpacFilePath = SchemaCompareTestUtils.CreateDacpac(sourceDb);
+ string targetDacpacFilePath = SchemaCompareTestUtils.CreateDacpac(targetDb);
SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo();
SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo();
@@ -86,8 +80,8 @@ CREATE TABLE [dbo].[table3]
Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences);
// cleanup
- VerifyAndCleanup(sourceDacpacFilePath);
- VerifyAndCleanup(targetDacpacFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(sourceDacpacFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(targetDacpacFilePath);
}
finally
{
@@ -100,7 +94,7 @@ CREATE TABLE [dbo].[table3]
private async Task>> SendAndValidateSchemaCompareRequestDatabaseToDatabase()
{
- var result = GetLiveAutoCompleteTestObjects();
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
var schemaCompareRequestContext = new Mock>();
schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
@@ -143,7 +137,7 @@ CREATE TABLE [dbo].[table3]
private async Task>> SendAndValidateSchemaCompareRequestDatabaseToDacpac()
{
- var result = GetLiveAutoCompleteTestObjects();
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
var schemaCompareRequestContext = new Mock>();
schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
@@ -152,7 +146,7 @@ CREATE TABLE [dbo].[table3]
try
{
- string targetDacpacFilePath = CreateDacpac(targetDb);
+ string targetDacpacFilePath = SchemaCompareTestUtils.CreateDacpac(targetDb);
SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo();
SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo();
@@ -176,7 +170,7 @@ CREATE TABLE [dbo].[table3]
Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences);
// cleanup
- VerifyAndCleanup(targetDacpacFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(targetDacpacFilePath);
}
finally
{
@@ -188,7 +182,7 @@ CREATE TABLE [dbo].[table3]
private async Task>> SendAndValidateSchemaCompareGenerateScriptRequestDatabaseToDatabase()
{
- var result = GetLiveAutoCompleteTestObjects();
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
var schemaCompareRequestContext = new Mock>();
schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
@@ -232,7 +226,7 @@ CREATE TABLE [dbo].[table3]
generateScriptOperation.Execute(TaskExecutionMode.Execute);
// cleanup
- VerifyAndCleanup(generateScriptParams.ScriptFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(generateScriptParams.ScriptFilePath);
}
finally
{
@@ -244,7 +238,7 @@ CREATE TABLE [dbo].[table3]
private async Task>> SendAndValidateSchemaCompareGenerateScriptRequestDacpacToDatabase()
{
- var result = GetLiveAutoCompleteTestObjects();
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
var schemaCompareRequestContext = new Mock>();
schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
@@ -255,7 +249,7 @@ CREATE TABLE [dbo].[table3]
try
{
- string sourceDacpacFilePath = CreateDacpac(sourceDb);
+ string sourceDacpacFilePath = SchemaCompareTestUtils.CreateDacpac(sourceDb);
SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo();
SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo();
@@ -290,8 +284,8 @@ CREATE TABLE [dbo].[table3]
generateScriptOperation.Execute(TaskExecutionMode.Execute);
// cleanup
- VerifyAndCleanup(generateScriptParams.ScriptFilePath);
- VerifyAndCleanup(sourceDacpacFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(generateScriptParams.ScriptFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(sourceDacpacFilePath);
}
finally
{
@@ -303,7 +297,7 @@ CREATE TABLE [dbo].[table3]
private async Task>> SendAndValidateSchemaComparePublishChangesRequestDacpacToDatabase()
{
- var result = GetLiveAutoCompleteTestObjects();
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
var schemaCompareRequestContext = new Mock>();
schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
@@ -314,7 +308,7 @@ CREATE TABLE [dbo].[table3]
try
{
- string sourceDacpacFilePath = CreateDacpac(sourceDb);
+ string sourceDacpacFilePath = SchemaCompareTestUtils.CreateDacpac(sourceDb);
SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo();
SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo();
@@ -362,7 +356,7 @@ CREATE TABLE [dbo].[table3]
Assert.Empty(schemaCompareOperation.ComparisonResult.Differences);
// cleanup
- VerifyAndCleanup(sourceDacpacFilePath);
+ SchemaCompareTestUtils.VerifyAndCleanup(sourceDacpacFilePath);
}
finally
{
@@ -374,7 +368,7 @@ CREATE TABLE [dbo].[table3]
private async Task>> SendAndValidateSchemaComparePublishChangesRequestDatabaseToDatabase()
{
- var result = GetLiveAutoCompleteTestObjects();
+ var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects();
var schemaCompareRequestContext = new Mock>();
schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object()));
@@ -440,9 +434,9 @@ CREATE TABLE [dbo].[table3]
/// Verify the schema compare request comparing two dacpacs
///
[Fact]
- public void SchemaCompareDacpacToDacpac()
+ public async void SchemaCompareDacpacToDacpac()
{
- Assert.NotNull(SendAndValidateSchemaCompareRequestDacpacToDacpac());
+ Assert.NotNull(await SendAndValidateSchemaCompareRequestDacpacToDacpac());
}
///
@@ -490,7 +484,6 @@ CREATE TABLE [dbo].[table3]
Assert.NotNull(await SendAndValidateSchemaComparePublishChangesRequestDacpacToDatabase());
}
-
///
/// Verify the schema compare publish changes request comparing a database to a database
///
@@ -499,38 +492,5 @@ CREATE TABLE [dbo].[table3]
{
Assert.NotNull(await SendAndValidateSchemaComparePublishChangesRequestDatabaseToDatabase());
}
-
- private void VerifyAndCleanup(string filePath)
- {
- // Verify it was created
- Assert.True(File.Exists(filePath));
-
- // Remove the file
- if (File.Exists(filePath))
- {
- File.Delete(filePath);
- }
- }
-
- private string CreateDacpac(SqlTestDb testdb)
- {
- var result = GetLiveAutoCompleteTestObjects();
- string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest");
- Directory.CreateDirectory(folderPath);
-
- var extractParams = new ExtractParams
- {
- DatabaseName = testdb.DatabaseName,
- PackageFilePath = Path.Combine(folderPath, string.Format("{0}.dacpac", testdb.DatabaseName)),
- ApplicationName = "test",
- ApplicationVersion = "1.0.0.0"
- };
-
- DacFxService service = new DacFxService();
- ExtractOperation operation = new ExtractOperation(extractParams, result.ConnectionInfo);
- service.PerformOperation(operation);
-
- return extractParams.PackageFilePath;
- }
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs
new file mode 100644
index 00000000..d9c7a0b6
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs
@@ -0,0 +1,57 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.ServiceLayer.DacFx;
+using Microsoft.SqlTools.ServiceLayer.DacFx.Contracts;
+using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
+using Microsoft.SqlTools.ServiceLayer.Test.Common;
+using NUnit.Framework;
+using System;
+using System.IO;
+
+namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare
+{
+ internal static class SchemaCompareTestUtils
+ {
+ internal static void VerifyAndCleanup(string filePath)
+ {
+ // Verify it was created
+ Assert.True(File.Exists(filePath));
+
+ // Remove the file
+ if (File.Exists(filePath))
+ {
+ File.Delete(filePath);
+ }
+ }
+
+ internal static string CreateDacpac(SqlTestDb testdb)
+ {
+ var result = GetLiveAutoCompleteTestObjects();
+ string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest");
+ Directory.CreateDirectory(folderPath);
+
+ var extractParams = new ExtractParams
+ {
+ DatabaseName = testdb.DatabaseName,
+ PackageFilePath = Path.Combine(folderPath, string.Format("{0}.dacpac", testdb.DatabaseName)),
+ ApplicationName = "test",
+ ApplicationVersion = "1.0.0.0"
+ };
+
+ DacFxService service = new DacFxService();
+ ExtractOperation operation = new ExtractOperation(extractParams, result.ConnectionInfo);
+ service.PerformOperation(operation);
+
+ return extractParams.PackageFilePath;
+ }
+
+ internal static LiveConnectionHelper.TestConnectionResult GetLiveAutoCompleteTestObjects()
+ {
+ var result = LiveConnectionHelper.InitLiveConnectionInfo();
+ return result;
+ }
+ }
+}