diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareGenerateScriptRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareGenerateScriptRequest.cs new file mode 100644 index 00000000..f45cec9f --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/Contracts/SchemaCompareGenerateScriptRequest.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.Compare; +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.ServiceLayer.TaskServices; +using Microsoft.SqlTools.ServiceLayer.Utility; +using System.Collections.Generic; + +namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts +{ + /// + /// Parameters for a schema compare generate script request. + /// + public class SchemaCompareGenerateScriptParams + { + /// + /// Operation id of the schema compare operation + /// + public string OperationId { get; set; } + + /// + /// Name of target database + /// + public string TargetDatabaseName { get; set; } + + /// + /// Gets or sets the filepath where to save the generated script + /// + public string ScriptFilePath { get; set; } + + /// + /// Execution mode for the operation. Default is execution + /// + public TaskExecutionMode TaskExecutionMode { get; set; } + } + + /// + /// Defines the Schema Compare generate script request type + /// + class SchemaCompareGenerateScriptRequest + { + public static readonly RequestType Type = + RequestType.Create("schemaCompare/generateScript"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareGenerateScriptOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareGenerateScriptOperation.cs new file mode 100644 index 00000000..ad13ba8c --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareGenerateScriptOperation.cs @@ -0,0 +1,82 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +using Microsoft.SqlServer.Dac; +using Microsoft.SqlServer.Dac.Compare; +using Microsoft.SqlTools.ServiceLayer.Connection; +using Microsoft.SqlTools.ServiceLayer.SchemaCompare.Contracts; +using Microsoft.SqlTools.ServiceLayer.TaskServices; +using Microsoft.SqlTools.Utility; +using System; +using System.Diagnostics; +using System.IO; +using System.Threading; + +namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare +{ + /// + /// Class to represent an in-progress schema compare generate script operation + /// + class SchemaCompareGenerateScriptOperation : ITaskOperation + { + private CancellationTokenSource cancellation = new CancellationTokenSource(); + private bool disposed = false; + + /// + /// Gets the unique id associated with this instance. + /// + public string OperationId { get; private set; } + + public SchemaCompareGenerateScriptParams 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 SchemaCompareGenerateScriptOperation(SchemaCompareGenerateScriptParams parameters, SchemaComparisonResult comparisonResult) + { + Validate.IsNotNull("parameters", parameters); + Validate.IsNotNull("scriptFilePath", parameters.ScriptFilePath); + this.Parameters = parameters; + Validate.IsNotNull("comparisonResult", comparisonResult); + this.ComparisonResult = comparisonResult; + } + + public void Execute(TaskExecutionMode mode) + { + if (this.CancellationToken.IsCancellationRequested) + { + throw new OperationCanceledException(this.CancellationToken); + } + + try + { + SchemaCompareScriptGenerationResult result = this.ComparisonResult.GenerateScript(this.Parameters.TargetDatabaseName); + File.WriteAllText(this.Parameters.ScriptFilePath, result.Script); + + if (!string.IsNullOrEmpty(result.MasterScript)) + { + // master script is only used if the target is Azure SQL db and the script contains all operations that must be done against the master database + string masterScriptPath = Path.Combine(Path.GetDirectoryName(this.Parameters.ScriptFilePath), string.Concat("master_", Path.GetFileName(this.Parameters.ScriptFilePath))); + File.WriteAllText(masterScriptPath, result.MasterScript); + } + } + catch (Exception e) + { + ErrorMessage = e.Message; + Logger.Write(TraceEventType.Error, string.Format("Schema compare generate script 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() + { + } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOperation.cs index 15b37da6..61b043c7 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOperation.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareOperation.cs @@ -56,16 +56,9 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare /// public string ErrorMessage { get; set; } - /// - /// Cancel operation - /// + // The schema compare public api doesn't currently take a cancellation token so the operation can't be cancelled public void Cancel() { - if (!this.cancellation.IsCancellationRequested) - { - Logger.Write(TraceEventType.Verbose, string.Format("Cancel invoked for OperationId {0}", this.OperationId)); - this.cancellation.Cancel(); - } } /// @@ -110,7 +103,8 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCompare } catch (Exception e) { - Logger.Write(TraceEventType.Error, string.Format("Schema compare operation {0} failed with exception {1}", this.OperationId, e)); + ErrorMessage = e.Message; + Logger.Write(TraceEventType.Error, string.Format("Schema compare operation {0} failed with exception {1}", this.OperationId, e.Message)); throw; } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareService.cs b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareService.cs index d3cfa5af..55220e66 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SchemaCompare/SchemaCompareService.cs @@ -9,9 +9,10 @@ using Microsoft.SqlTools.ServiceLayer.Hosting; using Microsoft.SqlTools.ServiceLayer.TaskServices; using System; using System.Collections.Concurrent; -using System.Data.SqlClient; using System.Threading.Tasks; using Microsoft.SqlTools.ServiceLayer.SchemaCompare; +using Microsoft.SqlServer.Dac.Compare; +using Microsoft.SqlTools.ServiceLayer.Utility; namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare { @@ -21,7 +22,10 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare class SchemaCompareService { private static ConnectionService connectionService = null; + private SqlTaskManager sqlTaskManagerInstance = null; private static readonly Lazy instance = new Lazy(() => new SchemaCompareService()); + private Lazy> schemaCompareResults = + new Lazy>(() => new ConcurrentDictionary()); /// /// Gets the singleton instance object @@ -38,6 +42,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare public void InitializeService(ServiceHost serviceHost) { serviceHost.SetRequestHandler(SchemaCompareRequest.Type, this.HandleSchemaCompareRequest); + serviceHost.SetRequestHandler(SchemaCompareGenerateScriptRequest.Type, this.HandleSchemaCompareGenerateScriptRequest); } /// @@ -59,11 +64,16 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare Task schemaCompareTask = Task.Run(async () => { + SchemaCompareOperation operation = null; + try { - SchemaCompareOperation operation = new SchemaCompareOperation(parameters, sourceConnInfo, targetConnInfo); + operation = new SchemaCompareOperation(parameters, sourceConnInfo, targetConnInfo); operation.Execute(parameters.TaskExecutionMode); + // add result to dictionary of results + schemaCompareResults.Value[operation.OperationId] = operation.ComparisonResult; + await requestContext.SendResult(new SchemaCompareResult() { OperationId = operation.OperationId, @@ -73,9 +83,14 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare Differences = operation.Differences }); } - catch(Exception e) + catch { - await requestContext.SendError(e); + await requestContext.SendResult(new SchemaCompareResult() + { + OperationId = operation != null ? operation.OperationId : null, + Success = false, + ErrorMessage = operation.ErrorMessage, + }); } }); } @@ -85,6 +100,59 @@ namespace Microsoft.SqlTools.ServiceLayer.SchemaCopmare } } + /// + /// Handles request for schema compare generate deploy script + /// + /// + public async Task HandleSchemaCompareGenerateScriptRequest(SchemaCompareGenerateScriptParams parameters, RequestContext requestContext) + { + SchemaCompareGenerateScriptOperation operation = null; + try + { + SchemaComparisonResult compareResult = schemaCompareResults.Value[parameters.OperationId]; + operation = new SchemaCompareGenerateScriptOperation(parameters, compareResult); + SqlTask sqlTask = null; + TaskMetadata metadata = new TaskMetadata(); + metadata.TaskOperation = operation; + // want to show filepath in task history instead of server and database + metadata.ServerName = parameters.ScriptFilePath; + metadata.DatabaseName = string.Empty; + metadata.Name = "Generate Script"; + + sqlTask = SqlTaskManagerInstance.CreateAndRun(metadata); + + await requestContext.SendResult(new ResultStatus() + { + Success = true, + ErrorMessage = operation.ErrorMessage + }); + } + catch + { + await requestContext.SendResult(new ResultStatus() + { + Success = false, + ErrorMessage = operation.ErrorMessage + }); + } + } + + private SqlTaskManager SqlTaskManagerInstance + { + get + { + if (sqlTaskManagerInstance == null) + { + sqlTaskManagerInstance = SqlTaskManager.Instance; + } + return sqlTaskManagerInstance; + } + set + { + sqlTaskManagerInstance = value; + } + } + internal static ConnectionService ConnectionServiceInstance { get diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs index 8f3d13c6..cae9dda8 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/SchemaCompare/SchemaCompareServiceTests.cs @@ -51,6 +51,7 @@ CREATE TABLE [dbo].[table3] private async Task>> SendAndValidateSchemaCompareRequestDacpacToDacpac() { + var result = GetLiveAutoCompleteTestObjects(); var schemaCompareRequestContext = new Mock>(); schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object())); @@ -58,36 +59,41 @@ CREATE TABLE [dbo].[table3] // 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"); - string sourceDacpacFilePath = CreateDacpac(sourceDb); - string targetDacpacFilePath = CreateDacpac(targetDb); - - SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo(); - SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo(); - - sourceInfo.EndpointType = SchemaCompareEndpointType.Dacpac; - sourceInfo.PackageFilePath = sourceDacpacFilePath; - targetInfo.EndpointType = SchemaCompareEndpointType.Dacpac; - targetInfo.PackageFilePath = targetDacpacFilePath; - - var schemaCompareParams = new SchemaCompareParams + try { - SourceEndpointInfo = sourceInfo, - TargetEndpointInfo = targetInfo - }; + string sourceDacpacFilePath = CreateDacpac(sourceDb); + string targetDacpacFilePath = CreateDacpac(targetDb); - DacFxService service = new DacFxService(); - SchemaCompareOperation schemaCompareOperation = new SchemaCompareOperation(schemaCompareParams, null, null); - schemaCompareOperation.Execute(TaskExecutionMode.Execute); + SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo(); + SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo(); - Assert.True(schemaCompareOperation.ComparisonResult.IsValid); - Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); - Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + sourceInfo.EndpointType = SchemaCompareEndpointType.Dacpac; + sourceInfo.PackageFilePath = sourceDacpacFilePath; + targetInfo.EndpointType = SchemaCompareEndpointType.Dacpac; + targetInfo.PackageFilePath = targetDacpacFilePath; - // cleanup - VerifyAndCleanup(sourceDacpacFilePath); - VerifyAndCleanup(targetDacpacFilePath); - sourceDb.Cleanup(); - targetDb.Cleanup(); + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new SchemaCompareOperation(schemaCompareParams, null, null); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + + // cleanup + VerifyAndCleanup(sourceDacpacFilePath); + VerifyAndCleanup(targetDacpacFilePath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } return schemaCompareRequestContext; } @@ -100,35 +106,38 @@ CREATE TABLE [dbo].[table3] SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); - string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DacFxTest"); + string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest"); Directory.CreateDirectory(folderPath); - SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo(); - SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo(); - - sourceInfo.EndpointType = SchemaCompareEndpointType.Database; - sourceInfo.DatabaseName = sourceDb.DatabaseName; - targetInfo.EndpointType = SchemaCompareEndpointType.Database; - targetInfo.DatabaseName = targetDb.DatabaseName; - - var schemaCompareParams = new SchemaCompareParams + try { - SourceEndpointInfo = sourceInfo, - TargetEndpointInfo = targetInfo - }; + SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo(); + SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo(); - DacFxService service = new DacFxService(); - SchemaCompareOperation schemaCompareOperation = new SchemaCompareOperation(schemaCompareParams, result.ConnectionInfo, result.ConnectionInfo); - schemaCompareOperation.Execute(TaskExecutionMode.Execute); + sourceInfo.EndpointType = SchemaCompareEndpointType.Database; + sourceInfo.DatabaseName = sourceDb.DatabaseName; + targetInfo.EndpointType = SchemaCompareEndpointType.Database; + targetInfo.DatabaseName = targetDb.DatabaseName; - Assert.True(schemaCompareOperation.ComparisonResult.IsValid); - Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); - Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; - // cleanup - sourceDb.Cleanup(); - targetDb.Cleanup(); + SchemaCompareOperation schemaCompareOperation = new SchemaCompareOperation(schemaCompareParams, result.ConnectionInfo, result.ConnectionInfo); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + } + finally + { + // cleanup + sourceDb.Cleanup(); + targetDb.Cleanup(); + } return schemaCompareRequestContext; } @@ -140,35 +149,155 @@ CREATE TABLE [dbo].[table3] SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); - string targetDacpacFilePath = CreateDacpac(targetDb); - SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo(); - SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo(); - - sourceInfo.EndpointType = SchemaCompareEndpointType.Database; - sourceInfo.DatabaseName = sourceDb.DatabaseName; - targetInfo.EndpointType = SchemaCompareEndpointType.Dacpac; - targetInfo.PackageFilePath = targetDacpacFilePath; - - var schemaCompareParams = new SchemaCompareParams + try { - SourceEndpointInfo = sourceInfo, - TargetEndpointInfo = targetInfo - }; + string targetDacpacFilePath = CreateDacpac(targetDb); - DacFxService service = new DacFxService(); - SchemaCompareOperation schemaCompareOperation = new SchemaCompareOperation(schemaCompareParams, result.ConnectionInfo, null); - schemaCompareOperation.Execute(TaskExecutionMode.Execute); + SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo(); + SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo(); - Assert.True(schemaCompareOperation.ComparisonResult.IsValid); - Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); - Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + sourceInfo.EndpointType = SchemaCompareEndpointType.Database; + sourceInfo.DatabaseName = sourceDb.DatabaseName; + targetInfo.EndpointType = SchemaCompareEndpointType.Dacpac; + targetInfo.PackageFilePath = targetDacpacFilePath; - // cleanup - VerifyAndCleanup(targetDacpacFilePath); - sourceDb.Cleanup(); - targetDb.Cleanup(); + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + SchemaCompareOperation schemaCompareOperation = new SchemaCompareOperation(schemaCompareParams, result.ConnectionInfo, null); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + + // cleanup + VerifyAndCleanup(targetDacpacFilePath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + return schemaCompareRequestContext; + } + + private async Task>> SendAndValidateSchemaCompareGenerateScriptRequestDatabaseToDatabase() + { + var result = GetLiveAutoCompleteTestObjects(); + var schemaCompareRequestContext = new Mock>(); + schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object())); + + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); + string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest"); + Directory.CreateDirectory(folderPath); + + try + { + SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo(); + SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo(); + + sourceInfo.EndpointType = SchemaCompareEndpointType.Database; + sourceInfo.DatabaseName = sourceDb.DatabaseName; + targetInfo.EndpointType = SchemaCompareEndpointType.Database; + targetInfo.DatabaseName = targetDb.DatabaseName; + + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new SchemaCompareOperation(schemaCompareParams, result.ConnectionInfo, result.ConnectionInfo); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + + // generate script + var generateScriptParams = new SchemaCompareGenerateScriptParams + { + TargetDatabaseName = targetDb.DatabaseName, + OperationId = schemaCompareOperation.OperationId, + ScriptFilePath = Path.Combine(folderPath, string.Concat(sourceDb.DatabaseName, "_", "Update.publish.sql")) + }; + + SchemaCompareGenerateScriptOperation generateScriptOperation = new SchemaCompareGenerateScriptOperation(generateScriptParams, schemaCompareOperation.ComparisonResult); + generateScriptOperation.Execute(TaskExecutionMode.Execute); + + // cleanup + VerifyAndCleanup(generateScriptParams.ScriptFilePath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } + return schemaCompareRequestContext; + } + + private async Task>> SendAndValidateSchemaCompareGenerateScriptRequestDacpacToDatabase() + { + var result = GetLiveAutoCompleteTestObjects(); + var schemaCompareRequestContext = new Mock>(); + schemaCompareRequestContext.Setup(x => x.SendResult(It.IsAny())).Returns(Task.FromResult(new object())); + + SqlTestDb sourceDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, SourceScript, "SchemaCompareSource"); + SqlTestDb targetDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, TargetScript, "SchemaCompareTarget"); + string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest"); + Directory.CreateDirectory(folderPath); + + try + { + string sourceDacpacFilePath = CreateDacpac(sourceDb); + + SchemaCompareEndpointInfo sourceInfo = new SchemaCompareEndpointInfo(); + SchemaCompareEndpointInfo targetInfo = new SchemaCompareEndpointInfo(); + + sourceInfo.EndpointType = SchemaCompareEndpointType.Dacpac; + sourceInfo.PackageFilePath = sourceDacpacFilePath; + targetInfo.EndpointType = SchemaCompareEndpointType.Database; + targetInfo.DatabaseName = targetDb.DatabaseName; + + var schemaCompareParams = new SchemaCompareParams + { + SourceEndpointInfo = sourceInfo, + TargetEndpointInfo = targetInfo + }; + + SchemaCompareOperation schemaCompareOperation = new SchemaCompareOperation(schemaCompareParams, result.ConnectionInfo, result.ConnectionInfo); + schemaCompareOperation.Execute(TaskExecutionMode.Execute); + + Assert.True(schemaCompareOperation.ComparisonResult.IsValid); + Assert.False(schemaCompareOperation.ComparisonResult.IsEqual); + Assert.NotNull(schemaCompareOperation.ComparisonResult.Differences); + + // generate script + var generateScriptParams = new SchemaCompareGenerateScriptParams + { + TargetDatabaseName = targetDb.DatabaseName, + OperationId = schemaCompareOperation.OperationId, + ScriptFilePath = Path.Combine(folderPath, string.Concat(sourceDb.DatabaseName, "_", "Update.publish.sql")) + }; + + SchemaCompareGenerateScriptOperation generateScriptOperation = new SchemaCompareGenerateScriptOperation(generateScriptParams, schemaCompareOperation.ComparisonResult); + generateScriptOperation.Execute(TaskExecutionMode.Execute); + + // cleanup + VerifyAndCleanup(generateScriptParams.ScriptFilePath); + VerifyAndCleanup(sourceDacpacFilePath); + } + finally + { + sourceDb.Cleanup(); + targetDb.Cleanup(); + } return schemaCompareRequestContext; } @@ -199,6 +328,24 @@ CREATE TABLE [dbo].[table3] Assert.NotNull(await SendAndValidateSchemaCompareRequestDatabaseToDacpac()); } + /// + /// Verify the schema compare generate script request comparing a database to a database + /// + [Fact] + public async void SchemaCompareGenerateScriptDatabaseToDatabase() + { + Assert.NotNull(await SendAndValidateSchemaCompareGenerateScriptRequestDatabaseToDatabase()); + } + + /// + /// Verify the schema compare generate script request comparing a dacpac to a database + /// + [Fact] + public async void SchemaCompareGenerateScriptDacpacToDatabase() + { + Assert.NotNull(await SendAndValidateSchemaCompareGenerateScriptRequestDacpacToDatabase()); + } + private void VerifyAndCleanup(string filePath) { // Verify it was created @@ -214,7 +361,7 @@ CREATE TABLE [dbo].[table3] private string CreateDacpac(SqlTestDb testdb) { var result = GetLiveAutoCompleteTestObjects(); - string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DacFxTest"); + string folderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SchemaCompareTest"); Directory.CreateDirectory(folderPath); var extractParams = new ExtractParams