diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareGenerateScriptRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareGenerateScriptRequest.cs index d4ec99d5..25348870 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareGenerateScriptRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareGenerateScriptRequest.cs @@ -13,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts /// /// Parameters for a schema compare generate script request. /// - public class SchemaCompareGenerateScriptParams : SchemaComparePublishChangesParams + public class SchemaCompareGenerateScriptParams : SchemaComparePublishDatabaseChangesParams { } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishChangesRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishChangesRequest.cs index 28e2d5fc..0da9211a 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishChangesRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishChangesRequest.cs @@ -39,7 +39,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts /// class SchemaComparePublishChangesRequest { - public static readonly RequestType Type = - RequestType.Create("schemaCompare/publish"); + public static readonly RequestType Type = + RequestType.Create("schemaCompare/publish"); } -} +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishDatabaseChangesRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishDatabaseChangesRequest.cs new file mode 100644 index 00000000..53e5858c --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishDatabaseChangesRequest.cs @@ -0,0 +1,46 @@ +// +// 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.Contracts; +using Microsoft.SqlTools.ServiceLayer.TaskServices; +using Microsoft.SqlTools.ServiceLayer.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts +{ + /// + /// Parameters for a schema compare publish database changes request. + /// + public class SchemaComparePublishDatabaseChangesParams + { + /// + /// Operation id of the schema compare operation + /// + public string OperationId { get; set; } + + /// + /// Name of target server + /// + public string TargetServerName { get; set; } + + /// + /// Name of target database + /// + public string TargetDatabaseName { get; set; } + + /// + /// Execution mode for the operation. Default is execution + /// + public TaskExecutionMode TaskExecutionMode { get; set; } + } + + /// + /// Defines the Schema Compare publish database changes request type + /// + class SchemaComparePublishDatabaseChangesRequest + { + public static readonly RequestType Type = + RequestType.Create("schemaCompare/publishDatabase"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishProjectChangesRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishProjectChangesRequest.cs new file mode 100644 index 00000000..3d8e4aa8 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaComparePublishProjectChangesRequest.cs @@ -0,0 +1,47 @@ +// +// 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.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.ServiceLayer.TaskServices; + +namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts +{ + /// + /// Parameters for a schema compare publish project changes request. + /// + public class SchemaComparePublishProjectChangesParams + { + /// + /// Operation id of the schema compare operation + /// + public string OperationId { get; set; } + + /// + /// Path of project folder + /// + public string TargetProjectPath { get; set; } + + /// + /// folder structure of target folder + /// + public DacExtractTarget TargetFolderStructure { get; set; } + + /// + /// Execution mode for the operation. Default is execution + /// + public TaskExecutionMode TaskExecutionMode { get; set; } + } + + /// + /// Defines the Schema Compare publish project changes request type + /// + class SchemaComparePublishProjectChangesRequest + { + public static readonly RequestType Type = + RequestType.Create("schemaCompare/publishProject"); + } +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareRequest.cs index 13c1b9bf..5ea2a25c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareRequest.cs @@ -12,12 +12,21 @@ using Microsoft.SqlTools.ServiceLayer.Utility; namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts { + /// + /// Types of schema compare endpoints + /// public enum SchemaCompareEndpointType { - Database, - Dacpac + Database = 0, + Dacpac = 1, + Project = 2 + // must be kept in-sync with SchemaCompareEndpointType in Azure Data Studio + // located at \extensions\mssql\src\mssql.d.ts } + /// + /// Info needed from endpoints for schema comparison + /// public class SchemaCompareEndpointInfo { /// @@ -25,6 +34,21 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts /// public SchemaCompareEndpointType EndpointType { get; set; } + /// + /// Gets or sets the project file path + /// + public string ProjectFilePath { get; set; } + + /// + /// Gets or sets the scripts included in project + /// + public string[] TargetScripts { get; set; } + + /// + /// Gets or sets the project data schema provider + /// + public string DataSchemaProvider { get; set; } + /// /// Gets or sets package filepath /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOpenScmpOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOpenScmpOperation.cs index b8cf0d27..b6629114 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOpenScmpOperation.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOpenScmpOperation.cs @@ -100,13 +100,17 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare { SchemaCompareEndpointInfo endpointInfo = new SchemaCompareEndpointInfo(); - // if the endpoint is a dacpac we don't need to parse the xml - SchemaCompareDacpacEndpoint dacpacEndpoint = endpoint as SchemaCompareDacpacEndpoint; - if (dacpacEndpoint != null) + // if the endpoint is a dacpac or a project, we don't need to parse the xml + if (endpoint is SchemaCompareDacpacEndpoint dacpacEndpoint) { endpointInfo.EndpointType = SchemaCompareEndpointType.Dacpac; endpointInfo.PackageFilePath = dacpacEndpoint.FilePath; } + else if (endpoint is SchemaCompareProjectEndpoint projectEndpoint) + { + endpointInfo.EndpointType = SchemaCompareEndpointType.Project; + endpointInfo.ProjectFilePath = projectEndpoint.ProjectFilePath; + } else { // need to parse xml to get connection string of database @@ -131,7 +135,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare } catch (Exception e) { - ErrorMessage = string.Format(SR.OpenScmpConnectionBasedModelParsingError, ((SchemaCompareDatabaseEndpoint)endpoint).DatabaseName,e.Message); + ErrorMessage = string.Format(SR.OpenScmpConnectionBasedModelParsingError, ((SchemaCompareDatabaseEndpoint)endpoint).DatabaseName, e.Message); Logger.Write(TraceEventType.Error, string.Format("Schema compare open scmp operation failed during xml parsing with exception {0}", e.Message)); throw; } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishChangesOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishChangesOperation.cs index 16b5d0d7..0f09298b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishChangesOperation.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishChangesOperation.cs @@ -2,79 +2,38 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using System.Threading; using Microsoft.SqlServer.Dac.Compare; -using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts; using Microsoft.SqlTools.ServiceLayer.TaskServices; using Microsoft.SqlTools.Utility; -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading; namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare { - /// - /// Class to represent an in-progress schema compare publish changes operation - /// - class SchemaComparePublishChangesOperation : ITaskOperation + abstract class SchemaComparePublishChangesOperation : ITaskOperation { - private CancellationTokenSource cancellation = new CancellationTokenSource(); - - /// - /// Gets the unique id associated with this instance. - /// public string OperationId { get; private set; } - public SchemaComparePublishChangesParams Parameters { get; } - - protected CancellationToken CancellationToken { get { return this.cancellation.Token; } } - - public string ErrorMessage { get; set; } - public SqlTask SqlTask { get; set; } public SchemaComparisonResult ComparisonResult { get; set; } - public SchemaComparePublishResult PublishResult { get; set; } + public string ErrorMessage { get; set; } - public SchemaComparePublishChangesOperation(SchemaComparePublishChangesParams parameters, SchemaComparisonResult comparisonResult) + protected CancellationToken CancellationToken { get { return cancellation.Token; } } + + protected readonly CancellationTokenSource cancellation = new(); + + public SchemaComparePublishChangesOperation(SchemaComparisonResult comparisonResult) { - Validate.IsNotNull("parameters", parameters); - this.Parameters = parameters; - Validate.IsNotNull("comparisonResult", comparisonResult); - this.ComparisonResult = comparisonResult; + Validate.IsNotNull(nameof(comparisonResult), comparisonResult); + ComparisonResult = comparisonResult; } + + public abstract void Execute(TaskExecutionMode mode); - public void Execute(TaskExecutionMode mode) - { - if (this.CancellationToken.IsCancellationRequested) - { - throw new OperationCanceledException(this.CancellationToken); - } - - try - { - this.PublishResult = this.ComparisonResult.PublishChangesToTarget(this.CancellationToken); - if (!this.PublishResult.Success) - { - // Sending only errors and warnings - because overall message might be too big for task view - ErrorMessage = string.Join(Environment.NewLine, this.PublishResult.Errors.Where(x => x.MessageType == SqlServer.Dac.DacMessageType.Error || x.MessageType == SqlServer.Dac.DacMessageType.Warning)); - throw new Exception(ErrorMessage); - } - } - catch (Exception e) - { - ErrorMessage = e.Message; - Logger.Write(TraceEventType.Error, string.Format("Schema compare publish changes operation {0} failed with exception {1}", this.OperationId, e.Message)); - throw; - } - } - - // The schema compare public api doesn't currently take a cancellation token so the operation can't be cancelled public void Cancel() { - this.cancellation.Cancel(); + cancellation.Cancel(); } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishDatabaseChangesOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishDatabaseChangesOperation.cs new file mode 100644 index 00000000..9902f2e8 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishDatabaseChangesOperation.cs @@ -0,0 +1,56 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using Microsoft.SqlServer.Dac.Compare; +using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts; +using Microsoft.SqlTools.ServiceLayer.TaskServices; +using Microsoft.SqlTools.Utility; +using Microsoft.SqlServer.Dac; + +namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare +{ + /// + /// Class to represent an in-progress schema compare publish database changes operation + /// + class SchemaComparePublishDatabaseChangesOperation : SchemaComparePublishChangesOperation + { + public SchemaComparePublishDatabaseChangesParams Parameters { get; } + + public SchemaComparePublishResult PublishResult { get; set; } + + public SchemaComparePublishDatabaseChangesOperation(SchemaComparePublishDatabaseChangesParams parameters, SchemaComparisonResult comparisonResult) : base(comparisonResult) + { + Validate.IsNotNull(nameof(parameters), parameters); + Parameters = parameters; + } + + public override void Execute(TaskExecutionMode mode) + { + CancellationToken.ThrowIfCancellationRequested(); + + try + { + PublishResult = ComparisonResult.PublishChangesToDatabase(CancellationToken); + + if (!PublishResult.Success) + { + // Sending only errors and warnings - because overall message might be too big for task view + ErrorMessage = String.Join(Environment.NewLine, this.PublishResult.Errors.Where(x => x.MessageType == SqlServer.Dac.DacMessageType.Error || x.MessageType == SqlServer.Dac.DacMessageType.Warning)); + throw new DacServicesException(ErrorMessage); + } + } + catch (Exception e) + { + ErrorMessage = e.Message; + Logger.Write(TraceEventType.Error, string.Format("Schema compare publish database changes operation {0} failed with exception {1}", this.OperationId, e.Message)); + throw; + } + } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishProjectChangesOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishProjectChangesOperation.cs new file mode 100644 index 00000000..c90f1d95 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaComparePublishProjectChangesOperation.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 System; +using System.Diagnostics; +using System.Threading; +using Microsoft.SqlServer.Dac; +using Microsoft.SqlServer.Dac.Compare; +using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts; +using Microsoft.SqlTools.ServiceLayer.TaskServices; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare +{ + /// + /// Class to represent an in-progress schema compare publish project changes operation + /// + class SchemaComparePublishProjectChangesOperation: SchemaComparePublishChangesOperation + { + public SchemaComparePublishProjectChangesParams Parameters { get; } + + public SchemaComparePublishProjectResult PublishResult { get; set; } + + public SchemaComparePublishProjectChangesOperation(SchemaComparePublishProjectChangesParams parameters, SchemaComparisonResult comparisonResult) : base(comparisonResult) + { + Validate.IsNotNull(nameof(parameters), parameters); + Parameters = parameters; + } + + public override void Execute(TaskExecutionMode mode) + { + if (CancellationToken.IsCancellationRequested) + { + throw new OperationCanceledException(CancellationToken); + } + + try + { + PublishResult = ComparisonResult.PublishChangesToProject(Parameters.TargetProjectPath, Parameters.TargetFolderStructure); + + if (!PublishResult.Success) + { + ErrorMessage = PublishResult.ErrorMessage; + throw new DacServicesException(ErrorMessage); + } + } + catch (Exception e) + { + ErrorMessage = e.Message; + Logger.Write(TraceEventType.Error, string.Format("Schema compare publish project changes operation {0} failed with exception {1}", OperationId, e.Message)); + throw; + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareService.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareService.cs index 157f2eec..a9e0989b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareService.cs @@ -52,6 +52,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare serviceHost.SetRequestHandler(SchemaCompareCancellationRequest.Type, this.HandleSchemaCompareCancelRequest); serviceHost.SetRequestHandler(SchemaCompareGenerateScriptRequest.Type, this.HandleSchemaCompareGenerateScriptRequest); serviceHost.SetRequestHandler(SchemaComparePublishChangesRequest.Type, this.HandleSchemaComparePublishChangesRequest); + serviceHost.SetRequestHandler(SchemaComparePublishDatabaseChangesRequest.Type, this.HandleSchemaComparePublishDatabaseChangesRequest); + serviceHost.SetRequestHandler(SchemaComparePublishProjectChangesRequest.Type, this.HandleSchemaComparePublishProjectChangesRequest); serviceHost.SetRequestHandler(SchemaCompareIncludeExcludeNodeRequest.Type, this.HandleSchemaCompareIncludeExcludeNodeRequest); serviceHost.SetRequestHandler(SchemaCompareGetDefaultOptionsRequest.Type, this.HandleSchemaCompareGetDefaultOptionsRequest); serviceHost.SetRequestHandler(SchemaCompareOpenScmpRequest.Type, this.HandleSchemaCompareOpenScmpRequest); @@ -198,22 +200,19 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare /// Handles request for schema compare publish changes script /// /// - public async Task HandleSchemaComparePublishChangesRequest(SchemaComparePublishChangesParams parameters, RequestContext requestContext) + public async Task HandleSchemaComparePublishChangesRequest(SchemaComparePublishDatabaseChangesParams parameters, RequestContext requestContext) { - SchemaComparePublishChangesOperation operation = null; + SchemaComparePublishDatabaseChangesOperation operation = null; try { SchemaComparisonResult compareResult = schemaCompareResults.Value[parameters.OperationId]; - operation = new SchemaComparePublishChangesOperation(parameters, compareResult); - SqlTask sqlTask = null; + operation = new SchemaComparePublishDatabaseChangesOperation(parameters, compareResult); TaskMetadata metadata = new TaskMetadata(); metadata.TaskOperation = operation; metadata.ServerName = parameters.TargetServerName; metadata.DatabaseName = parameters.TargetDatabaseName; metadata.Name = SR.PublishChangesTaskName; - - sqlTask = SqlTaskManagerInstance.CreateAndRun(metadata); - + SqlTask sqlTask = SqlTaskManagerInstance.CreateAndRun(metadata); await requestContext.SendResult(new ResultStatus() { Success = true, @@ -231,6 +230,90 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare } } + /// + /// Handles request for schema compare publish database changes script + /// + /// + public async Task HandleSchemaComparePublishDatabaseChangesRequest(SchemaComparePublishDatabaseChangesParams parameters, RequestContext requestContext) + { + SchemaComparePublishDatabaseChangesOperation operation = null; + try + { + SchemaComparisonResult compareResult = schemaCompareResults.Value[parameters.OperationId]; + operation = new SchemaComparePublishDatabaseChangesOperation(parameters, compareResult); + SqlTask sqlTask = null; + TaskMetadata metadata = new TaskMetadata + { + TaskOperation = operation, + ServerName = parameters.TargetServerName, + DatabaseName = parameters.TargetDatabaseName, + Name = SR.PublishChangesTaskName + }; + + sqlTask = SqlTaskManagerInstance.CreateAndRun(metadata); + + await requestContext.SendResult(new ResultStatus() + { + Success = true, + ErrorMessage = operation.ErrorMessage + }); + } + catch (Exception e) + { + Logger.Write(TraceEventType.Error, "Failed to publish schema compare database changes. Error: " + e); + await requestContext.SendResult(new ResultStatus() + { + Success = false, + ErrorMessage = operation == null ? e.Message : operation.ErrorMessage, + }); + } + } + + /// + /// Handles request for schema compare publish database changes script + /// + /// + public async Task HandleSchemaComparePublishProjectChangesRequest(SchemaComparePublishProjectChangesParams parameters, RequestContext requestContext) + { + SchemaComparePublishProjectChangesOperation operation = null; + try + { + SchemaComparisonResult compareResult = schemaCompareResults.Value[parameters.OperationId]; + operation = new SchemaComparePublishProjectChangesOperation(parameters, compareResult); + + TaskMetadata metadata = new() + { + TaskOperation = operation, + TargetLocation = parameters.TargetProjectPath, + Name = SR.PublishChangesTaskName + }; + + SqlTask sqlTask = SqlTaskManagerInstance.CreateTask(metadata); + await sqlTask.RunAsync(); + + await requestContext.SendResult(new SchemaComparePublishProjectResult() + { + ChangedFiles = operation.PublishResult.ChangedFiles, + AddedFiles = operation.PublishResult.AddedFiles, + DeletedFiles = operation.PublishResult.DeletedFiles, + Success = true, + ErrorMessage = operation.ErrorMessage + }); + } + catch (Exception e) + { + Logger.Write(TraceEventType.Error, "Failed to publish schema compare database changes. Error: " + e); + await requestContext.SendResult(new SchemaComparePublishProjectResult() + { + ChangedFiles = Array.Empty(), + AddedFiles = Array.Empty(), + DeletedFiles = Array.Empty(), + Success = false, + ErrorMessage = operation?.ErrorMessage ?? e.Message + }); + } + } + /// /// Handles request for exclude incude node in Schema compare result /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs index 6b30cc85..6a33f178 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareUtils.cs @@ -114,6 +114,10 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare { switch (endpointInfo.EndpointType) { + case SchemaCompareEndpointType.Project: + { + return new SchemaCompareProjectEndpoint(endpointInfo.ProjectFilePath, endpointInfo.TargetScripts, endpointInfo.DataSchemaProvider); + } case SchemaCompareEndpointType.Dacpac: { return new SchemaCompareDacpacEndpoint(endpointInfo.PackageFilePath); diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs index 9686d9f5..8385bd96 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs @@ -19,6 +19,8 @@ using System.Linq; using System.Threading.Tasks; using NUnit.Framework; using System.Diagnostics; +using static Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility.LiveConnectionHelper; +using System.Collections.Generic; namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare { @@ -122,7 +124,7 @@ WITH VALUES } /// - /// Verify the schema compare request comparing a two databases + /// Verify the schema compare request comparing two databases /// [Test] public async Task SchemaCompareDatabaseToDatabase() @@ -160,6 +162,46 @@ WITH VALUES } } + /// + /// Verify the schema compare request comparing two projects + /// + [Test] + public async Task SchemaCompareProjectToProject() + { + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); + + try + { + string sourceProjectPath = SchemaCompareTestUtils.CreateProject(sourceDb, "SourceProject"); + string targetProjectPath = SchemaCompareTestUtils.CreateProject(targetDb, "TargetProject"); + + string[] sourceScripts = SchemaCompareTestUtils.GetProjectScripts(sourceProjectPath); + string[] targetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(sourceProjectPath, "SourceProject.sqlproj"), sourceScripts); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(targetProjectPath, "TargetProject.sqlproj"), targetScripts); + + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new(schemaCompareParams, null, null); + ValidateSchemaCompareWithExcludeIncludeResults(schemaCompareOperation); + + // cleanup + SchemaCompareTestUtils.VerifyAndCleanup(sourceProjectPath); + SchemaCompareTestUtils.VerifyAndCleanup(targetProjectPath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + /// /// Verify the schema compare request comparing a database to a dacpac /// @@ -201,6 +243,83 @@ WITH VALUES } } + /// + /// Verify the schema compare request comparing a database and a project + /// + [Test] + public async Task SchemaCompareDatabaseToProject() + { + TestConnectionResult result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects(); + + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); + + try + { + string targetProjectPath = SchemaCompareTestUtils.CreateProject(targetDb, "TargetProject"); + string[] targetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Database, sourceDb.DatabaseName); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(targetProjectPath, "TargetProject.sqlproj"), targetScripts); + + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new(schemaCompareParams, result.ConnectionInfo, null); + ValidateSchemaCompareWithExcludeIncludeResults(schemaCompareOperation); + + // cleanup + SchemaCompareTestUtils.VerifyAndCleanup(targetProjectPath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + + /// + /// Verify the schema compare request comparing a dacpac and a project + /// + [Test] + public async Task SchemaCompareDacpacToProject() + { + // 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 targetProjectPath = SchemaCompareTestUtils.CreateProject(targetDb, "TargetProject"); + string[] targetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Dacpac, sourceDacpacFilePath); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(targetProjectPath, "TargetProject.sqlproj"), targetScripts); + + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new(schemaCompareParams, null, null); + ValidateSchemaCompareWithExcludeIncludeResults(schemaCompareOperation); + + // cleanup + SchemaCompareTestUtils.VerifyAndCleanup(sourceDacpacFilePath); + SchemaCompareTestUtils.VerifyAndCleanup(targetProjectPath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + /// /// Verify the schema compare generate script request comparing a database to a database /// @@ -299,6 +418,59 @@ WITH VALUES } } + /// + /// Verify the schema compare generate script request comparing a project to a database + /// + [Test] + public async Task SchemaCompareGenerateScriptProjectToDatabase() + { + TestConnectionResult result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects(); + + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); + + try + { + string sourceProjectPath = SchemaCompareTestUtils.CreateProject(sourceDb, "SourceProject"); + string[] sourceScripts = SchemaCompareTestUtils.GetProjectScripts(sourceProjectPath); + + SchemaCompareEndpointInfo sourceInfo = new(); + sourceInfo.EndpointType = SchemaCompareEndpointType.Project; + sourceInfo.ProjectFilePath = Path.Combine(sourceProjectPath, "SourceProject.sqlproj"); + sourceInfo.TargetScripts = sourceScripts; + sourceInfo.DataSchemaProvider = "150"; + + SchemaCompareEndpointInfo targetInfo = new(); + targetInfo.EndpointType = SchemaCompareEndpointType.Database; + targetInfo.DatabaseName = targetDb.DatabaseName; + + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new(schemaCompareParams, result.ConnectionInfo, result.ConnectionInfo); + + // generate script + var generateScriptParams = new SchemaCompareGenerateScriptParams + { + TargetDatabaseName = targetDb.DatabaseName, + OperationId = schemaCompareOperation.OperationId, + }; + + ValidateSchemaCompareScriptGenerationWithExcludeIncludeResults(schemaCompareOperation, generateScriptParams); + + // cleanup + SchemaCompareTestUtils.VerifyAndCleanup(sourceProjectPath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + /// /// Verify the schema compare publish changes request comparing a dacpac to a database /// @@ -342,13 +514,13 @@ WITH VALUES Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table2]")); // update target - var publishChangesParams = new SchemaComparePublishChangesParams + var publishChangesParams = new SchemaComparePublishDatabaseChangesParams { TargetDatabaseName = targetDb.DatabaseName, OperationId = schemaCompareOperation.OperationId, }; - SchemaComparePublishChangesOperation publishChangesOperation = new SchemaComparePublishChangesOperation(publishChangesParams, schemaCompareOperation.ComparisonResult); + SchemaComparePublishDatabaseChangesOperation publishChangesOperation = new SchemaComparePublishDatabaseChangesOperation(publishChangesParams, schemaCompareOperation.ComparisonResult); publishChangesOperation.Execute(TaskExecutionMode.Execute); Assert.True(publishChangesOperation.PublishResult.Success); Assert.That(publishChangesOperation.PublishResult.Errors, Is.Empty); @@ -370,6 +542,73 @@ WITH VALUES } } + /// + /// Verify the schema compare publish changes request comparing a project to a database + /// + [Test] + public async Task SchemaComparePublishChangesProjectToDatabase() + { + TestConnectionResult result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects(); + + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, null, "SchemaCompareTarget"); + + try + { + string sourceProjectPath = SchemaCompareTestUtils.CreateProject(sourceDb, "SourceProject"); + string[] sourceScripts = SchemaCompareTestUtils.GetProjectScripts(sourceProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(sourceProjectPath, "SourceProject.sqlproj"), sourceScripts); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Database, targetDb.DatabaseName); + + SchemaCompareParams schemaCompareParams = new() + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new(schemaCompareParams, result.ConnectionInfo, result.ConnectionInfo); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + + IEnumerator enumerator = schemaCompareOperation.ComparisonResult.Differences.GetEnumerator(); + enumerator.MoveNext(); + Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table1]")); + enumerator.MoveNext(); + Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table2]")); + + // update target + SchemaComparePublishDatabaseChangesParams publishChangesParams = new() + { + TargetDatabaseName = targetDb.DatabaseName, + OperationId = schemaCompareOperation.OperationId, + }; + + SchemaComparePublishDatabaseChangesOperation publishChangesOperation = new(publishChangesParams, schemaCompareOperation.ComparisonResult); + publishChangesOperation.Execute(TaskExecutionMode.Execute); + Assert.True(publishChangesOperation.PublishResult.Success); + Assert.That(publishChangesOperation.PublishResult.Errors, Is.Empty); + + // Verify that there are no differences after the publish by running the comparison again + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.True(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.That(schemaCompareOperation.ComparisonResult.Differences, Is.Empty); + + // cleanup + SchemaCompareTestUtils.VerifyAndCleanup(sourceProjectPath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + /// /// Verify the schema compare publish changes request comparing a database to a database /// @@ -411,13 +650,13 @@ WITH VALUES Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table2]")); // update target - var publishChangesParams = new SchemaComparePublishChangesParams + var publishChangesParams = new SchemaComparePublishDatabaseChangesParams { TargetDatabaseName = targetDb.DatabaseName, OperationId = schemaCompareOperation.OperationId, }; - SchemaComparePublishChangesOperation publishChangesOperation = new SchemaComparePublishChangesOperation(publishChangesParams, schemaCompareOperation.ComparisonResult); + SchemaComparePublishDatabaseChangesOperation publishChangesOperation = new SchemaComparePublishDatabaseChangesOperation(publishChangesParams, schemaCompareOperation.ComparisonResult); publishChangesOperation.Execute(TaskExecutionMode.Execute); Assert.True(publishChangesOperation.PublishResult.Success); Assert.That(publishChangesOperation.PublishResult.Errors, Is.Empty); @@ -437,6 +676,237 @@ WITH VALUES } } + /// + /// Verify the schema compare publish changes request comparing a dacpac to a project + /// + [Test] + public async Task SchemaComparePublishChangesDacpacToProject() + { + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, null, "SchemaCompareTarget"); + + string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest"); + Directory.CreateDirectory(folderPath); + + try + { + string sourceDacpacFilePath = SchemaCompareTestUtils.CreateDacpac(sourceDb); + + string targetProjectPath = SchemaCompareTestUtils.CreateProject(targetDb, "TargetProject"); + string[] targetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Dacpac, sourceDacpacFilePath); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(targetProjectPath, "TargetProject.sqlproj"), targetScripts); + + SchemaCompareParams schemaCompareParams = new() + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new(schemaCompareParams, null, null); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + (schemaCompareOperation.ComparisonResult.Differences as List).RemoveAll(d => !d.Included); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + + IEnumerator enumerator = schemaCompareOperation.ComparisonResult.Differences.GetEnumerator(); + enumerator.MoveNext(); + Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table1]")); + enumerator.MoveNext(); + Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table2]")); + + // update target + SchemaComparePublishProjectChangesParams publishChangesParams = new() + { + OperationId = schemaCompareOperation.OperationId, + TargetProjectPath = targetProjectPath, + TargetFolderStructure = SqlServer.Dac.DacExtractTarget.Flat, + }; + + SchemaComparePublishProjectChangesOperation publishChangesOperation = new(publishChangesParams, schemaCompareOperation.ComparisonResult); + publishChangesOperation.Execute(TaskExecutionMode.Execute); + Assert.True(publishChangesOperation.PublishResult.Success); + Assert.AreEqual(publishChangesOperation.PublishResult.ErrorMessage, ""); + Assert.AreEqual(publishChangesOperation.PublishResult.ChangedFiles.Length, 0); + Assert.AreEqual(publishChangesOperation.PublishResult.AddedFiles.Length, 2); + Assert.AreEqual(publishChangesOperation.PublishResult.DeletedFiles.Length, 0); + + targetInfo.TargetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + // Verify that there are no differences after the publish by running the comparison again + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + (schemaCompareOperation.ComparisonResult.Differences as List).RemoveAll(d => !d.Included); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.True(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.That(schemaCompareOperation.ComparisonResult.Differences, Is.Empty); + + // cleanup + SchemaCompareTestUtils.VerifyAndCleanup(sourceDacpacFilePath); + SchemaCompareTestUtils.VerifyAndCleanup(targetProjectPath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + + /// + /// Verify the schema compare publish changes request comparing a database to a project + /// + [Test] + public async Task SchemaComparePublishChangesDatabaseToProject() + { + TestConnectionResult result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects(); + + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, null, "SchemaCompareTarget"); + + try + { + + string targetProjectPath = SchemaCompareTestUtils.CreateProject(targetDb, "TargetProject"); + string[] targetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Database, sourceDb.DatabaseName); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(targetProjectPath, "TargetProject.sqlproj"), targetScripts); + + SchemaCompareParams schemaCompareParams = new() + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new(schemaCompareParams, result.ConnectionInfo, result.ConnectionInfo); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + (schemaCompareOperation.ComparisonResult.Differences as List).RemoveAll(d => !d.Included); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + + IEnumerator enumerator = schemaCompareOperation.ComparisonResult.Differences.GetEnumerator(); + enumerator.MoveNext(); + Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table1]")); + enumerator.MoveNext(); + Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table2]")); + + // update target + SchemaComparePublishProjectChangesParams publishChangesParams = new() + { + OperationId = schemaCompareOperation.OperationId, + TargetProjectPath = targetProjectPath, + TargetFolderStructure = SqlServer.Dac.DacExtractTarget.Flat, + }; + + SchemaComparePublishProjectChangesOperation publishChangesOperation = new(publishChangesParams, schemaCompareOperation.ComparisonResult); + publishChangesOperation.Execute(TaskExecutionMode.Execute); + Assert.True(publishChangesOperation.PublishResult.Success); + Assert.AreEqual(publishChangesOperation.PublishResult.ErrorMessage, String.Empty); + Assert.AreEqual(publishChangesOperation.PublishResult.ChangedFiles.Length, 0); + Assert.AreEqual(publishChangesOperation.PublishResult.AddedFiles.Length, 2); + Assert.AreEqual(publishChangesOperation.PublishResult.DeletedFiles.Length, 0); + + targetInfo.TargetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + // Verify that there are no differences after the publish by running the comparison again + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + (schemaCompareOperation.ComparisonResult.Differences as List).RemoveAll(d => !d.Included); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.True(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.That(schemaCompareOperation.ComparisonResult.Differences, Is.Empty); + + // cleanup + SchemaCompareTestUtils.VerifyAndCleanup(targetProjectPath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + + /// + /// Verify the schema compare publish changes request comparing a project to a project + /// + [Test] + public async Task SchemaComparePublishChangesProjectToProject() + { + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, null, "SchemaCompareTarget"); + + try + { + string sourceProjectPath = SchemaCompareTestUtils.CreateProject(sourceDb, "SourceProject"); + string[] sourceScripts = SchemaCompareTestUtils.GetProjectScripts(sourceProjectPath); + string targetProjectPath = SchemaCompareTestUtils.CreateProject(targetDb, "TargetProject"); + string[] targetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(sourceProjectPath, "SourceProject.sqlproj"), sourceScripts); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(targetProjectPath, "TargetProject.sqlproj"), targetScripts); + + SchemaCompareParams schemaCompareParams = new() + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new(schemaCompareParams, null, null); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + (schemaCompareOperation.ComparisonResult.Differences as List).RemoveAll(d => !d.Included); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + + IEnumerator enumerator = schemaCompareOperation.ComparisonResult.Differences.GetEnumerator(); + enumerator.MoveNext(); + Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table1]")); + enumerator.MoveNext(); + Assert.True(enumerator.Current.SourceObject.Name.ToString().Equals("[dbo].[table2]")); + + // update target + SchemaComparePublishProjectChangesParams publishChangesParams = new() + { + OperationId = schemaCompareOperation.OperationId, + TargetProjectPath = targetProjectPath, + TargetFolderStructure = SqlServer.Dac.DacExtractTarget.Flat, + }; + + SchemaComparePublishProjectChangesOperation publishChangesOperation = new(publishChangesParams, schemaCompareOperation.ComparisonResult); + publishChangesOperation.Execute(TaskExecutionMode.Execute); + Assert.True(publishChangesOperation.PublishResult.Success); + Assert.AreEqual(publishChangesOperation.PublishResult.ErrorMessage, ""); + Assert.AreEqual(publishChangesOperation.PublishResult.ChangedFiles.Length, 0); + Assert.AreEqual(publishChangesOperation.PublishResult.AddedFiles.Length, 2); + Assert.AreEqual(publishChangesOperation.PublishResult.DeletedFiles.Length, 0); + + targetInfo.TargetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + // Verify that there are no differences after the publish by running the comparison again + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + (schemaCompareOperation.ComparisonResult.Differences as List).RemoveAll(d => !d.Included); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.True(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.That(schemaCompareOperation.ComparisonResult.Differences, Is.Empty); + + // cleanup + SchemaCompareTestUtils.VerifyAndCleanup(sourceProjectPath); + SchemaCompareTestUtils.VerifyAndCleanup(targetProjectPath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + /// /// Verify the schema compare Scmp File Save for database endpoints /// @@ -458,7 +928,7 @@ WITH VALUES targetInfo.EndpointType = SchemaCompareEndpointType.Database; targetInfo.DatabaseName = targetDb.DatabaseName; - CreateAndValidateScmpFile(sourceInfo, targetInfo, true, true); + CreateAndValidateScmpFile(sourceInfo, targetInfo, SchemaCompareEndpointType.Database, SchemaCompareEndpointType.Database); } finally { @@ -490,7 +960,37 @@ WITH VALUES targetInfo.EndpointType = SchemaCompareEndpointType.Dacpac; targetInfo.PackageFilePath = targetDacpac; - CreateAndValidateScmpFile(sourceInfo, targetInfo, false, false); + CreateAndValidateScmpFile(sourceInfo, targetInfo, SchemaCompareEndpointType.Dacpac, SchemaCompareEndpointType.Dacpac); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + + /// + /// Verify the schema compare Scmp File Save for project endpoints + /// + [Test] + public async Task SchemaCompareSaveScmpFileForProjects() + { + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); + + try + { + string filePath = SchemaCompareTestUtils.CreateScmpPath(); + + string sourceProjectPath = SchemaCompareTestUtils.CreateProject(sourceDb, "SourceProject"); + string[] sourceScripts = SchemaCompareTestUtils.GetProjectScripts(sourceProjectPath); + string targetProjectPath = SchemaCompareTestUtils.CreateProject(targetDb, "TargetProject"); + string[] targetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(sourceProjectPath, "SourceProject.sqlproj"), sourceScripts); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(targetProjectPath, "TargetProject.sqlproj"), targetScripts); + + CreateAndValidateScmpFile(sourceInfo, targetInfo, SchemaCompareEndpointType.Project, SchemaCompareEndpointType.Project); } finally { @@ -521,7 +1021,64 @@ WITH VALUES targetInfo.EndpointType = SchemaCompareEndpointType.Database; targetInfo.DatabaseName = targetDb.DatabaseName; - CreateAndValidateScmpFile(sourceInfo, targetInfo, false, true); + CreateAndValidateScmpFile(sourceInfo, targetInfo, SchemaCompareEndpointType.Dacpac, SchemaCompareEndpointType.Database); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + + /// + /// Verify the schema compare Scmp File Save for project and db endpoints combination + /// + [Test] + public async Task SchemaCompareSaveScmpFileForProjectToDB() + { + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); + + try + { + string filePath = SchemaCompareTestUtils.CreateScmpPath(); + + string sourceProjectPath = SchemaCompareTestUtils.CreateProject(sourceDb, "SourceProject"); + string[] sourceScripts = SchemaCompareTestUtils.GetProjectScripts(sourceProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(sourceProjectPath, "SourceProject.sqlproj"), sourceScripts); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Database, targetDb.DatabaseName); + + CreateAndValidateScmpFile(sourceInfo, targetInfo, SchemaCompareEndpointType.Project, SchemaCompareEndpointType.Database); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + } + + /// + /// Verify the schema compare Scmp File Save for dacpac and project endpoints combination + /// + [Test] + public async Task SchemaCompareSaveScmpFileForDacpacToProject() + { + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); + + try + { + string filePath = SchemaCompareTestUtils.CreateScmpPath(); + + string sourceDacpac = SchemaCompareTestUtils.CreateDacpac(sourceDb); + string targetProjectPath = SchemaCompareTestUtils.CreateProject(targetDb, "TargetProject"); + string[] targetScripts = SchemaCompareTestUtils.GetProjectScripts(targetProjectPath); + + SchemaCompareEndpointInfo sourceInfo = CreateTestEndpoint(SchemaCompareEndpointType.Dacpac, sourceDacpac); + SchemaCompareEndpointInfo targetInfo = CreateTestEndpoint(SchemaCompareEndpointType.Project, Path.Combine(targetProjectPath, "TargetProject.sqlproj"), targetScripts); + + CreateAndValidateScmpFile(sourceInfo, targetInfo, SchemaCompareEndpointType.Dacpac, SchemaCompareEndpointType.Project); } finally { @@ -548,6 +1105,15 @@ WITH VALUES await CreateAndOpenScmp(SchemaCompareEndpointType.Dacpac, SchemaCompareEndpointType.Database); } + /// + /// Verify opening an scmp comparing a project and database + /// + [Test] + public async Task SchemaCompareOpenScmpProjectToDatabaseRequest() + { + await CreateAndOpenScmp(SchemaCompareEndpointType.Project, SchemaCompareEndpointType.Database); + } + /// /// Verify opening an scmp comparing two dacpacs /// @@ -557,6 +1123,24 @@ WITH VALUES await CreateAndOpenScmp(SchemaCompareEndpointType.Dacpac, SchemaCompareEndpointType.Dacpac); } + /// + /// Verify opening an scmp comparing a project and dacpac + /// + [Test] + public async Task SchemaCompareOpenScmpProjectToDacpacRequest() + { + await CreateAndOpenScmp(SchemaCompareEndpointType.Project, SchemaCompareEndpointType.Dacpac); + } + + /// + /// Verify opening an scmp comparing two projects + /// + [Test] + public async Task SchemaCompareOpenScmpProjectToProjectRequest() + { + await CreateAndOpenScmp(SchemaCompareEndpointType.Project, SchemaCompareEndpointType.Project); + } + /// /// Verify the schema compare Service Calls ends to end /// @@ -639,14 +1223,14 @@ WITH VALUES SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(targetDb.ConnectionString); - var publishParams = new SchemaComparePublishChangesParams + var publishParams = new SchemaComparePublishDatabaseChangesParams { OperationId = operationId, TargetDatabaseName = targetDb.DatabaseName, TargetServerName = builder.DataSource, }; - await SchemaCompareService.Instance.HandleSchemaComparePublishChangesRequest(publishParams, publishRequestContext.Object); + await SchemaCompareService.Instance.HandleSchemaComparePublishDatabaseChangesRequest(publishParams, publishRequestContext.Object); ValidateTask(SR.PublishChangesTaskName); // Include/Exclude service call @@ -795,7 +1379,7 @@ WITH VALUES Assert.True(cek.SourceObject != null, "CEK obect is null"); Assert.True(cek.SourceObject.Name.ToString() == "[CEK_Auto1]", string.Format("CEK object name incorrect. Expected {0}, Actual {1}", "CEK_Auto1", cek.SourceObject.Name.ToString())); Assert.True(CreateKey.Contains(cek.SourceObject.GetScript().Trim()), string.Format("Expected script : {0}, Actual Script {1}", cek.SourceObject.GetScript(), CreateKey)); - + // validate CMK script var cmk = schemaCompareOperation.ComparisonResult.Differences.First(x => x.Name == "SqlColumnMasterKey"); Assert.NotNull(cmk); @@ -872,7 +1456,7 @@ WITH VALUES Assert.False(t2ExcludeOperation.Success, "Excluding Table t2 should fail because view v1 depends on it"); Assert.True(t2ExcludeOperation.ComparisonResult.Differences.Where(x => x.SourceObject != null && x.SourceObject.Name.Parts[1] == "t2").First().Included, "Difference Table t2 should still be included because the exclude request failed"); Assert.True(t2ExcludeOperation.BlockingDependencies.Count == 1, "There should be one dependency"); - Assert.True(t2ExcludeOperation.BlockingDependencies[0].SourceValue[1] == "v1", "Dependency should be View v1"); + Assert.True(t2ExcludeOperation.BlockingDependencies[0].SourceValue[1] == "v1", "Dependency should be View v1"); // exclude view v1, then t2 should also get excluded by this DiffEntry v1Diff = SchemaCompareUtils.CreateDiffEntry(schemaCompareOperation.ComparisonResult.Differences.Where(x => x.SourceObject != null && x.SourceObject.Name.Parts[1] == "v1").First(), null); @@ -1086,7 +1670,7 @@ WITH VALUES try { SchemaCompareEndpoint sourceEndpoint = CreateSchemaCompareEndpoint(sourceDb, sourceEndpointType); - SchemaCompareEndpoint targetEndpoint = CreateSchemaCompareEndpoint(targetDb, targetEndpointType); + SchemaCompareEndpoint targetEndpoint = CreateSchemaCompareEndpoint(targetDb, targetEndpointType, targetEndpointType == SchemaCompareEndpointType.Project); // create a comparison and exclude the first difference SchemaComparison compare = new SchemaComparison(sourceEndpoint, targetEndpoint); @@ -1122,11 +1706,30 @@ WITH VALUES Assert.That(schemaCompareOpenScmpOperation.Result.ExcludedSourceElements, Is.Not.Empty); Assert.AreEqual(1, schemaCompareOpenScmpOperation.Result.ExcludedSourceElements.Count()); Assert.That(schemaCompareOpenScmpOperation.Result.ExcludedTargetElements, Is.Empty); - Assert.AreEqual(targetDb.DatabaseName, schemaCompareOpenScmpOperation.Result.OriginalTargetName); + + if (targetEndpointType == SchemaCompareEndpointType.Project) + { + Assert.AreEqual(Path.GetFileName((targetEndpoint as SchemaCompareProjectEndpoint).ProjectFilePath), schemaCompareOpenScmpOperation.Result.OriginalTargetName); + } + else + { + Assert.AreEqual(targetDb.DatabaseName, schemaCompareOpenScmpOperation.Result.OriginalTargetName); + } + ValidateResultEndpointInfo(sourceEndpoint, schemaCompareOpenScmpOperation.Result.SourceEndpointInfo, sourceDb.ConnectionString); ValidateResultEndpointInfo(targetEndpoint, schemaCompareOpenScmpOperation.Result.TargetEndpointInfo, targetDb.ConnectionString); SchemaCompareTestUtils.VerifyAndCleanup(filePath); + + if (sourceEndpointType == SchemaCompareEndpointType.Project) + { + SchemaCompareTestUtils.VerifyAndCleanup(Directory.GetParent((sourceEndpoint as SchemaCompareProjectEndpoint).ProjectFilePath).FullName); + } + + if (targetEndpointType == SchemaCompareEndpointType.Project) + { + SchemaCompareTestUtils.VerifyAndCleanup(Directory.GetParent((targetEndpoint as SchemaCompareProjectEndpoint).ProjectFilePath).FullName); + } } finally { @@ -1135,13 +1738,19 @@ WITH VALUES } } - private SchemaCompareEndpoint CreateSchemaCompareEndpoint(SqlTestDb db, SchemaCompareEndpointType endpointType) + private SchemaCompareEndpoint CreateSchemaCompareEndpoint(SqlTestDb db, SchemaCompareEndpointType endpointType, bool isProjectTarget = false) { if (endpointType == SchemaCompareEndpointType.Dacpac) { string dacpacFilePath = SchemaCompareTestUtils.CreateDacpac(db); return new SchemaCompareDacpacEndpoint(dacpacFilePath); } + else if (endpointType == SchemaCompareEndpointType.Project) + { + string projectPath = SchemaCompareTestUtils.CreateProject(db, isProjectTarget ? "TargetProject" : "SourceProject"); + string[] scripts = SchemaCompareTestUtils.GetProjectScripts(projectPath); + return new SchemaCompareProjectEndpoint(Path.Combine(projectPath, isProjectTarget ? "TargetProject.sqlproj" : "SourceProject.sqlproj"), scripts, "150"); + } else { return new SchemaCompareDatabaseEndpoint(db.ConnectionString); @@ -1155,11 +1764,16 @@ WITH VALUES SchemaCompareDacpacEndpoint dacpacEndpoint = originalEndpoint as SchemaCompareDacpacEndpoint; Assert.AreEqual(dacpacEndpoint.FilePath, resultEndpoint.PackageFilePath); } + else if (resultEndpoint.EndpointType == SchemaCompareEndpointType.Project) + { + SchemaCompareProjectEndpoint projectEndpoint = originalEndpoint as SchemaCompareProjectEndpoint; + Assert.AreEqual(projectEndpoint.ProjectFilePath, resultEndpoint.ProjectFilePath); + } else { SchemaCompareDatabaseEndpoint databaseEndpoint = originalEndpoint as SchemaCompareDatabaseEndpoint; Assert.AreEqual(databaseEndpoint.DatabaseName, resultEndpoint.DatabaseName); - Assert.That(connectionString, Does.Contain(resultEndpoint.ConnectionDetails.ConnectionString), "connectionString has password but resultEndpoint doesn't"); + Assert.That(connectionString, Does.Contain(resultEndpoint.ConnectionDetails.ConnectionString), "connectionString has password but resultEndpoint doesn't"); } } @@ -1193,7 +1807,7 @@ WITH VALUES Assert.AreEqual(dacFxType, diffObjectTypeType); } - private void CreateAndValidateScmpFile(SchemaCompareEndpointInfo sourceInfo, SchemaCompareEndpointInfo targetInfo, bool isSourceDb, bool isTargetDb) + private void CreateAndValidateScmpFile(SchemaCompareEndpointInfo sourceInfo, SchemaCompareEndpointInfo targetInfo, SchemaCompareEndpointType sourceType, SchemaCompareEndpointType targetType) { string filePath = SchemaCompareTestUtils.CreateScmpPath(); var result = SchemaCompareTestUtils.GetLiveAutoCompleteTestObjects(); @@ -1236,29 +1850,41 @@ WITH VALUES // Validate with DacFx SchemaComparison object SchemaComparison sc = new SchemaComparison(filePath); - if (isSourceDb) + if (sourceType == SchemaCompareEndpointType.Database) { Assert.True(sc.Source is SchemaCompareDatabaseEndpoint, "Source should be SchemaCompareDatabaseEndpoint"); Assert.True((sc.Source as SchemaCompareDatabaseEndpoint).DatabaseName == sourceInfo.DatabaseName, $"Source Database {(sc.Source as SchemaCompareDatabaseEndpoint).DatabaseName} name does not match the params passed {sourceInfo.DatabaseName}"); } - else + else if (sourceType == SchemaCompareEndpointType.Dacpac) { Assert.True(sc.Source is SchemaCompareDacpacEndpoint, "Source should be SchemaCompareDacpacEndpoint"); Assert.True((sc.Source as SchemaCompareDacpacEndpoint).FilePath == sourceInfo.PackageFilePath, $"Source dacpac {(sc.Source as SchemaCompareDacpacEndpoint).FilePath} name does not match the params passed {sourceInfo.PackageFilePath}"); SchemaCompareTestUtils.VerifyAndCleanup(sourceInfo.PackageFilePath); } - - if (isTargetDb) + else if (sourceType == SchemaCompareEndpointType.Project) { - Assert.True(sc.Target is SchemaCompareDatabaseEndpoint, "Source should be SchemaCompareDatabaseEndpoint"); - Assert.True((sc.Target as SchemaCompareDatabaseEndpoint).DatabaseName == targetInfo.DatabaseName, $"Source Database {(sc.Target as SchemaCompareDatabaseEndpoint).DatabaseName} name does not match the params passed {targetInfo.DatabaseName}"); + Assert.True(sc.Source is SchemaCompareProjectEndpoint, "Source should be SchemaCompareProjectEndpoint"); + Assert.True((sc.Source as SchemaCompareProjectEndpoint).ProjectFilePath == sourceInfo.ProjectFilePath, $"Source project {(sc.Source as SchemaCompareProjectEndpoint).ProjectFilePath} name does not match the params passed {sourceInfo.ProjectFilePath}"); + SchemaCompareTestUtils.VerifyAndCleanup(Directory.GetParent(sourceInfo.ProjectFilePath).FullName); } - else + + if (targetType == SchemaCompareEndpointType.Database) { - Assert.True(sc.Target is SchemaCompareDacpacEndpoint, "Source should be SchemaCompareDacpacEndpoint"); - Assert.True((sc.Target as SchemaCompareDacpacEndpoint).FilePath == targetInfo.PackageFilePath, $"Source dacpac {(sc.Target as SchemaCompareDacpacEndpoint).FilePath} name does not match the params passed {targetInfo.PackageFilePath}"); + Assert.True(sc.Target is SchemaCompareDatabaseEndpoint, "Target should be SchemaCompareDatabaseEndpoint"); + Assert.True((sc.Target as SchemaCompareDatabaseEndpoint).DatabaseName == targetInfo.DatabaseName, $"Target Database {(sc.Target as SchemaCompareDatabaseEndpoint).DatabaseName} name does not match the params passed {targetInfo.DatabaseName}"); + } + else if (targetType == SchemaCompareEndpointType.Dacpac) + { + Assert.True(sc.Target is SchemaCompareDacpacEndpoint, "Target should be SchemaCompareDacpacEndpoint"); + Assert.True((sc.Target as SchemaCompareDacpacEndpoint).FilePath == targetInfo.PackageFilePath, $"Target dacpac {(sc.Target as SchemaCompareDacpacEndpoint).FilePath} name does not match the params passed {targetInfo.PackageFilePath}"); SchemaCompareTestUtils.VerifyAndCleanup(targetInfo.PackageFilePath); } + else if (targetType == SchemaCompareEndpointType.Project) + { + Assert.True(sc.Target is SchemaCompareProjectEndpoint, "Target should be SchemaCompareProjectEndpoint"); + Assert.True((sc.Target as SchemaCompareProjectEndpoint).ProjectFilePath == targetInfo.ProjectFilePath, $"Target project {(sc.Target as SchemaCompareProjectEndpoint).ProjectFilePath} name does not match the params passed {targetInfo.ProjectFilePath}"); + SchemaCompareTestUtils.VerifyAndCleanup(Directory.GetParent(targetInfo.ProjectFilePath).FullName); + } Assert.True(!sc.ExcludedTargetObjects.Any(), "Target Excluded Objects are expected to be Empty"); Assert.True(sc.ExcludedSourceObjects.Count == 1, $"Exactly {1} Source Excluded Object Should be present but {sc.ExcludedSourceObjects.Count} found"); @@ -1323,5 +1949,32 @@ WITH VALUES Console.WriteLine($"ValidateTask{expectedTaskName} completed at retry = {retry}"); TaskService.Instance.TaskManager.Reset(); } + + private SchemaCompareEndpointInfo CreateTestEndpoint(SchemaCompareEndpointType type, string comparisonObjectPath, string[] targetScripts = null) + { + SchemaCompareEndpointInfo result = new SchemaCompareEndpointInfo + { + EndpointType = type + }; + + switch (type) + { + case SchemaCompareEndpointType.Dacpac: + result.PackageFilePath = comparisonObjectPath; + break; + case SchemaCompareEndpointType.Database: + result.DatabaseName = comparisonObjectPath; + break; + case SchemaCompareEndpointType.Project: + result.ProjectFilePath = comparisonObjectPath; + result.TargetScripts = targetScripts; + result.DataSchemaProvider = "150"; + break; + default: + throw new ArgumentException($"Unexpected endpoint type: {type}"); + } + + return result; + } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs index a4e4d979..75b1b7e0 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareTestUtils.cs @@ -14,27 +14,34 @@ using NUnit.Framework; using System; using System.IO; using static Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility.LiveConnectionHelper; +using System.Collections.Generic; namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare { internal static class SchemaCompareTestUtils { - internal static void VerifyAndCleanup(string filePath) + internal static void VerifyAndCleanup(string path) { - // Verify it was created - Assert.True(File.Exists(filePath), $"File {filePath} was expected to exist but did not"); + // verify it was created... + Assert.True(File.Exists(path) || Directory.Exists(path), $"File or directory {path} was expected to exist but did not"); - // Remove the file - if (File.Exists(filePath)) + FileAttributes attr = File.GetAttributes(path); + + // ...then clean it up + if ((attr & FileAttributes.Directory) == FileAttributes.Directory) { - File.Delete(filePath); + new DirectoryInfo(path).Delete(recursive: true); + } + else + { + File.Delete(path); } } internal static string CreateDacpac(SqlTestDb testdb) { var result = GetLiveAutoCompleteTestObjects(); - string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest"); + string folderPath = Path.Combine(Path.GetTempPath(), "SchemaCompareTest"); Directory.CreateDirectory(folderPath); var extractParams = new ExtractParams @@ -52,6 +59,34 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.SchemaCompare return extractParams.PackageFilePath; } + internal static string CreateProject(SqlTestDb testdb, string projectName) + { + var result = GetLiveAutoCompleteTestObjects(); + string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest", projectName); + Directory.CreateDirectory(folderPath); + File.Create(Path.Combine(folderPath, projectName + ".sqlproj")).Close(); + + var extractParams = new ExtractParams + { + DatabaseName = testdb.DatabaseName, + ExtractTarget = DacExtractTarget.Flat, + PackageFilePath = folderPath, + ApplicationName = "test", + ApplicationVersion = "1.0.0.0" + }; + + DacFxService service = new(); + ExtractOperation operation = new(extractParams, result.ConnectionInfo); + service.PerformOperation(operation, TaskExecutionMode.Execute); + + return folderPath; + } + + internal static string[] GetProjectScripts(string projectPath) + { + return Directory.GetFiles(projectPath, "*.sql", SearchOption.AllDirectories); + } + internal static string CreateScmpPath() { var result = GetLiveAutoCompleteTestObjects();