diff --git a/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/CreateDatabaseObjects.cs b/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/CreateDatabaseObjects.cs
index d894a272..e592acb8 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/CreateDatabaseObjects.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/CreateDatabaseObjects.cs
@@ -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
///
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
///
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
+ ///
+ /// The ID of the file
+ ///
+ public int ID
+ {
+ get { return this.currentState.id; }
+
+ set
+ {
+ this.currentState.id = value;
+ this.database.NotifyObservers();
+ }
+ }
+
///
/// The logical name of the file, without extension
///
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs
index 2cf96c7f..0a19ae5c 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs
@@ -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 displayRecoveryModels = new Dictionary();
private static readonly Dictionary displayPageVerifyOptions = new Dictionary();
private static readonly Dictionary displayRestrictAccessOptions = new Dictionary();
+ private static readonly ConcurrentDictionary displayFileTypes = new ConcurrentDictionary();
private static readonly Dictionary compatLevelEnums = new Dictionary();
private static readonly Dictionary containmentTypeEnums = new Dictionary();
private static readonly Dictionary recoveryModelEnums = new Dictionary();
+ private static readonly Dictionary fileTypesEnums = new Dictionary();
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() ? 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 fileIdsToRemove = new HashSet(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;
+ }
+
///
/// Get supported database collations for this server.
///
@@ -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();
}
+
+ ///
+ /// Get the file group names from the database fileGroup
+ ///
+ /// smo database prototype
+ /// database view info object
+ private void GetFileGroupNames(Database database, DatabaseViewInfo databaseViewInfo)
+ {
+ var rowDataGroups = new List();
+ var fileStreamDataGroups = new List();
+ 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();
+ }
+
///
/// Get supported database compatibility levels for this Azure server.
///
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseInfo.cs
index 28e39ebb..08d3c335 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseInfo.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseInfo.cs
@@ -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
{
///
@@ -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; }
+ }
+
}
\ No newline at end of file
diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseViewInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseViewInfo.cs
index f8a36751..1d81772a 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseViewInfo.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseViewInfo.cs
@@ -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; }
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Utility/DatabaseUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/Utility/DatabaseUtils.cs
index 41511fa4..d84d5eda 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Utility/DatabaseUtils.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Utility/DatabaseUtils.cs
@@ -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 illegalFilenameCharacters = new HashSet(new char[] { '\\', '/', ':', '*', '?', '"', '<', '>', '|' });
+
+
+ ///
+ /// Converts path to local path with DirectorySeparatorChar
+ ///
+ ///
+ /// path with local directory separator
+ public static string ConvertToLocalMachinePath(string filePath)
+ {
+ string pathSeparator = Path.DirectorySeparatorChar.ToString();
+ string localPath = filePath.Replace("/", pathSeparator);
+ localPath = localPath.Replace("\\", pathSeparator);
+ return localPath;
+ }
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs
index 4ba271a4..5580dbdb 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs
@@ -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");
}
}
}
+ ///
+ /// Adding, modifying and deleting database files
+ ///
+ ///
+ [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 = new List();
+
+ // 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 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()
{
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs
index bb8f938c..65bd577f 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs
@@ -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 databaseFiles = new List() {
+ 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()