From 5663ddba68615d63bc564bbcf40eff8b044084f0 Mon Sep 17 00:00:00 2001 From: Sai Avishkar Sreerama <74571829+ssreerama@users.noreply.github.com> Date: Thu, 7 Jul 2022 16:56:16 -0500 Subject: [PATCH] =?UTF-8?q?OptionsMapTable=20preparing=20from=20DacFx=20de?= =?UTF-8?q?scription,value,displayname=20at=E2=80=A6=20(#1550)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * OptionsMapTable preparing from DacFx description,value,displayname attributes * Review Comments addressed for options map table changes * OptionsMapTable final changes * Code review comments updated code changes * Test fix: Adding missing change while splitting the PR * DacFx vBump * Reverted to displayName and code updates * final:prop name changed, references updated, tests fixed, comments addressed * Code review comments updated for name,exception etc * updates method names * property name changes to BooleanOptionsDictionary and comment updates * Removed the unused properties, null cases handeled, hardcoded values are replaced --- .../DacFx/Contracts/DeploymentOptions.cs | 427 +++--------------- .../SchemaCompare/SchemaCompareUtils.cs | 61 ++- .../DacFx/DacFxServiceTests.cs | 71 ++- .../SchemaCompareServiceOptionsTests.cs | 2 +- .../SchemaCompareServiceTests.cs | 22 +- .../SchemaCompare/SchemaCompareTestUtils.cs | 93 ++-- 6 files changed, 236 insertions(+), 440 deletions(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/DeploymentOptions.cs b/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/DeploymentOptions.cs index 29da5d3cff..f7d87ff28b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/DeploymentOptions.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DacFx/Contracts/DeploymentOptions.cs @@ -14,8 +14,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx.Contracts { /// - /// Class to define deployment option default value and the description + /// DeploymentOptionProperty class to define deployment options default value, description, and displayNames /// + /// public class DeploymentOptionProperty { public DeploymentOptionProperty(T value, string description = "", string displayName = "") @@ -25,197 +26,30 @@ public DeploymentOptionProperty(T value, string description = "", string display this.DisplayName = displayName; } - // Default and selected value of the deployment options + /// + /// Default and selected value of the deployment option + /// public T Value { get; set; } - // Description of the deployment options + /// + /// Description of the deployment option + /// public string Description { get; set; } - // To display the options in ADS extensions UI in SchemaCompare/SQL-DB-Project/Dacpac extensions + /// + /// Display name of the deployment option + /// public string DisplayName { get; set; } } /// /// 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 - /// NOTE: When new deployment options are added in DacFx, they need to be added here too + /// These property names will be given to the DeploymentOptions interface defined in ADS 'azuredatastudio\extensions\mssql\src\mssql.d.ts' and 'azuredatastudio\extensions\types\vscode-mssql.d.ts' + /// BooleanOptionsDictionary will automatically gets the newly added boolean properties from DacFx, All other types should be added here and ADS /// public class DeploymentOptions { #region Properties - - public DeploymentOptionProperty IgnoreTableOptions { get; set; } - - public DeploymentOptionProperty IgnoreSemicolonBetweenStatements { get; set; } - - public DeploymentOptionProperty IgnoreRouteLifetime { get; set; } - - public DeploymentOptionProperty IgnoreRoleMembership { get; set; } - - public DeploymentOptionProperty IgnoreQuotedIdentifiers { get; set; } - - public DeploymentOptionProperty IgnorePermissions { get; set; } - - public DeploymentOptionProperty IgnorePartitionSchemes { get; set; } - - public DeploymentOptionProperty IgnoreObjectPlacementOnPartitionScheme { get; set; } - - public DeploymentOptionProperty IgnoreNotForReplication { get; set; } - - public DeploymentOptionProperty IgnoreLoginSids { get; set; } - - public DeploymentOptionProperty IgnoreLockHintsOnIndexes { get; set; } - - public DeploymentOptionProperty IgnoreKeywordCasing { get; set; } - - public DeploymentOptionProperty IgnoreIndexPadding { get; set; } - - public DeploymentOptionProperty IgnoreIndexOptions { get; set; } - - public DeploymentOptionProperty IgnoreIncrement { get; set; } - - public DeploymentOptionProperty IgnoreIdentitySeed { get; set; } - - public DeploymentOptionProperty IgnoreUserSettingsObjects { get; set; } - - public DeploymentOptionProperty IgnoreFullTextCatalogFilePath { get; set; } - - public DeploymentOptionProperty IgnoreWhitespace { get; set; } - - public DeploymentOptionProperty IgnoreWithNocheckOnForeignKeys { get; set; } - - public DeploymentOptionProperty VerifyCollationCompatibility { get; set; } - - public DeploymentOptionProperty UnmodifiableObjectWarnings { get; set; } - - public DeploymentOptionProperty TreatVerificationErrorsAsWarnings { get; set; } - - public DeploymentOptionProperty ScriptRefreshModule { get; set; } - - public DeploymentOptionProperty ScriptNewConstraintValidation { get; set; } - - public DeploymentOptionProperty ScriptFileSize { get; set; } - - public DeploymentOptionProperty ScriptDeployStateChecks { get; set; } - - public DeploymentOptionProperty ScriptDatabaseOptions { get; set; } - - public DeploymentOptionProperty ScriptDatabaseCompatibility { get; set; } - - public DeploymentOptionProperty ScriptDatabaseCollation { get; set; } - - public DeploymentOptionProperty RunDeploymentPlanExecutors { get; set; } - - public DeploymentOptionProperty RegisterDataTierApplication { get; set; } - - public DeploymentOptionProperty PopulateFilesOnFileGroups { get; set; } - - public DeploymentOptionProperty NoAlterStatementsToChangeClrTypes { get; set; } - - public DeploymentOptionProperty IncludeTransactionalScripts { get; set; } - - public DeploymentOptionProperty IncludeCompositeObjects { get; set; } - - public DeploymentOptionProperty AllowUnsafeRowLevelSecurityDataMovement { get; set; } - - public DeploymentOptionProperty IgnoreWithNocheckOnCheckConstraints { get; set; } - - public DeploymentOptionProperty IgnoreFillFactor { get; set; } - - public DeploymentOptionProperty IgnoreFileSize { get; set; } - - public DeploymentOptionProperty IgnoreFilegroupPlacement { get; set; } - - public DeploymentOptionProperty DoNotAlterReplicatedObjects { get; set; } - - public DeploymentOptionProperty DoNotAlterChangeDataCaptureObjects { get; set; } - - public DeploymentOptionProperty DisableAndReenableDdlTriggers { get; set; } - - public DeploymentOptionProperty DeployDatabaseInSingleUserMode { get; set; } - - public DeploymentOptionProperty CreateNewDatabase { get; set; } - - public DeploymentOptionProperty CompareUsingTargetCollation { get; set; } - - public DeploymentOptionProperty CommentOutSetVarDeclarations { get; set; } - - // Command timeout to 120 seconds when executing queries against SQL Server. - public DeploymentOptionProperty CommandTimeout { get; set; } = new DeploymentOptionProperty(120); - - // LongRunningCommandTimeout 0 seconds to wait indefinitely. - public DeploymentOptionProperty LongRunningCommandTimeout { get; set; } = new DeploymentOptionProperty(0); - - // Wait 60 seconds to lock database when executing queries against SQL Server. - public DeploymentOptionProperty DatabaseLockTimeout { get; set; } = new DeploymentOptionProperty(60); - - public DeploymentOptionProperty BlockWhenDriftDetected { get; set; } - - public DeploymentOptionProperty BlockOnPossibleDataLoss { get; set; } - - public DeploymentOptionProperty BackupDatabaseBeforeChanges { get; set; } - - public DeploymentOptionProperty AllowIncompatiblePlatform { get; set; } - - public DeploymentOptionProperty AllowDropBlockingAssemblies { get; set; } - - public DeploymentOptionProperty AdditionalDeploymentContributorArguments { get; set; } - - public DeploymentOptionProperty AdditionalDeploymentContributors { get; set; } - - public DeploymentOptionProperty DropConstraintsNotInSource { get; set; } - - public DeploymentOptionProperty DropDmlTriggersNotInSource { get; set; } - - public DeploymentOptionProperty DropExtendedPropertiesNotInSource { get; set; } - - public DeploymentOptionProperty DropIndexesNotInSource { get; set; } - - public DeploymentOptionProperty IgnoreFileAndLogFilePath { get; set; } - - public DeploymentOptionProperty IgnoreExtendedProperties { get; set; } - - public DeploymentOptionProperty IgnoreDmlTriggerState { get; set; } - - public DeploymentOptionProperty IgnoreDmlTriggerOrder { get; set; } - - public DeploymentOptionProperty IgnoreDefaultSchema { get; set; } - - public DeploymentOptionProperty IgnoreDdlTriggerState { get; set; } - - public DeploymentOptionProperty IgnoreDdlTriggerOrder { get; set; } - - public DeploymentOptionProperty IgnoreCryptographicProviderFilePath { get; set; } - - public DeploymentOptionProperty VerifyDeployment { get; set; } - - public DeploymentOptionProperty IgnoreComments { get; set; } - - public DeploymentOptionProperty IgnoreColumnCollation { get; set; } - - public DeploymentOptionProperty IgnoreAuthorizer { get; set; } - - public DeploymentOptionProperty IgnoreAnsiNulls { get; set; } - - public DeploymentOptionProperty GenerateSmartDefaults { get; set; } - - public DeploymentOptionProperty DropStatisticsNotInSource { get; set; } - - public DeploymentOptionProperty DropRoleMembersNotInSource { get; set; } - - public DeploymentOptionProperty DropPermissionsNotInSource { get; set; } - - public DeploymentOptionProperty DropObjectsNotInSource { get; set; } - - public DeploymentOptionProperty IgnoreColumnOrder { get; set; } - - public DeploymentOptionProperty IgnoreTablePartitionOptions { get; set; } // DW Specific - - public DeploymentOptionProperty AdditionalDeploymentContributorPaths { get; set; } - - public DeploymentOptionProperty DoNotDropObjectTypes { get; set; } - public DeploymentOptionProperty ExcludeObjectTypes { get; set; } = new DeploymentOptionProperty ( new ObjectType[] { @@ -244,168 +78,17 @@ public class DeploymentOptions } ); - public DeploymentOptionProperty AllowExternalLibraryPaths { get; set; } - - public DeploymentOptionProperty AllowExternalLanguagePaths { get; set; } - - public DeploymentOptionProperty DoNotEvaluateSqlCmdVariables { get; set; } - - public DeploymentOptionProperty DisableParallelismForEnablingIndexes { get; set; } - - public DeploymentOptionProperty DoNotDropWorkloadClassifiers { get; set; } - - public DeploymentOptionProperty DisableIndexesForDataPhase { get; set; } - - public DeploymentOptionProperty DoNotDropDatabaseWorkloadGroups { get; set; } - - public DeploymentOptionProperty HashObjectNamesInLogs { get; set; } - - public DeploymentOptionProperty IgnoreWorkloadClassifiers { get; set; } - - public DeploymentOptionProperty IgnoreDatabaseWorkloadGroups { get; set; } - - public DeploymentOptionProperty IsAlwaysEncryptedParameterizationEnabled { get; set; } - - public DeploymentOptionProperty PreserveIdentityLastValues { get; set; } - - public DeploymentOptionProperty RestoreSequenceCurrentValue { get; set; } - - public DeploymentOptionProperty RebuildIndexesOfflineForDataPhase { get; set; } - - private Dictionary _displayNameMapDict; - - #endregion - /// - /// Mapping the DisplayName to the dac deploy option - /// Adding new properties here would give easy handling of new option to all extensions + /// BooleanOptionsDictionary contains all boolean type deployment options /// - private void SetDisplayNameForOption() - { - #region Display Name and Dac Options Mapping - DacDeployOptions d = new DacDeployOptions(); - _displayNameMapDict = new Dictionary(); + public Dictionary> BooleanOptionsDictionary { get; set; } = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); - // Ex: displayNameMapDict["DacFx Option Name"] = "ADS UI Display Name" - _displayNameMapDict[nameof(d.AdditionalDeploymentContributorArguments)] = "Additional Deployment Contributor Arguments"; - _displayNameMapDict[nameof(d.AdditionalDeploymentContributorPaths)] = "Additional Deployment Contributor Paths"; - _displayNameMapDict[nameof(d.AdditionalDeploymentContributors)] = "Additional Deployment Contributors"; - _displayNameMapDict[nameof(d.AllowDropBlockingAssemblies)] = "Allow Drop Blocking Assemblies"; - _displayNameMapDict[nameof(d.AllowExternalLanguagePaths)] = "Allow External Language Paths"; - _displayNameMapDict[nameof(d.AllowExternalLibraryPaths)] = "Allow External Library Paths"; - _displayNameMapDict[nameof(d.AllowIncompatiblePlatform)] = "Allow Incompatible Platform"; - _displayNameMapDict[nameof(d.AllowUnsafeRowLevelSecurityDataMovement)] = "Allow Unsafe RowLevel Security Data Movement"; - _displayNameMapDict[nameof(d.AzureSharedAccessSignatureToken)] = "Azure Shared Access Signature Token"; - _displayNameMapDict[nameof(d.AzureStorageBlobEndpoint)] = "Azure Storage Blob Endpoint"; - _displayNameMapDict[nameof(d.AzureStorageContainer)] = "Azure Storage Container"; - _displayNameMapDict[nameof(d.AzureStorageKey)] = "Azure Storage Key"; - _displayNameMapDict[nameof(d.AzureStorageRootPath)] = "Azure Storage Root Path"; - _displayNameMapDict[nameof(d.BackupDatabaseBeforeChanges)] = "Backup Database Before Changes"; - _displayNameMapDict[nameof(d.BlockOnPossibleDataLoss)] = "Block On Possible Data Loss"; - _displayNameMapDict[nameof(d.BlockWhenDriftDetected)] = "Block When Drift Detected"; - _displayNameMapDict[nameof(d.CommandTimeout)] = "Command Timeout"; - _displayNameMapDict[nameof(d.CommentOutSetVarDeclarations)] = "Comment Out SetVar Declarations"; - _displayNameMapDict[nameof(d.CompareUsingTargetCollation)] = "Compare Using Target Collation"; - _displayNameMapDict[nameof(d.CreateNewDatabase)] = "Create New Database"; - _displayNameMapDict[nameof(d.DatabaseLockTimeout)] = "Database Lock Timeout"; - _displayNameMapDict[nameof(d.DatabaseSpecification)] = "Database Specification"; - _displayNameMapDict[nameof(d.DataOperationStateProvider)] = "Data Operation State Provider"; - _displayNameMapDict[nameof(d.DeployDatabaseInSingleUserMode)] = "Deploy Database In Single User Mode"; - _displayNameMapDict[nameof(d.DisableAndReenableDdlTriggers)] = "Disable And Reenable Ddl Triggers"; - _displayNameMapDict[nameof(d.DisableIndexesForDataPhase)] = "Disable Indexes For Data Phase"; - _displayNameMapDict[nameof(d.DisableParallelismForEnablingIndexes)] = "Disable Parallelism For Enabling Indexes"; - _displayNameMapDict[nameof(d.DoNotAlterChangeDataCaptureObjects)] = "Do Not Alter Change Data Capture Objects"; - _displayNameMapDict[nameof(d.DoNotAlterReplicatedObjects)] = "Do Not Alter Replicated Objects"; - _displayNameMapDict[nameof(d.DoNotDropDatabaseWorkloadGroups)] = "Do Not Drop Database Workload Groups"; - _displayNameMapDict[nameof(d.DoNotDropObjectTypes)] = "Do Not Drop Object Types"; - _displayNameMapDict[nameof(d.DoNotDropWorkloadClassifiers)] = "Do Not Drop Workload Classifiers"; - _displayNameMapDict[nameof(d.DoNotEvaluateSqlCmdVariables)] = "Do Not Evaluate Sql Cmd Variables"; - _displayNameMapDict[nameof(d.DropConstraintsNotInSource)] = "Drop Constraints Not In Source"; - _displayNameMapDict[nameof(d.DropDmlTriggersNotInSource)] = "Drop Dml Triggers Not In Source"; - _displayNameMapDict[nameof(d.DropExtendedPropertiesNotInSource)] = "Drop Extended Properties Not In Source"; - _displayNameMapDict[nameof(d.DropIndexesNotInSource)] = "Drop Indexes Not In Source"; - _displayNameMapDict[nameof(d.DropObjectsNotInSource)] = "Drop Objects Not In Source"; - _displayNameMapDict[nameof(d.DropPermissionsNotInSource)] = "Drop Permissions Not In Source"; - _displayNameMapDict[nameof(d.DropRoleMembersNotInSource)] = "Drop Role Members Not In Source"; - _displayNameMapDict[nameof(d.DropStatisticsNotInSource)] = "Drop Statistics Not In Source"; - _displayNameMapDict[nameof(d.EnclaveAttestationProtocol)] = "Enclave Attestation Protocol"; - _displayNameMapDict[nameof(d.EnclaveAttestationUrl)] = "Enclave Attestation Url"; - _displayNameMapDict[nameof(d.ExcludeObjectTypes)] = "Exclude Object Types"; - _displayNameMapDict[nameof(d.GenerateSmartDefaults)] = "Generate Smart Defaults"; - _displayNameMapDict[nameof(d.HashObjectNamesInLogs)] = "Hash Object Names In Logs"; - _displayNameMapDict[nameof(d.IgnoreAnsiNulls)] = "Ignore Ansi Nulls"; - _displayNameMapDict[nameof(d.IgnoreAuthorizer)] = "Ignore Authorizer"; - _displayNameMapDict[nameof(d.IgnoreColumnCollation)] = "Ignore Column Collation"; - _displayNameMapDict[nameof(d.IgnoreColumnOrder)] = "Ignore Column Order"; - _displayNameMapDict[nameof(d.IgnoreComments)] = "Ignore Comments"; - _displayNameMapDict[nameof(d.IgnoreCryptographicProviderFilePath)] = "Ignore Cryptographic Provider File Path"; - _displayNameMapDict[nameof(d.IgnoreDatabaseWorkloadGroups)] = "Ignore Database Workload Groups"; - _displayNameMapDict[nameof(d.IgnoreDdlTriggerOrder)] = "Ignore Ddl Trigger Order"; - _displayNameMapDict[nameof(d.IgnoreDdlTriggerState)] = "Ignore Ddl Trigger State"; - _displayNameMapDict[nameof(d.IgnoreDefaultSchema)] = "Ignore Default Schema"; - _displayNameMapDict[nameof(d.IgnoreDmlTriggerOrder)] = "Ignore Dml Trigger Order"; - _displayNameMapDict[nameof(d.IgnoreDmlTriggerState)] = "Ignore Dml Trigger State"; - _displayNameMapDict[nameof(d.IgnoreExtendedProperties)] = "Ignore Extended Properties"; - _displayNameMapDict[nameof(d.IgnoreFileAndLogFilePath)] = "Ignore File And Log File Path"; - _displayNameMapDict[nameof(d.IgnoreFileSize)] = "Ignore File Size"; - _displayNameMapDict[nameof(d.IgnoreFilegroupPlacement)] = "Ignore File Group Placement"; - _displayNameMapDict[nameof(d.IgnoreFillFactor)] = "Ignore Fill Factor"; - _displayNameMapDict[nameof(d.IgnoreFullTextCatalogFilePath)] = "Ignore Full Text Catalog File Path"; - _displayNameMapDict[nameof(d.IgnoreIdentitySeed)] = "Ignore Identity Seed"; - _displayNameMapDict[nameof(d.IgnoreIncrement)] = "Ignore Increment"; - _displayNameMapDict[nameof(d.IgnoreIndexOptions)] = "Ignore Index Options"; - _displayNameMapDict[nameof(d.IgnoreIndexPadding)] = "Ignore Index Padding"; - _displayNameMapDict[nameof(d.IgnoreKeywordCasing)] = "Ignore Keyword Casing"; - _displayNameMapDict[nameof(d.IgnoreLockHintsOnIndexes)] = "IgnoreLock Hints On Indexes"; - _displayNameMapDict[nameof(d.IgnoreLoginSids)] = "IgnoreLogin Sids"; - _displayNameMapDict[nameof(d.IgnoreNotForReplication)] = "IgnoreNotForReplication"; - _displayNameMapDict[nameof(d.IgnoreObjectPlacementOnPartitionScheme)] = "Ignore Object Placement On Partition Scheme"; - _displayNameMapDict[nameof(d.IgnorePartitionSchemes)] = "Ignore Partition Schemes"; - _displayNameMapDict[nameof(d.IgnorePermissions)] = "Ignore Permissions"; - _displayNameMapDict[nameof(d.IgnoreQuotedIdentifiers)] = "Ignore Quoted Identifiers"; - _displayNameMapDict[nameof(d.IgnoreRoleMembership)] = "Ignore Role Membership"; - _displayNameMapDict[nameof(d.IgnoreRouteLifetime)] = "Ignore Route Lifetime"; - _displayNameMapDict[nameof(d.IgnoreSemicolonBetweenStatements)] = "Ignore Semicolon Between Statements"; - _displayNameMapDict[nameof(d.IgnoreTableOptions)] = "Ignore Table Options"; - _displayNameMapDict[nameof(d.IgnoreTablePartitionOptions)] = "Ignore Table Partition Options"; - _displayNameMapDict[nameof(d.IgnoreUserSettingsObjects)] = "Ignore User Settings Objects"; - _displayNameMapDict[nameof(d.IgnoreWhitespace)] = "Ignore Whitespace"; - _displayNameMapDict[nameof(d.IgnoreWithNocheckOnCheckConstraints)] = "Ignore With Nocheck On Check Constraints"; - _displayNameMapDict[nameof(d.IgnoreWithNocheckOnForeignKeys)] = "Ignore With Nocheck On Foreign Keys"; - _displayNameMapDict[nameof(d.IgnoreWorkloadClassifiers)] = "Ignore Workload Classifiers"; - _displayNameMapDict[nameof(d.IncludeCompositeObjects)] = "Include Composite Objects"; - _displayNameMapDict[nameof(d.IncludeTransactionalScripts)] = "Include Transactional Scripts"; - _displayNameMapDict[nameof(d.IsAlwaysEncryptedParameterizationEnabled)] = "Is Always Encrypted Parameterization Enabled"; - _displayNameMapDict[nameof(d.LongRunningCommandTimeout)] = "Long Running Command Timeout"; - _displayNameMapDict[nameof(d.NoAlterStatementsToChangeClrTypes)] = "No Alter Statements To Change Clr Types"; - _displayNameMapDict[nameof(d.PopulateFilesOnFileGroups)] = "Populate Files On File Groups"; - _displayNameMapDict[nameof(d.PreserveIdentityLastValues)] = "Preserve Identity Last Values"; - _displayNameMapDict[nameof(d.RebuildIndexesOfflineForDataPhase)] = "Rebuild Indexes Offline For Data Phase"; - _displayNameMapDict[nameof(d.RegisterDataTierApplication)] = "Register Data Tier Application"; - _displayNameMapDict[nameof(d.RestoreSequenceCurrentValue)] = "Restore Sequence Current Value"; - _displayNameMapDict[nameof(d.RunDeploymentPlanExecutors)] = "Run Deployment Plan Executors"; - _displayNameMapDict[nameof(d.ScriptDatabaseCollation)] = "Script Database Collation"; - _displayNameMapDict[nameof(d.ScriptDatabaseCompatibility)] = "Script Database Compatibility"; - _displayNameMapDict[nameof(d.ScriptDatabaseOptions)] = "Script Database Options"; - _displayNameMapDict[nameof(d.ScriptDeployStateChecks)] = "Script Deploy State Checks"; - _displayNameMapDict[nameof(d.ScriptFileSize)] = "Script File Size"; - _displayNameMapDict[nameof(d.ScriptNewConstraintValidation)] = "Script New Constraint Validation"; - _displayNameMapDict[nameof(d.ScriptRefreshModule)] = "Script Refresh Module"; - _displayNameMapDict[nameof(d.SqlCommandVariableValues)] = "Sql Command Variable Values"; - _displayNameMapDict[nameof(d.TreatVerificationErrorsAsWarnings)] = "Treat Verification Errors As Warnings"; - _displayNameMapDict[nameof(d.UnmodifiableObjectWarnings)] = "Unmodifiable Object Warnings"; - _displayNameMapDict[nameof(d.VerifyCollationCompatibility)] = "Verify Collation Compatibility"; - _displayNameMapDict[nameof(d.VerifyDeployment)] = "Verify Deployment"; - #endregion - } + #endregion public DeploymentOptions() { DacDeployOptions options = new DacDeployOptions(); - // Setting Display names for all dacDeploy options - SetDisplayNameForOption(); - // Adding these defaults to ensure behavior similarity with other tools. Dacfx and SSMS import/export wizards use these defaults. // Tracking the full fix : https://github.com/microsoft/azuredatastudio/issues/5599 options.AllowDropBlockingAssemblies = true; @@ -416,26 +99,13 @@ public DeploymentOptions() options.IgnoreKeywordCasing = false; options.IgnoreSemicolonBetweenStatements = false; - PropertyInfo[] deploymentOptionsProperties = this.GetType().GetProperties(); - - foreach (var deployOptionsProp in deploymentOptionsProperties) - { - var prop = options.GetType().GetProperty(deployOptionsProp.Name); - - // Note that we set excluded object types here since dacfx has this value as null; - if (prop != null && deployOptionsProp.Name != "ExcludeObjectTypes") - { - // Setting DacFx default values to the generic deployment options properties. - SetGenericDeployOptionProps(prop, options, deployOptionsProp); - } - } + // Initializing the default boolean type options to the BooleanOptionsDictionary + // Not considering DacFx default ExcludeObjectTypes, as it has some STS defaults which needs to be considered here, DacFx defaults are only considered for InitializeFromProfile(), where options are loading from profile + InitializeBooleanTypeOptions(options); } public DeploymentOptions(DacDeployOptions options) { - // Setting Display names for all dacDeploy options - SetDisplayNameForOption(); - SetOptions(options); } @@ -480,35 +150,66 @@ public async Task InitializeFromProfile(DacDeployOptions options, string profile SetOptions(options); } + /// + /// Populates BooleanOptionsDictionary with the boolean type properties + /// + /// + public void InitializeBooleanTypeOptions(DacDeployOptions options) + { + PropertyInfo[] dacDeploymentOptionsProperties = options.GetType().GetProperties(); + foreach (PropertyInfo prop in dacDeploymentOptionsProperties) + { + if (prop != null && prop.PropertyType == typeof(System.Boolean)) + { + object setProp = GetDeploymentOptionProp(prop, options); + this.BooleanOptionsDictionary[prop.Name] = (DeploymentOptionProperty)setProp; + } + } + } + public void SetOptions(DacDeployOptions options) { - System.Reflection.PropertyInfo[] deploymentOptionsProperties = this.GetType().GetProperties(); + // Set the default options properties + InitializeBooleanTypeOptions(options); + InitializeNonBooleanTypeOptions(options); + } - foreach (var deployOptionsProp in deploymentOptionsProperties) + /// + /// Preparing all non boolean properties (except BooleanOptionsDictionary) + /// + /// + public void InitializeNonBooleanTypeOptions(DacDeployOptions options) + { + // preparing remaining properties + PropertyInfo[] deploymentOptionsProperties = this.GetType().GetProperties(); + foreach (PropertyInfo deployOptionsProp in deploymentOptionsProperties) { - var prop = options.GetType().GetProperty(deployOptionsProp.Name); - // Note that we set excluded object types here since dacfx has this value as null; - if (prop != null) + if (deployOptionsProp.Name != nameof(DeploymentOptions.BooleanOptionsDictionary)) { - SetGenericDeployOptionProps(prop, options, deployOptionsProp); + PropertyInfo prop = options.GetType().GetProperty(deployOptionsProp.Name); + object setProp = GetDeploymentOptionProp(prop, options); + deployOptionsProp.SetValue(this, setProp); } } } /// - /// Sets the Value and Description to all properties + /// Prepares and returns the value and description of a property /// /// - /// - /// - public void SetGenericDeployOptionProps(PropertyInfo prop, DacDeployOptions options, PropertyInfo deployOptionsProp) + /// + public object GetDeploymentOptionProp(PropertyInfo prop, DacDeployOptions options) { var val = prop.GetValue(options); - var attribute = prop.GetCustomAttributes(true).FirstOrDefault(); - Type type = val != null ? typeof(DeploymentOptionProperty<>).MakeGenericType(val.GetType()) + DescriptionAttribute descriptionAttribute = prop.GetCustomAttributes().FirstOrDefault(); + DisplayNameAttribute displayNameAttribute = prop.GetCustomAttributes().FirstOrDefault(); + Type type = val != null ? typeof(DeploymentOptionProperty<>).MakeGenericType(val.GetType()) : typeof(DeploymentOptionProperty<>).MakeGenericType(prop.PropertyType); - object setProp = Activator.CreateInstance(type, val, attribute.Description,_displayNameMapDict[deployOptionsProp.Name]); - deployOptionsProp.SetValue(this, setProp); + + object setProp = Activator.CreateInstance(type, val, + (descriptionAttribute != null ? descriptionAttribute.Description : ""), + (displayNameAttribute != null ? displayNameAttribute.DisplayName : "")); + return setProp; } public static DeploymentOptions GetDefaultSchemaCompareOptions() diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs index 5c16aa31f5..5e4d610a82 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs @@ -4,6 +4,7 @@ // using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; @@ -14,6 +15,7 @@ using Microsoft.SqlTools.ServiceLayer.DacFx.Contracts; using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts; using Microsoft.SqlTools.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare { @@ -23,31 +25,60 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare /// internal static class SchemaCompareUtils { + /// + /// Converts DeploymentOptions used in STS and ADS to DacDeployOptions which can be passed to the DacFx apis + /// + /// + /// DacDeployOptions> booleanOptionsDictionary = new Dictionary>(); + + foreach (PropertyInfo deployOptionsProp in deploymentOptionsProperties) { - var val = deployOptionsProp.GetValue(deploymentOptions); - var selectedVal = val.GetType().GetProperty("Value").GetValue(val); + var prop = propType.GetProperty(deployOptionsProp.Name); + if (prop != null) + { + var val = deployOptionsProp.GetValue(deploymentOptions); + var selectedVal = val.GetType().GetProperty("Value").GetValue(val); + + // Set the excludeObjectTypes values to the DacDeployOptions + if (selectedVal != null && deployOptionsProp.Name == nameof(deploymentOptions.ExcludeObjectTypes)) + { + prop.SetValue(dacOptions, selectedVal); + } + } - // JSON.NET by default reads Number type as Int64, deserializing an object type to dacOptions of Int32 type required to convert into Int32 from Int64. - // If not converted setting value(Int64) to dacOption(Int32) will throw {"Object of type 'System.Int64' cannot be converted to type 'System.Int32'."}. - // As these integer type options are non-editable and are not availbale in ADS to update, integer overflow exception will not be happening here. - if (selectedVal != null && selectedVal.GetType() == typeof(System.Int64)) + // BooleanOptionsDictionary has all the deployment options and is being processed separately in the second iteration by collecting here + if (deployOptionsProp.Name == nameof(deploymentOptions.BooleanOptionsDictionary)) { - selectedVal = Convert.ToInt32(selectedVal); + booleanOptionsDictionary = deploymentOptions.BooleanOptionsDictionary as Dictionary>; } + } - prop.SetValue(dacOptions, selectedVal); + // Iterating through the updated boolean options coming from the booleanOptionsDictionary and assigning them to DacDeployOptions + foreach (KeyValuePair> deployOptionsProp in booleanOptionsDictionary) + { + var prop = propType.GetProperty(deployOptionsProp.Key); + if (prop != null) + { + var selectedVal = deployOptionsProp.Value.Value; + prop.SetValue(dacOptions, selectedVal); + } } + return dacOptions; + } + catch (Exception e) + { + Logger.Write(TraceEventType.Error, string.Format("Schema compare create options model failed: {0}", e.Message)); + throw; } - return dacOptions; } internal static DiffEntry CreateDiffEntry(SchemaDifference difference, DiffEntry parent) diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs index de8f632838..6f7c201e04 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DacFx/DacFxServiceTests.cs @@ -18,6 +18,7 @@ using Microsoft.SqlTools.ServiceLayer.Test.Common; using NUnit.Framework; using Moq; +using System.Reflection; namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DacFx { @@ -586,11 +587,13 @@ public async Task DeployWithOptions() UpgradeExisting = true, DeploymentOptions = new DeploymentOptions() { - DropObjectsNotInSource = new DeploymentOptionProperty(false), ExcludeObjectTypes = new DeploymentOptionProperty(new[] { ObjectType.Views }) } }; + // Updating the BooleanOptionsDictionary since it has all the boolean type options + deployParams.DeploymentOptions.BooleanOptionsDictionary[nameof(DacDeployOptions.DropObjectsNotInSource)].Value = false; + // expect table3 to not have been dropped and view1 to not have been created await VerifyDeployWithOptions(deployParams, targetDb, service, result.ConnectionInfo, expectedTableResult: "table3", expectedViewResult: null); @@ -664,11 +667,13 @@ public async Task GenerateDeployScriptWithOptions() DatabaseName = targetDb.DatabaseName, DeploymentOptions = new DeploymentOptions() { - DropObjectsNotInSource = new DeploymentOptionProperty(false), ExcludeObjectTypes = new DeploymentOptionProperty(new[] { ObjectType.Views }) } }; + // Updating the BooleanOptionsDictionary since it has all the boolean type properties + generateScriptFalseOptionParams.DeploymentOptions.BooleanOptionsDictionary[nameof(DacDeployOptions.DropObjectsNotInSource)].Value = false; + var generateScriptFalseOptionOperation = new GenerateDeployScriptOperation(generateScriptFalseOptionParams, result.ConnectionInfo); service.PerformOperation(generateScriptFalseOptionOperation, TaskExecutionMode.Execute); @@ -682,7 +687,6 @@ public async Task GenerateDeployScriptWithOptions() DatabaseName = targetDb.DatabaseName, DeploymentOptions = new DeploymentOptions() { - DropObjectsNotInSource = new DeploymentOptionProperty(true), ExcludeObjectTypes = new DeploymentOptionProperty( new[] { ObjectType.Views }) } }; @@ -727,10 +731,10 @@ public async Task GetOptionsFromProfile() DeploymentOptions expectedResults = DeploymentOptions.GetDefaultPublishOptions(); expectedResults.ExcludeObjectTypes = null; - expectedResults.IncludeCompositeObjects = new DeploymentOptionProperty(true); - expectedResults.BlockOnPossibleDataLoss = new DeploymentOptionProperty(true); - expectedResults.AllowIncompatiblePlatform = new DeploymentOptionProperty(true); - expectedResults.DisableIndexesForDataPhase = new DeploymentOptionProperty(false); + expectedResults.BooleanOptionsDictionary[nameof(DacDeployOptions.IncludeCompositeObjects)].Value = true; + expectedResults.BooleanOptionsDictionary[nameof(DacDeployOptions.BlockOnPossibleDataLoss)].Value = true; + expectedResults.BooleanOptionsDictionary[nameof(DacDeployOptions.AllowIncompatiblePlatform)].Value = true; + expectedResults.BooleanOptionsDictionary[nameof(DacDeployOptions.DisableIndexesForDataPhase)].Value = false; var dacfxRequestContext = new Mock>(); dacfxRequestContext.Setup((RequestContext x) => x.SendResult(It.Is((result) => ValidateOptions(expectedResults, result.DeploymentOptions) == true))).Returns(Task.FromResult(new object())); @@ -755,7 +759,7 @@ public async Task GetOptionsFromProfileWithoutOptions() { DeploymentOptions expectedResults = DeploymentOptions.GetDefaultPublishOptions(); expectedResults.ExcludeObjectTypes = null; - expectedResults.DisableIndexesForDataPhase = new DeploymentOptionProperty(false); + expectedResults.BooleanOptionsDictionary["DisableIndexesForDataPhase"].Value = false; var dacfxRequestContext = new Mock>(); dacfxRequestContext.Setup((RequestContext x) => x.SendResult(It.Is((result) => ValidateOptions(expectedResults, result.DeploymentOptions) == true))).Returns(Task.FromResult(new object())); @@ -842,26 +846,37 @@ private bool ValidateStreamingJobErrors(ValidateStreamingJobResult expected, Val private bool ValidateOptions(DeploymentOptions expected, DeploymentOptions actual) { System.Reflection.PropertyInfo[] deploymentOptionsProperties = expected.GetType().GetProperties(); - foreach (var v in deploymentOptionsProperties) + var booleanOptionsDictionary = new Dictionary>(); + foreach (PropertyInfo v in deploymentOptionsProperties) { - var defaultP = v.GetValue(expected); - var defaultPValue = defaultP != null ? defaultP.GetType().GetProperty("Value").GetValue(defaultP): defaultP; - var actualP = v.GetValue(actual); - var actualPValue = actualP.GetType().GetProperty("Value").GetValue(actualP); - - if (v.Name == "ExcludeObjectTypes") + if (v.Name != nameof(DeploymentOptions.BooleanOptionsDictionary)) { - Assert.True((defaultP as ObjectType[])?.Length == (actualP as ObjectType[])?.Length, "Number of excluded objects is different not equal"); + var defaultP = v.GetValue(expected); + var defaultPValue = defaultP != null ? defaultP.GetType().GetProperty("Value").GetValue(defaultP) : defaultP; + var actualP = v.GetValue(actual); + var actualPValue = actualP.GetType().GetProperty("Value").GetValue(actualP); + + if (v.Name == nameof(DeploymentOptions.ExcludeObjectTypes)) + { + Assert.True((defaultP as ObjectType[])?.Length == (actualP as ObjectType[])?.Length, "Number of excluded objects is different not equal"); + } + else + { + //Verifying expected and actual deployment options properties are equal + Assert.True((defaultPValue == null && String.IsNullOrEmpty(actualPValue as string)) + || (defaultPValue).Equals(actualPValue) + , $"Actual Property from Service is not equal to default property for {v.Name}, Actual value: {actualPValue} and Default value: {defaultPValue}"); + } } else { - //Verifying expected and actual deployment options properties are equal - Assert.True((defaultPValue == null && String.IsNullOrEmpty(actualPValue as string)) - || (defaultPValue).Equals(actualPValue) - , $"Actual Property from Service is not equal to default property for {v.Name}, Actual value: {actualPValue} and Default value: {defaultPValue}"); + booleanOptionsDictionary = v.GetValue(expected) as Dictionary>; } } + // Verify expected and actual DeploymentOptions BooleanOptionsDictionary + VerifyExpectedAndActualBooleanOptionsDictionary(booleanOptionsDictionary, actual.BooleanOptionsDictionary); + return true; } @@ -895,5 +910,21 @@ private void VerifyAndCleanup(string filePath) File.Delete(filePath); } } + + /// + /// Verify expected and actual DeploymentOptions BooleanOptionsDictionary values + /// + /// + /// + public void VerifyExpectedAndActualBooleanOptionsDictionary(Dictionary> expectedBooleanOptionsDictionary, Dictionary> actualBooleanOptionsDictionary) + { + foreach (KeyValuePair> optionRow in expectedBooleanOptionsDictionary) + { + var expectedValue = optionRow.Value.Value; + var actualValue = actualBooleanOptionsDictionary[optionRow.Key].Value; + + Assert.That(actualValue, Is.EqualTo(expectedValue), $"Actual Property from Service is not equal to default property for {optionRow.Key}"); + } + } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs index ba362a934e..c6d980bfe0 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceOptionsTests.cs @@ -72,7 +72,7 @@ INSERT @returntable private DeploymentOptions GetIgnoreColumnOptions() { var options = new DeploymentOptions(); - options.IgnoreColumnOrder = new DeploymentOptionProperty(true); + options.BooleanOptionsDictionary[nameof(DacDeployOptions.IgnoreColumnOrder)].Value = true; return options; } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs index d7365a6afc..e28967e579 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs @@ -20,6 +20,7 @@ using NUnit.Framework; using static Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility.LiveConnectionHelper; using System.Collections.Generic; +using Microsoft.SqlServer.Dac; namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare { @@ -1823,22 +1824,21 @@ private void CreateAndValidateScmpFile(SchemaCompareEndpointInfo sourceInfo, Sch { SourceEndpointInfo = sourceInfo, TargetEndpointInfo = targetInfo, - DeploymentOptions = new DeploymentOptions() - { - // change some random ones explicitly - AllowDropBlockingAssemblies = new DeploymentOptionProperty(true), - DropConstraintsNotInSource = new DeploymentOptionProperty(true), - IgnoreAnsiNulls = new DeploymentOptionProperty(true), - NoAlterStatementsToChangeClrTypes = new DeploymentOptionProperty(false), - PopulateFilesOnFileGroups = new DeploymentOptionProperty(false), - VerifyDeployment = new DeploymentOptionProperty(false), - DisableIndexesForDataPhase = new DeploymentOptionProperty(false) - }, + DeploymentOptions = new DeploymentOptions(), ScmpFilePath = filePath, ExcludedSourceObjects = schemaCompareObjectIds, ExcludedTargetObjects = null, }; + // change some random ones explicitly + schemaCompareParams.DeploymentOptions.BooleanOptionsDictionary[nameof(DacDeployOptions.AllowDropBlockingAssemblies)].Value = true; + schemaCompareParams.DeploymentOptions.BooleanOptionsDictionary[nameof(DacDeployOptions.DropConstraintsNotInSource)].Value = true; + schemaCompareParams.DeploymentOptions.BooleanOptionsDictionary[nameof(DacDeployOptions.IgnoreAnsiNulls)].Value = true; + schemaCompareParams.DeploymentOptions.BooleanOptionsDictionary[nameof(DacDeployOptions.NoAlterStatementsToChangeClrTypes)].Value = false; + schemaCompareParams.DeploymentOptions.BooleanOptionsDictionary[nameof(DacDeployOptions.PopulateFilesOnFileGroups)].Value = false; + schemaCompareParams.DeploymentOptions.BooleanOptionsDictionary[nameof(DacDeployOptions.VerifyDeployment)].Value = false; + schemaCompareParams.DeploymentOptions.BooleanOptionsDictionary[nameof(DacDeployOptions.DisableIndexesForDataPhase)].Value = false; + SchemaCompareSaveScmpOperation schemaCompareOperation = new SchemaCompareSaveScmpOperation(schemaCompareParams, result.ConnectionInfo, result.ConnectionInfo); 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 7e6d363308..51f2a3a253 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs @@ -6,6 +6,7 @@ using Microsoft.SqlServer.Dac; using Microsoft.SqlTools.ServiceLayer.DacFx; using Microsoft.SqlTools.ServiceLayer.DacFx.Contracts; +using Microsoft.SqlTools.ServiceLayer.IntegrationTests.DacFx; using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility; using Microsoft.SqlTools.ServiceLayer.TaskServices; using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts; @@ -14,6 +15,8 @@ using System; using System.IO; using static Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility.LiveConnectionHelper; +using System.Collections.Generic; +using System.Reflection; namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare { @@ -129,25 +132,29 @@ internal static void CompareOptions(DeploymentOptions deploymentOptions, DacDepl // TODO: update with new options. Tracking issue: https://github.com/microsoft/azuredatastudio/issues/15336 //Assert.True(deploymentOptionsProperties.Length == dacDeployProperties.Length - 2, $"Number of properties is not same Deployment options : {deploymentOptionsProperties.Length} DacFx options : {dacDeployProperties.Length}"); - foreach (var deployOptionsProp in deploymentOptionsProperties) + foreach (PropertyInfo deployOptionsProp in deploymentOptionsProperties) { - var dacProp = dacDeployOptions.GetType().GetProperty(deployOptionsProp.Name); - Assert.True(dacProp != null, $"DacDeploy property not present for {deployOptionsProp.Name}"); - - var deployOptionsValue = deployOptionsProp.GetValue(deploymentOptions); - var changedDacValue = deployOptionsValue != null ? deployOptionsValue.GetType().GetProperty("Value").GetValue(deployOptionsValue) : deployOptionsValue; - var dafaultDacValue = dacProp.GetValue(dacDeployOptions); - - if (deployOptionsProp.Name != "ExcludeObjectTypes") // do not compare for ExcludeObjectTypes because it will be different + if (deployOptionsProp.Name != nameof(DeploymentOptions.BooleanOptionsDictionary)) { - Assert.True((deployOptionsValue == null && dafaultDacValue == null) - || deployOptionsValue.Equals(dafaultDacValue) - || changedDacValue == null && (dafaultDacValue as string) == string.Empty - || changedDacValue == null && dafaultDacValue == null - || (changedDacValue).Equals(dafaultDacValue) - , $"DacFx DacDeploy property not equal to Tools Service DeploymentOptions for { deployOptionsProp.Name}, SchemaCompareOptions value: {changedDacValue} and DacDeployOptions value: {dafaultDacValue} "); + var dacProp = dacDeployOptions.GetType().GetProperty(deployOptionsProp.Name); + Assert.That(dacProp, Is.Not.Null, $"DacDeploy property not present for {deployOptionsProp.Name}"); + + var defaultP = deployOptionsProp.GetValue(deploymentOptions); + var defaultPValue = defaultP != null ? defaultP.GetType().GetProperty("Value").GetValue(defaultP) : defaultP; + var actualPValue = dacProp.GetValue(dacDeployOptions); + + if (deployOptionsProp.Name != nameof(DeploymentOptions.ExcludeObjectTypes)) // do not compare for ExcludeObjectTypes because it will be different + { + // Verifying expected and actual deployment options properties are equal + Assert.True((defaultPValue == null && String.IsNullOrEmpty(actualPValue as string)) + || (defaultPValue).Equals(actualPValue) + , $"DacFx DacDeploy property not equal to Tools Service DeploymentOptions for {deployOptionsProp.Name}, Actual value: {actualPValue} and Default value: {defaultPValue}"); + } } } + + // Verify the booleanOptionsDictionary with the DacDeployOptions property values + VerifyBooleanOptionsDictionary(deploymentOptions.BooleanOptionsDictionary, dacDeployOptions); } internal static bool ValidateOptionsEqualsDefault(SchemaCompareOptionsResult options) @@ -156,26 +163,52 @@ internal static bool ValidateOptionsEqualsDefault(SchemaCompareOptionsResult opt DeploymentOptions actualOpt = options.DefaultDeploymentOptions; System.Reflection.PropertyInfo[] deploymentOptionsProperties = defaultOpt.GetType().GetProperties(); - foreach (var v in deploymentOptionsProperties) + foreach (PropertyInfo v in deploymentOptionsProperties) { - var defaultP = v.GetValue(defaultOpt); - var defaultPValue = defaultP != null ? defaultP.GetType().GetProperty("Value").GetValue(defaultP) : defaultP; - var actualP = v.GetValue(actualOpt); - var actualPValue = actualP.GetType().GetProperty("Value").GetValue(actualP); - - if (v.Name == "ExcludeObjectTypes") + if (v.Name != nameof(DeploymentOptions.BooleanOptionsDictionary)) { - Assert.True((defaultPValue as ObjectType[]).Length == (actualPValue as ObjectType[]).Length, $"Number of excluded objects is different; expected: {(defaultPValue as ObjectType[]).Length} actual: {(actualPValue as ObjectType[]).Length}"); - } - else - { - // Verifying expected and actual deployment options properties are equal - Assert.True((defaultPValue == null && String.IsNullOrEmpty(actualPValue as string)) - || (defaultPValue).Equals(actualPValue) - , $"Actual Property from Service is not equal to default property for {v.Name}, Actual value: {actualPValue} and Default value: {defaultPValue}"); + var defaultP = v.GetValue(defaultOpt); + var defaultPValue = defaultP != null ? defaultP.GetType().GetProperty("Value").GetValue(defaultP) : defaultP; + var actualP = v.GetValue(actualOpt); + var actualPValue = actualP.GetType().GetProperty("Value").GetValue(actualP); + + if (v.Name == nameof(DeploymentOptions.ExcludeObjectTypes)) + { + Assert.That((defaultPValue as ObjectType[]).Length, Is.EqualTo((actualPValue as ObjectType[]).Length), $"Number of excluded objects is different; expected: {(defaultPValue as ObjectType[]).Length} actual: {(actualPValue as ObjectType[]).Length}"); + } + else + { + // Verifying expected and actual deployment options properties are equal + Assert.True((defaultPValue == null && String.IsNullOrEmpty(actualPValue as string)) + || (defaultPValue).Equals(actualPValue) + , $"Actual Property from Service is not equal to default property for {v.Name}, Actual value: {actualPValue} and Default value: {defaultPValue}"); + } } } + + // Verify the default booleanOptionsDictionary with the SchemaCompareOptionsResult options property values + DacFxServiceTests dacFxServiceTests = new DacFxServiceTests(); + dacFxServiceTests.VerifyExpectedAndActualBooleanOptionsDictionary(defaultOpt.BooleanOptionsDictionary, options.DefaultDeploymentOptions.BooleanOptionsDictionary); + return true; } + + /// + /// Validates the DeploymentOptions booleanOptionsDictionary with the DacDeployOptions + /// + /// + /// + private static void VerifyBooleanOptionsDictionary(Dictionary> expectedBooleanOptionsDictionary, DacDeployOptions dacDeployOptions) + { + foreach (KeyValuePair> optionRow in expectedBooleanOptionsDictionary) + { + var dacProp = dacDeployOptions.GetType().GetProperty(optionRow.Key); + Assert.That(dacProp, Is.Not.Null, $"DacDeploy property not present for {optionRow.Key}"); + var actualValue = dacProp.GetValue(dacDeployOptions); + var expectedValue = optionRow.Value.Value; + + Assert.That(actualValue, Is.EqualTo(expectedValue), $"Actual Property from Service is not equal to default property for {optionRow.Key}"); + } + } } }