mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-28 09:35:37 -05:00
Create remote file browser service (#448)
* code refactoring * Add filebrowser service and tests * change dataset reference * Address pr comments * add more tests * address pr comments * address pr comments and added more tests * minor change * minor fix * Fix test break and add dataset result check
This commit is contained in:
@@ -14,6 +14,8 @@ using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.FileBrowser;
|
||||
using Microsoft.SqlTools.ServiceLayer.FileBrowser.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using Moq;
|
||||
@@ -77,7 +79,7 @@ CREATE CERTIFICATE {1} WITH SUBJECT = 'Backup Encryption Certificate'; ";
|
||||
DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
|
||||
SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
|
||||
|
||||
string backupPath = GetDefaultBackupPath(service, databaseName, helper.DataContainer, sqlConn);
|
||||
string backupPath = GetDefaultBackupFullPath(service, databaseName, helper.DataContainer, sqlConn);
|
||||
|
||||
BackupInfo backupInfo = CreateDefaultBackupInfo(databaseName,
|
||||
BackupType.Full,
|
||||
@@ -101,7 +103,7 @@ CREATE CERTIFICATE {1} WITH SUBJECT = 'Backup Encryption Certificate'; ";
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(databaseName);
|
||||
DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
|
||||
SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
|
||||
string backupPath = GetDefaultBackupPath(service, databaseName, helper.DataContainer, sqlConn);
|
||||
string backupPath = GetDefaultBackupFullPath(service, databaseName, helper.DataContainer, sqlConn);
|
||||
|
||||
BackupInfo backupInfo = CreateDefaultBackupInfo(databaseName,
|
||||
BackupType.Full,
|
||||
@@ -134,7 +136,7 @@ CREATE CERTIFICATE {1} WITH SUBJECT = 'Backup Encryption Certificate'; ";
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(databaseName);
|
||||
DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
|
||||
SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
|
||||
string backupPath = GetDefaultBackupPath(service, databaseName, helper.DataContainer, sqlConn);
|
||||
string backupPath = GetDefaultBackupFullPath(service, databaseName, helper.DataContainer, sqlConn);
|
||||
|
||||
string certificateName = CreateCertificate(testDb);
|
||||
string cleanupCertificateQuery = string.Format(CleanupCertificateQueryFormat, certificateName);
|
||||
@@ -186,7 +188,7 @@ CREATE CERTIFICATE {1} WITH SUBJECT = 'Backup Encryption Certificate'; ";
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(databaseName);
|
||||
DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
|
||||
SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
|
||||
string backupPath = GetDefaultBackupPath(service, databaseName, helper.DataContainer, sqlConn);
|
||||
string backupPath = GetDefaultBackupFullPath(service, databaseName, helper.DataContainer, sqlConn);
|
||||
|
||||
string certificateName = CreateCertificate(testDb);
|
||||
string cleanupCertificateQuery = string.Format(CleanupCertificateQueryFormat, certificateName);
|
||||
@@ -228,6 +230,86 @@ CREATE CERTIFICATE {1} WITH SUBJECT = 'Backup Encryption Certificate'; ";
|
||||
testDb.Cleanup();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void BackupFileBrowserTest()
|
||||
{
|
||||
string databaseName = "testfilebrowser_" + new Random().Next(10000000, 99999999);
|
||||
SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, databaseName);
|
||||
|
||||
// Initialize backup service
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(databaseName);
|
||||
DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
|
||||
SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
|
||||
DisasterRecoveryService disasterRecoveryService = new DisasterRecoveryService();
|
||||
BackupConfigInfo backupConfigInfo = disasterRecoveryService.GetBackupConfigInfo(helper.DataContainer, sqlConn, sqlConn.Database);
|
||||
|
||||
// Create backup file
|
||||
string backupPath = Path.Combine(backupConfigInfo.DefaultBackupFolder, databaseName + ".bak");
|
||||
string query = $"BACKUP DATABASE [{databaseName}] TO DISK = N'{backupPath}' WITH NOFORMAT, NOINIT, NAME = N'{databaseName}-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10";
|
||||
await TestServiceProvider.Instance.RunQueryAsync(TestServerType.OnPrem, "master", query);
|
||||
|
||||
FileBrowserService service = new FileBrowserService();
|
||||
|
||||
string[] backupFilters = new string[2] { "*.bak", "*.trn" };
|
||||
var openParams = new FileBrowserOpenParams
|
||||
{
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
ExpandPath = backupConfigInfo.DefaultBackupFolder,
|
||||
FileFilters = backupFilters
|
||||
};
|
||||
|
||||
var serviceHostMock = new Mock<IProtocolEndpoint>();
|
||||
service.ServiceHost = serviceHostMock.Object;
|
||||
|
||||
await service.RunFileBrowserOpenTask(openParams);
|
||||
|
||||
// Verify complete notification event was fired and the result
|
||||
serviceHostMock.Verify(x => x.SendEvent(FileBrowserOpenCompleteNotification.Type,
|
||||
It.Is<FileBrowserOpenCompleteParams>(p => p.Succeeded == true
|
||||
&& p.FileTree != null
|
||||
&& p.FileTree.RootNode != null
|
||||
&& p.FileTree.RootNode.Children != null
|
||||
&& p.FileTree.RootNode.Children.Count > 0
|
||||
&& p.FileTree.SelectedNode.FullPath == backupConfigInfo.DefaultBackupFolder
|
||||
&& p.FileTree.SelectedNode.Children.Count > 0
|
||||
&& ContainsFileInTheFolder(p.FileTree.SelectedNode, backupPath))),
|
||||
Times.Once());
|
||||
|
||||
var expandParams = new FileBrowserExpandParams
|
||||
{
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
ExpandPath = backupConfigInfo.DefaultBackupFolder
|
||||
};
|
||||
|
||||
// Expand the node in file browser
|
||||
await service.RunFileBrowserExpandTask(expandParams);
|
||||
|
||||
// Verify result
|
||||
serviceHostMock.Verify(x => x.SendEvent(FileBrowserExpandCompleteNotification.Type,
|
||||
It.Is<FileBrowserExpandCompleteParams>(p => p.Succeeded == true
|
||||
&& p.ExpandedNode.FullPath == backupConfigInfo.DefaultBackupFolder)),
|
||||
Times.Once());
|
||||
|
||||
var validateParams = new FileBrowserValidateParams
|
||||
{
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
ServiceType = FileValidationServiceConstants.Backup,
|
||||
SelectedFiles = new string[] { backupPath }
|
||||
};
|
||||
|
||||
// Validate selected files in the browser
|
||||
await service.RunFileBrowserValidateTask(validateParams);
|
||||
|
||||
// Verify complete notification event was fired and the result
|
||||
serviceHostMock.Verify(x => x.SendEvent(FileBrowserValidateCompleteNotification.Type, It.Is<FileBrowserValidateCompleteParams>(p => p.Succeeded == true)), Times.Once());
|
||||
|
||||
// Remove the backup file
|
||||
if (File.Exists(backupPath))
|
||||
{
|
||||
File.Delete(backupPath);
|
||||
}
|
||||
}
|
||||
|
||||
#region private methods
|
||||
|
||||
private string CreateCertificate(SqlTestDb testDb)
|
||||
@@ -258,7 +340,7 @@ CREATE CERTIFICATE {1} WITH SUBJECT = 'Backup Encryption Certificate'; ";
|
||||
return backupInfo;
|
||||
}
|
||||
|
||||
private string GetDefaultBackupPath(DisasterRecoveryService service, string databaseName, CDataContainer dataContainer, SqlConnection sqlConn)
|
||||
private string GetDefaultBackupFullPath(DisasterRecoveryService service, string databaseName, CDataContainer dataContainer, SqlConnection sqlConn)
|
||||
{
|
||||
BackupConfigInfo backupConfigInfo = service.GetBackupConfigInfo(dataContainer, sqlConn, sqlConn.Database);
|
||||
return Path.Combine(backupConfigInfo.DefaultBackupFolder, databaseName + ".bak");
|
||||
@@ -287,6 +369,17 @@ CREATE CERTIFICATE {1} WITH SUBJECT = 'Backup Encryption Certificate'; ";
|
||||
}
|
||||
}
|
||||
|
||||
private bool ContainsFileInTheFolder(FileTreeNode folderNode, string filePath)
|
||||
{
|
||||
foreach (FileTreeNode node in folderNode.Children)
|
||||
{
|
||||
if (node.FullPath == filePath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Data.SqlClient;
|
||||
using System.IO;
|
||||
using Microsoft.SqlTools.ServiceLayer.Admin;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery;
|
||||
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.FileBrowser;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||
using Xunit;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery
|
||||
{
|
||||
/// <summary>
|
||||
/// Integration tests for disaster recovery file validator
|
||||
/// </summary>
|
||||
public class DisasterRecoveryFileValidatorTests
|
||||
{
|
||||
[Fact]
|
||||
public void ValidateDefaultBackupFullFilePath()
|
||||
{
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo("master");
|
||||
DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
|
||||
SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
|
||||
string backupPath = Path.Combine(GetDefaultBackupFolderPath(helper.DataContainer, sqlConn), "master.bak");
|
||||
|
||||
string message;
|
||||
bool result = DisasterRecoveryFileValidator.ValidatePaths(new FileBrowserValidateEventArgs
|
||||
{
|
||||
ServiceType = FileValidationServiceConstants.Backup,
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
FilePaths = new string[] { backupPath }
|
||||
}, out message);
|
||||
|
||||
Assert.True(result);
|
||||
Assert.Empty(message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateDefaultBackupFolderPath()
|
||||
{
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo("master");
|
||||
DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
|
||||
SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo);
|
||||
string backupPath = GetDefaultBackupFolderPath(helper.DataContainer, sqlConn);
|
||||
|
||||
bool isFolder;
|
||||
bool result = DisasterRecoveryFileValidator.IsPathExisting(sqlConn, backupPath, out isFolder);
|
||||
Assert.True(isFolder);
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidatorShouldReturnFalseForInvalidPath()
|
||||
{
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo("master");
|
||||
DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true);
|
||||
|
||||
string message;
|
||||
bool result = DisasterRecoveryFileValidator.ValidatePaths(new FileBrowserValidateEventArgs
|
||||
{
|
||||
ServiceType = FileValidationServiceConstants.Backup,
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
FilePaths = new string[] { Guid.NewGuid().ToString() }
|
||||
}, out message);
|
||||
|
||||
Assert.False(result);
|
||||
Assert.True(!string.IsNullOrEmpty(message));
|
||||
}
|
||||
|
||||
#region private methods
|
||||
|
||||
private string GetDefaultBackupFolderPath(CDataContainer dataContainer, SqlConnection sqlConn)
|
||||
{
|
||||
DisasterRecoveryService service = new DisasterRecoveryService();
|
||||
BackupConfigInfo backupConfigInfo = service.GetBackupConfigInfo(dataContainer, sqlConn, sqlConn.Database);
|
||||
return backupConfigInfo.DefaultBackupFolder;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.FileBrowser;
|
||||
using Microsoft.SqlTools.ServiceLayer.FileBrowser.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.FileBrowser
|
||||
{
|
||||
/// <summary>
|
||||
/// File browser service tests
|
||||
/// </summary>
|
||||
public class FileBrowserServiceTests
|
||||
{
|
||||
#region Request handle tests
|
||||
|
||||
[Fact]
|
||||
public async void HandleFileBrowserOpenRequestTest()
|
||||
{
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo();
|
||||
FileBrowserService service = new FileBrowserService();
|
||||
var openRequestContext = new Mock<RequestContext<bool>>();
|
||||
openRequestContext.Setup(x => x.SendResult(It.IsAny<bool>()))
|
||||
.Returns(Task.FromResult(new object()));
|
||||
|
||||
var openParams = new FileBrowserOpenParams
|
||||
{
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
ExpandPath = "",
|
||||
FileFilters = new string[1] {"*"}
|
||||
};
|
||||
|
||||
await service.HandleFileBrowserOpenRequest(openParams, openRequestContext.Object);
|
||||
openRequestContext.Verify(x => x.SendResult(It.Is<bool>(p => p == true)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void HandleFileBrowserExpandRequestTest()
|
||||
{
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo();
|
||||
FileBrowserService service = new FileBrowserService();
|
||||
var requestContext = new Mock<RequestContext<bool>>();
|
||||
requestContext.Setup(x => x.SendResult(It.IsAny<bool>())).Returns(Task.FromResult(new object()));
|
||||
|
||||
var inputParams = new FileBrowserExpandParams
|
||||
{
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
ExpandPath = ""
|
||||
};
|
||||
|
||||
await service.HandleFileBrowserExpandRequest(inputParams, requestContext.Object);
|
||||
requestContext.Verify(x => x.SendResult(It.Is<bool>(p => p == true)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void HandleFileBrowserValidateRequestTest()
|
||||
{
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo();
|
||||
FileBrowserService service = new FileBrowserService();
|
||||
var requestContext = new Mock<RequestContext<bool>>();
|
||||
requestContext.Setup(x => x.SendResult(It.IsAny<bool>())).Returns(Task.FromResult(new object()));
|
||||
|
||||
var inputParams = new FileBrowserValidateParams
|
||||
{
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
ServiceType = ""
|
||||
};
|
||||
|
||||
await service.HandleFileBrowserValidateRequest(inputParams, requestContext.Object);
|
||||
requestContext.Verify(x => x.SendResult(It.Is<bool>(p => p == true)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void HandleFileBrowserCloseRequestTest()
|
||||
{
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo();
|
||||
FileBrowserService service = new FileBrowserService();
|
||||
var requestContext = new Mock<RequestContext<FileBrowserCloseResponse>>();
|
||||
requestContext.Setup(x => x.SendResult(It.IsAny<FileBrowserCloseResponse>())).Returns(Task.FromResult(new object()));
|
||||
|
||||
var inputParams = new FileBrowserCloseParams
|
||||
{
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri
|
||||
};
|
||||
|
||||
await service.HandleFileBrowserCloseRequest(inputParams, requestContext.Object);
|
||||
|
||||
// Result should return false since it's trying to close a filebrowser that was never opened
|
||||
requestContext.Verify(x => x.SendResult(It.Is<FileBrowserCloseResponse>(p => p.Succeeded == false)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Fact]
|
||||
public async void OpenFileBrowserTest()
|
||||
{
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo();
|
||||
FileBrowserService service = new FileBrowserService();
|
||||
|
||||
var openParams = new FileBrowserOpenParams
|
||||
{
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
ExpandPath = "",
|
||||
FileFilters = new string[1] { "*" }
|
||||
};
|
||||
|
||||
var serviceHostMock = new Mock<IProtocolEndpoint>();
|
||||
service.ServiceHost = serviceHostMock.Object;
|
||||
await service.RunFileBrowserOpenTask(openParams);
|
||||
|
||||
// Verify complete notification event was fired and the result
|
||||
serviceHostMock.Verify(x => x.SendEvent(FileBrowserOpenCompleteNotification.Type,
|
||||
It.Is<FileBrowserOpenCompleteParams>(p => p.Succeeded == true
|
||||
&& p.FileTree != null
|
||||
&& p.FileTree.RootNode != null
|
||||
&& p.FileTree.RootNode.Children != null
|
||||
&& p.FileTree.RootNode.Children.Count > 0)),
|
||||
Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void ValidateSelectedFilesWithNullValidatorTest()
|
||||
{
|
||||
var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo();
|
||||
FileBrowserService service = new FileBrowserService();
|
||||
|
||||
var validateParams = new FileBrowserValidateParams
|
||||
{
|
||||
// Do not pass any service so that the file validator will be null
|
||||
ServiceType = "",
|
||||
OwnerUri = liveConnection.ConnectionInfo.OwnerUri,
|
||||
SelectedFiles = new string[] { "" }
|
||||
};
|
||||
|
||||
var serviceHostMock = new Mock<IProtocolEndpoint>();
|
||||
service.ServiceHost = serviceHostMock.Object;
|
||||
|
||||
// Validate files with null file validator
|
||||
await service.RunFileBrowserValidateTask(validateParams);
|
||||
|
||||
// Verify complete notification event was fired and the result
|
||||
serviceHostMock.Verify(x => x.SendEvent(FileBrowserValidateCompleteNotification.Type, It.Is<FileBrowserValidateCompleteParams>(p => p.Succeeded == true)), Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void InvalidFileValidationTest()
|
||||
{
|
||||
FileBrowserService service = new FileBrowserService();
|
||||
service.RegisterValidatePathsCallback("TestService", ValidatePaths);
|
||||
|
||||
var validateParams = new FileBrowserValidateParams
|
||||
{
|
||||
// Do not pass any service so that the file validator will be null
|
||||
ServiceType = "TestService",
|
||||
SelectedFiles = new string[] { "" }
|
||||
};
|
||||
|
||||
var serviceHostMock = new Mock<IProtocolEndpoint>();
|
||||
service.ServiceHost = serviceHostMock.Object;
|
||||
|
||||
// Validate files with null file validator
|
||||
await service.RunFileBrowserValidateTask(validateParams);
|
||||
|
||||
// Verify complete notification event was fired and the result
|
||||
serviceHostMock.Verify(x => x.SendEvent(FileBrowserValidateCompleteNotification.Type, It.Is<FileBrowserValidateCompleteParams>(p => p.Succeeded == false)), Times.Once());
|
||||
}
|
||||
|
||||
#region private methods
|
||||
|
||||
private bool ValidatePaths(FileBrowserValidateEventArgs eventArgs, out string message)
|
||||
{
|
||||
message = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user