Retrieve Azure SLO details in Database Handler (#2094)

This commit is contained in:
Cory Rivera
2023-06-12 11:44:17 -07:00
committed by GitHub
parent 323f3827e2
commit 808172bc20
10 changed files with 462 additions and 73 deletions

View File

@@ -21,19 +21,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
[DebuggerDisplay("{Name,nq}")]
public class AzureEdition
{
public static readonly AzureEdition Basic = new AzureEdition("Basic", "SR.BasicAzureEdition");
public static readonly AzureEdition Standard = new AzureEdition("Standard", "SR.StandardAzureEdition");
public static readonly AzureEdition Premium = new AzureEdition("Premium", "SR.PremiumAzureEdition");
public static readonly AzureEdition DataWarehouse = new AzureEdition("DataWarehouse", "SR.DataWarehouseAzureEdition");
public static readonly AzureEdition GeneralPurpose = new AzureEdition("GeneralPurpose", "SR.GeneralPurposeAzureEdition");
public static readonly AzureEdition BusinessCritical = new AzureEdition("BusinessCritical", "SR.BusinessCriticalAzureEdition");
public static readonly AzureEdition Hyperscale = new AzureEdition("Hyperscale", "SR.HyperscaleAzureEdition");
// Free does not offer DatabaseSize >=1GB, hence it's not "supported".
//public static readonly AzureEdition Free = new AzureEdition("Free", SR.FreeAzureEdition);
// Stretch and system do not seem to be applicable, so I'm commenting them out
//public static readonly AzureEdition Stretch = new AzureEdition("Stretch", SR.StretchAzureEdition);
//public static readonly AzureEdition System = new AzureEdition("System", SR.SystemAzureEdition);
public static readonly AzureEdition Basic = new AzureEdition("Basic", SR.BasicAzureEdition);
public static readonly AzureEdition Standard = new AzureEdition("Standard", SR.StandardAzureEdition);
public static readonly AzureEdition Premium = new AzureEdition("Premium", SR.PremiumAzureEdition);
public static readonly AzureEdition DataWarehouse = new AzureEdition("DataWarehouse", SR.DataWarehouseAzureEdition);
public static readonly AzureEdition GeneralPurpose = new AzureEdition("GeneralPurpose", SR.GeneralPurposeAzureEdition);
public static readonly AzureEdition BusinessCritical = new AzureEdition("BusinessCritical", SR.BusinessCriticalAzureEdition);
public static readonly AzureEdition Hyperscale = new AzureEdition("Hyperscale", SR.HyperscaleAzureEdition);
internal string Name { get; private set; }
internal string DisplayName { get; private set; }
@@ -320,6 +314,18 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{ "LRS", "Local" },
{ "ZRS", "Zone" }
};
private static readonly string[] backupRedundancyLevels = bsrAPIToUIValueMapping.Values.ToArray();
/// <summary>
/// All valid backup storage redundancy levels for an Azure SQL database
/// </summary>
public static string[] BackupStorageRedundancyLevels
{
get
{
return backupRedundancyLevels;
}
}
//KeyValuePair contains the BackupStorageRedundancy values for all azure editions.
private static readonly KeyValuePair<int, string[]> keyValuePair = new KeyValuePair<int, string[]>(0, bsrAPIToUIValueMapping.Values.ToArray());
@@ -516,7 +522,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// We do this so that the AzureEdition enum can have values such as NONE or DEFAULT added
/// without requiring clients to explicitly filter out those values themselves each time.
/// <returns></returns>
public static IEnumerable<AzureEdition> GetValidAzureEditionOptions(object unused)
public static IEnumerable<AzureEdition> GetValidAzureEditionOptions()
{
yield return AzureEdition.Basic;
yield return AzureEdition.Standard;
@@ -524,10 +530,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
yield return AzureEdition.DataWarehouse;
yield return AzureEdition.BusinessCritical;
yield return AzureEdition.GeneralPurpose;
//yield return AzureEdition.Free;
yield return AzureEdition.Hyperscale;
//yield return AzureEdition.Stretch;
//yield return AzureEdition.System;
}
}
}

View File

@@ -16,6 +16,8 @@ using Microsoft.SqlTools.ServiceLayer.Management;
using AzureEdition = Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper.AzureEdition;
using System;
using System.Data;
using Microsoft.SqlTools.Utility;
using System.Diagnostics;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
@@ -91,58 +93,56 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
return AzureSqlDbHelper.GetAzureEditionDisplayName(this.currentState.azureEdition);
}
// set
// {
// AzureEdition edition;
// if (AzureSqlDbHelper.TryGetAzureEditionFromDisplayName(value, out edition))
// {
// //Try to get the ServiceLevelObjective from the api,if not the default hardcoded service level objectives will be retrieved.
// string serverLevelObjective = AzureServiceLevelObjectiveProvider.TryGetAzureServiceLevelObjective(value, AzureServiceLocation);
set
{
AzureEdition edition;
if (AzureSqlDbHelper.TryGetAzureEditionFromDisplayName(value, out edition))
{
//Try to get the ServiceLevelObjective from the api,if not the default hardcoded service level objectives will be retrieved.
// string serverLevelObjective = AzureServiceLevelObjectiveProvider.TryGetAzureServiceLevelObjective(value, AzureServiceLocation);
// if (!string.IsNullOrEmpty(serverLevelObjective))
// {
// this.currentState.azureEdition = edition;
// this.currentState.currentServiceLevelObjective = serverLevelObjective;
// // Instead of creating db instance with default Edition, update EditionToCreate while selecting Edition from the UI.
// this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
// string storageAccountType = AzureServiceLevelObjectiveProvider.TryGetAzureStorageType(value, AzureServiceLocation);
// if (!string.IsNullOrEmpty(storageAccountType))
// {
// this.currentState.backupStorageRedundancy = storageAccountType;
// }
// if (!string.IsNullOrEmpty(serverLevelObjective))
// {
// this.currentState.azureEdition = edition;
// this.currentState.currentServiceLevelObjective = serverLevelObjective;
// // Instead of creating db instance with default Edition, update EditionToCreate while selecting Edition from the UI.
// this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
// string storageAccountType = AzureServiceLevelObjectiveProvider.TryGetAzureStorageType(value, AzureServiceLocation);
// if (!string.IsNullOrEmpty(storageAccountType))
// {
// this.currentState.backupStorageRedundancy = storageAccountType;
// }
// // Try to get the azure maxsize from the api,if not the default hardcoded maxsize will be retrieved.
// DbSize dbSize = AzureServiceLevelObjectiveProvider.TryGetAzureMaxSize(value, serverLevelObjective, AzureServiceLocation);
// if (!string.IsNullOrEmpty(dbSize.ToString()))
// {
// this.currentState.maxSize = new DbSize(dbSize.Size, dbSize.SizeUnit);
// }
// }
// else
// {
// if (edition == this.currentState.azureEdition)
// { //No changes, return early since we don't need to do any of the changes below
// return;
// }
// // Try to get the azure maxsize from the api,if not the default hardcoded maxsize will be retrieved.
// DbSize dbSize = AzureServiceLevelObjectiveProvider.TryGetAzureMaxSize(value, serverLevelObjective, AzureServiceLocation);
// if (!string.IsNullOrEmpty(dbSize.ToString()))
// {
// this.currentState.maxSize = new DbSize(dbSize.Size, dbSize.SizeUnit);
// }
// }
// else
// {
if (edition == this.currentState.azureEdition)
{ // No changes, return early since we don't need to do any of the changes below
return;
}
// this.currentState.azureEdition = edition;
// this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
// this.CurrentServiceLevelObjective = AzureSqlDbHelper.GetDefaultServiceObjective(edition);
// this.BackupStorageRedundancy = AzureSqlDbHelper.GetDefaultBackupStorageRedundancy(edition);
// var defaultSize = AzureSqlDbHelper.GetDatabaseDefaultSize(edition);
this.currentState.azureEdition = edition;
this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
this.CurrentServiceLevelObjective = AzureSqlDbHelper.GetDefaultServiceObjective(edition);
this.BackupStorageRedundancy = AzureSqlDbHelper.GetDefaultBackupStorageRedundancy(edition);
var defaultSize = AzureSqlDbHelper.GetDatabaseDefaultSize(edition);
// this.MaxSize = defaultSize == null ? String.Empty : defaultSize.ToString();
// }
// this.NotifyObservers();
// }
// else
// {
// //Can't really do much if we fail to parse the display name so just leave it as is and log a message
// System.Diagnostics.Debug.Assert(false,
// string.Format(CultureInfo.InvariantCulture,
// "Failed to parse edition display name '{0}' back into AzureEdition", value));
// }
// }
this.MaxSize = defaultSize == null ? String.Empty : defaultSize.ToString();
// }
this.NotifyObservers();
}
else
{
// Can't really do much if we fail to parse the display name so just leave it as is and log a message
Logger.Write(TraceEventType.Error, $"Failed to parse edition display name '{value}' back into AzureEdition");
}
}
}
/// <summary>

View File

@@ -12437,6 +12437,70 @@ namespace Microsoft.SqlTools.ServiceLayer
}
}
public static string BasicAzureEdition
{
get
{
return Keys.GetString(Keys.BasicAzureEdition);
}
}
public static string StandardAzureEdition
{
get
{
return Keys.GetString(Keys.StandardAzureEdition);
}
}
public static string PremiumAzureEdition
{
get
{
return Keys.GetString(Keys.PremiumAzureEdition);
}
}
public static string DataWarehouseAzureEdition
{
get
{
return Keys.GetString(Keys.DataWarehouseAzureEdition);
}
}
public static string GeneralPurposeAzureEdition
{
get
{
return Keys.GetString(Keys.GeneralPurposeAzureEdition);
}
}
public static string BusinessCriticalAzureEdition
{
get
{
return Keys.GetString(Keys.BusinessCriticalAzureEdition);
}
}
public static string ErrorInvalidEdition
{
get
{
return Keys.GetString(Keys.ErrorInvalidEdition);
}
}
public static string HyperscaleAzureEdition
{
get
{
return Keys.GetString(Keys.HyperscaleAzureEdition);
}
}
public static string ConnectionServiceListDbErrorNotConnected(string uri)
{
return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri);
@@ -17794,6 +17858,30 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string prototype_file_noApplicableFileGroup = "prototype_file_noApplicableFileGroup";
public const string BasicAzureEdition = "BasicAzureEdition";
public const string StandardAzureEdition = "StandardAzureEdition";
public const string PremiumAzureEdition = "PremiumAzureEdition";
public const string DataWarehouseAzureEdition = "DataWarehouseAzureEdition";
public const string GeneralPurposeAzureEdition = "GeneralPurposeAzureEdition";
public const string BusinessCriticalAzureEdition = "BusinessCriticalAzureEdition";
public const string ErrorInvalidEdition = "ErrorInvalidEdition";
public const string HyperscaleAzureEdition = "HyperscaleAzureEdition";
private Keys()
{ }

View File

@@ -6760,4 +6760,36 @@ The Query Processor estimates that implementing the following index could improv
<value>No Applicable Filegroup</value>
<comment></comment>
</data>
<data name="BasicAzureEdition" xml:space="preserve">
<value>Basic</value>
<comment></comment>
</data>
<data name="StandardAzureEdition" xml:space="preserve">
<value>Standard</value>
<comment></comment>
</data>
<data name="PremiumAzureEdition" xml:space="preserve">
<value>Premium</value>
<comment></comment>
</data>
<data name="DataWarehouseAzureEdition" xml:space="preserve">
<value>DataWarehouse</value>
<comment></comment>
</data>
<data name="GeneralPurposeAzureEdition" xml:space="preserve">
<value>General Purpose</value>
<comment></comment>
</data>
<data name="BusinessCriticalAzureEdition" xml:space="preserve">
<value>Business Critical</value>
<comment></comment>
</data>
<data name="ErrorInvalidEdition" xml:space="preserve">
<value>Edition value is not valid</value>
<comment></comment>
</data>
<data name="HyperscaleAzureEdition" xml:space="preserve">
<value>Hyperscale</value>
<comment></comment>
</data>
</root>

View File

@@ -2801,4 +2801,16 @@ compatibilityLevel_sqlv160 = SQL Server 2022 (160)
general_containmentType_None = None
general_containmentType_Partial = Partial
filegroups_filestreamFiles = FILESTREAM Files
prototype_file_noApplicableFileGroup = No Applicable Filegroup
prototype_file_noApplicableFileGroup = No Applicable Filegroup
############################################################################
# Azure SQL DB
BasicAzureEdition = Basic
StandardAzureEdition = Standard
PremiumAzureEdition = Premium
DataWarehouseAzureEdition = DataWarehouse
GeneralPurposeAzureEdition = General Purpose
BusinessCriticalAzureEdition = Business Critical
ErrorInvalidEdition = Edition value is not valid
HyperscaleAzureEdition = Hyperscale

View File

@@ -8281,6 +8281,46 @@ The Query Processor estimates that implementing the following index could improv
<target state="new">No Applicable Filegroup</target>
<note></note>
</trans-unit>
<trans-unit id="BasicAzureEdition">
<source>Basic</source>
<target state="new">Basic</target>
<note></note>
</trans-unit>
<trans-unit id="StandardAzureEdition">
<source>Standard</source>
<target state="new">Standard</target>
<note></note>
</trans-unit>
<trans-unit id="PremiumAzureEdition">
<source>Premium</source>
<target state="new">Premium</target>
<note></note>
</trans-unit>
<trans-unit id="DataWarehouseAzureEdition">
<source>DataWarehouse</source>
<target state="new">DataWarehouse</target>
<note></note>
</trans-unit>
<trans-unit id="GeneralPurposeAzureEdition">
<source>General Purpose</source>
<target state="new">General Purpose</target>
<note></note>
</trans-unit>
<trans-unit id="BusinessCriticalAzureEdition">
<source>Business Critical</source>
<target state="new">Business Critical</target>
<note></note>
</trans-unit>
<trans-unit id="ErrorInvalidEdition">
<source>Edition value is not valid</source>
<target state="new">Edition value is not valid</target>
<note></note>
</trans-unit>
<trans-unit id="HyperscaleAzureEdition">
<source>Hyperscale</source>
<target state="new">Hyperscale</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -17,6 +17,7 @@ using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Management;
using Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
@@ -37,6 +38,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
private static readonly Dictionary<string, ContainmentType> containmentTypeEnums = new Dictionary<string, ContainmentType>();
private static readonly Dictionary<string, RecoveryModel> recoveryModelEnums = new Dictionary<string, RecoveryModel>();
internal static readonly string[] AzureEditionNames;
internal static readonly string[] AzureBackupLevels;
internal static readonly AzureEditionDetails[] AzureMaxSizes;
internal static readonly AzureEditionDetails[] AzureServiceLevels;
static DatabaseHandler()
{
displayCompatLevels.Add(CompatibilityLevel.Version70, SR.compatibilityLevel_sphinx);
@@ -71,6 +77,13 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
recoveryModelEnums.Add(displayRecoveryModels[key], key);
}
// Azure SLO info is invariant of server information, so set up static objects we can return later
var editions = AzureSqlDbHelper.GetValidAzureEditionOptions();
AzureEditionNames = editions.Select(edition => edition.DisplayName).ToArray();
AzureBackupLevels = AzureSqlDbHelper.BackupStorageRedundancyLevels;
AzureMaxSizes = GetAzureMaxSizes(editions);
AzureServiceLevels = GetAzureServiceLevels(editions);
}
public DatabaseHandler(ConnectionService connectionService) : base(connectionService)
@@ -99,18 +112,17 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
var prototype = taskHelper.Prototype;
var azurePrototype = prototype as DatabasePrototypeAzure;
bool isDw = azurePrototype != null && azurePrototype.AzureEdition == AzureEdition.DataWarehouse;
bool isAzureDB = dataContainer.Server.ServerType == DatabaseEngineType.SqlAzureDatabase;
var databaseViewInfo = new DatabaseViewInfo()
{
ObjectInfo = new DatabaseInfo()
ObjectInfo = new DatabaseInfo(),
IsAzureDB = isAzureDB
};
// azure sql db doesn't have a sysadmin fixed role
var compatibilityLevelEnabled = !isDw &&
(dataContainer.LoggedInUserIsSysadmin ||
dataContainer.Server.ServerType ==
DatabaseEngineType.SqlAzureDatabase);
if (dataContainer.Server.ServerType == DatabaseEngineType.SqlAzureDatabase)
var compatibilityLevelEnabled = !isDw && (dataContainer.LoggedInUserIsSysadmin || isAzureDB);
if (isAzureDB)
{
// Azure doesn't allow modifying the collation after DB creation
bool collationEnabled = !prototype.Exists;
@@ -133,6 +145,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
databaseViewInfo.CompatibilityLevels = GetCompatibilityLevels(dataContainer.SqlServerVersion, prototype);
}
}
databaseViewInfo.AzureBackupRedundancyLevels = AzureBackupLevels;
databaseViewInfo.AzureServiceLevelObjectives = AzureServiceLevels;
databaseViewInfo.AzureEditions = AzureEditionNames;
databaseViewInfo.AzureMaxSizes = AzureMaxSizes;
}
else
{
@@ -148,7 +164,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
// Skip adding logins if running against an Azure SQL DB
if (dataContainer.Server.ServerType != DatabaseEngineType.SqlAzureDatabase)
if (!isAzureDB)
{
var logins = new List<string>();
foreach (Login login in dataContainer.Server.Logins)
@@ -283,6 +299,27 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
db110.DatabaseContainmentType = containmentTypeEnums[database.ContainmentType];
}
if (prototype is DatabasePrototypeAzure dbAz)
{
// Set edition first since the prototype will fill all the Azure fields with default values
if (database.AzureEdition != null)
{
dbAz.AzureEditionDisplay = database.AzureEdition;
}
if (database.AzureBackupRedundancyLevel != null)
{
dbAz.BackupStorageRedundancy = database.AzureBackupRedundancyLevel;
}
if (database.AzureServiceLevelObjective != null)
{
dbAz.CurrentServiceLevelObjective = database.AzureServiceLevelObjective;
}
if (database.AzureMaxSize != null)
{
dbAz.MaxSize = database.AzureMaxSize;
}
}
string sqlScript = string.Empty;
using (var actions = new DatabaseActions(dataContainer, configAction, prototype))
using (var executionHandler = new ExecutonHandler(actions))
@@ -583,5 +620,65 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
// previous loop did not find the prototype compatibility level in this server's compatability options, so treat compatibility levels as unsupported for this server
return Array.Empty<string>();
}
/// <summary>
/// Get supported service level objectives for this Azure server.
/// </summary>
private static AzureEditionDetails[] GetAzureServiceLevels(IEnumerable<AzureEdition> editions)
{
var levels = new List<AzureEditionDetails>();
foreach (AzureEdition edition in editions)
{
if (AzureSqlDbHelper.TryGetServiceObjectiveInfo(edition, out var serviceInfoPair))
{
// Move default value to the front of the list
var serviceLevelsList = new List<string>(serviceInfoPair.Value);
var defaultIndex = serviceInfoPair.Key;
if (defaultIndex >= 0 && defaultIndex < serviceLevelsList.Count)
{
var defaultServiceObjective = serviceLevelsList[defaultIndex];
serviceLevelsList.RemoveAt(defaultIndex);
serviceLevelsList.Insert(0, defaultServiceObjective);
}
var details = new AzureEditionDetails() { EditionDisplayName = edition.DisplayName, Details = serviceLevelsList.ToArray() };
levels.Add(details);
}
else
{
Logger.Error($"Failed to get service level objective info for edition '{edition.Name}'");
}
}
return levels.ToArray();
}
/// <summary>
/// Get supported maximum sizes for this Azure server.
/// </summary>
private static AzureEditionDetails[] GetAzureMaxSizes(IEnumerable<AzureEdition> editions)
{
var sizes = new List<AzureEditionDetails>();
foreach (AzureEdition edition in editions)
{
if (AzureSqlDbHelper.TryGetDatabaseSizeInfo(edition, out var sizeInfoPair))
{
// Move default value to the front of the list
var sizeInfoList = new List<DbSize>(sizeInfoPair.Value);
var defaultIndex = sizeInfoPair.Key;
if (defaultIndex >= 0 && defaultIndex < sizeInfoList.Count)
{
var defaultSizeInfo = sizeInfoList[defaultIndex];
sizeInfoList.RemoveAt(defaultIndex);
sizeInfoList.Insert(0, defaultSizeInfo);
}
var details = new AzureEditionDetails() { EditionDisplayName = edition.DisplayName, Details = sizeInfoList.Select(info => info.ToString()).ToArray() };
sizes.Add(details);
}
else
{
Logger.Error($"Failed to get database size info for edition '{edition.Name}'");
}
}
return sizes.ToArray();
}
}
}

View File

@@ -15,5 +15,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string? RecoveryModel { get; set; }
public string? CompatibilityLevel { get; set; }
public string? ContainmentType { get; set; }
public string? AzureBackupRedundancyLevel { get; set; }
public string? AzureServiceLevelObjective { get; set; }
public string? AzureEdition { get; set; }
public string? AzureMaxSize { get; set; }
}
}

View File

@@ -14,5 +14,17 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string[] CompatibilityLevels { get; set; }
public string[] ContainmentTypes { get; set; }
public string[] RecoveryModels { get; set; }
public bool IsAzureDB { get; set; }
public string[] AzureBackupRedundancyLevels { get; set; }
public AzureEditionDetails[] AzureServiceLevelObjectives { get; set; }
public string[] AzureEditions { get; set; }
public AzureEditionDetails[] AzureMaxSizes { get; set; }
}
public class AzureEditionDetails
{
public string EditionDisplayName { get; set; }
public string[] Details { get; set; }
}
}

View File

@@ -3,15 +3,19 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Admin;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
using Microsoft.SqlTools.ServiceLayer.ObjectManagement;
using Microsoft.SqlTools.ServiceLayer.Test.Common;
using NUnit.Framework;
using static Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper;
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
{
@@ -162,6 +166,102 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
}
}
[Test]
public void GetAzureEditionsTest()
{
var actualEditionNames = DatabaseHandler.AzureEditionNames;
var expectedEditionNames = AzureSqlDbHelper.GetValidAzureEditionOptions().Select(edition => edition.DisplayName);
Assert.That(actualEditionNames, Is.EquivalentTo(expectedEditionNames));
}
[Test]
public void GetAzureBackupRedundancyLevelsTest()
{
var actualLevels = DatabaseHandler.AzureBackupLevels;
var expectedLevels = new string[] { "Geo", "Local", "Zone" };
Assert.That(actualLevels, Is.EquivalentTo(expectedLevels));
}
[Test]
public void GetAzureServiceLevelObjectivesTest()
{
var actualLevelsMap = new Dictionary<string, string[]>();
foreach (AzureEditionDetails serviceDetails in DatabaseHandler.AzureServiceLevels)
{
actualLevelsMap.Add(serviceDetails.EditionDisplayName, serviceDetails.Details);
}
var expectedDefaults = new Dictionary<AzureEdition, string>()
{
{ AzureEdition.Basic, "Basic" },
{ AzureEdition.Standard, "S0" },
{ AzureEdition.Premium, "P1" },
{ AzureEdition.DataWarehouse, "DW400" },
{ AzureEdition.BusinessCritical, "BC_Gen5_2" },
{ AzureEdition.GeneralPurpose, "GP_Gen5_2" },
{ AzureEdition.Hyperscale, "HS_Gen5_2" }
};
Assert.That(actualLevelsMap.Count, Is.EqualTo(expectedDefaults.Count), "Did not get expected number of editions for DatabaseHandler's service levels");
foreach(AzureEdition edition in expectedDefaults.Keys)
{
if (AzureSqlDbHelper.TryGetServiceObjectiveInfo(edition, out var expectedLevelInfo))
{
var expectedServiceLevels = expectedLevelInfo.Value;
var actualServiceLevels = actualLevelsMap[edition.DisplayName];
Assert.That(actualServiceLevels, Is.EquivalentTo(expectedServiceLevels), "Did not get expected SLO list for edition '{0}'", edition.DisplayName);
var expectedDefaultIndex = expectedLevelInfo.Key;
var expectedDefault = expectedServiceLevels[expectedDefaultIndex];
var actualDefault = actualServiceLevels[0];
Assert.That(actualDefault, Is.EqualTo(expectedDefault), "Did not get expected default SLO for edition '{0}'", edition.DisplayName);
}
else
{
Assert.Fail("Could not retrieve SLO info for Azure edition '{0}'", edition.DisplayName);
}
}
}
[Test]
public void GetAzureMaxSizesTest()
{
var actualSizesMap = new Dictionary<string, string[]>();
foreach (AzureEditionDetails sizeDetails in DatabaseHandler.AzureMaxSizes)
{
actualSizesMap.Add(sizeDetails.EditionDisplayName, sizeDetails.Details);
}
var expectedDefaults = new Dictionary<AzureEdition, string>()
{
{ AzureEdition.Basic, "2GB" },
{ AzureEdition.Standard, "250GB" },
{ AzureEdition.Premium, "500GB" },
{ AzureEdition.DataWarehouse, "10240GB" },
{ AzureEdition.BusinessCritical, "32GB" },
{ AzureEdition.GeneralPurpose, "32GB" },
{ AzureEdition.Hyperscale, "0MB" }
};
Assert.That(actualSizesMap.Count, Is.EqualTo(expectedDefaults.Count), "Did not get expected number of editions for DatabaseHandler's max sizes");
foreach(AzureEdition edition in expectedDefaults.Keys)
{
if (AzureSqlDbHelper.TryGetDatabaseSizeInfo(edition, out var expectedSizeInfo))
{
var expectedSizes = expectedSizeInfo.Value.Select(size => size.ToString()).ToArray();
var actualSizes = actualSizesMap[edition.DisplayName];
Assert.That(actualSizes, Is.EquivalentTo(expectedSizes), "Did not get expected size list for edition '{0}'", edition.DisplayName);
var expectedDefaultIndex = expectedSizeInfo.Key;
var expectedDefault = expectedSizes[expectedDefaultIndex];
var actualDefault = actualSizes[0];
Assert.That(actualDefault, Is.EqualTo(expectedDefault.ToString()), "Did not get expected default size for edition '{0}'", edition.DisplayName);
}
else
{
Assert.Fail("Could not retrieve max size info for Azure edition '{0}'", edition.DisplayName);
}
}
}
private bool DatabaseExists(string dbName, Server server)
{
server.Databases.Refresh();