diff --git a/.gitignore b/.gitignore index 344650f9..ba8f8bd3 100644 --- a/.gitignore +++ b/.gitignore @@ -289,4 +289,6 @@ metadata # Stuff from cake /artifacts/ /.tools/ -/.dotnet/ \ No newline at end of file +/.dotnet/ +/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Properties/launchSettings.json +/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Properties/launchSettings.json diff --git a/sqltoolsservice.sln b/sqltoolsservice.sln index 06934702..4cbdec69 100644 --- a/sqltoolsservice.sln +++ b/sqltoolsservice.sln @@ -59,6 +59,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.SqlTools.ServiceL EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.SqlTools.ServiceLayer.TestDriver.Tests", "test\Microsoft.SqlTools.ServiceLayer.TestDriver.Tests\Microsoft.SqlTools.ServiceLayer.TestDriver.Tests.xproj", "{E7CF630E-E084-4DA4-BF69-F61BF0A8F5BE}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.SqlTools.ServiceLayer.TestEnvConfig", "test\Microsoft.SqlTools.ServiceLayer.TestEnvConfig\Microsoft.SqlTools.ServiceLayer.TestEnvConfig.xproj", "{6CF2E945-C7D1-44B5-9E28-ADDD09E3E983}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -108,6 +110,12 @@ Global {E7CF630E-E084-4DA4-BF69-F61BF0A8F5BE}.Integration|Any CPU.Build.0 = Debug|Any CPU {E7CF630E-E084-4DA4-BF69-F61BF0A8F5BE}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7CF630E-E084-4DA4-BF69-F61BF0A8F5BE}.Release|Any CPU.Build.0 = Release|Any CPU + {6CF2E945-C7D1-44B5-9E28-ADDD09E3E983}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CF2E945-C7D1-44B5-9E28-ADDD09E3E983}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CF2E945-C7D1-44B5-9E28-ADDD09E3E983}.Integration|Any CPU.ActiveCfg = Debug|Any CPU + {6CF2E945-C7D1-44B5-9E28-ADDD09E3E983}.Integration|Any CPU.Build.0 = Debug|Any CPU + {6CF2E945-C7D1-44B5-9E28-ADDD09E3E983}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CF2E945-C7D1-44B5-9E28-ADDD09E3E983}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -122,5 +130,6 @@ Global {08AF0209-D598-47BB-9DFD-FC9E74C0FE56} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {B6F4BECE-82EE-4AB6-99AC-108AEE466274} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {E7CF630E-E084-4DA4-BF69-F61BF0A8F5BE} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} + {6CF2E945-C7D1-44B5-9E28-ADDD09E3E983} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} EndGlobalSection -EndGlobal \ No newline at end of file +EndGlobal diff --git a/src/Microsoft.SqlTools.ServiceLayer/Credentials/CredentialService.cs b/src/Microsoft.SqlTools.ServiceLayer/Credentials/CredentialService.cs index 5802a34d..6b558f8c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Credentials/CredentialService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Credentials/CredentialService.cs @@ -105,18 +105,23 @@ namespace Microsoft.SqlTools.ServiceLayer.Credentials { return await Task.Factory.StartNew(() => { - Credential.ValidateForLookup(credential); - - Credential result = Credential.Copy(credential); - string password; - if (credStore.TryGetPassword(credential.CredentialId, out password)) - { - result.Password = password; - } - return result; + return ReadCredential(credential); }); } + public Credential ReadCredential(Credential credential) + { + Credential.ValidateForLookup(credential); + + Credential result = Credential.Copy(credential); + string password; + if (credStore.TryGetPassword(credential.CredentialId, out password)) + { + result.Password = password; + } + return result; + } + public async Task HandleSaveCredentialRequest(Credential credential, RequestContext requestContext) { Func> doSave = () => @@ -126,15 +131,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Credentials await HandleRequest(doSave, requestContext, "HandleSaveCredentialRequest"); } - private async Task SaveCredentialAsync(Credential credential) + public async Task SaveCredentialAsync(Credential credential) { return await Task.Factory.StartNew(() => { - Credential.ValidateForSave(credential); - return credStore.Save(credential); + return SaveCredential(credential); }); } + public bool SaveCredential(Credential credential) + { + Credential.ValidateForSave(credential); + return credStore.Save(credential); + } + public async Task HandleDeleteCredentialRequest(Credential credential, RequestContext requestContext) { Func> doDelete = () => diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ConnectionServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ConnectionServiceTests.cs index b78a2770..4138a80e 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ConnectionServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ConnectionServiceTests.cs @@ -23,14 +23,14 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection public class ConnectionServiceTests { [Fact] - public async Task RunningMultipleQueriesCreatesOnlyOneConnection() + public void RunningMultipleQueriesCreatesOnlyOneConnection() { // Connect/disconnect twice to ensure reconnection can occur ConnectionService service = ConnectionService.Instance; service.OwnerToConnectionMap.Clear(); for (int i = 0; i < 2; i++) { - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); ConnectionInfo connectionInfo = result.ConnectionInfo; string uri = connectionInfo.OwnerUri; @@ -65,11 +65,11 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection } [Fact] - public async Task DatabaseChangesAffectAllConnections() + public void DatabaseChangesAffectAllConnections() { // If we make a connection to a live database ConnectionService service = ConnectionService.Instance; - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); ConnectionInfo connectionInfo = result.ConnectionInfo; ConnectionDetails details = connectionInfo.ConnectionDetails; string uri = connectionInfo.OwnerUri; diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs index 6abd18d5..2016b97e 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs @@ -33,8 +33,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// public class ReliableConnectionTests { - private TestConnectionProfileService connectionProfileService = new TestConnectionProfileService(); - internal class TestDataTransferErrorDetectionStrategy : DataTransferErrorDetectionStrategy { public bool InvokeCanRetrySqlException(SqlException exception) @@ -235,9 +233,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// /// Helper method to create an integrated auth connection builder for testing. /// - private async Task CreateTestConnectionStringBuilder() + private SqlConnectionStringBuilder CreateTestConnectionStringBuilder() { - ConnectParams connectParams = await this.connectionProfileService.GetConnectionParametersAsync(); + ConnectParams connectParams = TestConnectionProfileService.Instance.GetConnectionParameters(TestServerType.OnPrem); SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder(); csb.DataSource = connectParams.Connection.ServerName; csb.IntegratedSecurity = connectParams.Connection.AuthenticationType == AuthenticationType.Integrated.ToString(); @@ -259,9 +257,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// /// Helper method to create an integrated auth reliable connection for testing. /// - private async Task CreateTestConnection() + private DbConnection CreateTestConnection() { - SqlConnectionStringBuilder csb = await CreateTestConnectionStringBuilder(); + SqlConnectionStringBuilder csb = CreateTestConnectionStringBuilder(); RetryPolicy connectionRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy(); RetryPolicy commandRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy(); @@ -274,10 +272,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// Test ReliableConnectionHelper.GetDefaultDatabaseFilePath() /// [Fact] - public async Task TestGetDefaultDatabaseFilePath() + public void TestGetDefaultDatabaseFilePath() { - var connectionBuilder = await CreateTestConnectionStringBuilder(); + var connectionBuilder = CreateTestConnectionStringBuilder(); Assert.NotNull(connectionBuilder); string filePath = string.Empty; @@ -301,16 +299,16 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// Test ReliableConnectionHelper.GetServerVersion() /// [Fact] - public async Task TestGetServerVersion() + public void TestGetServerVersion() { - using (var connection = await CreateTestConnection()) + using (var connection = CreateTestConnection()) { Assert.NotNull(connection); connection.Open(); ReliableConnectionHelper.ServerInfo serverInfo = ReliableConnectionHelper.GetServerVersion(connection); ReliableConnectionHelper.ServerInfo serverInfo2; - using (var connection2 = await CreateTestConnection()) + using (var connection2 = CreateTestConnection()) { connection2.Open(); serverInfo2 = ReliableConnectionHelper.GetServerVersion(connection); @@ -346,9 +344,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// Tests ReliableConnectionHelper.IsDatabaseReadonly() /// [Fact] - public async Task TestIsDatabaseReadonly() + public void TestIsDatabaseReadonly() { - var connectionBuilder = await CreateTestConnectionStringBuilder(); + var connectionBuilder = CreateTestConnectionStringBuilder(); Assert.NotNull(connectionBuilder); bool isReadOnly = ReliableConnectionHelper.IsDatabaseReadonly(connectionBuilder); @@ -368,9 +366,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// Verify ANSI_NULL and QUOTED_IDENTIFIER settings can be set and retrieved for a session /// [Fact] - public async Task VerifyAnsiNullAndQuotedIdentifierSettingsReplayed() + public void VerifyAnsiNullAndQuotedIdentifierSettingsReplayed() { - using (ReliableSqlConnection conn = (ReliableSqlConnection) ReliableConnectionHelper.OpenConnection(await CreateTestConnectionStringBuilder(), useRetry: true)) + using (ReliableSqlConnection conn = (ReliableSqlConnection) ReliableConnectionHelper.OpenConnection(CreateTestConnectionStringBuilder(), useRetry: true)) { VerifySessionSettings(conn, true); VerifySessionSettings(conn, false); @@ -477,9 +475,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// ReliableConnectionHelper.IsCloud() should be false for a local server /// [Fact] - public async Task TestIsCloudIsFalseForLocalServer() + public void TestIsCloudIsFalseForLocalServer() { - using (var connection = await CreateTestConnection()) + using (var connection = CreateTestConnection()) { Assert.NotNull(connection); @@ -492,9 +490,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// Tests that ReliableConnectionHelper.OpenConnection() opens a connection if it is closed /// [Fact] - public async Task TestOpenConnectionOpensConnection() + public void TestOpenConnectionOpensConnection() { - using (var connection = await CreateTestConnection()) + using (var connection = CreateTestConnection()) { Assert.NotNull(connection); @@ -508,10 +506,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// Tests that ReliableConnectionHelper.ExecuteNonQuery() runs successfully /// [Fact] - public async Task TestExecuteNonQuery() + public void TestExecuteNonQuery() { var result = ReliableConnectionHelper.ExecuteNonQuery( - await CreateTestConnectionStringBuilder(), + CreateTestConnectionStringBuilder(), "SET NOCOUNT ON; SET NOCOUNT OFF;", ReliableConnectionHelper.SetCommandTimeout, null, @@ -524,10 +522,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection /// Test that TryGetServerVersion() gets server information /// [Fact] - public async Task TestTryGetServerVersion() + public void TestTryGetServerVersion() { ReliableConnectionHelper.ServerInfo info = null; - var connBuilder = await CreateTestConnectionStringBuilder(); + var connBuilder = CreateTestConnectionStringBuilder(); Assert.True(ReliableConnectionHelper.TryGetServerVersion(connBuilder.ConnectionString, out info)); Assert.NotNull(info); @@ -681,9 +679,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection } [Fact] - public async Task ReliableConnectionHelperTest() + public void ReliableConnectionHelperTest() { - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); ConnectionInfo connInfo = result.ConnectionInfo; DbConnection connection = connInfo.ConnectionTypeToConnectionMap[ConnectionType.Default]; @@ -726,9 +724,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection } [Fact] - public async Task InitReliableSqlConnectionTest() + public void InitReliableSqlConnectionTest() { - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); ConnectionInfo connInfo = result.ConnectionInfo; DbConnection dbConnection; connInfo.TryGetConnection(ConnectionType.Default, out dbConnection); diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/LanguageServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/LanguageServiceTests.cs index 6a29b635..31747992 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/LanguageServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/LanguageServiceTests.cs @@ -3,6 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using System.Threading; using System.Threading.Tasks; using Microsoft.SqlServer.Management.SqlParser.Parser; using Microsoft.SqlTools.ServiceLayer.Connection; @@ -21,7 +22,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer /// public class LanguageServiceTests { - private async static Task GetLiveAutoCompleteTestObjects() + private TestConnectionResult GetLiveAutoCompleteTestObjects() { var textDocument = new TextDocumentPosition { @@ -33,7 +34,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer } }; - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); result.TextDocumentPosition = textDocument; return result; } @@ -46,7 +47,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer { try { - TestServiceProvider.InitializeTestServices(); + TestServiceProvider serviceProvider = TestServiceProvider.Instance; + Assert.NotNull(serviceProvider); } catch (System.ArgumentException) { @@ -62,9 +64,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer /// Test the service initialization code path and verify nothing throws /// [Fact] - public async Task PrepopulateCommonMetadata() + public void PrepopulateCommonMetadata() { - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); var connInfo = result.ConnectionInfo; ScriptParseInfo scriptInfo = new ScriptParseInfo { IsConnected = true }; @@ -76,9 +78,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer // SMO connected metadata provider. Since we don't want a live DB dependency // in the CI unit tests this scenario is currently disabled. [Fact] - public async Task AutoCompleteFindCompletions() + public void AutoCompleteFindCompletions() { - var result = await GetLiveAutoCompleteTestObjects(); + var result = GetLiveAutoCompleteTestObjects(); result.TextDocumentPosition.Position.Character = 7; result.ScriptFile.Contents = "select "; @@ -102,7 +104,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer { // When we make a connection to a live database Hosting.ServiceHost.SendEventIgnoreExceptions = true; - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); // And we place the cursor after a function that should prompt for signature help string queryWithFunction = "EXEC sys.fn_isrolemember "; @@ -123,6 +125,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer // If the SQL has already been parsed var service = LanguageService.Instance; await service.UpdateLanguageServiceOnConnection(result.ConnectionInfo); + Thread.Sleep(2000); // We should get back a non-null ScriptParseInfo ScriptParseInfo parseInfo = service.GetScriptParseInfo(result.ScriptFile.ClientFilePath); diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/PeekDefinitionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/PeekDefinitionTests.cs index e619e657..3452e41b 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/PeekDefinitionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/LanguageServer/PeekDefinitionTests.cs @@ -5,22 +5,17 @@ using System; using System.IO; using System.Threading; -using System.Threading.Tasks; using Microsoft.SqlServer.Management.Common; -using Microsoft.SqlServer.Management.SqlParser.Binder; using Microsoft.SqlTools.ServiceLayer.Connection; -using Microsoft.SqlServer.Management.SqlParser.MetadataProvider; -using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.LanguageServices; -using Microsoft.SqlTools.ServiceLayer.LanguageServices.Completion; -using Microsoft.SqlTools.ServiceLayer.SqlContext; -using Microsoft.SqlTools.ServiceLayer.Workspace; using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; using Microsoft.SqlTools.Test.Utility; using Moq; using Xunit; using Location = Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Location; using Microsoft.SqlServer.Management.SqlParser.Intellisense; +using Microsoft.SqlTools.ServiceLayer.Test.Common; +using static Microsoft.SqlTools.ServiceLayer.LanguageServices.PeekDefinition; namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices { @@ -30,15 +25,66 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices public class PeekDefinitionTests { private const string OwnerUri = "testFile1"; + private const string ReturnTableFunctionName = "pd_returnTable"; + private const string ReturnTableTableFunctionQuery = @" +CREATE FUNCTION [dbo].[" + ReturnTableFunctionName + @"] () +RETURNS TABLE +AS +RETURN +( + select * from master.dbo.spt_monitor +); + +GO"; + + private const string AddTwoFunctionName = "pd_addTwo"; + private const string AddTwoFunctionQuery = @" +CREATE FUNCTION[dbo].[" + AddTwoFunctionName + @"](@number int) +RETURNS int +AS +BEGIN + RETURN @number + 2; + END; + +GO"; + + + private const string SsnTypeName = "pd_ssn"; + private const string SsnTypeQuery = @" +CREATE TYPE [dbo].[" + SsnTypeName + @"] FROM [varchar](11) NOT NULL +GO"; + + private const string LocationTableTypeName = "pd_locationTableType"; + + private const string LocationTableTypeQuery = @" +CREATE TYPE [dbo].[" + LocationTableTypeName + @"] AS TABLE( + [LocationName] [varchar](50) NULL, + [CostRate] [int] NULL +) +GO"; + + private const string TestTableSynonymName = "pd_testTable"; + private const string TestTableSynonymQuery = @" +CREATE SYNONYM [dbo].[pd_testTable] FOR master.dbo.spt_monitor +GO"; + + private const string TableValuedFunctionTypeName = "TableValuedFunction"; + private const string ScalarValuedFunctionTypeName = "ScalarValuedFunction"; + private const string UserDefinedDataTypeTypeName = "UserDefinedDataType"; + private const string UserDefinedTableTypeTypeName = "UserDefinedTableType"; + private const string SynonymTypeName = "Synonym"; + private const string StoredProcedureTypeName = "StoredProcedure"; + private const string ViewTypeName = "View"; + private const string TableTypeName = "Table"; /// /// Test get definition for a table object with active connection /// [Fact] - public async Task GetValidTableDefinitionTest() + public void GetValidTableDefinitionTest() { // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -57,10 +103,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a invalid table object with active connection /// [Fact] - public async Task GetTableDefinitionInvalidObjectTest() + public void GetTableDefinitionInvalidObjectTest() { // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -77,10 +123,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a valid table object with schema and active connection /// [Fact] - public async Task GetTableDefinitionWithSchemaTest() + public void GetTableDefinitionWithSchemaTest() { // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -99,7 +145,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test GetDefinition with an unsupported type(schema - dbo). Expect a error result. /// [Fact] - public async Task GetUnsupportedDefinitionErrorTest() + public void GetUnsupportedDefinitionErrorTest() { TextDocumentPosition textDocument = new TextDocumentPosition { @@ -112,7 +158,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices } }; - TestConnectionResult connectionResult = await TestObjects.InitLiveConnectionInfo(); + TestConnectionResult connectionResult = TestObjects.InitLiveConnectionInfo(); connectionResult.ScriptFile.Contents = "select * from dbo.func ()"; var languageService = new LanguageService(); ScriptParseInfo scriptInfo = new ScriptParseInfo { IsConnected = true }; @@ -130,9 +176,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Get Definition for a object with no definition. Expect a error result /// [Fact] - public async Task GetDefinitionWithNoResultsFoundError() + public void GetDefinitionWithNoResultsFoundError() { - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -155,7 +201,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test GetDefinition with a forced timeout. Expect a error result. /// [Fact] - public async Task GetDefinitionTimeoutTest() + public void GetDefinitionTimeoutTest() { // Given a binding queue that will automatically time out var languageService = new LanguageService(); @@ -175,10 +221,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices It.IsAny())) .Callback, Func, int?, int?>( (key, bindOperation, timeoutOperation, t1, t2) => - { - timeoutResult = (DefinitionResult) timeoutOperation((IBindingContext)null); - itemMock.Object.Result = timeoutResult; - }) + { + timeoutResult = (DefinitionResult)timeoutOperation((IBindingContext)null); + itemMock.Object.Result = timeoutResult; + }) .Returns(() => itemMock.Object); TextDocumentPosition textDocument = new TextDocumentPosition @@ -190,7 +236,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices Character = 20 } }; - TestConnectionResult connectionResult = await TestObjects.InitLiveConnectionInfo(); + TestConnectionResult connectionResult = TestObjects.InitLiveConnectionInfo(); ScriptFile scriptFile = connectionResult.ScriptFile; ConnectionInfo connInfo = connectionResult.ConnectionInfo; scriptFile.Contents = "select * from dbo.func ()"; @@ -212,9 +258,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a view object with active connection /// [Fact] - public async Task GetValidViewDefinitionTest() + public void GetValidViewDefinitionTest() { - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -231,10 +277,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for an invalid view object with no schema name and with active connection /// [Fact] - public async Task GetViewDefinitionInvalidObjectTest() + public void GetViewDefinitionInvalidObjectTest() { // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -250,10 +296,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a stored procedure object with active connection /// [Fact] - public async Task GetStoredProcedureDefinitionTest() + public void GetStoredProcedureDefinitionTest() { // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -271,10 +317,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a stored procedure object that does not exist with active connection /// [Fact] - public async Task GetStoredProcedureDefinitionFailureTest() + public void GetStoredProcedureDefinitionFailureTest() { // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -290,10 +336,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a stored procedure object with active connection and no schema /// [Fact] - public async Task GetStoredProcedureDefinitionWithoutSchemaTest() + public void GetStoredProcedureDefinitionWithoutSchemaTest() { // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -310,19 +356,76 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a scalar valued function object with active connection and explicit schema name. Expect non-null locations /// [Fact] - public async Task GetScalarValuedFunctionDefinitionWithSchemaNameSuccessTest() + public void GetScalarValuedFunctionDefinitionWithSchemaNameSuccessTest() + { + ExecuteAndValidatePeekTest(AddTwoFunctionQuery, AddTwoFunctionName, ScalarValuedFunctionTypeName); + } + + private void ExecuteAndValidatePeekTest(string query, string objectName, string objectType, string schemaName = "dbo") + { + if (!string.IsNullOrEmpty(query)) + { + using (SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, query)) + { + ValidatePeekTest(testDb.DatabaseName, objectName, objectType, schemaName, true); + } + } + else + { + ValidatePeekTest(null, objectName, objectType, schemaName, false); + } + } + + private void ValidatePeekTest(string databaseName, string objectName, string objectType, string schemaName, bool shouldReturnValidResult) { // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(databaseName); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_addTwo"; - string schemaName = "dbo"; - string objectType = "FUNCTION"; - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetScalarValuedFunctionScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); + ScriptGetter sqlScriptGetter = null; + switch (objectType) + { + case SynonymTypeName: + sqlScriptGetter = peekDefinition.GetSynonymScripts; + return; + case ScalarValuedFunctionTypeName: + sqlScriptGetter = peekDefinition.GetScalarValuedFunctionScripts; + objectType = "Function"; + return; + case TableValuedFunctionTypeName: + sqlScriptGetter = peekDefinition.GetTableValuedFunctionScripts; + objectType = "Function"; + return; + case TableTypeName: + sqlScriptGetter = peekDefinition.GetTableScripts; + return; + case ViewTypeName: + sqlScriptGetter = peekDefinition.GetViewScripts; + return; + case StoredProcedureTypeName: + sqlScriptGetter = peekDefinition.GetStoredProcedureScripts; + return; + case UserDefinedDataTypeTypeName: + sqlScriptGetter = peekDefinition.GetUserDefinedDataTypeScripts; + objectType = "Type"; + return; + case UserDefinedTableTypeTypeName: + sqlScriptGetter = peekDefinition.GetUserDefinedTableTypeScripts; + objectType = "Type"; + return; + } + + Location[] locations = peekDefinition.GetSqlObjectDefinition(sqlScriptGetter, objectName, schemaName, objectType); + if (shouldReturnValidResult) + { + Assert.NotNull(locations); + } + else + { + Assert.Null(locations); + } Cleanup(locations); } @@ -330,98 +433,52 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a table valued function object with active connection and explicit schema name. Expect non-null locations /// [Fact] - public async Task GetTableValuedFunctionDefinitionWithSchemaNameSuccessTest() + public void GetTableValuedFunctionDefinitionWithSchemaNameSuccessTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_returnTable"; - string schemaName = "dbo"; - string objectType = "FUNCTION"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableValuedFunctionScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); - Cleanup(locations); + ExecuteAndValidatePeekTest(ReturnTableTableFunctionQuery, ReturnTableFunctionName, TableValuedFunctionTypeName); } /// /// Test get definition for a scalar valued function object that doesn't exist with active connection. Expect null locations /// [Fact] - public async Task GetScalarValuedFunctionDefinitionWithNonExistentFailureTest() + public void GetScalarValuedFunctionDefinitionWithNonExistentFailureTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); string objectName = "doesNotExist"; string schemaName = "dbo"; - string objectType = "FUNCTION"; + string objectType = ScalarValuedFunctionTypeName; - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetScalarValuedFunctionScripts, objectName, schemaName, objectType); - Assert.Null(locations); + ExecuteAndValidatePeekTest(null, objectName, objectType, schemaName); } /// /// Test get definition for a table valued function object that doesn't exist with active connection. Expect null locations /// [Fact] - public async Task GetTableValuedFunctionDefinitionWithNonExistentObjectFailureTest() + public void GetTableValuedFunctionDefinitionWithNonExistentObjectFailureTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); string objectName = "doesNotExist"; string schemaName = "dbo"; - string objectType = "FUNCTION"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableValuedFunctionScripts, objectName, schemaName, objectType); - Assert.Null(locations); + string objectType = TableValuedFunctionTypeName; + ExecuteAndValidatePeekTest(null, objectName, objectType, schemaName); } /// /// Test get definition for a scalar valued function object with active connection. Expect non-null locations /// [Fact] - public async Task GetScalarValuedFunctionDefinitionWithoutSchemaNameSuccessTest() + public void GetScalarValuedFunctionDefinitionWithoutSchemaNameSuccessTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_addTwo"; - string schemaName = null; - string objectType = "FUNCTION"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetScalarValuedFunctionScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); - Cleanup(locations); + ExecuteAndValidatePeekTest(AddTwoFunctionQuery, AddTwoFunctionName, ScalarValuedFunctionTypeName, null); } /// /// Test get definition for a table valued function object with active connection. Expect non-null locations /// [Fact] - public async Task GetTableValuedFunctionDefinitionWithoutSchemaNameSuccessTest() + public void GetTableValuedFunctionDefinitionWithoutSchemaNameSuccessTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_returnTable"; - string schemaName = null; - string objectType = "FUNCTION"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetTableValuedFunctionScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); - Cleanup(locations); + ExecuteAndValidatePeekTest(ReturnTableTableFunctionQuery, ReturnTableFunctionName, TableValuedFunctionTypeName, null); } @@ -429,138 +486,70 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a user defined data type object with active connection and explicit schema name. Expect non-null locations /// [Fact] - public async Task GetUserDefinedDataTypeDefinitionWithSchemaNameSuccessTest() + public void GetUserDefinedDataTypeDefinitionWithSchemaNameSuccessTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_ssn"; - string schemaName = "dbo"; - string objectType = "Type"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedDataTypeScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); - Cleanup(locations); + ExecuteAndValidatePeekTest(SsnTypeQuery, SsnTypeName, UserDefinedDataTypeTypeName); } /// /// Test get definition for a user defined data type object with active connection. Expect non-null locations /// [Fact] - public async Task GetUserDefinedDataTypeDefinitionWithoutSchemaNameSuccessTest() + public void GetUserDefinedDataTypeDefinitionWithoutSchemaNameSuccessTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_ssn"; - string schemaName = null; - string objectType = "Type"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedDataTypeScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); - Cleanup(locations); + ExecuteAndValidatePeekTest(SsnTypeQuery, SsnTypeName, UserDefinedDataTypeTypeName, null); } /// /// Test get definition for a user defined data type object that doesn't exist with active connection. Expect null locations /// [Fact] - public async Task GetUserDefinedDataTypeDefinitionWithNonExistentFailureTest() + public void GetUserDefinedDataTypeDefinitionWithNonExistentFailureTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); string objectName = "doesNotExist"; string schemaName = "dbo"; - string objectType = "Type"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedDataTypeScripts, objectName, schemaName, objectType); - Assert.Null(locations); + string objectType = UserDefinedDataTypeTypeName; + ExecuteAndValidatePeekTest(null, objectName, objectType, schemaName); } /// /// Test get definition for a user defined table type object with active connection and explicit schema name. Expect non-null locations /// [Fact] - public async Task GetUserDefinedTableTypeDefinitionWithSchemaNameSuccessTest() + public void GetUserDefinedTableTypeDefinitionWithSchemaNameSuccessTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_locationTableType"; - string schemaName = "dbo"; - string objectType = "Type"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedTableTypeScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); - Cleanup(locations); + ExecuteAndValidatePeekTest(LocationTableTypeQuery, LocationTableTypeName, UserDefinedTableTypeTypeName); } /// /// Test get definition for a user defined table type object with active connection. Expect non-null locations /// [Fact] - public async Task GetUserDefinedTableTypeDefinitionWithoutSchemaNameSuccessTest() + public void GetUserDefinedTableTypeDefinitionWithoutSchemaNameSuccessTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_locationTableType"; - string schemaName = null; - string objectType = "Type"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedTableTypeScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); - Cleanup(locations); + ExecuteAndValidatePeekTest(LocationTableTypeQuery, LocationTableTypeName, UserDefinedTableTypeTypeName, null); } /// /// Test get definition for a user defined table type object that doesn't exist with active connection. Expect null locations /// [Fact] - public async Task GetUserDefinedTableTypeDefinitionWithNonExistentFailureTest() + public void GetUserDefinedTableTypeDefinitionWithNonExistentFailureTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); string objectName = "doesNotExist"; string schemaName = "dbo"; - string objectType = "Type"; + string objectType = UserDefinedTableTypeTypeName; + ExecuteAndValidatePeekTest(null, objectName, objectType, schemaName); - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetUserDefinedTableTypeScripts, objectName, schemaName, objectType); - Assert.Null(locations); } /// /// Test get definition for a synonym object with active connection and explicit schema name. Expect non-null locations /// [Fact] - public async Task GetSynonymDefinitionWithSchemaNameSuccessTest() + public void GetSynonymDefinitionWithSchemaNameSuccessTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_testTable"; - string schemaName = "dbo"; - string objectType = "Synonym"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetSynonymScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); - Cleanup(locations); + ExecuteAndValidatePeekTest(TestTableSynonymQuery, TestTableSynonymName, SynonymTypeName); } @@ -568,39 +557,21 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Test get definition for a Synonym object with active connection. Expect non-null locations /// [Fact] - public async Task GetSynonymDefinitionWithoutSchemaNameSuccessTest() + public void GetSynonymDefinitionWithoutSchemaNameSuccessTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); - string objectName = "pd_testTable"; - string schemaName = null; - string objectType = "Synonym"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetSynonymScripts, objectName, schemaName, objectType); - Assert.NotNull(locations); - Cleanup(locations); + ExecuteAndValidatePeekTest(TestTableSynonymQuery, TestTableSynonymName, SynonymTypeName, null); } /// /// Test get definition for a Synonym object that doesn't exist with active connection. Expect null locations /// [Fact] - public async Task GetSynonymDefinitionWithNonExistentFailureTest() + public void GetSynonymDefinitionWithNonExistentFailureTest() { - // Get live connectionInfo and serverConnection - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); - ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); - - PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); string objectName = "doesNotExist"; string schemaName = "dbo"; string objectType = "Synonym"; - - Location[] locations = peekDefinition.GetSqlObjectDefinition(peekDefinition.GetSynonymScripts, objectName, schemaName, objectType); - Assert.Null(locations); + ExecuteAndValidatePeekTest(null, objectName, objectType, schemaName); } /// @@ -608,9 +579,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Expect a non-null result with location /// [Fact] - public async Task GetDefinitionUsingDeclarationTypeWithValidObjectTest() + public void GetDefinitionUsingDeclarationTypeWithValidObjectTest() { - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -630,9 +601,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Expect a non-null result with location /// [Fact] - public async Task GetDefinitionUsingDeclarationTypeWithNonexistentObjectTest() + public void GetDefinitionUsingDeclarationTypeWithNonexistentObjectTest() { - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -649,9 +620,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Expect a non-null result with location /// [Fact] - public async Task GetDefinitionUsingQuickInfoTextWithValidObjectTest() + public void GetDefinitionUsingQuickInfoTextWithValidObjectTest() { - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -672,9 +643,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices /// Expect a non-null result with location /// [Fact] - public async Task GetDefinitionUsingQuickInfoTextWithNonexistentObjectTest() + public void GetDefinitionUsingQuickInfoTextWithNonexistentObjectTest() { - ConnectionInfo connInfo = await TestObjects.InitLiveConnectionInfoForDefinition(); + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfoForDefinition(); ServerConnection serverConnection = TestObjects.InitLiveServerConnectionForDefinition(connInfo); PeekDefinition peekDefinition = new PeekDefinition(serverConnection, connInfo); @@ -699,7 +670,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServices { File.Delete(fileUri.LocalPath); } - catch(Exception) + catch (Exception) { } diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/QueryExecution/DataStorage/StorageDataReaderTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/QueryExecution/DataStorage/StorageDataReaderTests.cs index 45c38aa6..5d33f0cf 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/QueryExecution/DataStorage/StorageDataReaderTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/QueryExecution/DataStorage/StorageDataReaderTests.cs @@ -16,9 +16,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.QueryExecution.DataSt { public class StorageDataReaderTests { - private async Task GetTestStorageDataReader(string query) + private StorageDataReader GetTestStorageDataReader(string query) { - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); DbConnection connection; result.ConnectionInfo.TryGetConnection(ConnectionType.Default, out connection); @@ -33,9 +33,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.QueryExecution.DataSt /// Validate GetBytesWithMaxCapacity /// [Fact] - public async Task GetBytesWithMaxCapacityTest() + public void GetBytesWithMaxCapacityTest() { - var storageReader = await GetTestStorageDataReader( + var storageReader = GetTestStorageDataReader( "SELECT CAST([name] as TEXT) As TextName FROM sys.all_columns"); DbDataReader reader = storageReader.DbDataReader; @@ -50,9 +50,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.QueryExecution.DataSt /// Validate GetCharsWithMaxCapacity /// [Fact] - public async Task GetCharsWithMaxCapacityTest() + public void GetCharsWithMaxCapacityTest() { - var storageReader = await GetTestStorageDataReader( + var storageReader = GetTestStorageDataReader( "SELECT name FROM sys.all_columns"); DbDataReader reader = storageReader.DbDataReader; @@ -72,9 +72,9 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.QueryExecution.DataSt /// Validate GetXmlWithMaxCapacity /// [Fact] - public async Task GetXmlWithMaxCapacityTest() + public void GetXmlWithMaxCapacityTest() { - var storageReader = await GetTestStorageDataReader( + var storageReader = GetTestStorageDataReader( "SELECT CAST('Test XML context' AS XML) As XmlColumn"); DbDataReader reader = storageReader.DbDataReader; diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/QueryExecution/ExecuteTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/QueryExecution/ExecuteTests.cs index 5b25a9d5..d037b019 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/QueryExecution/ExecuteTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/QueryExecution/ExecuteTests.cs @@ -17,12 +17,12 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.QueryExecution public class ExecuteTests { [Fact] - public async Task RollbackTransactionFailsWithoutBeginTransaction() + public void RollbackTransactionFailsWithoutBeginTransaction() { const string refactorText = "ROLLBACK TRANSACTION"; // Given a connection to a live database - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); ConnectionInfo connInfo = result.ConnectionInfo; var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary()); @@ -36,13 +36,13 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.QueryExecution } [Fact] - public async Task TransactionsSucceedAcrossQueries() + public void TransactionsSucceedAcrossQueries() { const string beginText = "BEGIN TRANSACTION"; const string rollbackText = "ROLLBACK TRANSACTION"; // Given a connection to a live database - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); ConnectionInfo connInfo = result.ConnectionInfo; var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary()); @@ -55,13 +55,13 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.QueryExecution } [Fact] - public async Task TempTablesPersistAcrossQueries() + public void TempTablesPersistAcrossQueries() { const string createTempText = "CREATE TABLE #someTempTable (id int)"; const string insertTempText = "INSERT INTO #someTempTable VALUES(1)"; // Given a connection to a live database - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); ConnectionInfo connInfo = result.ConnectionInfo; var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary()); @@ -74,14 +74,14 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.QueryExecution } [Fact] - public async Task DatabaseChangesWhenCallingUseDatabase() + public void DatabaseChangesWhenCallingUseDatabase() { const string master = "master"; const string tempdb = "tempdb"; const string useQuery = "USE {0}"; // Given a connection to a live database - var result = await TestObjects.InitLiveConnectionInfo(); + var result = TestObjects.InitLiveConnectionInfo(); ConnectionInfo connInfo = result.ConnectionInfo; DbConnection connection; connInfo.TryGetConnection(ConnectionType.Default, out connection); diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/CreateTestDbAttribute.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/CreateTestDbAttribute.cs index cb3ca53f..fc645979 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/CreateTestDbAttribute.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/CreateTestDbAttribute.cs @@ -28,8 +28,7 @@ namespace Microsoft.SqlTools.ServiceLayer.PerfTests public TestServerType ServerType { get; set; } public override void Before(MethodInfo methodUnderTest) { - Task task = SqlTestDb.CreateNew(ServerType, doNotCleanupDb: true, databaseName: Common.PerfTestDatabaseName, query: Scripts.CreateDatabaseObjectsQuery); - task.Wait(); + SqlTestDb.CreateNew(ServerType, doNotCleanupDb: true, databaseName: Common.PerfTestDatabaseName, query: Scripts.CreateDatabaseObjectsQuery); } public override void After(MethodInfo methodUnderTest) diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/Common.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/Common.cs index 03457cad..43e1e532 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/Common.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/Common.cs @@ -7,6 +7,9 @@ namespace Microsoft.SqlTools.ServiceLayer.PerfTests { public class Common { - public const string PerfTestDatabaseName = "SQLToolsCrossPlatPerfTestDb"; + /// + /// The name of the test db to be used for performance tests. Prefix "keep" is used so the db doesn't get deleted by cleanup jobs + /// + public const string PerfTestDatabaseName = "keep_SQLToolsCrossPlatPerfTestDb"; } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/ConnectionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/ConnectionTests.cs index 7b0dfbdf..81462d69 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/ConnectionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/ConnectionTests.cs @@ -41,7 +41,7 @@ namespace Microsoft.SqlTools.ServiceLayer.PerfTests Thread.Sleep(500); var connected = await testService.CalculateRunTime(async () => { - var connectParams = await testService.GetConnectionParametersAsync(serverType, Common.PerfTestDatabaseName); + var connectParams = testService.GetConnectionParameters(serverType, Common.PerfTestDatabaseName); return await testService.Connect(queryTempFile.FilePath, connectParams); }, true); Assert.True(connected, "Connection was not successful"); @@ -76,7 +76,7 @@ namespace Microsoft.SqlTools.ServiceLayer.PerfTests Thread.Sleep(500); var connected = await testService.CalculateRunTime(async () => { - var connectParams = await testService.GetConnectionParametersAsync(serverType, Common.PerfTestDatabaseName); + var connectParams = testService.GetConnectionParameters(serverType, Common.PerfTestDatabaseName); return await testService.Connect(queryTempFile.FilePath, connectParams); }, true); Assert.True(connected, "Connection was not successful"); diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/IntellisenseTests.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/IntellisenseTests.cs index b5173643..8b4a7617 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/IntellisenseTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/IntellisenseTests.cs @@ -54,7 +54,7 @@ namespace Microsoft.SqlTools.ServiceLayer.PerfTests public async Task DiagnosticsTests() { TestServerType serverType = TestServerType.OnPrem; - await SqlTestDb.CreateNew(serverType, doNotCleanupDb: true, databaseName: Common.PerfTestDatabaseName, query: Scripts.CreateDatabaseObjectsQuery); + SqlTestDb.CreateNew(serverType, doNotCleanupDb: true, databaseName: Common.PerfTestDatabaseName, query: Scripts.CreateDatabaseObjectsQuery); using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) @@ -165,7 +165,7 @@ namespace Microsoft.SqlTools.ServiceLayer.PerfTests } [Fact] - [CreateTestDb(TestServerType.Azure)] + [CreateTestDb(TestServerType.OnPrem)] public async Task BindingCacheColdOnPremComplexQuery() { TestServerType serverType = TestServerType.OnPrem; diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/ConnectionSetting.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/ConnectionSetting.cs index f94c9c7b..81fd1edb 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/ConnectionSetting.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/ConnectionSetting.cs @@ -3,8 +3,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using Newtonsoft.Json; @@ -16,9 +16,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common public class ConnectionSetting { [JsonProperty("mssql.connections")] - public List Connections { get; set; } + public List Connections { get; set; } - public ConnectionProfile GetConnectionProfile(string profileName, string serverName) + public InstanceInfo GetConnectionProfile(string profileName, string serverName) { if (!string.IsNullOrEmpty(profileName) && Connections != null) { @@ -33,52 +33,94 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common } /// - /// The model to deserializing the connections inside settings.json + /// The model to de-serializing the connections inside settings.json /// - public class ConnectionProfile + public class InstanceInfo { - public const string CRED_PREFIX = "Microsoft.SqlTools"; - public const string CRED_SEPARATOR = "|"; - public const string CRED_SERVER_PREFIX = "server:"; - public const string CRED_DB_PREFIX = "db:"; - public const string CRED_USER_PREFIX = "user:"; - public const string CRED_ITEMTYPE_PREFIX = "itemtype:"; + public InstanceInfo(string versionKey) + { + ConnectTimeout = 15; + VersionKey = versionKey; + } [JsonProperty("server")] public string ServerName { get; set; } + + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string Database { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string User { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string Password { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string ProfileName { get; set; } public TestServerType ServerType { get; set; } public AuthenticationType AuthenticationType { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public string RemoteSharePath { get; set; } - public string formatCredentialId(string itemType = "Profile") + public int ConnectTimeout { get; set; } + + public string VersionKey { get; set; } + + [JsonIgnore] + public string ConnectTimeoutAsString { - if (!string.IsNullOrEmpty(ServerName)) + get { return ConnectTimeout.ToString(); } + set { - List cred = new List(); - cred.Add(CRED_PREFIX); - AddToList(itemType, CRED_ITEMTYPE_PREFIX, cred); - AddToList(ServerName, CRED_SERVER_PREFIX, cred); - AddToList(Database, CRED_DB_PREFIX, cred); - AddToList(User, CRED_USER_PREFIX, cred); - return string.Join(CRED_SEPARATOR, cred.ToArray()); - } - return null; - } - private void AddToList(string item, string prefix, List list) - { - if (!string.IsNullOrEmpty(item)) - { - list.Add(string.Format(CultureInfo.InvariantCulture, "{0}{1}", prefix, item)); + int temp; + if (int.TryParse(value, out temp)) + { + this.ConnectTimeout = temp; + } + else + { + this.ConnectTimeout = 15; + } } } + + [JsonIgnore] + public string MachineName + { + get + { + string serverName = ServerName; + int index = ServerName.IndexOf('\\'); + if (index > 0) + { + serverName = ServerName.Substring(0, index); + } + if (StringComparer.OrdinalIgnoreCase.Compare("(local)", serverName) == 0 + || StringComparer.OrdinalIgnoreCase.Compare(".", serverName) == 0) + { + serverName = Environment.MachineName; + } + return serverName; + } + } + + [JsonIgnore] + public string InstanceName + { + get + { + string name = null; + int index = ServerName.IndexOf('\\'); + if (index > 0) + { + name = ServerName.Substring(index + 1); + } + return name; + } + } + } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/Constants.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/Constants.cs new file mode 100644 index 00000000..968c9d05 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/Constants.cs @@ -0,0 +1,12 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.SqlTools.ServiceLayer.Test.Common +{ + public static class Constants + { + public const string SqlConectionSettingsEnvironmentVariable = "SettingsFileName"; + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/FileUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/FileUtils.cs new file mode 100644 index 00000000..da44ccb4 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/FileUtils.cs @@ -0,0 +1,71 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.SqlTools.ServiceLayer.Test.Common +{ + public static class FileUtils + { + public static string UserRootFolder + { + get + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Environment.GetEnvironmentVariable("USERPROFILE"); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return Environment.GetEnvironmentVariable("HOME"); + } + else + { + return Environment.GetEnvironmentVariable("HOME"); + } + } + } + + public static string VsCodeSettingsFileName + { + get + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Environment.GetEnvironmentVariable("APPDATA") + @"\Code\User\settings.json"; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return Environment.GetEnvironmentVariable("HOME") + @"/Library/Application Support/Code/User/settings.json"; + } + else + { + return Environment.GetEnvironmentVariable("HOME") + @"/.config/Code/User/settings.json"; + } + } + } + + public static string TestServerNamesDefaultFileName + { + get + { + string testServerFileName = "testServerNames.json"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Environment.GetEnvironmentVariable("APPDATA") + @"\\" + testServerFileName; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return Environment.GetEnvironmentVariable("HOME") + @"/" + testServerFileName; + } + else + { + return Environment.GetEnvironmentVariable("HOME") + @"/" + testServerFileName; + } + } + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/SqlTestDb.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/SqlTestDb.cs index 1c6c268f..6b831814 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/SqlTestDb.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/SqlTestDb.cs @@ -5,7 +5,6 @@ using System; using System.Globalization; -using System.Threading.Tasks; namespace Microsoft.SqlTools.ServiceLayer.Test.Common { @@ -25,19 +24,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common /// /// Create the test db if not already exists /// - public static async Task CreateNew(TestServerType serverType, bool doNotCleanupDb = false, string databaseName = null, string query = null) + public static SqlTestDb CreateNew(TestServerType serverType, bool doNotCleanupDb = false, string databaseName = null, string query = null) { SqlTestDb testDb = new SqlTestDb(); - using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) + + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) { databaseName = databaseName ?? GetUniqueDBName(""); string createDatabaseQuery = Scripts.CreateDatabaseQuery.Replace("#DatabaseName#", databaseName); - await testService.RunQuery(serverType, MasterDatabaseName, createDatabaseQuery); - Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Verified test database '{0}' is created", databaseName)); + TestServiceProvider.Instance.RunQuery(serverType, MasterDatabaseName, createDatabaseQuery); + Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Test database '{0}' is created", databaseName)); if (!string.IsNullOrEmpty(query)) { - await testService.RunQuery(serverType, databaseName, query); - Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Verified test database '{0}' SQL types are created", databaseName)); + TestServiceProvider.Instance.RunQuery(serverType, databaseName, query); + Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "Test database '{0}' SQL types are created", databaseName)); } testDb.DatabaseName = databaseName; testDb.ServerType = serverType; @@ -47,6 +47,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common return testDb; } + /// + /// Create the test db if not already exists + /// + public static SqlTestDb CreateNew(TestServerType serverType, string query = null) + { + return CreateNew(serverType, false, null, query); + } + /// /// Returns a mangled name that unique based on Prefix + Machine + Process /// @@ -59,18 +67,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common namePrefix, safeMachineName, Guid.NewGuid().ToString().Replace("-", "")); } - public void Dispose() + public void Cleanup() { - if(!DoNotCleanupDb) + if (!DoNotCleanupDb) { - using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) { - string dropDatabaseQuery = string.Format(CultureInfo.InvariantCulture, - (ServerType == TestServerType.Azure ? Scripts.DropDatabaseIfExistAzure : Scripts.DropDatabaseIfExist), DatabaseName); - testService.RunQuery(ServerType, MasterDatabaseName, dropDatabaseQuery).Wait(); + string dropDatabaseQuery = string.Format(CultureInfo.InvariantCulture, + (ServerType == TestServerType.Azure ? Scripts.DropDatabaseIfExistAzure : Scripts.DropDatabaseIfExist), DatabaseName); + TestServiceProvider.Instance.RunQuery(ServerType, MasterDatabaseName, dropDatabaseQuery); } } } + + public void Dispose() + { + Cleanup(); + } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConfigPersistenceHelper.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConfigPersistenceHelper.cs new file mode 100644 index 00000000..b790dfb9 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConfigPersistenceHelper.cs @@ -0,0 +1,158 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Newtonsoft.Json; + +namespace Microsoft.SqlTools.ServiceLayer.Test.Common +{ + public sealed class TestConfigPersistenceHelper + { + private static string DefaultSettingFileName = Path.Combine(FileUtils.UserRootFolder, "sqlConnectionSettings.json"); + private static TestCredentialService credentialService = TestCredentialService.Instance; + + public static bool Write(IEnumerable instances) + { + try + { + ConnectionSetting connectionSetting = new Common.ConnectionSetting() + { + Connections = new List(instances) + }; + + //Remove the passwords and store in credential store and then store the copy without passwords in the file + foreach (var instance in connectionSetting.Connections) + { + if (!string.IsNullOrEmpty(instance.Password)) + { + + if (!credentialService.SaveCredential(instance)) + { + Console.WriteLine("Failed to store the password for server: " + instance.ServerName); + } + + instance.Password = null; //Make sure the password is not stored in sqlConnectionSettings.json + instance.AuthenticationType = AuthenticationType.SqlLogin; + } + else + { + instance.AuthenticationType = AuthenticationType.Integrated; + } + } + + Console.WriteLine("The SQL connection instances will be written to " + DefaultSettingFileName); + string jsonContent = JsonConvert.SerializeObject(connectionSetting); + + if (File.Exists(DefaultSettingFileName)) + { + Console.WriteLine("The file " + DefaultSettingFileName + " already exists and it will be overwritten."); + + } + File.WriteAllText(DefaultSettingFileName, jsonContent); + Environment.SetEnvironmentVariable(Constants.SqlConectionSettingsEnvironmentVariable, DefaultSettingFileName); + return true; + } + catch (Exception ex) + { + Console.WriteLine("Failed to store the instances.", ex); + return false; + } + } + + internal static IEnumerable InitTestServerNames() + { + try + { + string testServerNamesFileContent = GetTestServerNamesFileContent(); + if (!string.IsNullOrEmpty(testServerNamesFileContent)) + { + return Newtonsoft.Json.JsonConvert.DeserializeObject>(testServerNamesFileContent); + } + else + { + return Enumerable.Empty(); + } + } + catch (Exception ex) + { + return Enumerable.Empty(); + } + } + + internal static ConnectionSetting InitSetting() + { + try + { + string settingsFileContents = GetSettingFileContent(); + ConnectionSetting setting = Newtonsoft.Json.JsonConvert.DeserializeObject(settingsFileContents); + Console.WriteLine("Connection Settings loaded successfully"); + return setting; + } + catch (Exception ex) + { + Console.WriteLine("Failed to load the connection settings. error: " + ex.Message); + return new ConnectionSetting(); + } + } + + /// + /// Get the location of testServerNames.json. Returns the value of environment variable 'SettingsFileName' and if it's empty returns + /// the location of vs code testServerNames.json + /// + /// + private static string GetTestServerNamesFileContent() + { + var testServerNameFilePath = Environment.GetEnvironmentVariable("TestServerNamesFile"); + + if (string.IsNullOrEmpty(testServerNameFilePath)) + { + testServerNameFilePath = FileUtils.TestServerNamesDefaultFileName; + } + string testServerNamesFileContent = string.IsNullOrEmpty(testServerNameFilePath) ? string.Empty : File.ReadAllText(testServerNameFilePath); + + return testServerNamesFileContent; + } + + /// + /// Get the location of setting.json. Returns the value of environment variable 'SettingsFileName' and if it's empty returns + /// the location of vs code settings.json + /// + /// + private static string GetSettingFileContent() + { + var settingsFileName = Environment.GetEnvironmentVariable(Constants.SqlConectionSettingsEnvironmentVariable); + + if (string.IsNullOrEmpty(settingsFileName)) + { + if (File.Exists(DefaultSettingFileName)) + { + settingsFileName = DefaultSettingFileName; + Console.WriteLine(DefaultSettingFileName + " SQL connection instances are not configured. Will try to get connections from VS code settings.json"); + } + else + { + //If the SQL connection settings is not set use the VS code one + settingsFileName = FileUtils.VsCodeSettingsFileName; + } + } + + if (string.IsNullOrEmpty(settingsFileName)) + { + Console.WriteLine("SQL connection instances are not configured. Run dotnet run Microsoft.SqlTools.ServiceLayer.TestEnvConfig from the command line to configure"); + } + else + { + Console.WriteLine("SQL Connection settings are loaded from: " + settingsFileName); + } + + string settingsFileContents = string.IsNullOrEmpty(settingsFileName) ? string.Empty : File.ReadAllText(settingsFileName); + + return settingsFileContents; + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConnectionProfileService.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConnectionProfileService.cs index 13a10b7c..7f0ffc2e 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConnectionProfileService.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestConnectionProfileService.cs @@ -4,136 +4,179 @@ // using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading.Tasks; using Microsoft.SqlTools.ServiceLayer.Connection.Contracts; -using Microsoft.SqlTools.ServiceLayer.Credentials; using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts; -using Microsoft.SqlTools.ServiceLayer.TestDriver.Driver; using Xunit; namespace Microsoft.SqlTools.ServiceLayer.Test.Common { /// /// Service to get connection profiles from the configured settings - /// to get the credentials, test driver will be used if available otherwise the credential service will be called directly + /// credential service will be used to get the credentials /// public class TestConnectionProfileService { - private readonly IEnumerable _testServers = TestServersLazyInstance.Value; - private readonly ConnectionSetting _setting = ConnectionSettingLazyInstance.Value; - private static string _connectionSettingsFilename; - private static ConcurrentDictionary _connectionProfilesCache = new ConcurrentDictionary(); + private static Dictionary connectionProfilesCache = new Dictionary(); + private static TestConnectionProfileService instance = new TestConnectionProfileService(); - public TestConnectionProfileService(ServiceTestDriver driver) + public const string DefaultSql2005InstanceKey = "defaultSql2005"; + public const string DefaultSql2008InstanceKey = "defaultSql2008"; + public const string DefaultSql2011InstanceKey = "defaultSql2011"; + public const string DefaultSql2012Pcu1InstanceKey = "defaultSql2012pcu1"; + public const string DefaultSql2014InstanceKey = "defaultSql2014"; + public const string DefaultSqlAzureInstanceKey = "defaultSqlAzure"; + public const string DefaultServerlessInstanceKey = "defaultServerless"; + public const string DefaultSqlPdwInstanceKey = "defaultSqlPdw"; + public const string DefaultSqlAzureV12InstanceKey = "defaultSqlAzureV12"; + public const string DefaultSql2016InstanceKey = "defaultSql2016"; + public const string DefaultSqlvNextInstanceKey = "defaultSqlvNext"; + + private TestConnectionProfileService() { - Driver = driver; + LoadInstanceSettings(); } - public TestConnectionProfileService() + public static TestConnectionProfileService Instance { + get + { + return instance; + } } - private static readonly Lazy> TestServersLazyInstance = - new Lazy>(InitTestServerNames); - - private static readonly Lazy ConnectionSettingLazyInstance = - new Lazy(InitSetting); - - private ServiceTestDriver Driver { get; set; } - - private ConnectionProfile GetConnectionProfile(TestServerType serverType) + public static InstanceInfo DefaultSql2012Pcu1 { - ConnectionProfile connectionProfile = null; + get { return GetInstance(DefaultSql2012Pcu1InstanceKey); } + } - //Get the server or profile name for given type to use for database connection - TestServerIdentity serverIdentity = _testServers != null ? _testServers.FirstOrDefault(x => x.ServerType == serverType) : null; + public static InstanceInfo DefaultSql2014 + { + get { return GetInstance(DefaultSql2014InstanceKey); } + } - //Search for the connection info in settings.json - if (serverIdentity == null) - { - //If not server name found, try to find the connection info for given type - connectionProfile = _setting != null && _setting.Connections != null ? _setting.Connections.FirstOrDefault(x => x.ServerType == serverType) : null; - if (connectionProfile == null && _setting != null && _setting.Connections != null) - { - Console.WriteLine(string.Format(CultureInfo.InvariantCulture, - "Cannot find any connection profile for server type '{0}'. " - + " Make sure the serverType attribute is set in {1}. " + - "Or run CreateTestServerNameSettings.cmd to create a template for the server names", serverType, _connectionSettingsFilename)); - } - } - else - { - //Find the connection info for specific server name or profile name - connectionProfile = _setting != null ? _setting.GetConnectionProfile(serverIdentity.ProfileName, serverIdentity.ServerName) : null; + public static InstanceInfo DefaultSqlAzure + { + get { return GetInstance(DefaultSqlAzureInstanceKey); } + } - } + public static InstanceInfo DefaultSqlAzureV12 + { + get { return GetInstance(DefaultSqlAzureV12InstanceKey); } + } - Assert.True(connectionProfile != null, "Cannot find any connection profile for server type " + serverType.ToString()); - - return connectionProfile; + public static InstanceInfo DefaultSql2016 + { + get { return GetInstance(DefaultSql2016InstanceKey); } + } + + public static InstanceInfo DefaultSqlvNext + { + get { return GetInstance(DefaultSqlvNextInstanceKey); } } /// - /// Returns database connection parameters for given server type + /// Returns the SQL connection info for given version key /// - public async Task GetConnectionParametersAsync(TestServerType serverType = TestServerType.OnPrem, string databaseName = null) + public static InstanceInfo GetInstance(string key) { - ConnectionProfile connectionProfile; - if (!_connectionProfilesCache.TryGetValue(serverType, out connectionProfile)) - { - connectionProfile = GetConnectionProfile(serverType); + InstanceInfo instanceInfo; + connectionProfilesCache.TryGetValue(key, out instanceInfo); + Assert.True(instanceInfo != null, string.Format(CultureInfo.InvariantCulture, "Cannot find any instance for version key: {0}", key)); + return instanceInfo; + } - if (connectionProfile != null) - { - //If the password is empty, get the credential using the service - if (connectionProfile.AuthenticationType == AuthenticationType.SqlLogin && string.IsNullOrEmpty(connectionProfile.Password)) - { - Credential credential = await ReadCredentialAsync(connectionProfile.formatCredentialId()); - connectionProfile.Password = credential.Password; - } - _connectionProfilesCache.GetOrAdd(serverType, connectionProfile); - } - } - - if (connectionProfile != null) + public ConnectParams GetConnectionParameters(string key = DefaultSql2016InstanceKey, string databaseName = null) + { + InstanceInfo instanceInfo = GetInstance(key); + if (instanceInfo != null) { - ConnectParams connenctParam = CreateConnectParams(connectionProfile, serverType, databaseName); - + ConnectParams connenctParam = CreateConnectParams(instanceInfo, key, databaseName); + return connenctParam; } return null; } /// - /// Request a Read Credential for given credential id + /// Returns database connection parameters for given server type /// - private async Task ReadCredentialAsync(string credentialId) + public ConnectParams GetConnectionParameters(TestServerType serverType = TestServerType.OnPrem, string databaseName = null) { - var credentialParams = new Credential(); - credentialParams.CredentialId = credentialId; + string key = ConvertServerTypeToVersionKey(serverType); + return GetConnectionParameters(key, databaseName); + } - ServiceTestDriver driver = Driver; - if (driver == null) + /// + /// Forces the InstanceManager to load/reload it's instance list + /// + internal void LoadInstanceSettings() + { + try { - TestServiceProvider.InitializeTestServices(); - return await CredentialService.Instance.ReadCredentialAsync(credentialParams); + connectionProfilesCache = new Dictionary(); + IEnumerable testServers = TestConfigPersistenceHelper.InitTestServerNames(); + ConnectionSetting settings = TestConfigPersistenceHelper.InitSetting(); + if (settings == null) + { + Console.WriteLine("DBTestInstance not configured. Run 'dotnet run Microsoft.SqlTools.ServiceLayer.TestEnvConfig from the command line to configure"); + } + + if (testServers != null && settings != null) + { + foreach (var serverIdentity in testServers) + { + var instance = settings != null ? settings.GetConnectionProfile(serverIdentity.ProfileName, serverIdentity.ServerName) : null; + if (instance.ServerType == TestServerType.None) + { + instance.ServerType = serverIdentity.ServerType; + AddInstance(instance); + } + } + } + if (settings != null) + { + foreach (var instance in settings.Connections) + { + AddInstance(instance); + } + } } - else + catch(Exception ex) { - return await Driver.SendRequest(ReadCredentialRequest.Type, credentialParams); + Assert.True(false, "Fail to load the SQL connection instances. error: " + ex.Message); } } + private static void AddInstance(InstanceInfo instance) + { + if (instance != null && (instance.ServerType != TestServerType.None || !string.IsNullOrEmpty(instance.VersionKey))) + { + TestServerType serverType = instance.ServerType == TestServerType.None ? TestServerType.OnPrem : instance.ServerType; //Default to onPrem + string versionKey = string.IsNullOrEmpty(instance.VersionKey) ? ConvertServerTypeToVersionKey(serverType) : instance.VersionKey; + if (!connectionProfilesCache.ContainsKey(versionKey)) + { + //If the password is empty, get the credential using the service + if (instance.AuthenticationType == AuthenticationType.SqlLogin && string.IsNullOrEmpty(instance.Password)) + { + Credential credential = TestCredentialService.Instance.ReadCredential(instance); + instance.Password = credential.Password; + } + connectionProfilesCache.Add(versionKey, instance); + } + } + } + + private static string ConvertServerTypeToVersionKey(TestServerType serverType) + { + return serverType == TestServerType.OnPrem ? DefaultSql2016InstanceKey : DefaultSqlAzureV12InstanceKey; + } + /// /// Create a connection parameters object /// - private ConnectParams CreateConnectParams(ConnectionProfile connectionProfile, TestServerType serverType, string databaseName) + private ConnectParams CreateConnectParams(InstanceInfo connectionProfile, string key, string databaseName) { ConnectParams connectParams = new ConnectParams(); connectParams.Connection = new ConnectionDetails(); @@ -146,7 +189,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common { connectParams.Connection.DatabaseName = databaseName; } - if (serverType == TestServerType.Azure) + if (key == DefaultSqlAzureInstanceKey || key == DefaultSqlAzureV12InstanceKey) { connectParams.Connection.ConnectTimeout = 30; connectParams.Connection.Encrypt = true; @@ -154,112 +197,5 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common } return connectParams; } - - private static IEnumerable InitTestServerNames() - { - try - { - string testServerNamesFileContent = GetTestServerNamesFileContent(); - if (!string.IsNullOrEmpty(testServerNamesFileContent)) - { - return Newtonsoft.Json.JsonConvert.DeserializeObject>(testServerNamesFileContent); - } - else - { - return Enumerable.Empty(); - } - } - catch (Exception ex) - { - Console.WriteLine("Failed to load the database connection server name settings. error: " + ex.Message); - return Enumerable.Empty(); - } - } - - private static ConnectionSetting InitSetting() - { - try - { - string settingsFileContents = GetSettingFileContent(); - ConnectionSetting setting = Newtonsoft.Json.JsonConvert.DeserializeObject(settingsFileContents); - Console.WriteLine("Connection Settings loaded successfully"); - return setting; - } - catch (Exception ex) - { - Console.WriteLine("Failed to load the connection settings. error: " + ex.Message); - return new ConnectionSetting(); - } - } - - /// - /// Get the location of testServerNames.json. Returns the value of environment variable 'SettingsFileName' and if it's empty returns - /// the location of vs code testServerNames.json - /// - /// - private static string GetTestServerNamesFileContent() - { - var testServerNameFilePath = Environment.GetEnvironmentVariable("TestServerNamesFile"); - string testServerFileName = "testServerNames.json"; - - if (string.IsNullOrEmpty(testServerNameFilePath)) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - testServerNameFilePath = Environment.GetEnvironmentVariable("APPDATA") + @"\\" + testServerFileName; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - testServerNameFilePath = Environment.GetEnvironmentVariable("HOME") + @"/" + testServerFileName; - } - else - { - testServerNameFilePath = Environment.GetEnvironmentVariable("HOME") + @"/" + testServerFileName; - } - } - string testServerNamesFileContent = string.IsNullOrEmpty(testServerNameFilePath) ? string.Empty : File.ReadAllText(testServerNameFilePath); - - return testServerNamesFileContent; - } - - /// - /// Get the location of setting.json. Returns the value of environment variable 'SettingsFileName' and if it's empty returns - /// the location of vs code settings.json - /// - /// - private static string GetSettingFileContent() - { - var settingsFilename = Environment.GetEnvironmentVariable("SettingsFileName"); - - if (string.IsNullOrEmpty(settingsFilename)) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - settingsFilename = Environment.GetEnvironmentVariable("APPDATA") + @"\Code\User\settings.json"; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - settingsFilename = Environment.GetEnvironmentVariable("HOME") + @"/Library/Application Support/Code/User/settings.json"; - } - else - { - settingsFilename = Environment.GetEnvironmentVariable("HOME") + @"/.config/Code/User/settings.json"; - } - } - - if (string.IsNullOrEmpty(settingsFilename)) - { - Console.WriteLine("Cannot find any connection settings. Please run CreateConnectionSettings.cmd to generate a template for the connection settings."); - } - else - { - Console.WriteLine("Connection settings: " + settingsFilename); - _connectionSettingsFilename = settingsFilename; - } - - string settingsFileContents = string.IsNullOrEmpty(settingsFilename) ? string.Empty : File.ReadAllText(settingsFilename); - - return settingsFileContents; - } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestCredentialService.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestCredentialService.cs new file mode 100644 index 00000000..18d5f72c --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestCredentialService.cs @@ -0,0 +1,98 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using System.Globalization; +using Microsoft.SqlTools.ServiceLayer.Credentials; +using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts; + +namespace Microsoft.SqlTools.ServiceLayer.Test.Common +{ + public class TestCredentialService + { + private CredentialService credentialService = TestServiceProvider.Instance.CredentialService; + + private static TestCredentialService instance = new TestCredentialService(); + + /// + /// The singleton instance of the service + /// + public static TestCredentialService Instance + { + get + { + return instance; + } + } + + private const string MSSQL_CRED_PREFIX = "Microsoft.SqlTools"; + private const string TEST_CRED_PREFIX = "SqlToolsTestInstance"; + private const string CRED_SEPARATOR = "|"; + private const string CRED_SERVER_PREFIX = "server:"; + private const string CRED_DB_PREFIX = "db:"; + private const string CRED_USER_PREFIX = "user:"; + private const string CRED_ITEMTYPE_PREFIX = "itemtype:"; + + /// + /// Read Credential for given instance Info. Tries the test credential id and if no password found + /// will try the MSSQL credential id + /// + public Credential ReadCredential(InstanceInfo connectionProfile) + { + var credentialParams = new Credential(); + credentialParams.CredentialId = FormatCredentialIdForTest(connectionProfile); + Credential credential = credentialService.ReadCredential(credentialParams); + if (credential == null || string.IsNullOrEmpty(credential.Password)) + { + credentialParams.CredentialId = FormatCredentialIdForMsSql(connectionProfile); + credential = credentialService.ReadCredential(credentialParams); + } + + return credential; + } + + /// + /// Stored the credential to credential store using the test prefix + /// + public bool SaveCredential(InstanceInfo connectionProfile) + { + Credential credential = new Credential(FormatCredentialIdForTest(connectionProfile), connectionProfile.Password); + return credentialService.SaveCredential(credential); + } + + private string FormatCredentialIdForMsSql(InstanceInfo connectionProfile, string itemType = "Profile") + { + return FormatCredentialId(connectionProfile, itemType, MSSQL_CRED_PREFIX); + } + + private string FormatCredentialIdForTest(InstanceInfo connectionProfile, string itemType = "Profile") + { + return FormatCredentialId(connectionProfile, itemType, TEST_CRED_PREFIX); + } + + private string FormatCredentialId(InstanceInfo connectionProfile, string itemType = "Profile", string credPrefix = TEST_CRED_PREFIX) + { + if (!string.IsNullOrEmpty(connectionProfile.ServerName)) + { + List cred = new List(); + cred.Add(credPrefix); + AddToList(itemType, CRED_ITEMTYPE_PREFIX, cred); + AddToList(connectionProfile.ServerName, CRED_SERVER_PREFIX, cred); + AddToList(connectionProfile.Database, CRED_DB_PREFIX, cred); + AddToList(connectionProfile.User, CRED_USER_PREFIX, cred); + return string.Join(CRED_SEPARATOR, cred.ToArray()); + } + return null; + } + + private void AddToList(string item, string prefix, List list) + { + if (!string.IsNullOrEmpty(item)) + { + list.Add(string.Format(CultureInfo.InvariantCulture, "{0}{1}", prefix, item)); + } + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceDriverProvider.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceDriverProvider.cs index 643aa5e0..0d3c1ce5 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceDriverProvider.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceDriverProvider.cs @@ -66,7 +66,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common { get { - return (testConnectionService = testConnectionService ?? new TestConnectionProfileService(Driver)); + return (testConnectionService = testConnectionService ?? TestConnectionProfileService.Instance); } } @@ -101,23 +101,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common WriteToFile(ownerUri, query); } - /* - DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification - { - TextDocument = new TextDocumentItem - { - Uri = ownerUri, - LanguageId = "enu", - Version = 1, - Text = query - } - }; - - await RequestOpenDocumentNotification(openParams); - - Thread.Sleep(500); - */ - return await Connect(serverType, ownerUri, databaseName, timeout); } @@ -127,7 +110,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common public async Task Connect(TestServerType serverType, string ownerUri, string databaseName = null, int timeout = 15000) { - var connectParams = await GetConnectionParametersAsync(serverType, databaseName); + var connectParams = GetConnectionParameters(serverType, databaseName); bool connected = await Connect(ownerUri, connectParams, timeout); Assert.True(connected, "Connection is successful"); @@ -215,9 +198,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common /// /// Returns database connection parameters for given server type /// - public async Task GetConnectionParametersAsync(TestServerType serverType, string databaseName = null) + public ConnectParams GetConnectionParameters(TestServerType serverType, string databaseName = null) { - return await TestConnectionService.GetConnectionParametersAsync(serverType, databaseName); + return TestConnectionService.GetConnectionParameters(serverType, databaseName); } /// @@ -339,6 +322,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common { await ConnectForQuery(serverType, query, queryTempFile.FilePath, databaseName); var queryResult = await CalculateRunTime(() => RunQueryAndWaitToComplete(queryTempFile.FilePath, query, 50000), false); + Assert.NotNull(queryResult); + Assert.NotNull(queryResult.BatchSummaries); await Disconnect(queryTempFile.FilePath); } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceProvider.cs b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceProvider.cs index 8d28ac7b..c92c5261 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceProvider.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestServiceProvider.cs @@ -4,13 +4,20 @@ // using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; using Microsoft.SqlTools.ServiceLayer.Connection; +using Microsoft.SqlTools.ServiceLayer.Connection.Contracts; using Microsoft.SqlTools.ServiceLayer.Credentials; using Microsoft.SqlTools.ServiceLayer.Hosting; using Microsoft.SqlTools.ServiceLayer.LanguageServices; using Microsoft.SqlTools.ServiceLayer.QueryExecution; +using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage; using Microsoft.SqlTools.ServiceLayer.SqlContext; using Microsoft.SqlTools.ServiceLayer.Workspace; +using Moq; +using Xunit; namespace Microsoft.SqlTools.ServiceLayer.Test.Common { @@ -19,39 +26,140 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Common /// public class TestServiceProvider { + private TestServiceProvider() + { + InitializeTestServices(); + } + + private static object _lockObject = new object(); + private static TestServiceProvider _instance = new TestServiceProvider(); + + + public static TestServiceProvider Instance + { + get + { + return _instance; + } + } + + public CredentialService CredentialService + { + get + { + return CredentialService.Instance; + } + } + + public TestConnectionProfileService ConnectionProfileService + { + get + { + return TestConnectionProfileService.Instance; + } + } + + public WorkspaceService WorkspaceService + { + get + { + return WorkspaceService.Instance; + } + } + + /// + /// Runs a query by calling the services directly (not using the test driver) + /// + public void RunQuery(TestServerType serverType, string databaseName, string queryText) + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + { + ConnectionInfo connInfo = InitLiveConnectionInfo(serverType, databaseName, queryTempFile.FilePath); + Query query = new Query(queryText, connInfo, new QueryExecutionSettings(), GetFileStreamFactory(new Dictionary())); + query.Execute(); + query.ExecutionTask.Wait(); + } + } + + private ConnectionInfo InitLiveConnectionInfo(TestServerType serverType, string databaseName, string scriptFilePath) + { + ConnectParams connectParams = ConnectionProfileService.GetConnectionParameters(serverType, databaseName); + + string ownerUri = scriptFilePath; + var connectionService = ConnectionService.Instance; + var connectionResult = connectionService.Connect(new ConnectParams() + { + OwnerUri = ownerUri, + Connection = connectParams.Connection + }); + + connectionResult.Wait(); + + ConnectionInfo connInfo = null; + connectionService.TryFindConnection(ownerUri, out connInfo); + Assert.NotNull(connInfo); + return connInfo; + } + + private static IFileStreamFactory GetFileStreamFactory(Dictionary storage) + { + Mock mock = new Mock(); + mock.Setup(fsf => fsf.CreateFile()) + .Returns(() => + { + string fileName = Guid.NewGuid().ToString(); + storage.Add(fileName, new byte[8192]); + return fileName; + }); + mock.Setup(fsf => fsf.GetReader(It.IsAny())) + .Returns(output => new ServiceBufferFileStreamReader(new MemoryStream(storage[output]))); + mock.Setup(fsf => fsf.GetWriter(It.IsAny())) + .Returns(output => new ServiceBufferFileStreamWriter(new MemoryStream(storage[output]), 1024, 1024)); + + return mock.Object; + } + private static bool hasInitServices = false; - public static void InitializeTestServices() + private static void InitializeTestServices() { if (TestServiceProvider.hasInitServices) { return; } - TestServiceProvider.hasInitServices = true; + lock (_lockObject) + { + if (TestServiceProvider.hasInitServices) + { + return; + } + TestServiceProvider.hasInitServices = true; - const string hostName = "SQ Tools Test Service Host"; - const string hostProfileId = "SQLToolsTestService"; - Version hostVersion = new Version(1, 0); + const string hostName = "SQ Tools Test Service Host"; + const string hostProfileId = "SQLToolsTestService"; + Version hostVersion = new Version(1, 0); - // set up the host details and profile paths - var hostDetails = new HostDetails(hostName, hostProfileId, hostVersion); - SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails); + // set up the host details and profile paths + var hostDetails = new HostDetails(hostName, hostProfileId, hostVersion); + SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails); - // Grab the instance of the service host - ServiceHost serviceHost = ServiceHost.Instance; + // Grab the instance of the service host + ServiceHost serviceHost = ServiceHost.Instance; - // Start the service - serviceHost.Start().Wait(); + // Start the service + serviceHost.Start().Wait(); - // Initialize the services that will be hosted here - WorkspaceService.Instance.InitializeService(serviceHost); - LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext); - ConnectionService.Instance.InitializeService(serviceHost); - CredentialService.Instance.InitializeService(serviceHost); - QueryExecutionService.Instance.InitializeService(serviceHost); + // Initialize the services that will be hosted here + WorkspaceService.Instance.InitializeService(serviceHost); + LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext); + ConnectionService.Instance.InitializeService(serviceHost); + CredentialService.Instance.InitializeService(serviceHost); + QueryExecutionService.Instance.InitializeService(serviceHost); - serviceHost.Initialize(); + serviceHost.Initialize(); + } } + } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/PeekDefinitionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/PeekDefinitionTests.cs index a1d19476..d15aed2d 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/PeekDefinitionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/PeekDefinitionTests.cs @@ -126,7 +126,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices [Fact] public async Task DefinitionsHandlerWithNoConnectionTest() { - TestServiceProvider.InitializeTestServices(); InitializeTestObjects(); // request definition var definitionTask = await Task.WhenAny(LanguageService.HandleDefinitionRequest(textDocument, requestContext.Object), Task.Delay(TaskTimeout)); @@ -204,9 +203,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices { PeekDefinition peekDefinition = new PeekDefinition(null, null); var languageService = LanguageService.Instance; - Assert.True(Directory.Exists(FileUtils.PeekDefinitionTempFolder)); + Assert.True(Directory.Exists(ServiceLayer.QueryExecution.FileUtils.PeekDefinitionTempFolder)); languageService.DeletePeekDefinitionScripts(); - Assert.False(Directory.Exists(FileUtils.PeekDefinitionTempFolder)); + Assert.False(Directory.Exists(ServiceLayer.QueryExecution.FileUtils.PeekDefinitionTempFolder)); } /// @@ -217,8 +216,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices { var languageService = LanguageService.Instance; PeekDefinition peekDefinition = new PeekDefinition(null, null); - FileUtils.SafeDirectoryDelete(FileUtils.PeekDefinitionTempFolder, true); - Assert.False(Directory.Exists(FileUtils.PeekDefinitionTempFolder)); + ServiceLayer.QueryExecution.FileUtils.SafeDirectoryDelete(ServiceLayer.QueryExecution.FileUtils.PeekDefinitionTempFolder, true); + Assert.False(Directory.Exists(ServiceLayer.QueryExecution.FileUtils.PeekDefinitionTempFolder)); // Expected not to throw any exception languageService.DeletePeekDefinitionScripts(); } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs index fd512b68..04d0c7f1 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs @@ -96,6 +96,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution public static Query GetBasicExecutedQuery(QueryExecutionSettings querySettings) { ConnectionInfo ci = CreateTestConnectionInfo(new[] {StandardTestData}, false); + // Query won't be able to request a new query DbConnection unless the ConnectionService has a + // ConnectionInfo with the same URI as the query, so we will manually set it + ConnectionService.Instance.OwnerToConnectionMap[ci.OwnerUri] = ci; + Query query = new Query(StandardQuery, ci, querySettings, GetFileStreamFactory(new Dictionary())); query.Execute(); query.ExecutionTask.Wait(); diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/TestObjects.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/TestObjects.cs index 95e4d1e3..c8419bc4 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/TestObjects.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/TestObjects.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Data.SqlClient; +using System.Globalization; using System.IO; using System.Reflection; using System.Threading.Tasks; @@ -20,6 +21,7 @@ using Microsoft.SqlTools.ServiceLayer.Test.Common; using Microsoft.SqlTools.ServiceLayer.Test.Utility; using Microsoft.SqlTools.ServiceLayer.Workspace; using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; +using Xunit; namespace Microsoft.SqlTools.Test.Utility { @@ -28,7 +30,9 @@ namespace Microsoft.SqlTools.Test.Utility /// public class TestObjects { + public const string ScriptUriTemplate = "file://some/{0}.sql"; public const string ScriptUri = "file://some/file.sql"; + private static TestServiceProvider _serviceProvider = TestServiceProvider.Instance; /// /// Creates a test connection service @@ -124,14 +128,11 @@ namespace Microsoft.SqlTools.Test.Utility return filePath; } - public static async Task InitLiveConnectionInfo() + public static TestConnectionResult InitLiveConnectionInfo() { - TestServiceProvider.InitializeTestServices(); - string sqlFilePath = GetTestSqlFile(); - ScriptFile scriptFile = WorkspaceService.Instance.Workspace.GetFile(sqlFilePath); - TestConnectionProfileService connectionProfileService = new TestConnectionProfileService(); - ConnectParams connectParams = await connectionProfileService.GetConnectionParametersAsync(); + ScriptFile scriptFile = TestServiceProvider.Instance.WorkspaceService.Workspace.GetFile(sqlFilePath); + ConnectParams connectParams = TestServiceProvider.Instance.ConnectionProfileService.GetConnectionParameters(TestServerType.OnPrem); string ownerUri = scriptFile.ClientFilePath; var connectionService = TestObjects.GetLiveTestConnectionService(); @@ -150,13 +151,11 @@ namespace Microsoft.SqlTools.Test.Utility return new TestConnectionResult () { ConnectionInfo = connInfo, ScriptFile = scriptFile }; } - public static async Task InitLiveConnectionInfoForDefinition() + public static ConnectionInfo InitLiveConnectionInfoForDefinition(string databaseName = null) { - TestServiceProvider.InitializeTestServices(); - TestConnectionProfileService connectionProfileService = new TestConnectionProfileService(); - ConnectParams connectParams = await connectionProfileService.GetConnectionParametersAsync(); + ConnectParams connectParams = _serviceProvider.ConnectionProfileService.GetConnectionParameters(TestServerType.OnPrem, databaseName); - string ownerUri = ScriptUri; + string ownerUri = string.Format(CultureInfo.InvariantCulture, ScriptUriTemplate, string.IsNullOrEmpty(databaseName) ? "file" : databaseName); var connectionService = TestObjects.GetLiveTestConnectionService(); var connectionResult = connectionService @@ -170,6 +169,8 @@ namespace Microsoft.SqlTools.Test.Utility ConnectionInfo connInfo = null; connectionService.TryFindConnection(ownerUri, out connInfo); + + Assert.NotNull(connInfo); return connInfo; } diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver.Tests/StressTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver.Tests/StressTests.cs index d793cc49..d5aa7915 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver.Tests/StressTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver.Tests/StressTests.cs @@ -196,7 +196,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests using (TestServiceDriverProvider testService = new TestServiceDriverProvider()) { - var connection = await testService.GetConnectionParametersAsync(TestServerType.OnPrem); + var connection = testService.GetConnectionParameters(TestServerType.OnPrem); connection.Connection.Pooling = false; // Connect/disconnect repeatedly diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Microsoft.SqlTools.ServiceLayer.TestEnvConfig.xproj b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Microsoft.SqlTools.ServiceLayer.TestEnvConfig.xproj new file mode 100644 index 00000000..9e93b5aa --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Microsoft.SqlTools.ServiceLayer.TestEnvConfig.xproj @@ -0,0 +1,21 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 6cf2e945-c7d1-44b5-9e28-addd09e3e983 + Microsoft.SqlTools.ServiceLayer.TestEnvConfig + .\obj + .\bin\ + v4.5.2 + + + + 2.0 + + + diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Program.cs b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Program.cs new file mode 100644 index 00000000..3c801203 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Program.cs @@ -0,0 +1,115 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Microsoft.SqlTools.ServiceLayer.Test.Common; + +namespace Microsoft.SqlTools.ServiceLayer.TestEnvConfig +{ + class Program + { + static void Main(string[] args) + { + if (args.Length == 1) + { + string arg = args[0]; + + if (arg.Equals("-?", StringComparison.OrdinalIgnoreCase) || + arg.Equals("/?", StringComparison.OrdinalIgnoreCase) || + arg.Equals("-help", StringComparison.OrdinalIgnoreCase) || + arg.Equals("/help", StringComparison.OrdinalIgnoreCase)) + { + ShowUsage(); + } + else if (File.Exists(arg) == false) + { + Console.WriteLine("setting file {0} does not exist.", arg); + } + else + { + try + { + SaveSettings(arg); + Console.WriteLine("Completed saving the settings"); + } + catch (Exception ex) + { + Console.WriteLine("Error encountered: {0}", ex.Message); + } + } + } + else + { + ShowUsage(); + } + } + + private static void ShowUsage() + { + Console.WriteLine(@"Usage: + TestEnvConfig + Show this help message + + TestEnvConfig -? + Show this help message + + TestEnvConfig setting_file + Run the program as a command line application + The program reads the test configurations from the setting_file and + saves them locally. the passwords will be stored in the credential store + + The following is an example of a setting_file: + + + + SQL2005 servername + RemoteShare + SQL 2005 remote share + + + SQL2008 servername + RemoteShare + SQL 2008 remote share + + + SQL2011 servername + RemoteShare + SQL 20011 remote share + + + SQLAzure servername + RemoteShare + SQLAzure remote share + user id + password + + +"); + } + + private static void SaveSettings(string settingFile) + { + + var xdoc = XDocument.Load(settingFile); + var settings = + from setting in xdoc.Descendants("Instance") + select new InstanceInfo(setting.Attribute("VersionKey").Value) // VersionKey is required + { + ServerName = setting.Element("DataSource").Value, // DataSource is required + ConnectTimeoutAsString = (string)setting.Element("ConnectTimeout"), //ConnectTimeout is optional + User = (string)setting.Element("UserId"), // UserID is optional + Password = (string)setting.Element("Password"), + RemoteSharePath = (string)setting.Element("RemoteShare"), // RemoteShare is optional + AuthenticationType = string.IsNullOrEmpty((string)setting.Element("UserId")) ? AuthenticationType.Integrated : AuthenticationType.SqlLogin + }; + + TestConfigPersistenceHelper.Write(settings); + + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Properties/AssemblyInfo.cs b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..4efbd126 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Microsoft.SqlTools.ServiceLayer.TestEnvConfig")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6cf2e945-c7d1-44b5-9e28-addd09e3e983")] diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/project.json b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/project.json new file mode 100644 index 00000000..340036f1 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.TestEnvConfig/project.json @@ -0,0 +1,25 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true + }, + + "dependencies": { + "Microsoft.SqlTools.ServiceLayer.Test.Common": "1.0.0-*" + }, + "testRunner": "xunit", + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0" + } + }, + "imports": [ + "dotnet5.4", + "portable-net451+win8" + ] + } + } +}