mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 01:25:40 -05:00
Add object management handler for creating a database (#2071)
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// 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.Data.SqlClient;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
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;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests for the Database management component
|
||||
/// </summary>
|
||||
public class DatabaseHandlerTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test the basic Create Database method handler by creating, updating, and then deleting a database.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task DatabaseCreateAndUpdateTest_OnPrem()
|
||||
{
|
||||
await RunDatabaseCreateAndUpdateTest(TestServerType.OnPrem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test the Create Database method handler functionality against an Azure SQL database.
|
||||
/// </summary>
|
||||
[Test]
|
||||
[Ignore("Test is not supported in the integration test pipeline.")]
|
||||
public async Task DatabaseCreateAndUpdateTest_Azure()
|
||||
{
|
||||
await RunDatabaseCreateAndUpdateTest(TestServerType.Azure);
|
||||
}
|
||||
|
||||
private async Task RunDatabaseCreateAndUpdateTest(TestServerType serverType)
|
||||
{
|
||||
// setup, drop database if exists.
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", serverType: serverType);
|
||||
using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo))
|
||||
{
|
||||
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
|
||||
{
|
||||
// create and update
|
||||
var parametersForCreation = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Database, "", "");
|
||||
await ObjectManagementTestUtils.SaveObject(parametersForCreation, testDatabase);
|
||||
Assert.True(databaseExists(testDatabase.Name!, server), $"Expected database '{testDatabase.Name}' was not created succesfully");
|
||||
|
||||
var parametersForUpdate = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", false, SqlObjectType.Database, "", objUrn);
|
||||
await ObjectManagementTestUtils.SaveObject(parametersForUpdate, testDatabase);
|
||||
|
||||
// cleanup
|
||||
await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn, throwIfNotExist: true);
|
||||
Assert.False(databaseExists(testDatabase.Name!, server), $"Database '{testDatabase.Name}' was not dropped succesfully");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup using SMO if Drop didn't work
|
||||
dropDatabase(server, testDatabase.Name!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that the handler can export the Create Database operation to a SQL script.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task DatabaseScriptTest()
|
||||
{
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master");
|
||||
using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo))
|
||||
{
|
||||
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 parametersForCreation = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Database, "", "");
|
||||
var script = await ObjectManagementTestUtils.ScriptObject(parametersForCreation, testDatabase);
|
||||
Assert.True(!databaseExists(testDatabase.Name!, server), $"Database should not have been created for scripting operation");
|
||||
Assert.True(script.ToLowerInvariant().Contains($"create database [{testDatabase.Name!.ToLowerInvariant()}]"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup database on the off-chance that scripting somehow created the database
|
||||
dropDatabase(server, testDatabase.Name!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that the handler correctly throws an error when trying to drop a database that doesn't exist.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task DatabaseNotExistsErrorTest()
|
||||
{
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master");
|
||||
var testDatabase = ObjectManagementTestUtils.GetTestDatabaseInfo();
|
||||
var objUrn = ObjectManagementTestUtils.GetDatabaseURN(testDatabase.Name);
|
||||
try
|
||||
{
|
||||
await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn, throwIfNotExist: true);
|
||||
Assert.Fail("Did not throw an exception when trying to drop non-existent database.");
|
||||
}
|
||||
catch (FailedOperationException ex)
|
||||
{
|
||||
Assert.NotNull(ex.InnerException, "Expected inner exception was null.");
|
||||
Assert.True(ex.InnerException is MissingObjectException, $"Received unexpected inner exception type: {ex.InnerException!.GetType()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that the handler correctly throws an error when trying to create a database with the same name as an existing database.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task DatabaseAlreadyExistsErrorTest()
|
||||
{
|
||||
var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master");
|
||||
using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo))
|
||||
{
|
||||
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 parametersForCreation = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Database, "", "");
|
||||
await ObjectManagementTestUtils.SaveObject(parametersForCreation, testDatabase);
|
||||
Assert.True(databaseExists(testDatabase.Name!, server), $"Expected database '{testDatabase.Name}' was not created succesfully");
|
||||
|
||||
await ObjectManagementTestUtils.SaveObject(parametersForCreation, testDatabase);
|
||||
Assert.Fail("Did not throw an exception when trying to create database with same name.");
|
||||
}
|
||||
catch (FailedOperationException ex)
|
||||
{
|
||||
Assert.NotNull(ex.InnerException, "Expected inner exception was null.");
|
||||
Assert.True(ex.InnerException is ExecutionFailureException, $"Received unexpected inner exception type: {ex.InnerException!.GetType()}");
|
||||
Assert.NotNull(ex.InnerException.InnerException, "Expected inner-inner exception was null.");
|
||||
Assert.True(ex.InnerException.InnerException is SqlException, $"Received unexpected inner-inner exception type: {ex.InnerException.InnerException!.GetType()}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
dropDatabase(server, testDatabase.Name!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool databaseExists(string dbName, Server server)
|
||||
{
|
||||
server.Databases.Refresh();
|
||||
bool dbFound = false;
|
||||
foreach (Database db in server.Databases)
|
||||
{
|
||||
if (db.Name == dbName)
|
||||
{
|
||||
dbFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dbFound;
|
||||
}
|
||||
|
||||
private void dropDatabase(Server server, string databaseName)
|
||||
{
|
||||
server.Databases.Refresh();
|
||||
foreach (Database db in server.Databases)
|
||||
{
|
||||
if (db.Name == databaseName)
|
||||
{
|
||||
db.DropIfExists();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,11 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
|
||||
return string.Format(@"{0}\{1}", Environment.UserDomainName, Environment.UserName);
|
||||
}
|
||||
|
||||
internal static string GetDatabaseURN(string name)
|
||||
{
|
||||
return string.Format("Server/Database[@Name='{0}']", name);
|
||||
}
|
||||
|
||||
internal static string GetLoginURN(string name)
|
||||
{
|
||||
return string.Format("Server/Login[@Name='{0}']", name);
|
||||
@@ -56,6 +61,19 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
|
||||
return string.Format("Server/Credential[@Name = '{0}']", name);
|
||||
}
|
||||
|
||||
internal static DatabaseInfo GetTestDatabaseInfo()
|
||||
{
|
||||
return new DatabaseInfo()
|
||||
{
|
||||
Name = "TestDatabaseName_" + new Random().NextInt64(10000000, 90000000).ToString(),
|
||||
Owner = "<default>",
|
||||
CollationName = "SQL_Latin1_General_CP1_CI_AS",
|
||||
CompatibilityLevel = "SQL Server 2022 (160)",
|
||||
ContainmentType = "None",
|
||||
RecoveryModel = "Full"
|
||||
};
|
||||
}
|
||||
|
||||
internal static LoginInfo GetTestLoginInfo()
|
||||
{
|
||||
return new LoginInfo()
|
||||
@@ -134,7 +152,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
|
||||
await Service.HandleDisposeViewRequest(new DisposeViewRequestParams { ContextId = parameters.ContextId }, disposeViewRequestContext.Object);
|
||||
}
|
||||
|
||||
internal static async Task ScriptObject(InitializeViewRequestParams parameters, SqlObject obj)
|
||||
internal static async Task<string> ScriptObject(InitializeViewRequestParams parameters, SqlObject obj)
|
||||
{
|
||||
// Initialize the view
|
||||
var initViewRequestContext = new Mock<RequestContext<SqlObjectViewInfo>>();
|
||||
@@ -143,9 +161,12 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
|
||||
await Service.HandleInitializeViewRequest(parameters, initViewRequestContext.Object);
|
||||
|
||||
// Script the object
|
||||
string script = string.Empty;
|
||||
var scriptObjectRequestContext = new Mock<RequestContext<string>>();
|
||||
scriptObjectRequestContext.Setup(x => x.SendResult(It.IsAny<string>()))
|
||||
.Returns(Task.FromResult<string>(""));
|
||||
scriptObjectRequestContext
|
||||
.Setup(x => x.SendResult(It.IsAny<string>()))
|
||||
.Returns(Task.FromResult<string>(""))
|
||||
.Callback<string>(scriptResult => script = scriptResult);
|
||||
await Service.HandleScriptObjectRequest(new ScriptObjectRequestParams { ContextId = parameters.ContextId, Object = JToken.FromObject(obj) }, scriptObjectRequestContext.Object);
|
||||
|
||||
// Dispose the view
|
||||
@@ -153,14 +174,17 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
|
||||
disposeViewRequestContext.Setup(x => x.SendResult(It.IsAny<DisposeViewRequestResponse>()))
|
||||
.Returns(Task.FromResult<DisposeViewRequestResponse>(new DisposeViewRequestResponse()));
|
||||
await Service.HandleDisposeViewRequest(new DisposeViewRequestParams { ContextId = parameters.ContextId }, disposeViewRequestContext.Object);
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
internal static async Task DropObject(string connectionUri, string objectUrn)
|
||||
internal static async Task DropObject(string connectionUri, string objectUrn, bool throwIfNotExist = false)
|
||||
{
|
||||
var dropParams = new DropRequestParams
|
||||
{
|
||||
ConnectionUri = connectionUri,
|
||||
ObjectUrn = objectUrn
|
||||
ObjectUrn = objectUrn,
|
||||
ThrowIfNotExist = throwIfNotExist
|
||||
};
|
||||
|
||||
var dropRequestContext = new Mock<RequestContext<DropRequestResponse>>();
|
||||
|
||||
Reference in New Issue
Block a user