Enabling Files Tab to the database properties (#2169)

* sending dsc values to ADS

* modifying dsc method with unsupportable property IsValuedefault

* getting the options and added a bool flag to maintian checkbox for secondary to save

* sending data to ads

* Ready for PR with minimal changes of loading UI as expected, TODO:saving logic

* Excluding maxdop and resumable options from primary value conversion for 1/0's

* Adding Id to the info, as we cannot depend on names, as names can be altered in future

* saving successfully, todo-diff servers, script (secondary - primary compare and dont update),test, send null for unsupported

* adding nullable dsc for unsupported servers

* fixing script generation for some properties that are not touched. the generated script is unharmed but unnecessary here

* adding test conditions for database scoped configurations

* adding switch case method to get the values

* Removing Loc string for the TSQL options

* removing unnecessary using statement

* sending required data, verify autogrowth...

* using fullTextIndexing to open the files tab for sql server and not to other servers

* Adding test case and fixing createDatabase issue

* sending files as objecinfo

* Update src/Microsoft.SqlTools.ServiceLayer/Admin/Database/DatabasePrototype130.cs

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>

* comment update

* preparing filegroup and filetype options

* sending required all fields

* saving file code changes, need more to work

* Saving file is completed, todo:edit  & remove

* Logic to remove the file

* add,edit,save working

* cleaning merge conflicts accidentally added code

* Adding tests to validates Files by adding, removing, updating files

* adding comments

* all working including tests, except fileStream size question

* code review comments updates

* memoryoptimized filegroups should be part of filestream group

* failing tests fix

* Modify tests by create database using SqlTestDb

* Update src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs

Co-authored-by: Cory Rivera <corivera@microsoft.com>

* fixing test

* commenting remove file testing as failing pipeline but passing locally

* using enum for type

* trying to fix the test in server, removed the complaining file from test

* removing fulltext param and test fix

* fixing the path..

* test fix

* missing conflict resolving

---------

Co-authored-by: Charles Gagnon <chgagnon@microsoft.com>
Co-authored-by: Cory Rivera <corivera@microsoft.com>
This commit is contained in:
Sai Avishkar Sreerama
2023-08-29 11:24:31 -05:00
committed by GitHub
parent 41ae066b46
commit 07c8069cfa
7 changed files with 314 additions and 51 deletions

View File

@@ -843,6 +843,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
private class FileData
{
public int id;
public string name;
public string physicalName;
public string folder;
@@ -859,6 +860,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <param name="type"></param>
public FileData(DatabasePrototype parent, FileType type)
{
this.id = 0;
this.name = String.Empty;
this.physicalName = String.Empty;
this.folder = String.Empty;
@@ -879,6 +881,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
this.autogrowth = new Autogrowth(parent, file);
this.name = file.Name;
this.id = file.ID;
if (file.FileName.EndsWith(":", StringComparison.Ordinal))
{
@@ -923,6 +926,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
this.autogrowth = new Autogrowth(parent, file);
this.name = file.Name;
this.id = file.ID;
try
{
@@ -960,6 +964,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <param name="other"></param>
public FileData(FileData other)
{
this.id = other.id;
this.name = other.name;
this.physicalName = other.physicalName;
this.folder = other.folder;
@@ -1001,6 +1006,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
#region properties
/// <summary>
/// The ID of the file
/// </summary>
public int ID
{
get { return this.currentState.id; }
set
{
this.currentState.id = value;
this.database.NotifyObservers();
}
}
/// <summary>
/// The logical name of the file, without extension
/// </summary>

View File

@@ -22,6 +22,7 @@ using System.IO;
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
using System.Collections.Specialized;
using Microsoft.SqlTools.SqlCore.Utility;
using System.Collections.Concurrent;
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
@@ -39,10 +40,12 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
private static readonly Dictionary<RecoveryModel, string> displayRecoveryModels = new Dictionary<RecoveryModel, string>();
private static readonly Dictionary<PageVerify, string> displayPageVerifyOptions = new Dictionary<PageVerify, string>();
private static readonly Dictionary<DatabaseUserAccess, string> displayRestrictAccessOptions = new Dictionary<DatabaseUserAccess, string>();
private static readonly ConcurrentDictionary<FileType, string> displayFileTypes = new ConcurrentDictionary<FileType, string>();
private static readonly Dictionary<string, CompatibilityLevel> compatLevelEnums = new Dictionary<string, CompatibilityLevel>();
private static readonly Dictionary<string, ContainmentType> containmentTypeEnums = new Dictionary<string, ContainmentType>();
private static readonly Dictionary<string, RecoveryModel> recoveryModelEnums = new Dictionary<string, RecoveryModel>();
private static readonly Dictionary<string, FileType> fileTypesEnums = new Dictionary<string, FileType>();
internal static readonly string[] AzureEditionNames;
internal static readonly string[] AzureBackupLevels;
@@ -81,6 +84,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
displayRestrictAccessOptions.Add(DatabaseUserAccess.Single, SR.prototype_db_prop_restrictAccess_value_single);
displayRestrictAccessOptions.Add(DatabaseUserAccess.Restricted, SR.prototype_db_prop_restrictAccess_value_restricted);
displayFileTypes.TryAdd(FileType.Data, SR.prototype_file_dataFile);
displayFileTypes.TryAdd(FileType.Log, SR.prototype_file_logFile);
displayFileTypes.TryAdd(FileType.FileStream, SR.prototype_file_filestreamFile);
DscOnOffOptions = new[]{
CommonConstants.DatabaseScopedConfigurations_Value_On,
CommonConstants.DatabaseScopedConfigurations_Value_Off
@@ -111,6 +118,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
recoveryModelEnums.Add(displayRecoveryModels[key], key);
}
foreach (FileType key in displayFileTypes.Keys)
{
fileTypesEnums.Add(displayFileTypes[key], key);
}
// Azure SLO info is invariant of server information, so set up static objects we can return later
var editions = AzureSqlDbHelper.GetValidAzureEditionOptions();
@@ -203,6 +214,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
((DatabaseInfo)databaseViewInfo.ObjectInfo).PageVerify = displayPageVerifyOptions[smoDatabase.PageVerify];
((DatabaseInfo)databaseViewInfo.ObjectInfo).TargetRecoveryTimeInSec = smoDatabase.TargetRecoveryTime;
// Files tab is only supported in SQL Server, but files exists for all servers and used in detach database, cannot depend on files property to check the supportability
((DatabaseInfo)databaseViewInfo.ObjectInfo).IsFilesTabSupported = true;
}
if (prototype is DatabasePrototype160)
@@ -211,6 +224,10 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
}
databaseScopedConfigurationsCollection = smoDatabase.IsSupportedObject<DatabaseScopedConfiguration>() ? smoDatabase.DatabaseScopedConfigurations : null;
databaseViewInfo.FileTypesOptions = displayFileTypes.Values.ToArray();
// Get file groups names
GetFileGroupNames(smoDatabase, databaseViewInfo);
}
databaseViewInfo.DscOnOffOptions = DscOnOffOptions;
databaseViewInfo.DscElevateOptions = DscElevateOptions;
@@ -263,7 +280,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
var smoDatabase = dataContainer.SqlDialogSubject as Database;
if (smoDatabase != null)
{
databaseViewInfo.Files = GetDatabaseFiles(smoDatabase);
((DatabaseInfo)databaseViewInfo.ObjectInfo).Files = GetDatabaseFiles(smoDatabase);
}
}
}
@@ -605,7 +622,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
}
if (database.Owner != null && database.Owner != SR.general_default && viewParams.IsNewObject)
if (database.Owner != null && database.Owner != SR.general_default)
{
prototype.Owner = database.Owner;
}
@@ -681,6 +698,61 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
}
if (!viewParams.IsNewObject && database.Files != null)
{
HashSet<int> fileIdsToRemove = new HashSet<int>(prototype.Files.Select(file => file.ID));
foreach (var file in database.Files)
{
// Add a New file
if (file.Id == 0)
{
DatabaseFilePrototype newFile = new DatabaseFilePrototype(dataContainer, prototype, fileTypesEnums[file.Type]);
newFile.Name = file.Name;
newFile.InitialSize = (int)file.SizeInMb;
newFile.PhysicalName = file.FileNameWithExtension;
newFile.DatabaseFileType = fileTypesEnums[file.Type];
newFile.Exists = false;
newFile.Autogrowth = GetAutogrowth(prototype, file);
if (!string.IsNullOrEmpty(file.Path.Trim()))
{
newFile.Folder = Utility.DatabaseUtils.ConvertToLocalMachinePath(Path.GetFullPath(file.Path));
}
// Log file do not support file groups
if (fileTypesEnums[file.Type] != FileType.Log)
{
FilegroupPrototype fileGroup = new FilegroupPrototype(prototype);
fileGroup.Name = file.FileGroup;
newFile.FileGroup = fileGroup;
}
// Add newFile to the prototype files
prototype.Files.Add(newFile);
}
// Edit file properties: updating the existed files with modified data
else
{
var existedFile = prototype.Files.FirstOrDefault(x => x.ID == file.Id);
if (existedFile != null)
{
fileIdsToRemove.Remove(file.Id);
existedFile.Name = file.Name;
existedFile.InitialSize = (int)file.SizeInMb;
existedFile.Autogrowth = GetAutogrowth(prototype, file);
}
}
}
// Remove the file
foreach (var currentFile in prototype.Files)
{
if (fileIdsToRemove.Contains(currentFile.ID))
{
currentFile.Removed = true;
}
}
}
// AutoCreateStatisticsIncremental can only be set when AutoCreateStatistics is enabled
prototype.AutoCreateStatisticsIncremental = database.AutoCreateIncrementalStatistics;
prototype.AutoCreateStatistics = database.AutoCreateStatistics;
@@ -738,6 +810,20 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
}
private Autogrowth GetAutogrowth(DatabasePrototype prototype, DatabaseFile file)
{
Autogrowth fileAutogrowth = new Autogrowth(prototype);
fileAutogrowth.IsEnabled = file.IsAutoGrowthEnabled;
bool isGrowthInPercent = file.AutoFileGrowthType == FileGrowthType.Percent;
fileAutogrowth.IsGrowthInPercent = isGrowthInPercent;
fileAutogrowth.GrowthInPercent = isGrowthInPercent ? (int)file.AutoFileGrowth : fileAutogrowth.GrowthInPercent;
fileAutogrowth.GrowthInMegabytes = !isGrowthInPercent ? (int)file.AutoFileGrowth : fileAutogrowth.GrowthInMegabytes;
fileAutogrowth.MaximumFileSizeInMegabytes = (int)((0.0 <= file.MaxSizeLimitInMb) ? file.MaxSizeLimitInMb : 0.0);
fileAutogrowth.IsGrowthRestricted = file.MaxSizeLimitInMb > 0.0;
return fileAutogrowth;
}
/// <summary>
/// Get supported database collations for this server.
/// </summary>
@@ -898,10 +984,17 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
filesList.Add(new DatabaseFile()
{
Id = file.ID,
Name = file.Name,
Type = FileType.Data.ToString(),
Path = Path.GetDirectoryName(file.FileName),
FileGroup = fileGroup.Name
Type = file.Parent.FileGroupType == FileGroupType.RowsFileGroup ? displayFileTypes[FileType.Data] : displayFileTypes[FileType.FileStream],
Path = Utility.DatabaseUtils.ConvertToLocalMachinePath(Path.GetDirectoryName(file.FileName)),
FileGroup = fileGroup.Name,
FileNameWithExtension = Path.GetFileName(file.FileName),
SizeInMb = ByteConverter.ConvertKbtoMb(file.Size),
AutoFileGrowth = file.GrowthType == FileGrowthType.Percent ? file.Growth : ByteConverter.ConvertKbtoMb(file.Growth),
AutoFileGrowthType = file.GrowthType,
MaxSizeLimitInMb = file.MaxSize == -1 ? file.MaxSize : ByteConverter.ConvertKbtoMb(file.MaxSize),
IsAutoGrowthEnabled = file.GrowthType != FileGrowthType.None,
});
}
}
@@ -909,15 +1002,53 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
filesList.Add(new DatabaseFile()
{
Id = file.ID,
Name = file.Name,
Type = FileType.Log.ToString(),
Path = Path.GetDirectoryName(file.FileName),
FileGroup = string.Empty
Type = displayFileTypes[FileType.Log],
Path = Utility.DatabaseUtils.ConvertToLocalMachinePath(Path.GetDirectoryName(file.FileName)),
FileGroup = SR.prototype_file_noFileGroup,
FileNameWithExtension = Path.GetFileName(file.FileName),
SizeInMb = ByteConverter.ConvertKbtoMb(file.Size),
AutoFileGrowth = file.GrowthType == FileGrowthType.Percent ? file.Growth : ByteConverter.ConvertKbtoMb(file.Growth),
AutoFileGrowthType = file.GrowthType,
MaxSizeLimitInMb = file.MaxSize == -1 ? file.MaxSize : ByteConverter.ConvertKbtoMb(file.MaxSize),
IsAutoGrowthEnabled = file.GrowthType != FileGrowthType.None
});
}
return filesList.ToArray();
}
/// <summary>
/// Get the file group names from the database fileGroup
/// </summary>
/// <param name="database">smo database prototype</param>
/// <param name="databaseViewInfo">database view info object</param>
private void GetFileGroupNames(Database database, DatabaseViewInfo databaseViewInfo)
{
var rowDataGroups = new List<string>();
var fileStreamDataGroups = new List<string>();
foreach (FileGroup fileGroup in database.FileGroups)
{
if (fileGroup.FileGroupType == FileGroupType.FileStreamDataFileGroup || fileGroup.FileGroupType == FileGroupType.MemoryOptimizedDataFileGroup)
{
fileStreamDataGroups.Add(fileGroup.Name);
}
else
{
rowDataGroups.Add(fileGroup.Name);
}
}
// If no fileStream groups available
if (fileStreamDataGroups.Count == 0)
{
fileStreamDataGroups.Add(SR.prototype_file_noApplicableFileGroup);
}
databaseViewInfo.RowDataFileGroupsOptions = rowDataGroups.ToArray();
databaseViewInfo.FileStreamFileGroupsOptions = fileStreamDataGroups.ToArray();
}
/// <summary>
/// Get supported database compatibility levels for this Azure server.
/// </summary>

View File

@@ -3,6 +3,8 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlServer.Management.Smo;
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
/// <summary>
@@ -40,6 +42,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public bool EncryptionEnabled { get; set; }
public string? RestrictAccess { get; set; }
public DatabaseScopedConfigurationsInfo[]? DatabaseScopedConfigurations { get; set; }
public bool? IsFilesTabSupported { get; set; }
public DatabaseFile[] Files { get; set; }
}
public class DatabaseScopedConfigurationsInfo
@@ -49,4 +53,20 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string ValueForPrimary { get; set; }
public string ValueForSecondary { get; set; }
}
public class DatabaseFile
{
public int Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string Path { get; set; }
public string FileGroup { get; set; }
public string FileNameWithExtension { get; set; }
public double SizeInMb { get; set; }
public bool IsAutoGrowthEnabled { get; set; }
public double AutoFileGrowth { get; set; }
public FileGrowthType AutoFileGrowthType { get; set; }
public double MaxSizeLimitInMb { get; set; }
}
}

View File

@@ -14,7 +14,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public OptionsCollection CompatibilityLevels { get; set; }
public OptionsCollection ContainmentTypes { get; set; }
public OptionsCollection RecoveryModels { get; set; }
public DatabaseFile[] Files { get; set; }
public bool IsAzureDB { get; set; }
public bool IsManagedInstance { get; set; }
@@ -28,6 +27,9 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string[] DscOnOffOptions { get; set; }
public string[] DscElevateOptions { get; set; }
public string[] DscEnableDisableOptions { get; set; }
public string[] RowDataFileGroupsOptions { get; set; }
public string[] FileStreamFileGroupsOptions { get; set; }
public string[] FileTypesOptions { get; set; }
}
public class AzureEditionDetails
@@ -36,14 +38,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public OptionsCollection EditionOptions { get; set; }
}
public class DatabaseFile
{
public string Name { get; set; }
public string Type { get; set; }
public string Path { get; set; }
public string FileGroup { get; set; }
}
public class OptionsCollection {
public string[] Options { get; set; }
public int DefaultValueIndex { get; set; }

View File

@@ -112,7 +112,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
return false;
}
}
return true;
return true;
}
finally
{
@@ -346,5 +346,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
return new string(nameChars);
}
private static readonly HashSet<char> illegalFilenameCharacters = new HashSet<char>(new char[] { '\\', '/', ':', '*', '?', '"', '<', '>', '|' });
/// <summary>
/// Converts path to local path with DirectorySeparatorChar
/// </summary>
/// <param name="filePath"></param>
/// <returns>path with local directory separator</returns>
public static string ConvertToLocalMachinePath(string filePath)
{
string pathSeparator = Path.DirectorySeparatorChar.ToString();
string localPath = filePath.Replace("/", pathSeparator);
localPath = localPath.Replace("\\", pathSeparator);
return localPath;
}
}
}

View File

@@ -21,6 +21,7 @@ using Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts;
using Microsoft.SqlTools.ServiceLayer.Test.Common;
using NUnit.Framework;
using static Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper;
using DatabaseFile = Microsoft.SqlTools.ServiceLayer.ObjectManagement.DatabaseFile;
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
{
@@ -305,6 +306,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).RestrictAccess, Is.EqualTo(testDatabase.RestrictAccess), $"RestrictAccess should match with testdata");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).DatabaseScopedConfigurations, Is.Not.Null, $"DatabaseScopedConfigurations is not null");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).DatabaseScopedConfigurations.Count, Is.GreaterThan(0), $"DatabaseScopedConfigurations should have at least a+ few properties");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files.Count, Is.EqualTo(2), $"Create database should create two database files");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files[0].Type, Is.EqualTo("ROWS Data"), $"Database files first file should be Row type database files");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files[1].Type, Is.EqualTo("LOG"), $"Database files first file should be Log type database files");
// cleanup
await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn, throwIfNotExist: true);
@@ -325,58 +329,116 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
[Test]
public async Task VerifyDatabaseScopedConfigurationsTest()
{
// setup, drop database if exists.
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", serverType: TestServerType.OnPrem);
using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo))
using (var testDatabase = await SqlTestDb.CreateNewAsync(serverType: TestServerType.OnPrem, dbNamePrefix: "VerifyDatabaseFilesTest"))
{
var server = new Server(new ServerConnection(sqlConn));
var testDatabase = ObjectManagementTestUtils.GetTestDatabaseInfo();
var objUrn = ObjectManagementTestUtils.GetDatabaseURN(testDatabase.Name);
await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn);
try
var connectionResult = LiveConnectionHelper.InitLiveConnectionInfo(testDatabase.DatabaseName);
using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo))
{
// create database
var parametersForCreation = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Database, "", "");
await ObjectManagementTestUtils.SaveObject(parametersForCreation, testDatabase);
Assert.That(DatabaseExists(testDatabase.Name!, server), $"Expected database '{testDatabase.Name}' was not created succesfully");
var server = new Server(new ServerConnection(sqlConn));
var testDatabaseInfo = ObjectManagementTestUtils.GetTestDatabaseInfo();
testDatabaseInfo.Name = testDatabase.DatabaseName;
testDatabaseInfo.CollationName = "";
var objUrn = ObjectManagementTestUtils.GetDatabaseURN(testDatabase.DatabaseName);
// Get database properties and verify
var parametersForUpdate = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, testDatabase.Name, false, SqlObjectType.Database, "", objUrn);
DatabaseViewInfo databaseViewInfo = await ObjectManagementTestUtils.GetDatabaseObject(parametersForUpdate, testDatabase);
var parametersForUpdate = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, testDatabase.DatabaseName, false, SqlObjectType.Database, "", objUrn);
DatabaseViewInfo databaseViewInfo = await ObjectManagementTestUtils.GetDatabaseObject(parametersForUpdate, testDatabaseInfo);
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).DatabaseScopedConfigurations, Is.Not.Null, $"DatabaseScopedConfigurations is not null");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).DatabaseScopedConfigurations.Count, Is.GreaterThan(0), $"DatabaseScopedConfigurations should have at least a+ few properties");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).DatabaseScopedConfigurations[0].ValueForPrimary, Is.EqualTo("ON"), $"DatabaseScopedConfigurations primary value should match");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).DatabaseScopedConfigurations[0].ValueForSecondary, Is.EqualTo("ON"), $"DatabaseScopedConfigurations secondary value should match");
// Update few database scoped configurations
testDatabase.DatabaseScopedConfigurations = ((DatabaseInfo)databaseViewInfo.ObjectInfo).DatabaseScopedConfigurations;
if (testDatabase.DatabaseScopedConfigurations.Length > 0)
testDatabaseInfo.DatabaseScopedConfigurations = ((DatabaseInfo)databaseViewInfo.ObjectInfo).DatabaseScopedConfigurations;
if (testDatabaseInfo.DatabaseScopedConfigurations.Length > 0)
{
// ACCELERATED_PLAN_FORCING
testDatabase.DatabaseScopedConfigurations[0].ValueForPrimary = "OFF";
testDatabase.DatabaseScopedConfigurations[0].ValueForSecondary = "OFF";
testDatabaseInfo.DatabaseScopedConfigurations[0].ValueForPrimary = "OFF";
testDatabaseInfo.DatabaseScopedConfigurations[0].ValueForSecondary = "OFF";
}
await ObjectManagementTestUtils.SaveObject(parametersForUpdate, testDatabase);
DatabaseViewInfo updatedDatabaseViewInfo = await ObjectManagementTestUtils.GetDatabaseObject(parametersForUpdate, testDatabase);
await ObjectManagementTestUtils.SaveObject(parametersForUpdate, testDatabaseInfo);
DatabaseViewInfo updatedDatabaseViewInfo = await ObjectManagementTestUtils.GetDatabaseObject(parametersForUpdate, testDatabaseInfo);
// verify the modified properties
Assert.That(((DatabaseInfo)updatedDatabaseViewInfo.ObjectInfo).DatabaseScopedConfigurations[0].ValueForPrimary, Is.EqualTo(testDatabase.DatabaseScopedConfigurations[0].ValueForPrimary), $"DSC updated primary value should match");
Assert.That(((DatabaseInfo)updatedDatabaseViewInfo.ObjectInfo).DatabaseScopedConfigurations[0].ValueForSecondary, Is.EqualTo(testDatabase.DatabaseScopedConfigurations[0].ValueForSecondary), $"DSC updated Secondary value should match");
// cleanup
await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn, throwIfNotExist: true);
Assert.That(DatabaseExists(testDatabase.Name!, server), Is.False, $"Database '{testDatabase.Name}' was not dropped succesfully");
}
finally
{
// Cleanup using SMO if Drop didn't work
DropDatabase(server, testDatabase.Name!);
Assert.That(((DatabaseInfo)updatedDatabaseViewInfo.ObjectInfo).DatabaseScopedConfigurations[0].ValueForPrimary, Is.EqualTo(testDatabaseInfo.DatabaseScopedConfigurations[0].ValueForPrimary), $"DSC updated primary value should match");
Assert.That(((DatabaseInfo)updatedDatabaseViewInfo.ObjectInfo).DatabaseScopedConfigurations[0].ValueForSecondary, Is.EqualTo(testDatabaseInfo.DatabaseScopedConfigurations[0].ValueForSecondary), $"DSC updated Secondary value should match");
}
}
}
/// <summary>
/// Adding, modifying and deleting database files
/// </summary>
/// <returns></returns>
[Test]
public async Task VerifyDatabaseFilesTest()
{
using (var testDatabase = await SqlTestDb.CreateNewAsync(serverType: TestServerType.OnPrem, dbNamePrefix: "VerifyDatabaseFilesTest"))
{
var connectionResult = LiveConnectionHelper.InitLiveConnectionInfo(testDatabase.DatabaseName);
using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo))
{
var testDatabaseInfo = ObjectManagementTestUtils.GetTestDatabaseInfo();
testDatabaseInfo.Name = testDatabase.DatabaseName;
testDatabaseInfo.CollationName = "";
var objUrn = ObjectManagementTestUtils.GetDatabaseURN(testDatabase.DatabaseName);
// Get database properties and verify
var parametersForUpdate = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, testDatabase.DatabaseName, false, SqlObjectType.Database, "", objUrn);
DatabaseViewInfo databaseViewInfo = await ObjectManagementTestUtils.GetDatabaseObject(parametersForUpdate, testDatabaseInfo);
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files.Count, Is.EqualTo(2), $"Create database should create two database files");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files[0].Type, Is.EqualTo("ROWS Data"), $"Database files first file should be Row type database files");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files[1].Type, Is.EqualTo("LOG"), $"Database files first file should be Log type database files");
List<DatabaseFile> databaseFile = new List<DatabaseFile>();
// copy exisitng Row data files to the list
databaseFile.Add(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files[0]);
databaseFile.Add(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files[1]);
// Update existing file
databaseFile[0].SizeInMb = 15; // size modified from 8 to 15
databaseFile[0].AutoFileGrowth = 74; // size modified from 64 to 74
// Add new Files of Row and Log types
var testDatabaseFiles = ObjectManagementTestUtils.GetTestDatabaseFiles();
databaseFile.AddRange(testDatabaseFiles);
// Attaching the files to the testdatabase
testDatabaseInfo.Files = databaseFile.ToArray();
// Validate the result files
await ObjectManagementTestUtils.SaveObject(parametersForUpdate, testDatabaseInfo);
DatabaseViewInfo updatedDatabaseViewInfo = await ObjectManagementTestUtils.GetDatabaseObject(parametersForUpdate, testDatabaseInfo);
// verify the modified properties
Assert.That(((DatabaseInfo)updatedDatabaseViewInfo.ObjectInfo).Files.Count, Is.EqualTo(3), $"Three files should exists, as we modified one and added one new files");
var file = ((DatabaseInfo)updatedDatabaseViewInfo.ObjectInfo).Files.FirstOrDefault(x => x.Name == databaseFile[0].Name);
Assert.That(file, Is.Not.Null, $"Primary file should exists");
Assert.That(file.SizeInMb, Is.EqualTo(15), $"Files updated value should match");
Assert.That(file.AutoFileGrowth, Is.EqualTo(74), $"Files updated value should match");
// Validate newly created files
file = ((DatabaseInfo)updatedDatabaseViewInfo.ObjectInfo).Files.FirstOrDefault(x => x.Name == testDatabaseFiles[0].Name);
Assert.That(file, Is.Not.Null, $"New file should be created");
Assert.That(file, Is.Not.EqualTo(0), $"Newly created file should have an Id");
// Deleting newly created file
List<DatabaseFile> newfiles = ((DatabaseInfo)updatedDatabaseViewInfo.ObjectInfo).Files.ToList();
var fileIndexTobeRemoved = newfiles.FindIndex(x => x.Name == testDatabaseFiles[0].Name);
newfiles.RemoveAt(fileIndexTobeRemoved);
testDatabaseInfo.Files = newfiles.ToArray();
// Validate the result files
await ObjectManagementTestUtils.SaveObject(parametersForUpdate, testDatabaseInfo);
DatabaseViewInfo databaseViewInfoAfterFileDelete = await ObjectManagementTestUtils.GetDatabaseObject(parametersForUpdate, testDatabaseInfo);
Assert.That(((DatabaseInfo)databaseViewInfoAfterFileDelete.ObjectInfo).Files.Count, Is.EqualTo(2), $"Should have only 2 files as we removed one");
}
}
}
[Test]
public async Task DetachDatabaseTest()
{

View File

@@ -6,13 +6,16 @@
#nullable disable
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
using Microsoft.SqlTools.ServiceLayer.ObjectManagement;
using Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts;
using Moq;
using Newtonsoft.Json.Linq;
using DatabaseFile = Microsoft.SqlTools.ServiceLayer.ObjectManagement.DatabaseFile;
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
{
@@ -104,6 +107,26 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
};
}
internal static DatabaseFile[] GetTestDatabaseFiles()
{
List<DatabaseFile> databaseFiles = new List<DatabaseFile>() {
new DatabaseFile() {
Id = 0,
Name = "TestDatabaseName_File1_" + new Random().NextInt64(10000000, 90000000).ToString(),
Type = "LOG",
AutoFileGrowth = 100,
AutoFileGrowthType = FileGrowthType.KB,
FileGroup = "Not Applicable",
FileNameWithExtension = "",
SizeInMb = 10,
IsAutoGrowthEnabled = true,
MaxSizeLimitInMb = -1,
Path = ""
}
};
return databaseFiles.ToArray();
}
internal static UserInfo GetTestUserInfo(DatabaseUserType userType, string userName = null, string loginName = null)
{
return new UserInfo()