diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseHelper.cs
index 816161e7..f2b934e3 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseHelper.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseHelper.cs
@@ -171,14 +171,13 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
if (restoreDataObject != null && restoreDataObject.IsValid)
{
response.SessionId = restoreDataObject.SessionId;
- response.DatabaseName = restoreDataObject.TargetDatabase;
- response.PlanDetails.Add(RestoreOptionsHelper.TargetDatabaseName, RestorePlanDetailInfo.Create(
- name: RestoreOptionsHelper.TargetDatabaseName,
- currentValue: restoreDataObject.TargetDatabase,
- isReadOnly: !CanChangeTargetDatabase(restoreDataObject)));
- response.PlanDetails.Add(RestoreOptionsHelper.SourceDatabaseName, RestorePlanDetailInfo.Create(
- name: RestoreOptionsHelper.SourceDatabaseName,
- currentValue: restoreDataObject.RestorePlanner.DatabaseName));
+ response.DatabaseName = restoreDataObject.TargetDatabaseName;
+
+ response.PlanDetails.Add(RestoreOptionsHelper.TargetDatabaseName,
+ RestoreOptionFactory.Instance.CreateAndValidate(RestoreOptionsHelper.TargetDatabaseName, restoreDataObject));
+ response.PlanDetails.Add(RestoreOptionsHelper.SourceDatabaseName,
+ RestoreOptionFactory.Instance.CreateAndValidate(RestoreOptionsHelper.SourceDatabaseName, restoreDataObject));
+
response.PlanDetails.Add(RestoreOptionsHelper.ReadHeaderFromMedia, RestorePlanDetailInfo.Create(
name: RestoreOptionsHelper.ReadHeaderFromMedia,
currentValue: restoreDataObject.RestorePlanner.ReadHeaderFromMedia));
@@ -191,16 +190,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
});
response.CanRestore = CanRestore(restoreDataObject);
- if (!response.CanRestore)
- {
- response.ErrorMessage = SR.RestoreNotSupported;
- }
-
response.PlanDetails.Add(LastBackupTaken,
RestorePlanDetailInfo.Create(name: LastBackupTaken, currentValue: restoreDataObject.GetLastBackupTaken(), isReadOnly: true));
response.BackupSetsToRestore = restoreDataObject.GetSelectedBakupSets();
- var dbNames = restoreDataObject.GetPossibleTargerDbNames();
+ var dbNames = restoreDataObject.SourceDbNames;
response.DatabaseNamesFromBackupSets = dbNames == null ? new string[] { } : dbNames.ToArray();
RestoreOptionsHelper.AddOptions(response, restoreDataObject);
@@ -259,11 +253,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
if (!sessions.TryGetValue(sessionId, out restoreTaskObject))
{
restoreTaskObject = CreateRestoreForNewSession(restoreParams.OwnerUri, restoreParams.TargetDatabaseName);
+ sessions.AddOrUpdate(sessionId, restoreTaskObject, (key, old) => restoreTaskObject);
}
restoreTaskObject.SessionId = sessionId;
restoreTaskObject.RestoreParams = restoreParams;
- restoreTaskObject.TargetDatabase = restoreParams.TargetDatabaseName;
- restoreTaskObject.RestorePlanner.DatabaseName = restoreParams.TargetDatabaseName;
+
return restoreTaskObject;
}
@@ -308,33 +302,24 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
///
private void UpdateRestorePlan(RestoreDatabaseTaskDataObject restoreDataObject)
{
+ bool shouldCreateNewPlan = restoreDataObject.ShouldCreateNewPlan();
+
if (!string.IsNullOrEmpty(restoreDataObject.RestoreParams.BackupFilePaths))
{
restoreDataObject.AddFiles(restoreDataObject.RestoreParams.BackupFilePaths);
}
restoreDataObject.RestorePlanner.ReadHeaderFromMedia = restoreDataObject.RestoreParams.ReadHeaderFromMedia;
- if (string.IsNullOrWhiteSpace(restoreDataObject.RestoreParams.SourceDatabaseName))
- {
- restoreDataObject.RestorePlanner.DatabaseName = restoreDataObject.DefaultDbName;
- }
- else
- {
- restoreDataObject.RestorePlanner.DatabaseName = restoreDataObject.RestoreParams.SourceDatabaseName;
- }
+ RestoreOptionFactory.Instance.SetAndValidate(RestoreOptionsHelper.SourceDatabaseName, restoreDataObject);
+ RestoreOptionFactory.Instance.SetAndValidate(RestoreOptionsHelper.TargetDatabaseName, restoreDataObject);
- if (CanChangeTargetDatabase(restoreDataObject))
+ if (shouldCreateNewPlan)
{
- restoreDataObject.TargetDatabase = restoreDataObject.RestoreParams.TargetDatabaseName;
+ restoreDataObject.CreateNewRestorePlan();
}
- else
- {
- restoreDataObject.TargetDatabase = restoreDataObject.Server.ConnectionContext.DatabaseName;
- }
-
-
restoreDataObject.UpdateRestorePlan();
+
}
private bool CanChangeTargetDatabase(RestoreDatabaseTaskDataObject restoreDataObject)
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseTaskDataObject.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseTaskDataObject.cs
index 44a2e8de..046db852 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseTaskDataObject.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseTaskDataObject.cs
@@ -12,6 +12,7 @@ using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
+using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
{
@@ -43,6 +44,19 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
RestoreParams RestoreParams { get; set; }
bool BackupTailLog { get; set; }
+
+ string DefaultSourceDbName { get; }
+
+ string SourceDatabaseName { get; set; }
+
+ List SourceDbNames { get; }
+
+ bool CanChangeTargetDatabase { get; }
+
+ string DefaultTargetDbName { get; }
+ string TargetDatabaseName { get; set; }
+
+
}
///
/// Includes the plan with all the data required to do a restore operation on server
@@ -56,6 +70,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
private BackupSetsFilterInfo backupSetsFilterInfo = new BackupSetsFilterInfo();
private bool? isTailLogBackupPossible = false;
private bool? isTailLogBackupWithNoRecoveryPossible = false;
+ private string backupMediaList = string.Empty;
public RestoreDatabaseTaskDataObject(Server server, String databaseName)
{
@@ -95,11 +110,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
///
public SqlTask SqlTask { get; set; }
- public string TargetDatabase
+ public string TargetDatabaseName
{
get
{
- return string.IsNullOrEmpty(targetDbName) ? DefaultDbName : targetDbName;
+ return string.IsNullOrEmpty(targetDbName) ? DefaultSourceDbName : targetDbName;
}
set
{
@@ -121,9 +136,19 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
/// Database names includes in the restore plan
///
///
- public List GetPossibleTargerDbNames()
+ public List SourceDbNames
{
- return Util.GetSourceDbNames(this.restorePlanner.BackupMediaList, this.CredentialName);
+ get
+ {
+ if (RestorePlanner.ReadHeaderFromMedia)
+ {
+ return Util.GetSourceDbNames(this.restorePlanner.BackupMediaList, this.CredentialName);
+ }
+ else
+ {
+ return Util.GetSourceDbNames();
+ }
+ }
}
///
@@ -135,6 +160,23 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
return Util.GetSourceDbNames();
}
+ public bool CanChangeTargetDatabase
+ {
+ get
+ {
+ return DatabaseUtils.IsSystemDatabaseConnection(Server.ConnectionContext.DatabaseName);
+ }
+ }
+
+ public string DefaultTargetDbName
+ {
+ get
+ {
+ return Server.ConnectionContext.DatabaseName;
+ }
+ }
+
+
///
/// Current sqlserver instance
///
@@ -154,6 +196,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
///
public void AddFiles(string filePaths)
{
+ backupMediaList = filePaths;
PlanUpdateRequired = true;
if (!string.IsNullOrWhiteSpace(filePaths))
{
@@ -634,16 +677,40 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
///
/// The database from the backup file used to restore to by default
///
- public string DefaultDbName
+ public string DefaultSourceDbName
{
get
{
- var dbNames = GetPossibleTargerDbNames();
+ var dbNames = SourceDbNames;
string dbName = dbNames.FirstOrDefault();
return dbName;
}
}
+ ///
+ /// Current value of source db name in the planner
+ ///
+ public string SourceDatabaseName
+ {
+ get
+ {
+ return this.RestorePlanner == null ? string.Empty : this.RestorePlanner.DatabaseName;
+ }
+ set
+ {
+ if(this.RestorePlanner != null)
+ {
+ string currentDatabaseName = this.RestorePlanner.DatabaseName;
+ this.RestorePlanner.DatabaseName = value;
+
+ if (string.Compare(currentDatabaseName, value, StringComparison.InvariantCultureIgnoreCase) != 0)
+ {
+ ResetOptions();
+ }
+ }
+ }
+ }
+
///
/// Gets or sets a value indicating whether [close existing connections].
///
@@ -682,10 +749,10 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
private string GetTargetDbFilePhysicalName(string sourceDbFilePhysicalLocation)
{
string fileName = Path.GetFileName(sourceDbFilePhysicalLocation);
- if (!string.IsNullOrEmpty(this.DefaultDbName) && !string.IsNullOrEmpty(this.targetDbName))
+ if (!string.IsNullOrEmpty(this.DefaultSourceDbName) && !string.IsNullOrEmpty(this.targetDbName))
{
string sourceFilename = fileName;
- fileName = sourceFilename.Replace(this.DefaultDbName, this.targetDbName);
+ fileName = sourceFilename.Replace(this.DefaultSourceDbName, this.targetDbName);
}
return fileName;
}
@@ -798,13 +865,8 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
bool isTailLogBackupWithNoRecoveryPossibleValue = isTailLogBackupPossibleValue;
}
- ///
- /// Updates restore plan
- ///
- public void UpdateRestorePlan()
+ public void CreateNewRestorePlan()
{
-
- ResetOptions();
this.ActiveException = null; //Clear any existing exceptions as the plan is getting recreated.
//Clear any existing exceptions as new plan is getting recreated.
this.CreateOrUpdateRestorePlanException = null;
@@ -820,17 +882,14 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
{
this.RestorePlan = this.CreateRestorePlan(this.RestorePlanner, this.RestoreOptions);
this.Util.AddCredentialNameForUrlBackupSet(this.restorePlan, this.CredentialName);
- RestoreOptionsHelper.UpdateOptionsInPlan(this);
+
if (this.ActiveException == null)
{
this.dbFiles = this.GetDbFiles();
- UpdateDBFilesPhysicalRelocate();
- if (RelocateAllFiles)
- {
- UpdateDbFiles();
- }
- this.SetRestorePlanProperties(this.restorePlan);
+ UpdateDBFilesPhysicalRelocate();
+
+
}
}
if (this.restorePlan == null)
@@ -838,6 +897,26 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
this.RestorePlan = new RestorePlan(this.Server);
this.Util.AddCredentialNameForUrlBackupSet(this.RestorePlan, this.CredentialName);
}
+ }
+
+ public bool ShouldCreateNewPlan()
+ {
+ return string.Compare(RestorePlanner.DatabaseName, this.RestoreParams.GetOptionValue(RestoreOptionsHelper.SourceDatabaseName), StringComparison.InvariantCultureIgnoreCase) != 0 ||
+ RestorePlanner.ReadHeaderFromMedia != this.RestoreParams.ReadHeaderFromMedia ||
+ string.Compare(this.backupMediaList, RestoreParams.BackupFilePaths, StringComparison.InvariantCultureIgnoreCase) != 0;
+ }
+
+ ///
+ /// Updates restore plan
+ ///
+ public void UpdateRestorePlan()
+ {
+ RestoreOptionsHelper.UpdateOptionsInPlan(this);
+ if (RelocateAllFiles)
+ {
+ UpdateDbFiles();
+ }
+ this.SetRestorePlanProperties(this.restorePlan);
UpdateSelectedBackupSets();
}
@@ -863,9 +942,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
}
rp.SetRestoreOptions(this.RestoreOptions);
rp.CloseExistingConnections = this.CloseExistingConnections;
- if (this.TargetDatabase != null && !this.TargetDatabase.Equals(string.Empty))
+ if (this.TargetDatabaseName != null && !this.TargetDatabaseName.Equals(string.Empty))
{
- rp.DatabaseName = TargetDatabase;
+ rp.DatabaseName = TargetDatabaseName;
}
rp.RestoreOperations[0].RelocateFiles.Clear();
foreach (DbFile dbFile in this.DbFiles)
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreOptionFactory.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreOptionFactory.cs
index fbf31a6a..fc4117bc 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreOptionFactory.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreOptionFactory.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
@@ -32,6 +33,13 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
}
}
+ public RestorePlanDetailInfo CreateAndValidate(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject)
+ {
+ RestorePlanDetailInfo restorePlanDetailInfo = CreateOptionInfo(optionKey, restoreDataObject);
+ UpdateOption(optionKey, restoreDataObject, restorePlanDetailInfo);
+ return restorePlanDetailInfo;
+ }
+
///
/// Create option info using the current values
///
@@ -74,13 +82,24 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
}
///
- /// Set the option value if restore tak object using the values in the restore request
+ /// Set the option value in restore task object using the values in the restore request
+ ///
+ ///
+ ///
+ public void SetAndValidate(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject)
+ {
+ this.SetValue(optionKey, restoreDataObject);
+ this.ValidateOption(optionKey, restoreDataObject);
+ }
+
+ ///
+ /// Set the option value in restore task object using the values in the restore request
///
///
///
public void SetValue(string optionKey, IRestoreDatabaseTaskDataObject restoreDataObject)
{
- if(restoreDataObject != null)
+ if (restoreDataObject != null)
{
if (optionBuilders.ContainsKey(optionKey))
{
@@ -107,7 +126,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
var defaultValue = builder.DefaultValueFunction(restoreDataObject);
builder.SetValueFunction(restoreDataObject, defaultValue);
}
- catch(Exception)
+ catch (Exception)
{
Logger.Write(LogLevel.Warning, $"Failed to set restore option {optionKey} to default value");
}
@@ -143,10 +162,15 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
errorMessage = $"{optionKey} is ready only and cannot be modified";
}
}
+ if (!string.IsNullOrEmpty(result.ErrorMessage))
+ {
+ errorMessage = result.ErrorMessage;
+ builder.SetValueFunction(restoreDataObject, defaultValue);
+ }
}
else
{
- errorMessage = "cannot find restore option builder for {optionKey}";
+ errorMessage = $"cannot find restore option builder for {optionKey}";
Logger.Write(LogLevel.Warning, errorMessage);
}
@@ -469,6 +493,64 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
return true;
}
});
+ Register(RestoreOptionsHelper.SourceDatabaseName,
+ new OptionBuilder
+ {
+ DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
+ {
+ return restoreDataObject.DefaultSourceDbName;
+ },
+ CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
+ {
+ return restoreDataObject.SourceDatabaseName;
+ },
+ ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
+ {
+ string errorMessage = string.Empty;
+ var sourceDbNames = restoreDataObject.SourceDbNames;
+ if (currentValue == null || (sourceDbNames != null &&
+ !sourceDbNames.Any(x => string.Compare(x, currentValue.ToString(), StringComparison.InvariantCultureIgnoreCase) == 0)))
+ {
+ errorMessage = "Source database name is not valid";
+ }
+ return new OptionValidationResult()
+ {
+ ErrorMessage = errorMessage
+ };
+ },
+ SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
+ {
+
+ restoreDataObject.SourceDatabaseName = GetValueAs(value);
+ return true;
+ }
+ });
+ Register(RestoreOptionsHelper.TargetDatabaseName,
+ new OptionBuilder
+ {
+ DefaultValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
+ {
+ return restoreDataObject.CanChangeTargetDatabase ? restoreDataObject.DefaultSourceDbName : restoreDataObject.DefaultTargetDbName;
+ },
+ CurrentValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject) =>
+ {
+ return restoreDataObject.TargetDatabaseName;
+ },
+ ValidateFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object currentValue, object defaultValue) =>
+ {
+
+ return new OptionValidationResult()
+ {
+ IsReadOnly = !restoreDataObject.CanChangeTargetDatabase
+ };
+ },
+ SetValueFunction = (IRestoreDatabaseTaskDataObject restoreDataObject, object value) =>
+ {
+
+ restoreDataObject.TargetDatabaseName = GetValueAs(value);
+ return true;
+ }
+ });
}
internal T GetValueAs(object value)
diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOptionsHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOptionsHelper.cs
index a5bba18d..e684ac6d 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOptionsHelper.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOptionsHelper.cs
@@ -15,7 +15,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
{
public class RestoreOptionsHelper
{
- //The list of name that service sends to client as options
+ //The list of names service uses to sends restore options to client
private static string[] optionNames = new string[] { KeepReplication, ReplaceDatabase , SetRestrictedUser, RecoveryState ,
BackupTailLog , TailLogBackupFile, TailLogWithNoRecovery, CloseExistingConnections, RelocateDbFiles, DataFileFolder, LogFileFolder,
StandbyFile,
@@ -241,6 +241,8 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
Dictionary options = new Dictionary();
RestoreOptionFactory restoreOptionFactory = RestoreOptionFactory.Instance;
+
+ //Create the options using the current values
foreach (var optionKey in optionNames)
{
var optionInfo = restoreOptionFactory.CreateOptionInfo(optionKey, restoreDataObject);
@@ -248,6 +250,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
}
// After all options are set verify them all again to set the read only
+ // Because some options can change the readonly mode of other options.( e.g Recovery state can affect StandBy to be readyonly)
foreach (var optionKey in optionNames)
{
restoreOptionFactory.UpdateOption(optionKey, restoreDataObject, options[optionKey]);
@@ -292,7 +295,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery
string error = restoreOptionFactory.ValidateOption(optionKey, restoreDataObject);
if (!string.IsNullOrEmpty(error))
{
- //TODO: we could send back the error message so client knows the option is set incorrectly
+ //TODO: we could send back the error message so client knows the option is set incorrectly
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/RestoreDatabaseTaskDataObjectStub.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/RestoreDatabaseTaskDataObjectStub.cs
index 6a865701..ddc22c94 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/RestoreDatabaseTaskDataObjectStub.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/RestoreDatabaseTaskDataObjectStub.cs
@@ -41,5 +41,16 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
public string DefaultStandbyFile { get; set; }
public string DefaultTailLogbackupFile { get; set; }
+
+ public string DefaultSourceDbName { get; set; }
+ public string SourceDatabaseName { get; set; }
+
+ public List SourceDbNames { get; set; }
+
+ public bool CanChangeTargetDatabase { get; set; }
+
+ public string DefaultTargetDbName { get; set; }
+
+ public string TargetDatabaseName { get; set; }
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/RestoreOptionsHelperTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/RestoreOptionsHelperTests.cs
index 59d9ef37..277fa209 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/RestoreOptionsHelperTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/RestoreOptionsHelperTests.cs
@@ -3,14 +3,12 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-using System;
using System.Collections.Generic;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation;
using Microsoft.SqlTools.ServiceLayer.Utility;
-using Moq;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
@@ -33,14 +31,73 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
{
GeneralRequestDetails optionValues = CreateOptionsTestData();
optionValues.Options["DbFiles"] = new List();
+ optionValues.Options[RestoreOptionsHelper.RelocateDbFiles] = true;
IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
Dictionary result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
Assert.NotNull(result);
- VerifyOptions(result, optionValues);
Assert.True(result[RestoreOptionsHelper.RelocateDbFiles].IsReadOnly);
}
+ [Fact]
+ public void DataFileFolderShouldBeReadOnlyGivenRelocateAllFilesSetToFalse()
+ {
+ GeneralRequestDetails optionValues = CreateOptionsTestData();
+ optionValues.Options["DbFiles"] = new List() { new DbFile("", '1', "") };
+ optionValues.Options[RestoreOptionsHelper.RelocateDbFiles] = false;
+ IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
+
+ Dictionary result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
+ Assert.NotNull(result);
+ Assert.True(result[RestoreOptionsHelper.DataFileFolder].IsReadOnly);
+ Assert.True(result[RestoreOptionsHelper.LogFileFolder].IsReadOnly);
+ }
+
+ [Fact]
+ public void DataFileFolderShouldBeCurrentValueGivenRelocateAllFilesSetToTrue()
+ {
+ string dataFile = "data files";
+ string logFile = "log files";
+ GeneralRequestDetails optionValues = CreateOptionsTestData();
+ optionValues.Options["DbFiles"] = new List() { new DbFile("", '1', "") };
+ optionValues.Options[RestoreOptionsHelper.RelocateDbFiles] = true;
+ optionValues.Options[RestoreOptionsHelper.DataFileFolder] = dataFile;
+ optionValues.Options[RestoreOptionsHelper.LogFileFolder] = logFile;
+ IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
+
+ Dictionary result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
+ Assert.NotNull(result);
+ Assert.False(result[RestoreOptionsHelper.DataFileFolder].IsReadOnly);
+ Assert.False(result[RestoreOptionsHelper.LogFileFolder].IsReadOnly);
+ Assert.Equal(result[RestoreOptionsHelper.DataFileFolder].CurrentValue, dataFile);
+ Assert.Equal(result[RestoreOptionsHelper.LogFileFolder].CurrentValue, logFile);
+ }
+
+
+ [Fact]
+ public void KeepReplicationShouldBeReadOnlyGivenRecoveryStateWithNoRecovery()
+ {
+ GeneralRequestDetails optionValues = CreateOptionsTestData();
+ optionValues.Options[RestoreOptionsHelper.RecoveryState] = DatabaseRecoveryState.WithNoRecovery;
+ IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
+
+ Dictionary result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
+ Assert.NotNull(result);
+ Assert.True(result[RestoreOptionsHelper.KeepReplication].IsReadOnly);
+ }
+
+ [Fact]
+ public void StandbyFileShouldBeReadOnlyGivenRecoveryStateNotWithStandBy()
+ {
+ GeneralRequestDetails optionValues = CreateOptionsTestData();
+ optionValues.Options[RestoreOptionsHelper.RecoveryState] = DatabaseRecoveryState.WithNoRecovery;
+ IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(optionValues);
+
+ Dictionary result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
+ Assert.NotNull(result);
+ Assert.True(result[RestoreOptionsHelper.StandbyFile].IsReadOnly);
+ }
+
[Fact]
public void BackupTailLogShouldBeReadOnlyTailLogBackupNotPossible()
{
@@ -50,7 +107,6 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
Dictionary result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
Assert.NotNull(result);
- VerifyOptions(result, optionValues);
Assert.True(result[RestoreOptionsHelper.BackupTailLog].IsReadOnly);
Assert.True(result[RestoreOptionsHelper.TailLogBackupFile].IsReadOnly);
}
@@ -64,7 +120,6 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
Dictionary result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
Assert.NotNull(result);
- VerifyOptions(result, optionValues);
Assert.True(result[RestoreOptionsHelper.TailLogWithNoRecovery].IsReadOnly);
}
@@ -77,7 +132,6 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
Dictionary result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
Assert.NotNull(result);
- VerifyOptions(result, optionValues);
Assert.False(result[RestoreOptionsHelper.StandbyFile].IsReadOnly);
}
@@ -90,7 +144,6 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
Dictionary result = RestoreOptionsHelper.CreateRestorePlanOptions(restoreDatabaseTaskDataObject);
Assert.NotNull(result);
- VerifyOptions(result, optionValues);
Assert.True(result[RestoreOptionsHelper.KeepReplication].IsReadOnly);
}
@@ -130,6 +183,82 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
}
+ [Fact]
+ public void SourceDatabaseNameShouldSetToDefaultIfNotValid()
+ {
+ RestoreParams restoreParams = CreateOptionsTestData();
+ string defaultDbName = "default";
+ string currentDbName = "db3";
+ restoreParams.Options["SourceDbNames"] = new List { "db1", "db2" };
+ restoreParams.Options["DefaultSourceDbName"] = defaultDbName;
+ restoreParams.Options[RestoreOptionsHelper.SourceDatabaseName] = currentDbName;
+
+ IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(restoreParams);
+
+ RestoreOptionFactory.Instance.SetAndValidate(RestoreOptionsHelper.SourceDatabaseName, restoreDatabaseTaskDataObject);
+
+ string actual = restoreDatabaseTaskDataObject.SourceDatabaseName;
+ string expected = defaultDbName;
+ Assert.Equal(actual, expected);
+ }
+
+ [Fact]
+ public void SourceDatabaseNameShouldStayTheSameIfValid()
+ {
+ RestoreParams restoreParams = CreateOptionsTestData();
+ string defaultDbName = "default";
+ string currentDbName = "db3";
+ restoreParams.Options["SourceDbNames"] = new List { "db1", "db2", "db3" };
+ restoreParams.Options["DefaultSourceDbName"] = defaultDbName;
+ restoreParams.Options[RestoreOptionsHelper.SourceDatabaseName] = currentDbName;
+
+ IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(restoreParams);
+
+ RestoreOptionFactory.Instance.SetAndValidate(RestoreOptionsHelper.SourceDatabaseName, restoreDatabaseTaskDataObject);
+
+ string actual = restoreDatabaseTaskDataObject.SourceDatabaseName;
+ string expected = currentDbName;
+ Assert.Equal(actual, expected);
+ }
+
+ [Fact]
+ public void TargetDatabaseNameShouldSetToDefaultIfNotValid()
+ {
+ RestoreParams restoreParams = CreateOptionsTestData();
+ string defaultDbName = "default";
+ string currentDbName = "db3";
+ restoreParams.Options["DefaultTargetDbName"] = defaultDbName;
+ restoreParams.Options[RestoreOptionsHelper.TargetDatabaseName] = currentDbName;
+ restoreParams.Options["CanChangeTargetDatabase"] = false;
+
+ IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(restoreParams);
+
+ RestoreOptionFactory.Instance.SetAndValidate(RestoreOptionsHelper.TargetDatabaseName, restoreDatabaseTaskDataObject);
+
+ string actual = restoreDatabaseTaskDataObject.TargetDatabaseName;
+ string expected = defaultDbName;
+ Assert.Equal(actual, expected);
+ }
+
+ [Fact]
+ public void TargetDatabaseNameShouldStayTheSameIfValid()
+ {
+ RestoreParams restoreParams = CreateOptionsTestData();
+ string defaultDbName = "default";
+ string currentDbName = "db3";
+ restoreParams.Options["DefaultTargetDbName"] = defaultDbName;
+ restoreParams.Options[RestoreOptionsHelper.TargetDatabaseName] = currentDbName;
+ restoreParams.Options["CanChangeTargetDatabase"] = true;
+
+ IRestoreDatabaseTaskDataObject restoreDatabaseTaskDataObject = CreateRestoreDatabaseTaskDataObject(restoreParams);
+
+ RestoreOptionFactory.Instance.SetAndValidate(RestoreOptionsHelper.TargetDatabaseName, restoreDatabaseTaskDataObject);
+
+ string actual = restoreDatabaseTaskDataObject.TargetDatabaseName;
+ string expected = currentDbName;
+ Assert.Equal(actual, expected);
+ }
+
private RestoreParams CreateOptionsTestData()
{
@@ -143,16 +272,22 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
optionValues.Options.Add("IsTailLogBackupWithNoRecoveryPossible", true);
optionValues.Options.Add("GetDefaultStandbyFile", "default standby file");
optionValues.Options.Add("GetDefaultTailLogbackupFile", "default tail log backup file");
- optionValues.Options.Add("LogFilesFolder", "Log file folder");
- optionValues.Options.Add("RelocateAllFiles", false);
+ optionValues.Options.Add(RestoreOptionsHelper.LogFileFolder, "Log file folder");
+ optionValues.Options.Add(RestoreOptionsHelper.RelocateDbFiles, true);
optionValues.Options.Add("TailLogBackupFile", "tail log backup file");
optionValues.Options.Add("TailLogWithNoRecovery", false);
- optionValues.Options.Add("BackupTailLog", false);
+ optionValues.Options.Add(RestoreOptionsHelper.BackupTailLog, false);
optionValues.Options.Add(RestoreOptionsHelper.KeepReplication, false);
- optionValues.Options.Add("ReplaceDatabase", false);
- optionValues.Options.Add("SetRestrictedUser", false);
- optionValues.Options.Add("StandbyFile", "Stand by file");
+ optionValues.Options.Add(RestoreOptionsHelper.ReplaceDatabase, false);
+ optionValues.Options.Add(RestoreOptionsHelper.SetRestrictedUser, false);
+ optionValues.Options.Add(RestoreOptionsHelper.StandbyFile, "Stand by file");
optionValues.Options.Add(RestoreOptionsHelper.RecoveryState, DatabaseRecoveryState.WithNoRecovery.ToString());
+ optionValues.Options.Add(RestoreOptionsHelper.TargetDatabaseName, "target db name");
+ optionValues.Options.Add(RestoreOptionsHelper.SourceDatabaseName, "source db name");
+ optionValues.Options.Add("CanChangeTargetDatabase", true);
+ optionValues.Options.Add("DefaultSourceDbName", "DefaultSourceDbName");
+ optionValues.Options.Add("DefaultTargetDbName", "DefaultTargetDbName");
+ optionValues.Options.Add("SourceDbNames", new List());
return optionValues;
}
@@ -168,18 +303,24 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
restoreDataObject.IsTailLogBackupWithNoRecoveryPossible = optionValues.GetOptionValue("IsTailLogBackupWithNoRecoveryPossible");
restoreDataObject.DefaultStandbyFile = optionValues.GetOptionValue("GetDefaultStandbyFile");
restoreDataObject.DefaultTailLogbackupFile = optionValues.GetOptionValue("GetDefaultTailLogbackupFile");
- restoreDataObject.LogFilesFolder = optionValues.GetOptionValue("LogFilesFolder");
- restoreDataObject.RelocateAllFiles = optionValues.GetOptionValue("RelocateAllFiles");
+ restoreDataObject.LogFilesFolder = optionValues.GetOptionValue(RestoreOptionsHelper.LogFileFolder);
+ restoreDataObject.RelocateAllFiles = optionValues.GetOptionValue(RestoreOptionsHelper.RelocateDbFiles);
restoreDataObject.TailLogBackupFile = optionValues.GetOptionValue("TailLogBackupFile");
+ restoreDataObject.SourceDatabaseName = optionValues.GetOptionValue(RestoreOptionsHelper.SourceDatabaseName);
+ restoreDataObject.TargetDatabaseName = optionValues.GetOptionValue(RestoreOptionsHelper.TargetDatabaseName);
restoreDataObject.TailLogWithNoRecovery = optionValues.GetOptionValue("TailLogWithNoRecovery");
- restoreDataObject.BackupTailLog = optionValues.GetOptionValue("BackupTailLog");
+ restoreDataObject.CanChangeTargetDatabase = optionValues.GetOptionValue("CanChangeTargetDatabase");
+ restoreDataObject.DefaultSourceDbName = optionValues.GetOptionValue("DefaultSourceDbName");
+ restoreDataObject.SourceDbNames = optionValues.GetOptionValue>("SourceDbNames");
+ restoreDataObject.DefaultTargetDbName = optionValues.GetOptionValue("DefaultTargetDbName");
+ restoreDataObject.BackupTailLog = optionValues.GetOptionValue(RestoreOptionsHelper.BackupTailLog);
restoreDataObject.RestoreParams = optionValues as RestoreParams;
restoreDataObject.RestorePlan = null;
RestoreOptions restoreOptions = new RestoreOptions();
restoreOptions.KeepReplication = optionValues.GetOptionValue(RestoreOptionsHelper.KeepReplication);
- restoreOptions.ReplaceDatabase = optionValues.GetOptionValue("ReplaceDatabase");
- restoreOptions.SetRestrictedUser = optionValues.GetOptionValue("SetRestrictedUser");
- restoreOptions.StandByFile = optionValues.GetOptionValue("StandbyFile");
+ restoreOptions.ReplaceDatabase = optionValues.GetOptionValue(RestoreOptionsHelper.ReplaceDatabase);
+ restoreOptions.SetRestrictedUser = optionValues.GetOptionValue(RestoreOptionsHelper.SetRestrictedUser);
+ restoreOptions.StandByFile = optionValues.GetOptionValue(RestoreOptionsHelper.StandbyFile);
restoreOptions.RecoveryState = optionValues.GetOptionValue(RestoreOptionsHelper.RecoveryState);
restoreDataObject.RestoreOptions = restoreOptions;
@@ -191,29 +332,29 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
{
RestorePlanDetailInfo planDetailInfo = optionInResponse[RestoreOptionsHelper.DataFileFolder];
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.DataFileFolder);
- Assert.Equal(planDetailInfo.IsReadOnly, !optionValues.GetOptionValue("RelocateAllFiles"));
+ Assert.Equal(planDetailInfo.IsReadOnly, !optionValues.GetOptionValue(RestoreOptionsHelper.RelocateDbFiles));
Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue(RestoreOptionsHelper.DataFileFolder));
Assert.Equal(planDetailInfo.DefaultValue, optionValues.GetOptionValue("DefaultDataFileFolder"));
Assert.Equal(planDetailInfo.IsVisiable, true);
planDetailInfo = optionInResponse[RestoreOptionsHelper.LogFileFolder];
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.LogFileFolder);
- Assert.Equal(planDetailInfo.IsReadOnly, !optionValues.GetOptionValue("RelocateAllFiles"));
- Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue("LogFilesFolder"));
+ Assert.Equal(planDetailInfo.IsReadOnly, !optionValues.GetOptionValue(RestoreOptionsHelper.RelocateDbFiles));
+ Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue(RestoreOptionsHelper.LogFileFolder));
Assert.Equal(planDetailInfo.DefaultValue, optionValues.GetOptionValue("DefaultLogFileFolder"));
Assert.Equal(planDetailInfo.IsVisiable, true);
planDetailInfo = optionInResponse[RestoreOptionsHelper.RelocateDbFiles];
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.RelocateDbFiles);
Assert.Equal(planDetailInfo.IsReadOnly, (optionValues.GetOptionValue>("DbFiles").Count == 0));
- Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue("LogFilesFolder"));
+ Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue(RestoreOptionsHelper.RelocateDbFiles));
Assert.Equal(planDetailInfo.DefaultValue, false);
Assert.Equal(planDetailInfo.IsVisiable, true);
planDetailInfo = optionInResponse[RestoreOptionsHelper.ReplaceDatabase];
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.ReplaceDatabase);
Assert.Equal(planDetailInfo.IsReadOnly, false);
- Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue("ReplaceDatabase"));
+ Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue(RestoreOptionsHelper.ReplaceDatabase));
Assert.Equal(planDetailInfo.DefaultValue, false);
Assert.Equal(planDetailInfo.IsVisiable, true);
@@ -227,7 +368,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
planDetailInfo = optionInResponse[RestoreOptionsHelper.SetRestrictedUser];
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.SetRestrictedUser);
Assert.Equal(planDetailInfo.IsReadOnly, false);
- Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue("SetRestrictedUser"));
+ Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue(RestoreOptionsHelper.SetRestrictedUser));
Assert.Equal(planDetailInfo.DefaultValue, false);
Assert.Equal(planDetailInfo.IsVisiable, true);
@@ -241,14 +382,14 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
planDetailInfo = optionInResponse[RestoreOptionsHelper.StandbyFile];
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.StandbyFile);
Assert.Equal(planDetailInfo.IsReadOnly, optionValues.GetOptionValue(RestoreOptionsHelper.RecoveryState) != DatabaseRecoveryState.WithStandBy);
- Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue("StandbyFile"));
+ Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue(RestoreOptionsHelper.StandbyFile));
Assert.Equal(planDetailInfo.DefaultValue, optionValues.GetOptionValue("GetDefaultStandbyFile"));
Assert.Equal(planDetailInfo.IsVisiable, true);
planDetailInfo = optionInResponse[RestoreOptionsHelper.BackupTailLog];
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.BackupTailLog);
Assert.Equal(planDetailInfo.IsReadOnly, !optionValues.GetOptionValue("IsTailLogBackupPossible"));
- Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue("BackupTailLog"));
+ Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue(RestoreOptionsHelper.BackupTailLog));
Assert.Equal(planDetailInfo.DefaultValue, optionValues.GetOptionValue("IsTailLogBackupPossible"));
Assert.Equal(planDetailInfo.IsVisiable, true);
@@ -271,7 +412,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery
planDetailInfo = optionInResponse[RestoreOptionsHelper.CloseExistingConnections];
Assert.Equal(planDetailInfo.Name, RestoreOptionsHelper.CloseExistingConnections);
Assert.Equal(planDetailInfo.IsReadOnly, false);
- Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue("CloseExistingConnections"));
+ Assert.Equal(planDetailInfo.CurrentValue, optionValues.GetOptionValue(RestoreOptionsHelper.CloseExistingConnections));
Assert.Equal(planDetailInfo.DefaultValue, false);
Assert.Equal(planDetailInfo.IsVisiable, true);
}