diff --git a/Packages.props b/Packages.props index 2399365b..09e8d178 100644 --- a/Packages.props +++ b/Packages.props @@ -22,7 +22,7 @@ - + diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOpenScmpOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOpenScmpOperation.cs index 268e4fe1..38f4a18e 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOpenScmpOperation.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOpenScmpOperation.cs @@ -173,9 +173,19 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare if (fs != null) { DacExtractTarget extractTarget; - if (Enum.TryParse(fs.FirstOrDefault().Value, out extractTarget)) + if(fs.FirstOrDefault() != null) // it is possible that this value is not set { - endpointInfo.ExtractTarget = extractTarget; + if (Enum.TryParse(fs.FirstOrDefault().Value, out extractTarget)) + { + endpointInfo.ExtractTarget = extractTarget; + } else + { + endpointInfo.ExtractTarget = DacExtractTarget.SchemaObjectType; // set default but log an error + Logger.Write(TraceEventType.Error, string.Format("Schema compare open scmp operation failed during xml parsing with unknown ExtractTarget")); + } + } else + { + endpointInfo.ExtractTarget = DacExtractTarget.SchemaObjectType; // set the default if this value doesn't already exist in the scmp file } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompare/TestScmpFileTemplate.scmp b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompare/TestScmpFileTemplate.scmp new file mode 100644 index 00000000..74e4d07e --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompare/TestScmpFileTemplate.scmp @@ -0,0 +1,1025 @@ + + + 10 + + + @@SourceProjectFilePath@@ + [dummyFolder\table1.sql,dummyFolder\table2.sql] + 150 + + + + + @@TargetProjectFilePath@@ + [dummyFolder\table2.sql,dummyFolder\table3.sql] + 150 + + + + + + Version + 1 + + + + + PlanGenerationType + SqlDeploymentOptions + + + AllowExistingModelErrors + False + + + AllowIncompatiblePlatform + False + + + BackupDatabaseBeforeChanges + False + + + IgnoreIndexesStatisticsOnEnclaveEnabledColumns + False + + + BlockOnPossibleDataLoss + True + + + BlockWhenDriftDetected + False + + + CompareUsingTargetCollation + False + + + CommentOutSetVarDeclarations + False + + + CreateNewDatabase + False + + + DeployDatabaseInSingleUserMode + False + + + DisableAndReenableDdlTriggers + True + + + DisableIndexesForDataPhase + True + + + DisableParallelismForEnablingIndexes + False + + + DoNotAlterChangeDataCaptureObjects + True + + + DoNotAlterReplicatedObjects + True + + + DropConstraintsNotInSource + True + + + DropDmlTriggersNotInSource + True + + + DropExtendedPropertiesNotInSource + True + + + DropIndexesNotInSource + True + + + DropPermissionsNotInSource + False + + + DropObjectsNotInSource + True + + + DropRoleMembersNotInSource + False + + + DropStatisticsNotInSource + True + + + GenerateSmartDefaults + False + + + HashObjectNamesInLogs + False + + + IgnoreDdlTriggerOrder + False + + + IgnoreDdlTriggerState + False + + + IgnoreObjectPlacementOnPartitionScheme + True + + + IgnoreAuthorizer + False + + + IgnoreDefaultSchema + False + + + IgnoreRouteLifetime + True + + + IgnoreCryptographicProviderFilePath + True + + + IgnoreComments + False + + + IgnoreWhitespace + True + + + IgnoreKeywordCasing + True + + + IgnoreSemicolonBetweenStatements + True + + + IgnorePartitionSchemes + False + + + IgnoreTablePartitionOptions + False + + + IgnoreWithNocheckOnCheckConstraints + False + + + IgnoreWithNocheckOnForeignKeys + False + + + IgnoreIdentitySeed + False + + + IgnoreIncrement + False + + + IgnoreFillFactor + True + + + IgnoreIndexPadding + True + + + IgnoreColumnCollation + False + + + IgnoreColumnOrder + False + + + IgnoreLockHintsOnIndexes + False + + + IgnoreTableOptions + False + + + IgnoreIndexOptions + False + + + IgnoreDmlTriggerOrder + False + + + IgnoreDmlTriggerState + False + + + IgnoreAnsiNulls + True + + + IgnoreQuotedIdentifiers + True + + + IgnoreUserSettingsObjects + False + + + IgnoreFilegroupPlacement + True + + + IgnoreFullTextCatalogFilePath + True + + + IgnoreFileAndLogFilePath + True + + + IgnoreLoginSids + True + + + IgnoreNotForReplication + False + + + IgnoreFileSize + True + + + IgnoreSensitivityClassifications + False + + + AllowUnsafeRowLevelSecurityDataMovement + False + + + IncludeCompositeObjects + False + + + IncludeTransactionalScripts + False + + + IsAlwaysEncryptedParameterizationEnabled + False + + + NoAlterStatementsToChangeCLRTypes + False + + + PopulateFilesOnFileGroups + True + + + PreserveIdentityLastValues + False + + + RegisterDataTierApplication + False + + + RebuildIndexesOfflineForDataPhase + False + + + RestoreSequenceCurrentValue + True + + + ScriptDatabaseCollation + False + + + ScriptDatabaseCompatibility + False + + + ScriptDatabaseOptions + False + + + ScriptDeployStateChecks + False + + + ScriptFileSize + False + + + ScriptNewConstraintValidation + True + + + ScriptRefreshModule + True + + + TargetDatabaseName + TargetProject.sqlproj + + + TargetConnectionString + Integrated Security=True;Pooling=False;Connect Timeout=30 + + + TreatVerificationErrorsAsWarnings + False + + + UnmodifiableObjectWarnings + True + + + VerifyCollationCompatibility + True + + + VerifyDeployment + True + + + RunDeploymentPlanExecutors + False + + + AllowDropBlockingAssemblies + False + + + DoNotEvaluateSqlCmdVariables + True + + + DoNotDropAggregates + False + + + DoNotDropApplicationRoles + False + + + DoNotDropAssemblies + False + + + DoNotDropAsymmetricKeys + False + + + DoNotDropAudits + False + + + DoNotDropBrokerPriorities + False + + + DoNotDropCertificates + False + + + DoNotDropClrUserDefinedTypes + False + + + DoNotDropColumnEncryptionKeys + False + + + DoNotDropColumnMasterKeys + False + + + DoNotDropContracts + False + + + DoNotDropCredentials + False + + + DoNotDropDatabaseScopedCredentials + False + + + DoNotDropCryptographicProviders + False + + + DoNotDropDatabaseAuditSpecifications + False + + + DoNotDropDatabaseRoles + False + + + DoNotDropDatabaseTriggers + False + + + IgnoreDatabaseWorkloadGroups + False + + + DoNotDropDatabaseWorkloadGroups + False + + + IgnoreWorkloadClassifiers + False + + + DoNotDropWorkloadClassifiers + False + + + DoNotDropDefaults + False + + + DoNotDropEndpoints + False + + + DoNotDropErrorMessages + False + + + DoNotDropEventNotifications + False + + + DoNotDropEventSessions + False + + + DoNotDropExtendedProperties + False + + + DoNotDropExternalDataSources + False + + + DoNotDropExternalFileFormats + False + + + DoNotDropExternalLanguages + False + + + DoNotDropExternalLibraries + False + + + DoNotDropExternalStreamingJobs + False + + + DoNotDropExternalTables + False + + + DoNotDropExternalStreams + False + + + DoNotDropFilegroups + False + + + DoNotDropFiles + False + + + DoNotDropFileTables + False + + + DoNotDropFullTextCatalogs + False + + + DoNotDropFullTextStoplists + False + + + DoNotDropTableValuedFunctions + False + + + DoNotDropLinkedServerLogins + False + + + DoNotDropLinkedServers + False + + + DoNotDropLogins + False + + + DoNotDropMessageTypes + False + + + DoNotDropPartitionFunctions + False + + + DoNotDropPartitionSchemes + False + + + DoNotDropPermissions + False + + + DoNotDropQueues + False + + + DoNotDropRemoteServiceBindings + False + + + DoNotDropRoleMembership + False + + + DoNotDropRoutes + False + + + DoNotDropRules + False + + + DoNotDropScalarValuedFunctions + False + + + DoNotDropSearchPropertyLists + False + + + DoNotDropSecurityPolicies + False + + + DoNotDropSequences + False + + + DoNotDropServerAuditSpecifications + False + + + DoNotDropServerRoleMembership + False + + + DoNotDropServerRoles + False + + + DoNotDropServerTriggers + False + + + DoNotDropServices + False + + + DoNotDropSignatures + False + + + DoNotDropStoredProcedures + False + + + DoNotDropSymmetricKeys + False + + + DoNotDropSynonyms + False + + + DoNotDropTables + False + + + DoNotDropUserDefinedDataTypes + False + + + DoNotDropUserDefinedTableTypes + False + + + DoNotDropUsers + False + + + DoNotDropViews + False + + + DoNotDropXmlSchemaCollections + False + + + ExcludeAggregates + False + + + ExcludeApplicationRoles + False + + + ExcludeAssemblies + False + + + ExcludeAsymmetricKeys + False + + + ExcludeAudits + True + + + ExcludeBrokerPriorities + False + + + ExcludeCertificates + False + + + ExcludeClrUserDefinedTypes + False + + + ExcludeColumnEncryptionKeys + False + + + ExcludeColumnMasterKeys + False + + + ExcludeContracts + False + + + ExcludeCredentials + True + + + ExcludeDatabaseScopedCredentials + True + + + ExcludeCryptographicProviders + True + + + ExcludeDatabaseAuditSpecifications + True + + + ExcludeDatabaseRoles + False + + + ExcludeDatabaseTriggers + False + + + ExcludeDefaults + False + + + ExcludeEndpoints + True + + + ExcludeErrorMessages + True + + + ExcludeEventNotifications + False + + + ExcludeExternalDataSources + False + + + ExcludeExternalFileFormats + False + + + ExcludeExternalLanguages + False + + + ExcludeExternalLibraries + False + + + ExcludeExternalStreamingJobs + False + + + ExcludeExternalTables + False + + + ExcludeExternalStreams + False + + + ExcludeEventSessions + True + + + ExcludeFilegroups + False + + + ExcludeFiles + True + + + ExcludeFileTables + False + + + ExcludeFullTextCatalogs + False + + + ExcludeFullTextStoplists + False + + + ExcludeTableValuedFunctions + False + + + ExcludeLinkedServerLogins + True + + + ExcludeLinkedServers + True + + + ExcludeLogins + True + + + ExcludeMessageTypes + False + + + ExcludePartitionFunctions + False + + + ExcludePartitionSchemes + False + + + ExcludeQueues + False + + + ExcludeRemoteServiceBindings + False + + + ExcludeRoutes + True + + + ExcludeRules + False + + + ExcludeScalarValuedFunctions + False + + + ExcludeSearchPropertyLists + False + + + ExcludeSecurityPolicies + False + + + ExcludeSequences + False + + + ExcludeServerAuditSpecifications + True + + + ExcludeServerRoleMembership + True + + + ExcludeServerRoles + True + + + ExcludeServerTriggers + True + + + ExcludeServices + False + + + ExcludeSignatures + False + + + ExcludeStoredProcedures + False + + + ExcludeSymmetricKeys + False + + + ExcludeSynonyms + False + + + ExcludeTables + False + + + ExcludeUserDefinedDataTypes + False + + + ExcludeUserDefinedTableTypes + False + + + ExcludeUsers + False + + + ExcludeViews + False + + + ExcludeXmlSchemaCollections + False + + + AllowExternalLibraryPaths + False + + + AllowExternalLanguagePaths + False + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlServerDdlTrigger + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlRoute + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlLinkedServerLogin + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlEndpoint + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlErrorMessage + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlFile + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlLogin + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlLinkedServer + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlCredential + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlDatabaseCredential + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlDatabaseEncryptionKey + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlMasterKey + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlDatabaseAuditSpecification + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlServerAudit + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlServerAuditSpecification + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlCryptographicProvider + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlUserDefinedServerRole + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlEventSession + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlDatabaseOptions + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlEventNotification + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlServerRoleMembership + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlDatabaseEventSession + ExcludedType + + + Microsoft.Data.Tools.Schema.Sql.SchemaModel.SqlAssemblyFile + ExcludedType + + + + + 2 + 100 + Equals_Objects,Not_Supported_Deploy + + \ No newline at end of file diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs index 8ef7e3ef..a803e7c5 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs @@ -81,6 +81,8 @@ WITH VALUES ADD FILEGROUP [MyFileGroup] CONTAINS MEMORY_OPTIMIZED_DATA; GO"; + private string scmpFolder = Path.Combine("..", "..", "..", "SchemaCompare", "SchemaCompare"); + /// /// Verify the schema compare request comparing two dacpacs /// @@ -1225,7 +1227,6 @@ WITH VALUES string filePath = Path.Combine(folderPath, string.Format("SchemaCompareOpenScmpTest{0}.scmp", DateTime.Now.ToFileTime())); compare.SaveToFile(filePath); - SchemaCompareTestUtils.VerifyAndCleanup(Directory.GetParent((targetEndpoint as SchemaCompareProjectEndpoint).ProjectFilePath).FullName); await VerifyContentAndCleanupAsync(filePath, "ObjectType"); } finally @@ -1235,6 +1236,56 @@ WITH VALUES } } + /// + /// Verifies https://github.com/microsoft/azuredatastudio/issues/22728 -- Schema compare open scmp file not backward compatible + /// + [Test] + public void VerifyOpenScmpIsBackwardCompatible() + { + string testFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest", $"{TestContext.CurrentContext?.Test?.Name}_{DateTime.Now.Ticks.ToString()}"); + Directory.CreateDirectory(testFolderPath); + string testScmpFileTemplate = Path.Combine(testFolderPath, "TestScmpFileTemplate.scmp"); + File.Copy(Path.Combine(scmpFolder, "TestScmpFileTemplate.scmp"), testScmpFileTemplate); + + string testScmpFile = LoadScmpFileTemplate(testTemplateFolderPath: scmpFolder, testWorkingFolderPath: testFolderPath, templateFileName: "TestScmpFileTemplate.scmp", fileName: "TestScmpFile.scmp"); + var schemaCompareOpenScmpParams = new SchemaCompareOpenScmpParams + { + FilePath = testScmpFile + }; + + SchemaCompareOpenScmpOperation schemaCompareOpenScmpOperation = new SchemaCompareOpenScmpOperation(schemaCompareOpenScmpParams); + schemaCompareOpenScmpOperation.Execute(TaskExecutionMode.Execute); + + Assert.NotNull(schemaCompareOpenScmpOperation.Result); + Assert.True(schemaCompareOpenScmpOperation.Result.Success); + Assert.AreEqual(schemaCompareOpenScmpOperation.Result.SourceEndpointInfo.ProjectFilePath, Path.Combine(testFolderPath, "SourceProject.sqlproj"), "Source project was expected to exist but did not"); + Assert.AreEqual(schemaCompareOpenScmpOperation.Result.SourceEndpointInfo.ExtractTarget, DacExtractTarget.SchemaObjectType, $"Source project was expected to have SchemaObjectType as extract target but {schemaCompareOpenScmpOperation.Result.SourceEndpointInfo.ExtractTarget} was set instead"); + Assert.AreEqual(schemaCompareOpenScmpOperation.Result.TargetEndpointInfo.ProjectFilePath, Path.Combine(testFolderPath, "TargetProject.sqlproj"), "Target project was expected to exist but did not"); + Assert.AreEqual(schemaCompareOpenScmpOperation.Result.TargetEndpointInfo.ExtractTarget, DacExtractTarget.SchemaObjectType, $"Target project was expected to have SchemaObjectType as extract target but {schemaCompareOpenScmpOperation.Result.TargetEndpointInfo.ExtractTarget} was set instead"); + + SchemaCompareTestUtils.VerifyAndCleanup(testFolderPath); + } + + private string LoadScmpFileTemplate(string testTemplateFolderPath, string testWorkingFolderPath, string templateFileName, string fileName) + { + string templatePath = Path.Combine(testTemplateFolderPath, templateFileName); + string text = File.ReadAllText(templatePath); + + string sourceDummyProject = Path.Combine(testWorkingFolderPath, "SourceProject.sqlproj"); + string targetDummyProject = Path.Combine(testWorkingFolderPath, "TargetProject.sqlproj"); + + text = text.Replace($"@@SourceProjectFilePath@@", sourceDummyProject); + text = text.Replace($"@@TargetProjectFilePath@@", targetDummyProject); + + File.Create(sourceDummyProject).Close(); + File.Create(targetDummyProject).Close(); + + string scmpPath = Path.Combine(testWorkingFolderPath, fileName); + File.WriteAllText(scmpPath, text); + + return scmpPath; + } + /// /// Verify the schema compare Service Calls ends to end ///