Adding more features to restore operation (#420)

* Adding more features to restore operations and added tests
This commit is contained in:
Leila Lali
2017-07-24 09:41:32 -07:00
committed by GitHub
parent 354d702d6f
commit e1395cbd7d
34 changed files with 5861 additions and 269 deletions

View File

@@ -3,13 +3,17 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Admin;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
@@ -29,6 +33,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
private ConnectionService _connectService = TestServiceProvider.Instance.ConnectionService;
private Mock<IProtocolEndpoint> serviceHostMock;
private DisasterRecoveryService service;
private string fullBackUpDatabase;
public RestoreDatabaseServiceTests()
{
@@ -37,26 +42,81 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
service.InitializeService(serviceHostMock.Object);
}
private async Task VerifyBackupFileCreated()
{
if(fullBackUpDatabase == null)
{
fullBackUpDatabase = await CreateBackupFile();
}
}
[Fact]
public async void RestorePlanShouldCreatedSuccessfullyForFullBackup()
{
string backupFileName = "FullBackup.bak";
await VerifyBackupFileCreated();
bool canRestore = true;
await VerifyRestore(backupFileName, canRestore);
await VerifyRestore(fullBackUpDatabase, canRestore);
}
[Fact]
public async void RestoreShouldCreatedSuccessfullyGivenTwoBackupFiles()
{
string[] backupFileNames = new string[] { "FullBackup.bak", "DiffBackup.bak" };
bool canRestore = true;
var response = await VerifyRestore(backupFileNames, canRestore, false, "RestoredFromTwoBackupFile");
Assert.True(response.BackupSetsToRestore.Count() == 2);
}
[Fact]
public async void RestoreShouldFailGivenTwoBackupFilesButFilterFullBackup()
{
string[] backupFileNames = new string[] { "FullBackup.bak", "DiffBackup.bak" };
bool canRestore = true;
var response = await VerifyRestore(backupFileNames, canRestore, false, "RestoredFromTwoBackupFile");
Assert.True(response.BackupSetsToRestore.Count() == 2);
var fileInfo = response.BackupSetsToRestore.FirstOrDefault(x => x.GetPropertyValueAsString(BackupSetInfo.BackupTypePropertyName) != RestoreConstants.TypeFull);
if(fileInfo != null)
{
var selectedBackupSets = new string[] { fileInfo.Id };
await VerifyRestore(backupFileNames, false, false, "RestoredFromTwoBackupFile", selectedBackupSets);
}
}
[Fact]
public async void RestoreShouldCompletedSuccessfullyGivenTowBackupFilesButFilterDifferentialBackup()
{
string[] backupFileNames = new string[] { "FullBackup.bak", "DiffBackup.bak" };
bool canRestore = true;
var response = await VerifyRestore(backupFileNames, canRestore, false, "RestoredFromTwoBackupFile");
Assert.True(response.BackupSetsToRestore.Count() == 2);
var fileInfo = response.BackupSetsToRestore.FirstOrDefault(x => x.GetPropertyValueAsString(BackupSetInfo.BackupTypePropertyName) == RestoreConstants.TypeFull);
if (fileInfo != null)
{
var selectedBackupSets = new string[] { fileInfo.Id };
await VerifyRestore(backupFileNames, true, false, "RestoredFromTwoBackupFile2", selectedBackupSets);
}
}
[Fact]
public async void RestoreShouldExecuteSuccessfullyForFullBackup()
{
string backupFileName = "FullBackup.bak";
await VerifyBackupFileCreated();
string backupFileName = fullBackUpDatabase;
bool canRestore = true;
var restorePlan = await VerifyRestore(backupFileName, canRestore, true);
Assert.NotNull(restorePlan.BackupSetsToRestore);
}
[Fact]
public async void RestoreToAnotherDatabaseShouldExecuteSuccessfullyForFullBackup()
{
string backupFileName = "FullBackup.bak";
await VerifyBackupFileCreated();
string backupFileName = fullBackUpDatabase;
bool canRestore = true;
var restorePlan = await VerifyRestore(backupFileName, canRestore, true, "NewRestoredDatabase");
}
@@ -80,15 +140,17 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
[Fact]
public async Task RestorePlanRequestShouldReturnResponseWithDbFiles()
{
await VerifyBackupFileCreated();
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
{
TestConnectionResult connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
string filePath = GetBackupFilePath("FullBackup.bak");
string filePath = GetBackupFilePath(fullBackUpDatabase);
RestoreParams restoreParams = new RestoreParams
{
BackupFilePath = filePath,
BackupFilePaths = filePath,
OwnerUri = queryTempFile.FilePath
};
@@ -97,7 +159,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
verify: ((result) =>
{
Assert.True(result.DbFiles.Any());
Assert.Equal(result.DatabaseName, "BackupTestDb");
}));
}
}
@@ -113,7 +174,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
RestoreParams restoreParams = new RestoreParams
{
BackupFilePath = filePath,
BackupFilePaths = filePath,
OwnerUri = queryTempFile.FilePath
};
@@ -140,7 +201,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
RestoreParams restoreParams = new RestoreParams
{
BackupFilePath = filePath,
BackupFilePaths = filePath,
OwnerUri = queryTempFile.FilePath
};
@@ -164,7 +225,15 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
private async Task<RestorePlanResponse> VerifyRestore(string backupFileName, bool canRestore, bool execute = false, string targetDatabase = null)
{
string filePath = GetBackupFilePath(backupFileName);
return await VerifyRestore(new string[] { backupFileName }, canRestore, execute, targetDatabase);
}
private async Task<RestorePlanResponse> VerifyRestore(string[] backupFileNames, bool canRestore, bool execute = false, string targetDatabase = null, string[] selectedBackupSets = null)
{
var filePaths = backupFileNames.Select(x => GetBackupFilePath(x));
string backUpFilePath = filePaths.Aggregate((current, next) => current + " ," + next);
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
{
TestConnectionResult connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath);
@@ -172,15 +241,17 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
RestoreDatabaseHelper service = new RestoreDatabaseHelper();
var request = new RestoreParams
{
BackupFilePath = filePath,
DatabaseName = targetDatabase,
OwnerUri = queryTempFile.FilePath
BackupFilePaths = backUpFilePath,
TargetDatabaseName = targetDatabase,
OwnerUri = queryTempFile.FilePath,
SelectedBackupSets = selectedBackupSets
};
var restoreDataObject = service.CreateRestoreDatabaseTaskDataObject(request);
var response = service.CreateRestorePlanResponse(restoreDataObject);
Assert.NotNull(response);
Assert.False(string.IsNullOrWhiteSpace(response.RestoreSessionId));
Assert.Equal(response.CanRestore, canRestore);
if (canRestore)
{
@@ -193,11 +264,18 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
if(execute)
{
request.SessionId = response.RestoreSessionId;
restoreDataObject = service.CreateRestoreDatabaseTaskDataObject(request);
Assert.Equal(response.RestoreSessionId, restoreDataObject.SessionId);
await DropDatabase(targetDatabase);
Thread.Sleep(2000);
request.RelocateDbFiles = response.RelocateFilesNeeded;
service.ExecuteRestore(restoreDataObject);
Assert.True(restoreDataObject.Server.Databases.Contains(targetDatabase));
if(selectedBackupSets != null)
{
Assert.Equal(selectedBackupSets.Count(), restoreDataObject.RestorePlan.RestoreOperations.Count());
}
await DropDatabase(targetDatabase);
}
}
@@ -230,8 +308,15 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
private string GetBackupFilePath(string fileName)
{
FileInfo inputFile = GetBackupFile(fileName);
return inputFile.FullName;
if (!Path.IsPathRooted(fileName))
{
FileInfo inputFile = GetBackupFile(fileName);
return inputFile.FullName;
}
else
{
return fileName;
}
}
protected DisasterRecoveryService CreateService()
@@ -247,5 +332,56 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
return CreateProvider()
.RegisterSingleService(new DisasterRecoveryService());
}
public async Task<string> CreateBackupFile()
{
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
{
SqlTestDb testDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, null, "RestoreTest");
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(testDb.DatabaseName, queryTempFile.FilePath);
// 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, testDb.DatabaseName + ".bak");
BackupInfo backupInfo = CreateBackupInfo(testDb.DatabaseName,
BackupType.Full,
new List<string>() { backupPath },
new Dictionary<string, int>() { { 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);
// Clean up the database
testDb.Cleanup();
return backupPath;
}
}
private BackupInfo CreateBackupInfo(string databaseName, BackupType backupType, List<string> backupPathList, Dictionary<string, int> 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;
}
}
}