diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/BackupOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/BackupOperation.cs
index 7afae8c4..8022122e 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/BackupOperation.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/BackupOperation.cs
@@ -13,6 +13,7 @@ using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Admin;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
+using System.Globalization;
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
{
@@ -137,13 +138,14 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
///
///
///
- public BackupConfigInfo GetBackupConfigInfo(string databaseName)
+ public BackupConfigInfo CreateBackupConfigInfo(string databaseName)
{
- BackupConfigInfo databaseInfo = new BackupConfigInfo();
- databaseInfo.RecoveryModel = this.GetRecoveryModel(databaseName);
- databaseInfo.DefaultBackupFolder = this.GetDefaultBackupFolder();
- databaseInfo.LatestBackups = this.GetLatestBackupLocations(databaseName);
- return databaseInfo;
+ BackupConfigInfo configInfo = new BackupConfigInfo();
+ configInfo.RecoveryModel = GetRecoveryModel(databaseName);
+ configInfo.DefaultBackupFolder = GetDefaultBackupFolder();
+ configInfo.LatestBackups = GetLatestBackupLocations(databaseName);
+ configInfo.BackupEncryptors = GetBackupEncryptors();
+ return configInfo;
}
///
@@ -226,17 +228,78 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
}
this.backup.CopyOnly = this.backupInfo.IsCopyOnly;
+ this.backup.FormatMedia = this.backupInfo.FormatMedia;
+ this.backup.Initialize = this.backupInfo.Initialize;
+ this.backup.SkipTapeHeader = this.backupInfo.SkipTapeHeader;
+ this.backup.Checksum = this.backupInfo.Checksum;
+ this.backup.ContinueAfterError = this.backupInfo.ContinueAfterError;
- //TODO: This should be changed to get user inputs
- this.backup.FormatMedia = false;
- this.backup.Initialize = false;
- this.backup.SkipTapeHeader = true;
- this.backup.Checksum = false;
- this.backup.ContinueAfterError = false;
- this.backup.LogTruncation = BackupTruncateLogType.Truncate;
+ if (!string.IsNullOrEmpty(this.backupInfo.MediaName))
+ {
+ this.backup.MediaName = this.backupInfo.MediaName;
+ }
+
+ if (!string.IsNullOrEmpty(this.backupInfo.MediaDescription))
+ {
+ this.backup.MediaDescription = this.backupInfo.MediaDescription;
+ }
+ if (this.backupInfo.TailLogBackup
+ && !this.backupRestoreUtil.IsHADRDatabase(this.backupInfo.DatabaseName)
+ && !this.backupRestoreUtil.IsMirroringEnabled(this.backupInfo.DatabaseName))
+ {
+ this.backup.NoRecovery = true;
+ }
+
+ if (this.backupInfo.LogTruncation)
+ {
+ this.backup.LogTruncation = BackupTruncateLogType.Truncate;
+ }
+ else
+ {
+ this.backup.LogTruncation = BackupTruncateLogType.NoTruncate;
+ }
+
+ if (!string.IsNullOrEmpty(this.backupInfo.BackupSetDescription))
+ {
+ this.backup.BackupSetDescription = this.backupInfo.BackupSetDescription;
+ }
+
+ if (this.backupInfo.RetainDays >= 0)
+ {
+ this.backup.RetainDays = this.backupInfo.RetainDays;
+ }
+ else
+ {
+ this.backup.ExpirationDate = this.backupInfo.ExpirationDate;
+ }
+
+ this.backup.CompressionOption = (BackupCompressionOptions)this.backupInfo.CompressionOption;
+
+ if (!string.IsNullOrEmpty(this.backupInfo.EncryptorName))
+ {
+ this.backup.EncryptionOption = new BackupEncryptionOptions((BackupEncryptionAlgorithm)this.backupInfo.EncryptionAlgorithm,
+ (BackupEncryptorType)this.backupInfo.EncryptorType,
+ this.backupInfo.EncryptorName);
+ }
+
// Execute backup
this.backup.SqlBackup(this.dataContainer.Server);
+
+ // Verify backup if required
+ if (this.backupInfo.VerifyBackupRequired)
+ {
+ Restore restore = new Restore();
+ restore.Devices.AddRange(this.backup.Devices);
+ restore.Database = this.backup.Database;
+
+ string errorMessage = null;
+ restore.SqlVerifyLatest(this.dataContainer.Server, out errorMessage);
+ if (errorMessage != null)
+ {
+ throw new Exception(errorMessage);
+ }
+ }
}
///
@@ -277,11 +340,34 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
}
///
- /// Return true if backup to URL is supported in the current SQL Server version
+ /// Returns the certificates and asymmetric keys from master for encryption
///
- private bool BackupToUrlSupported()
+ public List GetBackupEncryptors()
{
- return BackupRestoreBase.IsBackupUrlDeviceSupported(this.dataContainer.Server.PingSqlServerVersion(this.dataContainer.ServerName));
+ List encryptors = new List();
+ if (this.dataContainer.Server.Databases.Contains("master"))
+ {
+ CertificateCollection certificates = this.dataContainer.Server.Databases["master"].Certificates;
+ DateTime currentUtcDateTime = DateTime.UtcNow;
+ foreach (Certificate item in certificates)
+ {
+ if ((item.Name.StartsWith("##", StringComparison.InvariantCulture) && item.Name.EndsWith("##", StringComparison.InvariantCulture)) ||
+ DateTime.Compare(item.ExpirationDate, currentUtcDateTime) < 0)
+ {
+ continue;
+ }
+ encryptors.Add(new BackupEncryptor((int)BackupEncryptorType.ServerCertificate, item.Name));
+ }
+ AsymmetricKeyCollection keys = this.dataContainer.Server.Databases["master"].AsymmetricKeys;
+ foreach (AsymmetricKey item in keys)
+ {
+ if (item.KeyEncryptionAlgorithm == AsymmetricKeyEncryptionAlgorithm.CryptographicProviderDefined)
+ {
+ encryptors.Add(new BackupEncryptor((int)BackupEncryptorType.ServerAsymmetricKey, item.Name));
+ }
+ }
+ }
+ return encryptors;
}
#endregion
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/CommonUtilities.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/CommonUtilities.cs
index 32377f0f..f7e1d759 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/CommonUtilities.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/CommonUtilities.cs
@@ -54,6 +54,33 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
StandBy
}
+ ///
+ /// Class for backup encryptor
+ ///
+ public class BackupEncryptor
+ {
+ ///
+ /// Ctor
+ ///
+ ///
+ ///
+ public BackupEncryptor(int encryptorType, string encryptorName)
+ {
+ this.EncryptorType = encryptorType;
+ this.EncryptorName = encryptorName;
+ }
+
+ ///
+ /// Encryptor type - certificate or asymetric key
+ ///
+ public int EncryptorType { get; set; }
+
+ ///
+ /// Encryptor name
+ ///
+ public string EncryptorName { get; set; }
+ }
+
///
/// Restore item source
///
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/BackupConfigInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/BackupConfigInfo.cs
index fbee8538..17fc6246 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/BackupConfigInfo.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/BackupConfigInfo.cs
@@ -13,11 +13,34 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
///
public class BackupConfigInfo
{
+ ///
+ /// Gets or sets default database info
+ ///
public DatabaseInfo DatabaseInfo { get; set; }
+
+ ///
+ /// Gets or sets recovery model of a database
+ ///
public string RecoveryModel { get; set; }
+
+ ///
+ /// Gets or sets the latest backup set of a database
+ ///
public List LatestBackups { get; set; }
+
+ ///
+ /// Gets or sets the default backup folder
+ ///
public string DefaultBackupFolder { get; set; }
+ ///
+ /// Gets or sets backup encryptors
+ ///
+ public List BackupEncryptors { get; set; }
+
+ ///
+ /// Ctor
+ ///
public BackupConfigInfo()
{
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/BackupInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/BackupInfo.cs
index cd99bd21..2636ce66 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/BackupInfo.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/BackupInfo.cs
@@ -3,6 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
+using System;
using System.Collections.Generic;
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
@@ -13,7 +14,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
/// Name of the datbase to perfom backup
///
public string DatabaseName { get; set; }
-
+
///
/// Component to backup - Database or Files
///
@@ -48,15 +49,104 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts
/// List of {key: backup path, value: device type}
///
public Dictionary BackupPathDevices { get; set; }
-
+
///
/// List of selected backup paths
///
public List BackupPathList { get; set; }
-
+
///
/// Indicates if the backup should be copy-only
///
public bool IsCopyOnly { get; set; }
+
+ ///
+ /// Gets or sets a Boolean property value that determines whether a media is formatted as the first step of the backup operation.
+ ///
+ public bool FormatMedia { get; set; }
+
+ ///
+ /// Gets or sets a Boolean property value that determines whether the devices associated with a backup operation are initialized as part of the backup operation.
+ ///
+ public bool Initialize { get; set; }
+
+ ///
+ /// Gets or sets Boolean property that determines whether the tape header is read.
+ ///
+ public bool SkipTapeHeader { get; set; }
+
+ ///
+ /// Gets or sets the name used to identify a particular media set.
+ ///
+ public string MediaName { get; set; }
+
+ ///
+ /// Gets or sets a textual description of the medium that contains a backup set.
+ ///
+ public string MediaDescription { get; set; }
+
+ ///
+ /// Gets or sets a Boolean property value that determines whether a checksum value is calculated during backup or restore operations.
+ ///
+ public bool Checksum { get; set; }
+
+ ///
+ /// Gets or sets a Boolean property value that determines whether the backup or restore continues after a checksum error occurs.
+ ///
+ public bool ContinueAfterError { get; set; }
+
+ ///
+ /// Gets or sets a Boolean property value that determines whether to truncate the database log.
+ ///
+ public bool LogTruncation { get; set; }
+
+ ///
+ /// Gets or sets a Boolean property value that determines whether to backup the tail of the log
+ ///
+ public bool TailLogBackup { get; set; }
+
+ ///
+ /// Gets or sets a textual description for a particular backup set.
+ ///
+ public string BackupSetDescription { get; set; }
+
+ ///
+ /// Gets or sets the number of days that must elapse before a backup set can be overwritten.
+ ///
+ public int RetainDays { get; set; }
+
+ ///
+ /// Gets or sets the date and time when the backup set expires and the backup data is no longer considered relevant.
+ ///
+ public DateTime ExpirationDate { get; set; }
+
+ ///
+ /// Gets or sets the backup compression option.
+ /// This should be converted to BackupCompressionOptions when setting it to Backup object.
+ ///
+ public int CompressionOption { get; set; }
+
+ ///
+ /// Gets or sets a Boolean property that determines whether verify is required.
+ ///
+ public bool VerifyBackupRequired { get; set; }
+
+ ///
+ /// Specifies the algorithm type used for backup encryption.
+ /// This should be converted to BackupEncryptionAlgorithm when creating BackupEncryptionOptions object.
+ ///
+ public int EncryptionAlgorithm { get; set; }
+
+ ///
+ /// Specifies the encryptor type used to encrypt an encryption key.
+ /// This should be converted to BackupEncryptorType when creating BackupEncryptionOptions object.
+ ///
+ public int EncryptorType { get; set; }
+
+ ///
+ /// Gets or sets the name of the encryptor.
+ ///
+ public string EncryptorName { get; set; }
+
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/DisasterRecoveryService.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/DisasterRecoveryService.cs
index 8afacc2a..02f2cc8a 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/DisasterRecoveryService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/DisasterRecoveryService.cs
@@ -281,7 +281,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
{
BackupOperation backupOperation = new BackupOperation();
backupOperation.Initialize(dataContainer, sqlConnection);
- return backupOperation.GetBackupConfigInfo(databaseName);
+ return backupOperation.CreateBackupConfigInfo(databaseName);
}
internal BackupOperation SetBackupInput(CDataContainer dataContainer, SqlConnection sqlConnection, BackupInfo input)
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/IBackupOperation.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/IBackupOperation.cs
index b2f72862..8358e68a 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/IBackupOperation.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/IBackupOperation.cs
@@ -26,7 +26,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
///
///
///
- BackupConfigInfo GetBackupConfigInfo(string databaseName);
+ BackupConfigInfo CreateBackupConfigInfo(string databaseName);
///
/// Set backup input properties
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings
index ba5bf52e..2616a842 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings
+++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings
@@ -812,7 +812,6 @@ Backup_TaskName = Backup Database
Task_InProgress = In progress
Task_Completed = Completed
-
###########################################################################
# Restore
ConflictWithNoRecovery = Specifying this option when restoring a backup with the NORECOVERY option is not permitted.
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupServiceTests.cs
new file mode 100644
index 00000000..42013e54
--- /dev/null
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupServiceTests.cs
@@ -0,0 +1,200 @@
+//
+// 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.Collections.Generic;
+using System.Data.SqlClient;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.SqlServer.Management.Smo;
+using Microsoft.SqlTools.Hosting.Protocol;
+using Microsoft.SqlTools.ServiceLayer.Admin;
+using Microsoft.SqlTools.ServiceLayer.Admin.Contracts;
+using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
+using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
+using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
+using Microsoft.SqlTools.ServiceLayer.Test.Common;
+using Moq;
+using Xunit;
+
+namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
+{
+ public class BackupServiceTests
+ {
+ // Query format to create master key and certificate for backup encryption
+ private const string CreateCertificateQueryFormat = @"USE master;
+IF NOT EXISTS(SELECT * FROM sys.symmetric_keys WHERE symmetric_key_id = 101)
+CREATE MASTER KEY ENCRYPTION BY PASSWORD = '{0}';
+IF NOT EXISTS(SELECT * FROM sys.certificates WHERE name = '{1}')
+CREATE CERTIFICATE {1} WITH SUBJECT = 'Backup Encryption Certificate'; ";
+
+ // Query format to clean up master key and certificate
+ private const string CleanupCertificateQueryFormat = @"USE master; DROP CERTIFICATE {0}; DROP MASTER KEY";
+
+ ///
+ /// Get backup configuration info
+ ///
+ /// Test is failing in code coverage runs. Reenable when stable.
+ ///[Fact]
+ public async void GetBackupConfigInfoTest()
+ {
+ string databaseName = "testbackup_" + new Random().Next(10000000, 99999999);
+ SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName);
+ var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(databaseName);
+
+ var requestContext = new Mock>();
+ requestContext.Setup(x => x.SendResult(It.IsAny()))
+ .Returns(Task.FromResult(new object()));
+
+ var dbParams = new DefaultDatabaseInfoParams
+ {
+ OwnerUri = liveConnection.ConnectionInfo.OwnerUri
+ };
+
+ await DisasterRecoveryService.HandleBackupConfigInfoRequest(dbParams, requestContext.Object);
+
+ requestContext.Verify(x => x.SendResult(It.Is
+ (p => p.BackupConfigInfo.RecoveryModel != string.Empty
+ && p.BackupConfigInfo.DefaultBackupFolder != string.Empty
+ && p.BackupConfigInfo.DatabaseInfo != null)));
+
+ testDb.Cleanup();
+ }
+
+ /// Test is failing in code coverage runs. Reenable when stable.
+ ///[Fact]
+ public void CreateBackupTest()
+ {
+ string databaseName = "testbackup_" + new Random().Next(10000000, 99999999);
+ SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName);
+ var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(databaseName);
+
+ // Initialize backup service
+ DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
+ SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
+
+ // Get default backup path
+ BackupConfigInfo backupConfigInfo = DisasterRecoveryService.Instance.GetBackupConfigInfo(helper.DataContainer, sqlConn, sqlConn.Database);
+ string backupPath = Path.Combine(backupConfigInfo.DefaultBackupFolder, databaseName + ".bak");
+
+ BackupInfo backupInfo = CreateBackupInfo(databaseName,
+ BackupType.Full,
+ new List(){ backupPath },
+ new Dictionary(){{ backupPath, (int)DeviceType.File }});
+
+ var backupParams = new BackupParams
+ {
+ OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
+ BackupInfo = backupInfo
+ };
+
+ // Backup the database
+ BackupOperation backupOperation = DisasterRecoveryService.Instance.SetBackupInput(helper.DataContainer, sqlConn, backupParams.BackupInfo);
+ DisasterRecoveryService.Instance.PerformBackup(backupOperation);
+
+ // Remove the backup file
+ if (File.Exists(backupPath))
+ {
+ File.Delete(backupPath);
+ }
+
+ // Clean up the database
+ testDb.Cleanup();
+ }
+
+ ///
+ /// Test creating backup with advanced options set.
+ ///
+ [Fact]
+ public void CreateBackupWithAdvancedOptionsTest()
+ {
+ string databaseName = "testbackup_" + new Random().Next(10000000, 99999999);
+ SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName);
+ string certificateName = "backupcertificate" + new Random().Next(10000000, 99999999);
+ string masterkeyPassword = Guid.NewGuid().ToString();
+ string createCertificateQuery = string.Format(CreateCertificateQueryFormat, masterkeyPassword, certificateName);
+ string cleanupCertificateQuery = string.Format(CleanupCertificateQueryFormat, certificateName);
+
+ // create master key and certificate
+ Console.WriteLine("Create master key and certificate..");
+ testDb.RunQuery(createCertificateQuery);
+
+ var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(databaseName);
+
+ // Initialize backup service
+ DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
+ SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
+
+ // Get default backup path
+ Console.WriteLine("Get default backup path..");
+ BackupConfigInfo backupConfigInfo = DisasterRecoveryService.Instance.GetBackupConfigInfo(helper.DataContainer, sqlConn, sqlConn.Database);
+ string backupPath = Path.Combine(backupConfigInfo.DefaultBackupFolder, databaseName + ".bak");
+
+ BackupInfo backupInfo = CreateBackupInfo(databaseName,
+ BackupType.Full,
+ new List(){ backupPath },
+ new Dictionary(){{ backupPath, (int)DeviceType.File }});
+
+ // Set advanced options
+ backupInfo.ContinueAfterError = true;
+ backupInfo.FormatMedia = true;
+ backupInfo.SkipTapeHeader = true;
+ backupInfo.Initialize = true;
+ backupInfo.MediaName = "backup test media";
+ backupInfo.MediaDescription = "backup test";
+ backupInfo.RetainDays = 90;
+ backupInfo.CompressionOption = (int)BackupCompressionOptions.On;
+
+ // Set encryption
+ backupInfo.EncryptionAlgorithm = (int)BackupEncryptionAlgorithm.Aes128;
+ backupInfo.EncryptorType = (int)BackupEncryptorType.ServerCertificate;
+ backupInfo.EncryptorName = certificateName;
+
+ var backupParams = new BackupParams
+ {
+ OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
+ BackupInfo = backupInfo
+ };
+
+ // Backup the database
+ Console.WriteLine("Perform backup operation..");
+ BackupOperation backupOperation = DisasterRecoveryService.Instance.SetBackupInput(helper.DataContainer, sqlConn, backupParams.BackupInfo);
+ DisasterRecoveryService.Instance.PerformBackup(backupOperation);
+
+ // Verify backup file is created
+ Assert.True(File.Exists(backupPath));
+
+ // Remove the backup file
+ Console.WriteLine("Remove backup file..");
+ if (File.Exists(backupPath))
+ {
+ File.Delete(backupPath);
+ }
+
+ // Delete certificate and master key
+ Console.WriteLine("Remove certificate and master key..");
+ testDb.RunQuery(cleanupCertificateQuery);
+
+ // Clean up the database
+ Console.WriteLine("Clean up database..");
+ testDb.Cleanup();
+ }
+
+ private BackupInfo CreateBackupInfo(string databaseName, BackupType backupType, List backupPathList, Dictionary backupPathDevices)
+ {
+ BackupInfo backupInfo = new BackupInfo();
+ backupInfo.BackupComponent = (int)BackupComponent.Database;
+ backupInfo.BackupDeviceType = (int)BackupDeviceType.Disk;
+ backupInfo.BackupPathDevices = backupPathDevices;
+ backupInfo.BackupPathList = backupPathList;
+ backupInfo.BackupsetName = "default_backup";
+ backupInfo.BackupType = (int)backupType;
+ backupInfo.DatabaseName = databaseName;
+ backupInfo.SelectedFileGroup = null;
+ backupInfo.SelectedFiles = "";
+ return backupInfo;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupTests.cs
deleted file mode 100644
index b3babd9a..00000000
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/BackupTests.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Data.SqlClient;
-using System.IO;
-using System.Threading.Tasks;
-using Microsoft.SqlServer.Management.Smo;
-using Microsoft.SqlTools.Hosting.Protocol;
-using Microsoft.SqlTools.ServiceLayer.Admin;
-using Microsoft.SqlTools.ServiceLayer.Admin.Contracts;
-using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
-using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
-using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
-using Microsoft.SqlTools.ServiceLayer.Test.Common;
-using Moq;
-using Xunit;
-
-namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
-{
- public class BackupTests
- {
- ///
- /// Get backup configuration info
- ///
- /// Test is failing in code coverage runs. Reenable when stable.
- /// [Fact]
- public async void GetBackupConfigInfoTest()
- {
- string databaseName = "testbackup_" + new Random().Next(10000000, 99999999);
- SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName);
- var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(databaseName);
-
- var requestContext = new Mock>();
- requestContext.Setup(x => x.SendResult(It.IsAny()))
- .Returns(Task.FromResult(new object()));
-
- var dbParams = new DefaultDatabaseInfoParams
- {
- OwnerUri = liveConnection.ConnectionInfo.OwnerUri
- };
-
- await DisasterRecoveryService.HandleBackupConfigInfoRequest(dbParams, requestContext.Object);
-
- requestContext.Verify(x => x.SendResult(It.Is
- (p => p.BackupConfigInfo.RecoveryModel != string.Empty
- && p.BackupConfigInfo.DefaultBackupFolder != string.Empty
- && p.BackupConfigInfo.DatabaseInfo != null)));
-
- testDb.Cleanup();
- }
-
- /// Test is failing in code coverage runs. Reenable when stable.
- ///[Fact]
- public void CreateBackupTest()
- {
- string databaseName = "testbackup_" + new Random().Next(10000000, 99999999);
- SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName);
- var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(databaseName);
-
- // Initialize backup service
- DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
- SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
-
- // Get default backup path
- BackupConfigInfo backupConfigInfo = DisasterRecoveryService.Instance.GetBackupConfigInfo(helper.DataContainer, sqlConn, sqlConn.Database);
- string backupPath = backupConfigInfo.DefaultBackupFolder + "\\" + databaseName + ".bak";
-
- var backupInfo = new BackupInfo();
- backupInfo.BackupComponent = (int)BackupComponent.Database;
- backupInfo.BackupDeviceType = (int)BackupDeviceType.Disk;
- backupInfo.BackupPathDevices = new Dictionary() { { backupPath, (int)DeviceType.File } };
- backupInfo.BackupPathList = new List(new string[] { backupPath });
- backupInfo.BackupsetName = "default_backup";
- backupInfo.BackupType = (int)BackupType.Full;
- backupInfo.DatabaseName = databaseName;
- backupInfo.SelectedFileGroup = null;
- backupInfo.SelectedFiles = "";
-
- var backupParams = new BackupParams
- {
- OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
- BackupInfo = backupInfo
- };
-
- // Backup the database
- BackupOperation backupOperation = DisasterRecoveryService.Instance.SetBackupInput(helper.DataContainer, sqlConn, backupParams.BackupInfo);
- DisasterRecoveryService.Instance.PerformBackup(backupOperation);
-
- // Remove the backup file
- if (File.Exists(backupPath))
- {
- File.Delete(backupPath);
- }
-
- // Clean up the database
- testDb.Cleanup();
- }
- }
-}
\ No newline at end of file
diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/BackupOperationStub.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/BackupOperationStub.cs
index 9a83086b..e3feccf5 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/BackupOperationStub.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/BackupOperationStub.cs
@@ -40,7 +40,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
///
///
///
- public BackupConfigInfo GetBackupConfigInfo(string databaseName)
+ public BackupConfigInfo CreateBackupConfigInfo(string databaseName)
{
return null;
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/BackupTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/BackupTests.cs
index ad1cd65a..c62b7111 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/BackupTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/BackupTests.cs
@@ -99,8 +99,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
/// Cancel multiple backup tasks
///
///
- /// Test is failing unreliably in AppVeyor runs so disabling for.
- ///[Fact]
+ [Fact]
public async Task VerifyCancelMultipleBackupTasks()
{
using (SqlTaskManager manager = new SqlTaskManager())
@@ -142,8 +141,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
/// Create two backup tasks and cancel one task
///
///
- /// Test is failing in AppVeyor unreliabily..disabling for now. please reenalbe when test is stable in AppVeyor builds.
- /// [Fact]
+ [Fact]
public async Task VerifyCombinationRunAndCancelBackupTasks()
{
using (SqlTaskManager manager = new SqlTaskManager())