diff --git a/sqltoolsservice.sln b/sqltoolsservice.sln index 26e27176..630d13a2 100644 --- a/sqltoolsservice.sln +++ b/sqltoolsservice.sln @@ -51,6 +51,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeCoverage", "CodeCoverag test\CodeCoverage\runintegration.bat = test\CodeCoverage\runintegration.bat EndProjectSection EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.SqlTools.ServiceLayer.PerfTests", "test\Microsoft.SqlTools.ServiceLayer.PerfTests\Microsoft.SqlTools.ServiceLayer.PerfTests.xproj", "{7E5968AB-83D7-4738-85A2-416A50F13D2F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,6 +71,10 @@ Global {CC785604-6277-4878-8DA9-360C47158E96}.Debug|Any CPU.Build.0 = Debug|Any CPU {CC785604-6277-4878-8DA9-360C47158E96}.Release|Any CPU.ActiveCfg = Release|Any CPU {CC785604-6277-4878-8DA9-360C47158E96}.Release|Any CPU.Build.0 = Release|Any CPU + {7E5968AB-83D7-4738-85A2-416A50F13D2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E5968AB-83D7-4738-85A2-416A50F13D2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E5968AB-83D7-4738-85A2-416A50F13D2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E5968AB-83D7-4738-85A2-416A50F13D2F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -79,5 +85,6 @@ Global {CC785604-6277-4878-8DA9-360C47158E96} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {B7D21727-2926-452B-9610-3ADB0BB6D789} = {F9978D78-78FE-4E92-A7D6-D436B7683EF6} {87D9C7D9-18F4-4AB9-B20D-66C02B6075E2} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} + {7E5968AB-83D7-4738-85A2-416A50F13D2F} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} EndGlobalSection EndGlobal diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Microsoft.SqlTools.ServiceLayer.PerfTests.xproj b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Microsoft.SqlTools.ServiceLayer.PerfTests.xproj new file mode 100644 index 00000000..bfdf13be --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Microsoft.SqlTools.ServiceLayer.PerfTests.xproj @@ -0,0 +1,22 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 7e5968ab-83d7-4738-85a2-416a50f13d2f + Microsoft.SqlTools.ServiceLayer.PerfTests + .\obj + .\bin\ + v4.5.2 + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Program.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Program.cs new file mode 100644 index 00000000..aa2dc482 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Program.cs @@ -0,0 +1,31 @@ +// +// 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 Microsoft.SqlTools.ServiceLayer.TestDriver.Driver; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility; +using Microsoft.SqlTools.ServiceLayer.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.PerfTests +{ + public class Program + { + internal static int Main(string[] args) + { + if (args.Length < 1) + { + Console.WriteLine("Microsoft.SqlTools.ServiceLayer.PerfTests.exe [tests]" + Environment.NewLine + + " [tests] is a space-separated list of tests to run." + Environment.NewLine + + " They are qualified within the Microsoft.SqlTools.ServiceLayer.TestDriver.PerfTests namespace" + Environment.NewLine + + $"Be sure to set the environment variable {ServiceTestDriver.ServiceHostEnvironmentVariable} to the full path of the sqltoolsservice executable."); + return 0; + } + + Logger.Initialize("testdriver", LogLevel.Verbose); + + return TestRunner.RunTests(args, "Microsoft.SqlTools.ServiceLayer.PerfTests.Tests.").Result; + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Properties/AssemblyInfo.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..825d07ad --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/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.PerfTests")] +[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("7e5968ab-83d7-4738-85a2-416a50f13d2f")] diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/Common.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/Common.cs new file mode 100644 index 00000000..0011d226 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/Common.cs @@ -0,0 +1,76 @@ +// +// 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.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Tests; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility; +using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.PerfTests.Tests +{ + public class Common + { + internal static async Task ExecuteWithTimeout(TestTimer timer, int timeout, Func> repeatedCode, + TimeSpan? delay = null, [CallerMemberName] string testName = "") + { + while (true) + { + if (await repeatedCode()) + { + timer.EndAndPrint(testName); + break; + } + if (timer.TotalMilliSecondsUntilNow >= timeout) + { + Assert.True(false, $"{testName} timed out after {timeout} milliseconds"); + break; + } + if (delay.HasValue) + { + await Task.Delay(delay.Value); + } + } + } + + internal static async Task ConnectAsync(TestHelper testHelper, TestServerType serverType, string query, string ownerUri) + { + testHelper.WriteToFile(ownerUri, query); + + DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification + { + TextDocument = new TextDocumentItem + { + Uri = ownerUri, + LanguageId = "enu", + Version = 1, + Text = query + } + }; + + await testHelper.RequestOpenDocumentNotification(openParams); + + Thread.Sleep(500); + var connectParams = await testHelper.GetDatabaseConnectionAsync(serverType); + bool connected = await testHelper.Connect(ownerUri, connectParams); + Assert.True(connected, "Connection is successful"); + Console.WriteLine($"Connection to {connectParams.Connection.ServerName} is successful"); + + return connected; + } + + internal static async Task CalculateRunTime(Func> testToRun, [CallerMemberName] string testName = "") + { + TestTimer timer = new TestTimer(); + T result = await testToRun(); + timer.EndAndPrint(testName); + + return result; + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/ConnectionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/ConnectionTests.cs new file mode 100644 index 00000000..a5edd3d5 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/ConnectionTests.cs @@ -0,0 +1,97 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Scripts; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Tests; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility; +using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.PerfTests.Tests +{ + public class ConnectionTests + { + + [Fact] + public async Task ConnectAzureTest() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + const string query = Scripts.SimpleQuery; + testHelper.WriteToFile(queryTempFile.FilePath, query); + + DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification + { + TextDocument = new TextDocumentItem + { + Uri = queryTempFile.FilePath, + LanguageId = "enu", + Version = 1, + Text = query + } + }; + + await testHelper.RequestOpenDocumentNotification(openParams); + + Thread.Sleep(500); + var connected = await Common.CalculateRunTime(async () => + { + var connectParams = await testHelper.GetDatabaseConnectionAsync(TestServerType.Azure); + return await testHelper.Connect(queryTempFile.FilePath, connectParams); + }); + Assert.True(connected, "Connection was not successful"); + } + } + + [Fact] + public async Task ConnectOnPremTest() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + const string query = Scripts.SimpleQuery; + testHelper.WriteToFile(queryTempFile.FilePath, query); + + DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification + { + TextDocument = new TextDocumentItem + { + Uri = queryTempFile.FilePath, + LanguageId = "enu", + Version = 1, + Text = query + } + }; + + await testHelper.RequestOpenDocumentNotification(openParams); + + Thread.Sleep(500); + var connected = await Common.CalculateRunTime(async () => + { + var connectParams = await testHelper.GetDatabaseConnectionAsync(TestServerType.OnPrem); + return await testHelper.Connect(queryTempFile.FilePath, connectParams); + }); + Assert.True(connected, "Connection was not successful"); + } + } + + [Fact] + public async Task DisconnectTest() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + await Common.ConnectAsync(testHelper, TestServerType.OnPrem, Scripts.SimpleQuery, queryTempFile.FilePath); + Thread.Sleep(1000); + var connected = await Common.CalculateRunTime(() => testHelper.Disconnect(queryTempFile.FilePath)); + Assert.True(connected); + } + } + + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/IntellisenseTests.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/IntellisenseTests.cs new file mode 100644 index 00000000..642007c5 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/IntellisenseTests.cs @@ -0,0 +1,214 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Scripts; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Tests; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility; +using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.PerfTests.Tests +{ + public class IntellisenseTests + { + [Fact] + public async Task HoverTestOnPrem() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + const string query = Scripts.SimpleQuery; + await Common.ConnectAsync(testHelper, TestServerType.OnPrem, query, queryTempFile.FilePath); + Hover hover = await Common.CalculateRunTime(() => testHelper.RequestHover(queryTempFile.FilePath, query, 0, 15)); + Assert.NotNull(hover); + await testHelper.Disconnect(queryTempFile.FilePath); + } + } + + [Fact] + public async Task SuggestionsTest() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + const string query = Scripts.SimpleQuery; + await Common.ConnectAsync(testHelper, TestServerType.OnPrem, query, queryTempFile.FilePath); + await ValidateCompletionResponse(testHelper, queryTempFile.FilePath, query, null); + await ValidateCompletionResponse(testHelper, queryTempFile.FilePath, query); + await testHelper.Disconnect(queryTempFile.FilePath); + } + } + + [Fact] + public async Task DiagnosticsTests() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + await Common.ConnectAsync(testHelper, TestServerType.OnPrem, Scripts.SimpleQuery, queryTempFile.FilePath); + + Thread.Sleep(500); + var contentChanges = new TextDocumentChangeEvent[1]; + contentChanges[0] = new TextDocumentChangeEvent() + { + Range = new Range + { + Start = new Position + { + Line = 0, + Character = 5 + }, + End = new Position + { + Line = 0, + Character = 6 + } + }, + RangeLength = 1, + Text = "z" + }; + DidChangeTextDocumentParams changeParams = new DidChangeTextDocumentParams + { + ContentChanges = contentChanges, + TextDocument = new VersionedTextDocumentIdentifier + { + Version = 2, + Uri = queryTempFile.FilePath + } + }; + + TestTimer timer = new TestTimer(); + await testHelper.RequestChangeTextDocumentNotification(changeParams); + await Common.ExecuteWithTimeout(timer, 60000, async () => + { + var completeEvent = await testHelper.Driver.WaitForEvent(PublishDiagnosticsNotification.Type, 15000); + return completeEvent?.Diagnostics != null && completeEvent.Diagnostics.Length > 0; + }); + await testHelper.Disconnect(queryTempFile.FilePath); + } + } + + [Fact] + public async Task BindingCacheColdAzureSimpleQuery() + { + using (TestHelper testHelper = new TestHelper()) + { + await VerifyBindingLoadScenario(testHelper, TestServerType.Azure, Scripts.SimpleQuery); + } + } + + [Fact] + public async Task BindingCacheColdOnPremSimpleQuery() + { + using (TestHelper testHelper = new TestHelper()) + { + await VerifyBindingLoadScenario(testHelper, TestServerType.OnPrem, Scripts.SimpleQuery); + } + } + + [Fact] + public async Task BindingCacheWarmAzureSimpleQuery() + { + using (TestHelper testHelper = new TestHelper()) + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + { + const string query = Scripts.SimpleQuery; + const TestServerType serverType = TestServerType.Azure; + await Common.ConnectAsync(testHelper, serverType, query, queryTempFile.FilePath); + Thread.Sleep(10000); + await VerifyBindingLoadScenario(testHelper, serverType, query); + } + } + + [Fact] + public async Task BindingCacheWarmOnPremSimpleQuery() + { + using (TestHelper testHelper = new TestHelper()) + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + { + const string query = Scripts.SimpleQuery; + const TestServerType serverType = TestServerType.OnPrem; + await Common.ConnectAsync(testHelper, serverType, query, queryTempFile.FilePath); + Thread.Sleep(10000); + await VerifyBindingLoadScenario(testHelper, serverType, query); + } + } + + [Fact] + public async Task BindingCacheColdAzureComplexQuery() + { + using (TestHelper testHelper = new TestHelper()) + { + await VerifyBindingLoadScenario(testHelper, TestServerType.Azure, Scripts.ComplexQuery); + } + } + + [Fact] + public async Task BindingCacheColdOnPremComplexQuery() + { + using (TestHelper testHelper = new TestHelper()) + { + await VerifyBindingLoadScenario(testHelper, TestServerType.OnPrem, Scripts.ComplexQuery); + } + } + + [Fact] + public async Task BindingCacheWarmAzureComplexQuery() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + string query = Scripts.ComplexQuery; + const TestServerType serverType = TestServerType.Azure; + await Common.ConnectAsync(testHelper, serverType, query, queryTempFile.FilePath); + Thread.Sleep(10000); + await VerifyBindingLoadScenario(testHelper, serverType, query); + } + } + + [Fact] + public async Task BindingCacheWarmOnPremComplexQuery() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + string query = Scripts.ComplexQuery; + const TestServerType serverType = TestServerType.OnPrem; + await Common.ConnectAsync(testHelper, serverType, query, queryTempFile.FilePath); + Thread.Sleep(10000); + await VerifyBindingLoadScenario(testHelper, serverType, query); + } + } + + #region Private Helper Methods + + private static async Task VerifyBindingLoadScenario(TestHelper testHelper, TestServerType serverType, string query, [CallerMemberName] string testName = "") + { + using(SelfCleaningTempFile testTempFile = new SelfCleaningTempFile()) { + testHelper.WriteToFile(testTempFile.FilePath, query); + await Common.ConnectAsync(testHelper, serverType, query, testTempFile.FilePath); + await ValidateCompletionResponse(testHelper, testTempFile.FilePath, query, testName); + await testHelper.Disconnect(testTempFile.FilePath); + } + } + + private static async Task ValidateCompletionResponse(TestHelper testHelper, string ownerUri, string query, [CallerMemberName] string testName="") + { + TestTimer timer = new TestTimer(); + await Common.ExecuteWithTimeout(timer, 60000, async () => + { + CompletionItem[] completions = await testHelper.RequestCompletion(ownerUri, query, 0, 15); + return completions != null && completions.Any(x => x.Label == "master"); + }, testName:testName); + } + + #endregion + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/QueryExecutionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/QueryExecutionTests.cs new file mode 100644 index 00000000..1b8ff999 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/QueryExecutionTests.cs @@ -0,0 +1,90 @@ +// +// 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.Linq; +using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Scripts; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Tests; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.PerfTests.Tests +{ + public class QueryExecutionTests + { + [Fact] + public async Task QueryResultSummaryOnPremTest() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + const string query = Scripts.SimpleQuery; + + await Common.ConnectAsync(testHelper, TestServerType.OnPrem, query, queryTempFile.FilePath); + var queryResult = await Common.CalculateRunTime(() => testHelper.RunQuery(queryTempFile.FilePath, query)); + + Assert.NotNull(queryResult); + Assert.True(queryResult.BatchSummaries.Any(x => x.ResultSetSummaries.Any(r => r.RowCount > 0))); + + await testHelper.Disconnect(queryTempFile.FilePath); + } + } + + [Fact] + public async Task QueryResultFirstOnPremTest() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + const string query = Scripts.SimpleQuery; + + await Common.ConnectAsync(testHelper, TestServerType.OnPrem, query, queryTempFile.FilePath); + + var queryResult = await Common.CalculateRunTime(async () => + { + await testHelper.RunQuery(queryTempFile.FilePath, query); + return await testHelper.ExecuteSubset(queryTempFile.FilePath, 0, 0, 0, 100); + }); + + Assert.NotNull(queryResult); + Assert.NotNull(queryResult.ResultSubset); + Assert.True(queryResult.ResultSubset.Rows.Any()); + + await testHelper.Disconnect(queryTempFile.FilePath); + } + } + + [Fact] + public async Task CancelQueryOnPremTest() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + await Common.ConnectAsync(testHelper, TestServerType.OnPrem, Scripts.DelayQuery, queryTempFile.FilePath); + var queryParams = new QueryExecuteParams + { + OwnerUri = queryTempFile.FilePath, + QuerySelection = null + }; + + var result = await testHelper.Driver.SendRequest(QueryExecuteRequest.Type, queryParams); + if (result != null && string.IsNullOrEmpty(result.Messages)) + { + TestTimer timer = new TestTimer(); + await Common.ExecuteWithTimeout(timer, 100000, + async () => await testHelper.CancelConnect(queryTempFile.FilePath), TimeSpan.FromMilliseconds(10)); + } + else + { + Assert.True(false, "Failed to run the query"); + } + + await testHelper.Disconnect(queryTempFile.FilePath); + } + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/SaveResultsTests.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/SaveResultsTests.cs new file mode 100644 index 00000000..adc0e7a9 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/SaveResultsTests.cs @@ -0,0 +1,52 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Scripts; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Tests; +using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.PerfTests.Tests +{ + public class SaveResultsTests + { + [Fact] + public async Task TestSaveResultsToCsvTest() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (SelfCleaningTempFile outputTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + const string query = Scripts.SimpleQuery; + + // Execute a query + await Common.ConnectAsync(testHelper, TestServerType.OnPrem, query, queryTempFile.FilePath); + await testHelper.RunQuery(queryTempFile.FilePath, query); + await Common.CalculateRunTime(() => testHelper.SaveAsCsv(queryTempFile.FilePath, outputTempFile.FilePath, 0, 0)); + await testHelper.Disconnect(queryTempFile.FilePath); + } + } + + [Fact] + public async Task TestSaveResultsToJsonTest() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (SelfCleaningTempFile outputTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + const string query = Scripts.SimpleQuery; + const TestServerType serverType = TestServerType.OnPrem; + + // Execute a query + await Common.ConnectAsync(testHelper, serverType, query, queryTempFile.FilePath); + await testHelper.RunQuery(queryTempFile.FilePath, query); + await Common.CalculateRunTime(() => testHelper.SaveAsJson(queryTempFile.FilePath, outputTempFile.FilePath, 0, 0)); + await testHelper.Disconnect(queryTempFile.FilePath); + } + } + + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/project.json b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/project.json new file mode 100644 index 00000000..abb50518 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/project.json @@ -0,0 +1,29 @@ +{ + "version": "1.0.0-*", + + "dependencies": { + "xunit": "2.1.0", + "dotnet-test-xunit": "1.0.0-rc2-192208-24", + "Microsoft.SqlTools.ServiceLayer": { + "target": "project" + }, + "Microsoft.SqlTools.ServiceLayer.TestDriver": "1.0.0-*" + }, + + "testRunner": "xunit", + + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version" : "1.0.0" + } + }, + "imports": [ + "dotnet5.4", + "portable-net451+win8" + ] + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/LanguageServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/LanguageServiceTests.cs index bc976498..c8c22986 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/LanguageServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/LanguageServer/LanguageServiceTests.cs @@ -3,28 +3,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -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.LanguageServices; -using Microsoft.SqlTools.ServiceLayer.QueryExecution; -using Microsoft.SqlTools.ServiceLayer.SqlContext; -using Microsoft.SqlTools.ServiceLayer.Test.QueryExecution; -using Microsoft.SqlTools.ServiceLayer.Test.Utility; -using Microsoft.SqlTools.ServiceLayer.Workspace; using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; using Microsoft.SqlTools.Test.Utility; -using Moq; -using Moq.Protected; using Xunit; -namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices +namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServer { /// /// Tests for the ServiceHost Language Service tests @@ -145,14 +130,32 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices #region "General Language Service tests" - #if LIVE_CONNECTION_TESTS + + private static void GetLiveAutoCompleteTestObjects( + out TextDocumentPosition textDocument, + out ScriptFile scriptFile, + out ConnectionInfo connInfo) + { + textDocument = new TextDocumentPosition + { + TextDocument = new TextDocumentIdentifier {Uri = TestObjects.ScriptUri}, + Position = new Position + { + Line = 0, + Character = 0 + } + }; + + connInfo = TestObjects.InitLiveConnectionInfo(out scriptFile); + } + /// /// Test the service initialization code path and verify nothing throws /// // Test is causing failures in build lab..investigating to reenable [Fact] - public void ServiceInitiailzation() + public void ServiceInitialization() { try { @@ -178,8 +181,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices ScriptFile scriptFile; ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfo(out scriptFile); - ScriptParseInfo scriptInfo = new ScriptParseInfo(); - scriptInfo.IsConnected = true; + ScriptParseInfo scriptInfo = new ScriptParseInfo {IsConnected = true}; AutoCompleteHelper.PrepopulateCommonMetadata(connInfo, scriptInfo, null); } @@ -193,7 +195,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices TextDocumentPosition textDocument; ConnectionInfo connInfo; ScriptFile scriptFile; - Common.GetAutoCompleteTestObjects(out textDocument, out scriptFile, out connInfo); + GetLiveAutoCompleteTestObjects(out textDocument, out scriptFile, out connInfo); textDocument.Position.Character = 7; scriptFile.Contents = "select "; @@ -209,52 +211,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices #endif - private Hosting.ServiceHost GetTestServiceHost() - { - // set up the host details and profile paths - var hostDetails = new HostDetails("Test Service Host", "SQLToolsService", new Version(1,0)); - SqlToolsContext context = new SqlToolsContext(hostDetails); - - // Grab the instance of the service host - Hosting.ServiceHost host = Hosting.ServiceHost.Instance; - - // Start the service - host.Start().Wait(); - - return host; - } - - #endregion - - #region "Autocomplete Tests" - - /// - /// Creates a mock db command that returns a predefined result set - /// - public static DbCommand CreateTestCommand(Dictionary[][] data) - { - var commandMock = new Mock { CallBase = true }; - var commandMockSetup = commandMock.Protected() - .Setup("ExecuteDbDataReader", It.IsAny()); - - commandMockSetup.Returns(new TestDbDataReader(data)); - - return commandMock.Object; - } - - /// - /// Creates a mock db connection that returns predefined data when queried for a result set - /// - public DbConnection CreateMockDbConnection(Dictionary[][] data) - { - var connectionMock = new Mock { CallBase = true }; - connectionMock.Protected() - .Setup("CreateDbCommand") - .Returns(CreateTestCommand(data)); - - return connectionMock.Object; - } - #endregion } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Driver/ServiceTestDriver.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Driver/ServiceTestDriver.cs index 8eb49dc6..be5d2e39 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Driver/ServiceTestDriver.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Driver/ServiceTestDriver.cs @@ -9,7 +9,10 @@ // using System; +using System.Diagnostics; using System.IO; +using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.SqlTools.ServiceLayer.Connection.Contracts; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; @@ -33,7 +36,11 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver public const string ServiceHostEnvironmentVariable = "SQLTOOLSSERVICE_EXE"; - public bool IsCoverageRun { get; set; } + public bool IsCoverageRun { get; set; } + + private Process[] serviceProcesses; + + private DateTime startTime; public ServiceTestDriver() { @@ -71,8 +78,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver coverageOutput = "coverage.xml"; } - serviceHostArguments = "-mergeoutput -target:" + serviceHostExecutable + " -targetargs:" + serviceHostArguments - + " -register:user -oldstyle -filter:\"+[Microsoft.SqlTools.*]* -[xunit*]*\" -output:" + coverageOutput + " -searchdirs:" + serviceHostDirectory; + serviceHostArguments = $"-mergeoutput -target:{serviceHostExecutable} -targetargs:{serviceHostArguments} " + + $"-register:user -oldstyle -filter:\"+[Microsoft.SqlTools.*]* -[xunit*]*\" -output:{coverageOutput} " + + $"-searchdirs:{serviceHostDirectory};"; serviceHostExecutable = coverageToolPath; this.IsCoverageRun = true; @@ -88,9 +96,28 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver /// public async Task Start() { + // Store the time we started + startTime = DateTime.Now; + + // Launch the process await this.protocolClient.Start(); await Task.Delay(1000); // Wait for the service host to start + // If this is a code coverage run, we need access to the service layer separate from open cover + if (IsCoverageRun) + { + CancellationTokenSource cancelSource = new CancellationTokenSource(); + Task getServiceProcess = GetServiceProcess(cancelSource.Token); + Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(15), cancelSource.Token); + if (await Task.WhenAny(getServiceProcess, timeoutTask) == timeoutTask) + { + cancelSource.Cancel(); + throw new Exception("Failed to capture service process"); + } + } + + Console.WriteLine("Successfully launched service"); + // Setup events to queue for testing this.QueueEventsForType(ConnectionCompleteNotification.Type); this.QueueEventsForType(IntelliSenseReadyNotification.Type); @@ -103,7 +130,38 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver /// public async Task Stop() { - await this.protocolClient.Stop(); + if (IsCoverageRun) + { + // Kill all the processes in the list + foreach (Process p in serviceProcesses.Where(p => !p.HasExited)) + { + p.Kill(); + } + ServiceProcess?.WaitForExit(); + } + else + { + await this.protocolClient.Stop(); + } + } + + private async Task GetServiceProcess(CancellationToken token) + { + while (serviceProcesses == null && !token.IsCancellationRequested) + { + var processes = Process.GetProcessesByName("Microsoft.SqlTools.ServiceLayer") + .Where(p => p.StartTime >= startTime).ToArray(); + + // Wait a second if we can't find the process + if (processes.Any()) + { + serviceProcesses = processes; + } + else + { + await Task.Delay(TimeSpan.FromSeconds(1), token); + } + } } } } \ No newline at end of file diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Microsoft.SqlTools.ServiceLayer.TestDriver.xproj b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Microsoft.SqlTools.ServiceLayer.TestDriver.xproj index 1319ccb7..6fc6a045 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Microsoft.SqlTools.ServiceLayer.TestDriver.xproj +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Microsoft.SqlTools.ServiceLayer.TestDriver.xproj @@ -1,4 +1,4 @@ - + 14.0 @@ -15,5 +15,8 @@ 2.0 + + + - + \ No newline at end of file diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Scripts/Scripts.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Scripts/Scripts.cs new file mode 100644 index 00000000..f2c28877 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Scripts/Scripts.cs @@ -0,0 +1,37 @@ +// +// 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.Reflection; + +namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Scripts +{ + public class Scripts + { + + public const string SimpleQuery = "SELECT * FROM sys.all_columns"; + + public const string DelayQuery = "WAITFOR DELAY '00:01:00'"; + + private static readonly Lazy ComplexQueryInstance = new Lazy(() => + { + try + { + string assemblyLocation = typeof(Scripts).GetTypeInfo().Assembly.Location; + string folderName = Path.GetDirectoryName(assemblyLocation); + string filePath = Path.Combine(folderName, "Scripts/AdventureWorks.sql"); + return File.ReadAllText(filePath); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to load the sql script. error: {ex.Message}"); + return string.Empty; + } + }); + + public static string ComplexQuery { get { return ComplexQueryInstance.Value; } } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/ConnectionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/ConnectionTests.cs index 8a6f3f95..8aefb01b 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/ConnectionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/ConnectionTests.cs @@ -13,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Language Service end-to-end integration tests /// - public class ConnectionTests : TestBase + public class ConnectionTest { /// /// Try to connect with invalid credentials @@ -21,23 +21,19 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests [Fact] public async Task InvalidConnection() { - try - { - string ownerUri = System.IO.Path.GetTempFileName(); - bool connected = await Connect(ownerUri, ConnectionTestUtils.InvalidConnection, 300000); + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.InvalidConnection, 300000); Assert.False(connected, "Invalid connection is failed to connect"); - await Connect(ownerUri, ConnectionTestUtils.InvalidConnection, 300000); + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.InvalidConnection, 300000); Thread.Sleep(1000); - await CancelConnect(ownerUri); + await testHelper.CancelConnect(queryTempFile.FilePath); - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } @@ -47,22 +43,17 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests [Fact] public async Task ListDatabasesTest() { - try - { - string ownerUri = System.IO.Path.GetTempFileName(); - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection); Assert.True(connected, "Connection successful"); - var listDatabaseResult = await ListDatabases(ownerUri); + var listDatabaseResult = await testHelper.ListDatabases(queryTempFile.FilePath); Assert.True(listDatabaseResult.DatabaseNames.Length > 0); - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } - } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/LanguageServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/LanguageServiceTests.cs index 74183c02..039b0b6f 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/LanguageServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/LanguageServiceTests.cs @@ -3,10 +3,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts; @@ -20,7 +16,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Language Service end-to-end integration tests /// - public class LanguageServiceTests : TestBase + public class LanguageServiceTests { /// @@ -29,42 +25,38 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests [Fact] public async Task HoverTest() { - try + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { - string ownerUri = System.IO.Path.GetTempFileName(); string query = "SELECT * FROM sys.objects"; - WriteToFile(ownerUri, query); + testHelper.WriteToFile(queryTempFile.FilePath, query); - DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() + DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification { - TextDocument = new TextDocumentItem() + TextDocument = new TextDocumentItem { - Uri = ownerUri, + Uri = queryTempFile.FilePath, LanguageId = "enu", Version = 1, Text = query } }; - await RequestOpenDocumentNotification(openParams); + await testHelper.RequestOpenDocumentNotification(openParams); Thread.Sleep(500); - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); - Assert.True(connected, "Connection is successful"); + bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection); + Assert.True(connected, "Connection was not successful"); Thread.Sleep(10000); - Hover hover = await RequestHover(ownerUri, query, 0, 15); + Hover hover = await testHelper.RequestHover(queryTempFile.FilePath, query, 0, 15); - Assert.True(hover != null, "Hover tooltop is not null"); + Assert.True(hover != null, "Hover tooltop is null"); - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } @@ -74,48 +66,44 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests [Fact] public async Task CompletionTest() { - try - { - string ownerUri = System.IO.Path.GetTempFileName(); + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { string query = "SELECT * FROM sys.objects"; - WriteToFile(ownerUri, query); + testHelper.WriteToFile(queryTempFile.FilePath, query); - DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() + DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification { - TextDocument = new TextDocumentItem() + TextDocument = new TextDocumentItem { - Uri = ownerUri, + Uri = queryTempFile.FilePath, LanguageId = "enu", Version = 1, Text = query } }; - await RequestOpenDocumentNotification(openParams); + await testHelper.RequestOpenDocumentNotification(openParams); Thread.Sleep(500); - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); + bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection); Assert.True(connected, "Connection is successful"); Thread.Sleep(10000); - CompletionItem[] completions = await RequestCompletion(ownerUri, query, 0, 15); + CompletionItem[] completions = await testHelper.RequestCompletion(queryTempFile.FilePath, query, 0, 15); - Assert.True(completions != null && completions.Length > 0, "Completion items list is not null and not empty"); + Assert.True(completions != null && completions.Length > 0, "Completion items list is null or empty"); Thread.Sleep(50); - CompletionItem item = await RequestResolveCompletion(completions[0]); + await testHelper.RequestResolveCompletion(completions[0]); - Assert.True(completions != null && completions.Length > 0, "Completion items list is not null and not empty"); + Assert.True(completions != null && completions.Length > 0, "Completion items list is null or empty"); - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } @@ -125,42 +113,42 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests [Fact] public async Task DiagnosticsTests() { - try - { - string ownerUri = System.IO.Path.GetTempFileName(); - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); - Assert.True(connected, "Connection is successful"); + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection); + Assert.True(connected, "Connection was not successful"); Thread.Sleep(500); string query = "SELECT *** FROM sys.objects"; - DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() + DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification { - TextDocument = new TextDocumentItem() + TextDocument = new TextDocumentItem { - Uri = ownerUri, + Uri = queryTempFile.FilePath, LanguageId = "enu", Version = 1, Text = query } }; - await RequestOpenDocumentNotification(openParams); + await testHelper.RequestOpenDocumentNotification(openParams); Thread.Sleep(100); var contentChanges = new TextDocumentChangeEvent[1]; - contentChanges[0] = new TextDocumentChangeEvent() + contentChanges[0] = new TextDocumentChangeEvent { - Range = new Range() + Range = new Range { - Start = new Position() + Start = new Position { Line = 0, Character = 5 }, - End = new Position() + End = new Position { Line = 0, Character = 6 @@ -176,24 +164,24 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests TextDocument = new VersionedTextDocumentIdentifier() { Version = 2, - Uri = ownerUri + Uri = queryTempFile.FilePath } }; - await RequestChangeTextDocumentNotification(changeParams); + await testHelper.RequestChangeTextDocumentNotification(changeParams); Thread.Sleep(100); - contentChanges[0] = new TextDocumentChangeEvent() + contentChanges[0] = new TextDocumentChangeEvent { - Range = new Range() + Range = new Range { - Start = new Position() + Start = new Position { Line = 0, Character = 5 }, - End = new Position() + End = new Position { Line = 0, Character = 6 @@ -203,25 +191,21 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests Text = "t" }; - changeParams = new DidChangeTextDocumentParams() + changeParams = new DidChangeTextDocumentParams { ContentChanges = contentChanges, - TextDocument = new VersionedTextDocumentIdentifier() + TextDocument = new VersionedTextDocumentIdentifier { Version = 3, - Uri = ownerUri + Uri = queryTempFile.FilePath } }; - await RequestChangeTextDocumentNotification(changeParams); + await testHelper.RequestChangeTextDocumentNotification(changeParams); Thread.Sleep(2500); - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } @@ -231,11 +215,11 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests [Fact] public async Task ChangeConfigurationTest() { - try - { - string ownerUri = System.IO.Path.GetTempFileName(); - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); - Assert.True(connected, "Connection is successful"); + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) + { + bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection); + Assert.True(connected, "Connection was not successful"); Thread.Sleep(500); @@ -246,37 +230,29 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests Settings = settings }; - await RequestChangeConfigurationNotification(configParams); + await testHelper.RequestChangeConfigurationNotification(configParams); Thread.Sleep(2000); - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } [Fact] public async Task NotificationIsSentAfterOnConnectionAutoCompleteUpdate() { - try + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { // Connect - string ownerUri = System.IO.Path.GetTempFileName(); - await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection); // An event signalling that IntelliSense is ready should be sent shortly thereafter - var readyParams = await Driver.WaitForEvent(IntelliSenseReadyNotification.Type, 30000); + var readyParams = await testHelper.Driver.WaitForEvent(IntelliSenseReadyNotification.Type, 30000); Assert.NotNull(readyParams); - Assert.Equal(ownerUri, readyParams.OwnerUri); + Assert.Equal(queryTempFile.FilePath, readyParams.OwnerUri); - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/PerformanceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/PerformanceTests.cs deleted file mode 100644 index 46372680..00000000 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/PerformanceTests.cs +++ /dev/null @@ -1,582 +0,0 @@ -// -// 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.Reflection; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts; -using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; -using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility; -using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; -using Xunit; - -namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests -{ - public class PerformanceTests : TestBase - { - - private static string ComplexQuery = LoadComplexScript(); - private static string SimpleQuery = "SELECT * FROM sys.all_columns"; - - private static string LoadComplexScript() - { - try - { - string assemblyLocation = Assembly.GetEntryAssembly().Location; - string folderName = Path.GetDirectoryName(assemblyLocation); - string filePath = Path.Combine(folderName, "Scripts/AdventureWorks.sql"); - return File.ReadAllText(filePath); - } - catch(Exception ex) - { - Console.WriteLine("Failed to load the sql script. error: " + ex.Message); - return ""; - } - } - - [Fact] - public async Task HoverTestOnPrem() - { - try - { - string ownerUri = Path.GetTempFileName(); - string query = SimpleQuery; - - await ConnectAsync(TestServerType.OnPrem, query, ownerUri); - Hover hover = await CalculateRunTime(async () => - { - return await RequestHover(ownerUri, query, 0, 15); - }); - Assert.True(hover != null, "Hover tool-tip is not null"); - - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task SuggestionsTest() - { - try - { - string query = SimpleQuery; - TestServerType serverType = TestServerType.OnPrem; - string ownerUri = Path.GetTempFileName(); - - WriteToFile(ownerUri, query); - - await ConnectAsync(serverType, query, ownerUri); - await ValidateCompletionResponse(ownerUri, query, null); - - await ValidateCompletionResponse(ownerUri, query); - - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task DiagnosticsTests() - { - try - { - string ownerUri = Path.GetTempFileName(); - string query = "SELECT * FROM sys.objects"; - - await ConnectAsync(TestServerType.OnPrem, query, ownerUri); - Thread.Sleep(500); - - var contentChanges = new TextDocumentChangeEvent[1]; - contentChanges[0] = new TextDocumentChangeEvent() - { - Range = new Range() - { - Start = new Position() - { - Line = 0, - Character = 5 - }, - End = new Position() - { - Line = 0, - Character = 6 - } - }, - RangeLength = 1, - Text = "z" - }; - - DidChangeTextDocumentParams changeParams = new DidChangeTextDocumentParams() - { - ContentChanges = contentChanges, - TextDocument = new VersionedTextDocumentIdentifier() - { - Version = 2, - Uri = ownerUri - } - }; - TestTimer timer = new TestTimer(); - await RequestChangeTextDocumentNotification(changeParams); - - while (true) - { - var completeEvent = await Driver.WaitForEvent(PublishDiagnosticsNotification.Type, 15000); - if (completeEvent != null && completeEvent.Diagnostics != null && completeEvent.Diagnostics.Length > 0) - { - timer.EndAndPrint(); - break; - } - if (timer.TotalMilliSecondsUntilNow >= 500000) - { - Assert.True(false, "Failed to get Diagnostics"); - break; - } - } - - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); - } - } - - private async Task ValidateCompletionResponse(string ownerUri, string query, [CallerMemberName] string testName = "") - { - TestTimer timer = new TestTimer(); - CompletionItem completion = null; - while (true) - { - CompletionItem[] completions = await RequestCompletion(ownerUri, query, 0, 15); - - completion = completions != null ? completions.FirstOrDefault(x => x.Label == "master") : null; - if (completion != null) - { - if (testName != null) - { - timer.EndAndPrint(testName); - } - break; - } - if (timer.TotalMilliSecondsUntilNow >= 500000) - { - Assert.True(false, "Failed to get a valid auto-complete list"); - break; - } - - Thread.Sleep(50); - } - } - - private async Task VerifyBindingLoadScenario(TestServerType serverType, string query, [CallerMemberName] string testName = "") - { - string ownerUri = Path.GetTempFileName(); - - WriteToFile(ownerUri, query); - - await ConnectAsync(serverType, query, ownerUri); - await ValidateCompletionResponse(ownerUri, query, testName); - - await Disconnect(ownerUri); - } - - [Fact] - public async Task BindingCacheColdAzureSimpleQuery() - { - try - { - string query = SimpleQuery; - Thread.Sleep(5000); - await VerifyBindingLoadScenario(TestServerType.Azure, query); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task BindingCacheColdOnPremSimpleQuery() - { - try - { - string query = SimpleQuery; - await VerifyBindingLoadScenario(TestServerType.OnPrem, query); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task BindingCacheWarmAzureSimpleQuery() - { - try - { - string query = SimpleQuery; - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.Azure; - await ConnectAsync(serverType, query, ownerUri); - Thread.Sleep(10000); - await VerifyBindingLoadScenario(serverType, query); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task BindingCacheWarmOnPremSimpleQuery() - { - try - { - string query = SimpleQuery; - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.OnPrem; - await ConnectAsync(serverType, query, ownerUri); - Thread.Sleep(10000); - await VerifyBindingLoadScenario(serverType, query); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task BindingCacheColdAzureComplexQuery() - { - try - { - string query = ComplexQuery; - await VerifyBindingLoadScenario(TestServerType.Azure, query); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task BindingCacheColdOnPremComplexQuery() - { - try - { - string query = ComplexQuery; - await VerifyBindingLoadScenario(TestServerType.OnPrem, query); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task BindingCacheWarmAzureComplexQuery() - { - try - { - string query = ComplexQuery; - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.Azure; - await ConnectAsync(serverType, query, ownerUri); - Thread.Sleep(100000); - await VerifyBindingLoadScenario(serverType, query); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task BindingCacheWarmOnPremComplexQuery() - { - try - { - string query = ComplexQuery; - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.OnPrem; - await ConnectAsync(serverType, query, ownerUri); - Thread.Sleep(10000); - await VerifyBindingLoadScenario(serverType, query); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task ConnectAzureTest() - { - try - { - string query = SimpleQuery; - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.Azure; - WriteToFile(ownerUri, query); - - DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() - { - TextDocument = new TextDocumentItem() - { - Uri = ownerUri, - LanguageId = "enu", - Version = 1, - Text = query - } - }; - - await RequestOpenDocumentNotification(openParams); - - Thread.Sleep(500); - var connected = await CalculateRunTime(async () => - { - var connectParams = await GetDatabaseConnectionAsync(serverType); - return await Connect(ownerUri, connectParams); - }); - Assert.True(connected, "Connection is successful"); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task ConnectOnPremTest() - { - try - { - string query = SimpleQuery; - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.OnPrem; - WriteToFile(ownerUri, query); - - DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() - { - TextDocument = new TextDocumentItem() - { - Uri = ownerUri, - LanguageId = "enu", - Version = 1, - Text = query - } - }; - - await RequestOpenDocumentNotification(openParams); - - Thread.Sleep(500); - var connected = await CalculateRunTime(async () => - { - var connectParams = await GetDatabaseConnectionAsync(serverType); - return await Connect(ownerUri, connectParams); - }); - Assert.True(connected, "Connection is successful"); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task DisconnectTest() - { - try - { - string query = SimpleQuery; - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.OnPrem; - await ConnectAsync(serverType, query, ownerUri); - Thread.Sleep(1000); - var connected = await CalculateRunTime(async () => - { - return await base.Disconnect(ownerUri); - }); - Assert.True(connected); - } - finally - { - WaitForExit(); - } - } - - [Fact] - public async Task QueryResultSummaryOnPremTest() - { - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.OnPrem; - string query = SimpleQuery; - - await ConnectAsync(serverType, query, ownerUri); - - var queryTask = await CalculateRunTime(async () => - { - return await RunQuery(ownerUri, query); - }); - - Assert.NotNull(queryTask); - Assert.True(queryTask.BatchSummaries.Any(x => x.ResultSetSummaries.Any( r => r.RowCount > 0))); - - await Disconnect(ownerUri); - } - - [Fact] - public async Task QueryResultFirstOnPremTest() - { - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.OnPrem; - string query = SimpleQuery; - - await ConnectAsync(serverType, query, ownerUri); - - var queryResult = await CalculateRunTime(async () => - { - var queryTask = await RunQuery(ownerUri, query); - return await ExecuteSubset(ownerUri, 0, 0, 0, 100); - }); - - Assert.NotNull(queryResult); - Assert.NotNull(queryResult.ResultSubset); - Assert.True(queryResult.ResultSubset.Rows.Count() > 0); - - await Disconnect(ownerUri); - } - - - [Fact] - public async Task CancelQueryOnPremTest() - { - string ownerUri = Path.GetTempFileName(); - TestServerType serverType = TestServerType.OnPrem; - string query = "WAITFOR DELAY '00:01:00';"; - - await ConnectAsync(serverType, query, ownerUri); - var queryParams = new QueryExecuteParams(); - queryParams.OwnerUri = ownerUri; - queryParams.QuerySelection = null; - - var result = await Driver.SendRequest(QueryExecuteRequest.Type, queryParams); - if (result != null && string.IsNullOrEmpty(result.Messages)) - { - TestTimer timer = new TestTimer(); - - while (true) - { - var queryTask = await CancelQuery(ownerUri); - if (queryTask != null) - { - timer.EndAndPrint(); - break; - } - if (timer.TotalMilliSecondsUntilNow >= 100000) - { - Assert.True(false, "Failed to cancel query"); - break; - } - - Thread.Sleep(10); - } - } - else - { - Assert.True(false, "Failed to run the query"); - } - - await Disconnect(ownerUri); - } - - [Fact] - public async Task TestSaveResultsToCsvTest() - { - string ownerUri = Path.GetTempFileName(); - string query = SimpleQuery; - TestServerType serverType = TestServerType.OnPrem; - string output = Path.GetTempFileName(); - await ConnectAsync(serverType, query, ownerUri); - - // Execute a query - await RunQuery(ownerUri, query); - - var saveTask = await CalculateRunTime(async () => - { - return await SaveAsCsv(ownerUri, output, 0, 0); - }); - - await Disconnect(ownerUri); - } - - [Fact] - public async Task TestSaveResultsToJsonTest() - { - string ownerUri = Path.GetTempFileName(); - string query = SimpleQuery; - TestServerType serverType = TestServerType.OnPrem; - await ConnectAsync(serverType, query, ownerUri); - string output = Path.GetTempFileName(); - // Execute a query - await RunQuery(ownerUri, query); - - var saveTask = await CalculateRunTime(async () => - { - return await SaveAsJson(ownerUri, output, 0, 0); - }); - - await Disconnect(ownerUri); - } - - private async Task ConnectAsync(TestServerType serverType, string query, string ownerUri) - { - WriteToFile(ownerUri, query); - - DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() - { - TextDocument = new TextDocumentItem() - { - Uri = ownerUri, - LanguageId = "enu", - Version = 1, - Text = query - } - }; - - await RequestOpenDocumentNotification(openParams); - - Thread.Sleep(500); - var connectParams = await GetDatabaseConnectionAsync(serverType); - bool connected = await Connect(ownerUri, connectParams); - Assert.True(connected, "Connection is successful"); - if (connected) - { - Console.WriteLine("Connection is successful"); - } - - return connected; - } - - private async Task CalculateRunTime(Func> testToRun, [CallerMemberName] string testName = "") - { - TestTimer timer = new TestTimer(); - T result = await testToRun(); - timer.EndAndPrint(testName); - - return result; - } - } -} diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/QueryExecutionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/QueryExecutionTests.cs index a06e1e90..d57f91d9 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/QueryExecutionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/QueryExecutionTests.cs @@ -14,219 +14,243 @@ using Xunit; namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests { - public class QueryExecutionTests : TestBase + public class QueryExecutionTests { [Fact] public async Task TestQueryCancelReliability() { - string ownerUri = System.IO.Path.GetTempFileName(); - string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c"; + const string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c"; - await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); - - // Run and cancel 100 queries - for (int i = 0; i < 100; i++) + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { - var queryTask = RunQuery(ownerUri, query); + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.AzureTestServerConnection); - var cancelResult = await CancelQuery(ownerUri); - Assert.NotNull(cancelResult); - Assert.True(string.IsNullOrEmpty(cancelResult.Messages)); + // Run and cancel 100 queries + for (int i = 0; i < 100; i++) + { + var queryTask = testHelper.RunQuery(queryTempFile.FilePath, query); - await queryTask; + var cancelResult = await testHelper.CancelQuery(queryTempFile.FilePath); + Assert.NotNull(cancelResult); + Assert.True(string.IsNullOrEmpty(cancelResult.Messages)); + + await queryTask; + } + + await testHelper.Disconnect(queryTempFile.FilePath); } - - await Disconnect(ownerUri); } [Fact] public async Task TestQueryDoesNotBlockOtherRequests() { - string ownerUri = System.IO.Path.GetTempFileName(); - string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c"; + const string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c"; - await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); - - // Start a long-running query - var queryTask = RunQuery(ownerUri, query, 60000); - - // Interact with the service. None of these requests should time out while waiting for the query to finish - for (int i = 0; i < 10; i++) + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { - string ownerUri2 = System.IO.Path.GetTempFileName(); + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.AzureTestServerConnection); - await Connect(ownerUri2, ConnectionTestUtils.AzureTestServerConnection); - Assert.NotNull(await RequestCompletion(ownerUri2, "SELECT * FROM sys.objects", 0, 10)); - await Disconnect(ownerUri2); + // Start a long-running query + var queryTask = testHelper.RunQuery(queryTempFile.FilePath, query, 60000); + + // Interact with the service. None of these requests should time out while waiting for the query to finish + for (int i = 0; i < 10; i++) + { + using (SelfCleaningTempFile queryFile2 = new SelfCleaningTempFile()) + { + await testHelper.Connect(queryFile2.FilePath, ConnectionTestUtils.AzureTestServerConnection); + Assert.NotNull(await testHelper.RequestCompletion(queryFile2.FilePath, "SELECT * FROM sys.objects", 0, 10)); + await testHelper.Disconnect(queryFile2.FilePath); + } + } + + await testHelper.CancelQuery(queryTempFile.FilePath); + await testHelper.Disconnect(queryTempFile.FilePath); } - - await CancelQuery(ownerUri); - await Disconnect(ownerUri); } [Fact] public async Task TestParallelQueryExecution() { - int queryCount = 10; + const int queryCount = 10; + const string query = "SELECT * FROM sys.objects"; - // Create n connections - string[] ownerUris = new string[queryCount]; - for (int i = 0; i < queryCount; i++) + using (TestHelper testHelper = new TestHelper()) { - ownerUris[i] = System.IO.Path.GetTempFileName(); - Assert.NotNull(await Connect(ownerUris[i], ConnectionTestUtils.AzureTestServerConnection)); - } + // Create n connections + SelfCleaningTempFile[] ownerUris = new SelfCleaningTempFile[queryCount]; + for (int i = 0; i < queryCount; i++) + { + ownerUris[i] = new SelfCleaningTempFile(); + Assert.NotNull(await testHelper.Connect(ownerUris[i].FilePath, ConnectionTestUtils.AzureTestServerConnection)); + } - // Run n queries at once - string query = "SELECT * FROM sys.objects"; - var queryTasks = new Task[queryCount]; - for (int i = 0; i < queryCount; i++) - { - queryTasks[i] = RunQuery(ownerUris[i], query); - } - await Task.WhenAll(queryTasks); + // Run n queries at once + var queryTasks = new Task[queryCount]; + for (int i = 0; i < queryCount; i++) + { + queryTasks[i] = testHelper.RunQuery(ownerUris[i].FilePath, query); + } + await Task.WhenAll(queryTasks); - // Verify that they all completed with results and Disconnect - for (int i = 0; i < queryCount; i++) - { - Assert.NotNull(queryTasks[i].Result); - Assert.NotNull(queryTasks[i].Result.BatchSummaries); - await Disconnect(ownerUris[i]); + // Verify that they all completed with results and Disconnect + for (int i = 0; i < queryCount; i++) + { + Assert.NotNull(queryTasks[i].Result); + Assert.NotNull(queryTasks[i].Result.BatchSummaries); + await testHelper.Disconnect(ownerUris[i].FilePath); + ownerUris[i].Dispose(); + } } } [Fact] public async Task TestSaveResultsDoesNotBlockOtherRequests() { - string ownerUri = System.IO.Path.GetTempFileName(); - string query = "SELECT * FROM sys.objects"; + const string query = "SELECT * FROM sys.objects"; - await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); - - // Execute a query - await RunQuery(ownerUri, query); - - // Spawn several tasks to save results - var saveTasks = new Task[100]; - for (int i = 0; i < 100; i++) + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { - if (i % 2 == 0) + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.AzureTestServerConnection); + + // Execute a query + await testHelper.RunQuery(queryTempFile.FilePath, query); + + // Spawn several tasks to save results + var saveTasks = new Task[100]; + for (int i = 0; i < 100; i++) { - saveTasks[i] = SaveAsCsv(ownerUri, System.IO.Path.GetTempFileName(), 0, 0); + if (i % 2 == 0) + { + saveTasks[i] = testHelper.SaveAsCsv(queryTempFile.FilePath, System.IO.Path.GetTempFileName(), 0, 0); + } + else + { + saveTasks[i] = testHelper.SaveAsJson(queryTempFile.FilePath, System.IO.Path.GetTempFileName(), 0, 0); + } } - else + + // Interact with the service. None of these requests should time out while waiting for the save results tasks to finish + for (int i = 0; i < 10; i++) { - saveTasks[i] = SaveAsJson(ownerUri, System.IO.Path.GetTempFileName(), 0, 0); + using(SelfCleaningTempFile queryFile2 = new SelfCleaningTempFile()) + { + await testHelper.Connect(queryFile2.FilePath, ConnectionTestUtils.AzureTestServerConnection); + Assert.NotNull(await testHelper.RequestCompletion(queryFile2.FilePath, "SELECT * FROM sys.objects", 0, 10)); + await testHelper.Disconnect(queryFile2.FilePath); + } } + + await Task.WhenAll(saveTasks); + + await testHelper.Disconnect(queryTempFile.FilePath); } - - // Interact with the service. None of these requests should time out while waiting for the save results tasks to finish - for (int i = 0; i < 10; i++) - { - string ownerUri2 = System.IO.Path.GetTempFileName(); - - await Connect(ownerUri2, ConnectionTestUtils.AzureTestServerConnection); - Assert.NotNull(await RequestCompletion(ownerUri2, "SELECT * FROM sys.objects", 0, 10)); - await Disconnect(ownerUri2); - } - - await Task.WhenAll(saveTasks); - - await Disconnect(ownerUri); } [Fact] public async Task TestQueryingSubsetDoesNotBlockOtherRequests() { - string ownerUri = System.IO.Path.GetTempFileName(); - string query = "SELECT * FROM sys.objects"; + const string query = "SELECT * FROM sys.objects"; - await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); - - // Execute a query - await RunQuery(ownerUri, query); - - // Spawn several tasks for subset requests - var subsetTasks = new Task[100]; - for (int i = 0; i < 100; i++) + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { - subsetTasks[i] = ExecuteSubset(ownerUri, 0, 0, 0, 100); + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.AzureTestServerConnection); + + // Execute a query + await testHelper.RunQuery(queryTempFile.FilePath, query); + + // Spawn several tasks for subset requests + var subsetTasks = new Task[100]; + for (int i = 0; i < 100; i++) + { + subsetTasks[i] = testHelper.ExecuteSubset(queryTempFile.FilePath, 0, 0, 0, 100); + } + + // Interact with the service. None of these requests should time out while waiting for the subset tasks to finish + for (int i = 0; i < 10; i++) + { + using (SelfCleaningTempFile queryFile2 = new SelfCleaningTempFile()) + { + await testHelper.Connect(queryFile2.FilePath, ConnectionTestUtils.AzureTestServerConnection); + Assert.NotNull(await testHelper.RequestCompletion(queryFile2.FilePath, "SELECT * FROM sys.objects", 0, 10)); + await testHelper.Disconnect(queryFile2.FilePath); + } + } + + await Task.WhenAll(subsetTasks); + + await testHelper.Disconnect(queryTempFile.FilePath); } - - // Interact with the service. None of these requests should time out while waiting for the subset tasks to finish - for (int i = 0; i < 10; i++) - { - string ownerUri2 = System.IO.Path.GetTempFileName(); - - await Connect(ownerUri2, ConnectionTestUtils.AzureTestServerConnection); - Assert.NotNull(await RequestCompletion(ownerUri2, "SELECT * FROM sys.objects", 0, 10)); - await Disconnect(ownerUri2); - } - - await Task.WhenAll(subsetTasks); - - await Disconnect(ownerUri); } [Fact] public async Task TestCancelQueryWhileOtherOperationsAreInProgress() { - string ownerUri = System.IO.Path.GetTempFileName(); - string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b"; - List tasks = new List(); + const string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b"; - await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); - - // Execute a long-running query - var queryTask = RunQuery(ownerUri, query, 60000); - - // Queue up some tasks that interact with the service - for (int i = 0; i < 10; i++) + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { - string ownerUri2 = System.IO.Path.GetTempFileName(); + List tasks = new List(); - tasks.Add(Task.Run(async () => + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.AzureTestServerConnection); + + // Execute a long-running query + var queryTask = testHelper.RunQuery(queryTempFile.FilePath, query, 60000); + + // Queue up some tasks that interact with the service + for (int i = 0; i < 10; i++) { - await Connect(ownerUri2, ConnectionTestUtils.AzureTestServerConnection); - await RequestCompletion(ownerUri2, "SELECT * FROM sys.objects", 0, 10); - await RunQuery(ownerUri2, "SELECT * FROM sys.objects"); - await Disconnect(ownerUri2); - })); + using (SelfCleaningTempFile queryFile2 = new SelfCleaningTempFile()) + { + tasks.Add(Task.Run(async () => + { + await testHelper.Connect(queryFile2.FilePath, ConnectionTestUtils.AzureTestServerConnection); + await testHelper.RequestCompletion(queryFile2.FilePath, "SELECT * FROM sys.objects", 0, 10); + await testHelper.RunQuery(queryFile2.FilePath, "SELECT * FROM sys.objects"); + await testHelper.Disconnect(queryFile2.FilePath); + })); + } + } + + // Cancel the long-running query + await testHelper.CancelQuery(queryTempFile.FilePath); + + await testHelper.Disconnect(queryTempFile.FilePath); } - - // Cancel the long-running query - await CancelQuery(ownerUri); - - await Disconnect(ownerUri); } [Fact] public async Task ExecuteBasicQueryTest() { - try + const string query = "SELECT * FROM sys.all_columns c"; + + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { - string ownerUri = System.IO.Path.GetTempFileName(); - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); + bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection); Assert.True(connected, "Connection is successful"); Thread.Sleep(500); - string query = "SELECT * FROM sys.all_columns c"; - DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() { TextDocument = new TextDocumentItem() { - Uri = ownerUri, + Uri = queryTempFile.FilePath, LanguageId = "enu", Version = 1, Text = query } }; - await RequestOpenDocumentNotification(openParams); + await testHelper.RequestOpenDocumentNotification(openParams); - var queryResult = await RunQuery(ownerUri, query); + var queryResult = await testHelper.RunQuery(queryTempFile.FilePath, query, 10000); Assert.NotNull(queryResult); Assert.NotNull(queryResult.BatchSummaries); @@ -241,69 +265,62 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests var subsetRequest = new QueryExecuteSubsetParams() { - OwnerUri = ownerUri, + OwnerUri = queryTempFile.FilePath, BatchIndex = 0, ResultSetIndex = 0, RowsStartIndex = 0, RowsCount = 100, }; - var querySubset = await RequestQueryExecuteSubset(subsetRequest); + var querySubset = await testHelper.RequestQueryExecuteSubset(subsetRequest); Assert.NotNull(querySubset); Assert.True(querySubset.ResultSubset.RowCount == 100); - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } [Fact] public async Task TestQueryingAfterCompletionRequests() { - try + const string query = "SELECT * FROM sys.objects"; + + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { - string ownerUri = System.IO.Path.GetTempFileName(); - string query = "SELECT * FROM sys.objects"; List tasks = new List(); - await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.AzureTestServerConnection); - Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(RequestCompletion(ownerUri, query, 0, 10))); - var queryTask = RunQuery(ownerUri, query); + Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(testHelper.RequestCompletion(queryTempFile.FilePath, query, 0, 10))); + var queryTask = testHelper.RunQuery(queryTempFile.FilePath, query); tasks.Add(queryTask); await Task.WhenAll(tasks); Assert.NotNull(queryTask.Result); Assert.NotNull(queryTask.Result.BatchSummaries); - await Connect(ownerUri, ConnectionTestUtils.DataToolsTelemetryAzureConnection); + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.DataToolsTelemetryAzureConnection); tasks.Clear(); - Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(RequestCompletion(ownerUri, query, 0, 10))); - queryTask = RunQuery(ownerUri, query); + Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(testHelper.RequestCompletion(queryTempFile.FilePath, query, 0, 10))); + queryTask = testHelper.RunQuery(queryTempFile.FilePath, query); tasks.Add(queryTask); await Task.WhenAll(tasks); Assert.NotNull(queryTask.Result); Assert.NotNull(queryTask.Result.BatchSummaries); - await Connect(ownerUri, ConnectionTestUtils.SqlDataToolsAzureConnection); + await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.SqlDataToolsAzureConnection); tasks.Clear(); - Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(RequestCompletion(ownerUri, query, 0, 10))); - queryTask = RunQuery(ownerUri, query); + Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(testHelper.RequestCompletion(queryTempFile.FilePath, query, 0, 10))); + queryTask = testHelper.RunQuery(queryTempFile.FilePath, query); tasks.Add(queryTask); await Task.WhenAll(tasks); Assert.NotNull(queryTask.Result); Assert.NotNull(queryTask.Result.BatchSummaries); - await Disconnect(ownerUri); - } - finally - { - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/StressTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/StressTests.cs index cbb603ca..bd39ee4a 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/StressTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/StressTests.cs @@ -13,7 +13,7 @@ using Xunit; namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests { - public class StressTests : TestBase + public class StressTests { /// /// Simulate typing by a user to stress test the language service @@ -21,24 +21,24 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests //[Fact] public async Task TestLanguageService() { - string textToType = - "SELECT * FROM sys.objects GO " + - "CREATE TABLE MyTable(" + - "FirstName CHAR," + - "LastName CHAR," + - "DateOfBirth DATETIME," + - "CONSTRAINT MyTableConstraint UNIQUE (FirstName, LastName, DateOfBirth)) GO " + - "INSERT INTO MyTable (FirstName, LastName, DateOfBirth) VALUES ('John', 'Doe', '19800101') GO " + - "SELECT * FROM MyTable GO " + - "ALTER TABLE MyTable DROP CONSTRAINT MyTableConstraint GO " + - "DROP TABLE MyTable GO "; - var ownerUri = System.IO.Path.GetTempFileName(); + const string textToType = "SELECT * FROM sys.objects GO " + + "CREATE TABLE MyTable(" + + "FirstName CHAR," + + "LastName CHAR," + + "DateOfBirth DATETIME," + + "CONSTRAINT MyTableConstraint UNIQUE (FirstName, LastName, DateOfBirth)) GO " + + "INSERT INTO MyTable (FirstName, LastName, DateOfBirth) VALUES ('John', 'Doe', '19800101') GO " + + "SELECT * FROM MyTable GO " + + "ALTER TABLE MyTable DROP CONSTRAINT MyTableConstraint GO " + + "DROP TABLE MyTable GO "; - try + + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { // Connect - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); - Assert.True(connected, "Connection is successful"); + bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection); + Assert.True(connected, "Connection was not successful"); Thread.Sleep(10000); // Wait for intellisense to warm up @@ -50,7 +50,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests { for (int i = 0; i < textToType.Length; i++) { - System.IO.File.WriteAllText(ownerUri, textToType.Substring(0, i + 1)); + System.IO.File.WriteAllText(queryTempFile.FilePath, textToType.Substring(0, i + 1)); var contentChanges = new TextDocumentChangeEvent[1]; contentChanges[0] = new TextDocumentChangeEvent() @@ -78,30 +78,30 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests TextDocument = new VersionedTextDocumentIdentifier() { Version = ++version, - Uri = ownerUri + Uri = queryTempFile.FilePath } }; - await RequestChangeTextDocumentNotification(changeParams); + await testHelper.RequestChangeTextDocumentNotification(changeParams); Thread.Sleep(50); // If we just typed a space, request/resolve completion if (textToType[i] == ' ') { - var completions = await RequestCompletion(ownerUri, textToType.Substring(0, i + 1), 0, i + 1); - Assert.True(completions != null && completions.Length > 0, "Completion items list is not null and not empty"); + var completions = await testHelper.RequestCompletion(queryTempFile.FilePath, textToType.Substring(0, i + 1), 0, i + 1); + Assert.True(completions != null && completions.Length > 0, "Completion items list was null or empty"); Thread.Sleep(50); - var item = await RequestResolveCompletion(completions[0]); + var item = await testHelper.RequestResolveCompletion(completions[0]); Assert.NotNull(item); } } // Clear the text document - System.IO.File.WriteAllText(ownerUri, ""); + System.IO.File.WriteAllText(queryTempFile.FilePath, ""); var contentChanges2 = new TextDocumentChangeEvent[1]; contentChanges2[0] = new TextDocumentChangeEvent() @@ -129,23 +129,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests TextDocument = new VersionedTextDocumentIdentifier() { Version = ++version, - Uri = ownerUri + Uri = queryTempFile.FilePath } }; - await RequestChangeTextDocumentNotification(changeParams2); + await testHelper.RequestChangeTextDocumentNotification(changeParams2); } - await Disconnect(ownerUri); - } - finally - { - try - { - System.IO.File.Delete(ownerUri); - } - catch {} - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } @@ -155,13 +146,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests //[Fact] public async Task TestQueryExecutionService() { - string queryToRun = "SELECT * FROM sys.all_objects GO SELECT * FROM sys.objects GO SELECT * FROM sys.tables GO SELECT COUNT(*) FROM sys.objects"; - var ownerUri = System.IO.Path.GetTempFileName(); + const string queryToRun = "SELECT * FROM sys.all_objects GO " + + "SELECT * FROM sys.objects GO " + + "SELECT * FROM sys.tables GO " + + "SELECT COUNT(*) FROM sys.objects"; - try + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + using (TestHelper testHelper = new TestHelper()) { // Connect - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); + bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection); Assert.True(connected, "Connection is successful"); // Run queries repeatedly @@ -169,7 +163,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests stopwatch.Start(); while (stopwatch.Elapsed < TimeSpan.FromMinutes(60)) { - var queryResult = await RunQuery(ownerUri, queryToRun, 10000); + var queryResult = await testHelper.RunQuery(queryTempFile.FilePath, queryToRun, 10000); Assert.NotNull(queryResult); Assert.NotNull(queryResult.BatchSummaries); @@ -179,24 +173,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests Assert.NotNull(queryResult.BatchSummaries[2].ResultSetSummaries); Assert.NotNull(queryResult.BatchSummaries[3].ResultSetSummaries); - Assert.NotNull(await ExecuteSubset(ownerUri, 0, 0, 0, 7)); - Assert.NotNull(await ExecuteSubset(ownerUri, 1, 0, 0, 7)); - Assert.NotNull(await ExecuteSubset(ownerUri, 2, 0, 0, 7)); - Assert.NotNull(await ExecuteSubset(ownerUri, 3, 0, 0, 1)); + Assert.NotNull(await testHelper.ExecuteSubset(queryTempFile.FilePath, 0, 0, 0, 7)); + Assert.NotNull(await testHelper.ExecuteSubset(queryTempFile.FilePath, 1, 0, 0, 7)); + Assert.NotNull(await testHelper.ExecuteSubset(queryTempFile.FilePath, 2, 0, 0, 7)); + Assert.NotNull(await testHelper.ExecuteSubset(queryTempFile.FilePath, 3, 0, 0, 1)); Thread.Sleep(500); } - await Disconnect(ownerUri); - } - finally - { - try - { - System.IO.File.Delete(ownerUri); - } - catch {} - WaitForExit(); + await testHelper.Disconnect(queryTempFile.FilePath); } } @@ -211,7 +196,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests var connection = ConnectionTestUtils.LocalhostConnection; connection.Connection.Pooling = false; - try + using (TestHelper testHelper = new TestHelper()) { // Connect/disconnect repeatedly Stopwatch stopwatch = new Stopwatch(); @@ -219,18 +204,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests while (stopwatch.Elapsed < TimeSpan.FromMinutes(60)) { // Connect - bool connected = await Connect(ownerUri, connection); + bool connected = await testHelper.Connect(ownerUri, connection); Assert.True(connected, "Connection is successful"); // Disconnect - bool disconnected = await Disconnect(ownerUri); + bool disconnected = await testHelper.Disconnect(ownerUri); Assert.True(disconnected, "Disconnect is successful"); } } - finally - { - WaitForExit(); - } } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestBase.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestHelper.cs similarity index 71% rename from test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestBase.cs rename to test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestHelper.cs index 5803d150..7f675941 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestBase.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestHelper.cs @@ -4,7 +4,6 @@ // using System; -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.SqlTools.ServiceLayer.Connection.Contracts; @@ -21,11 +20,11 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Base class for all test suites run by the test driver /// - public class TestBase : IDisposable + public sealed class TestHelper : IDisposable { private bool isRunning = false; - public TestBase() + public TestHelper() { Driver = new ServiceTestDriver(); Driver.Start().Wait(); @@ -44,21 +43,13 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests { try { - this.isRunning = false; - - if (!Driver.IsCoverageRun) - { - Driver.Stop().Wait(); - } - else - { - var p = Process.Start("taskkill", "/IM Microsoft.SqlTools.ServiceLayer.exe /F"); - p.WaitForExit(); - Driver.ServiceProcess?.WaitForExit(); - } + this.isRunning = false; + Driver.Stop().Wait(); + Console.WriteLine("Successfully killed process."); } - catch - { + catch(Exception e) + { + Console.WriteLine($"Exception while waiting for service exit: {e.Message}"); } } @@ -77,7 +68,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// Request a new connection to be created /// /// True if the connection completed successfully - protected async Task Connect(string ownerUri, ConnectParams connectParams, int timeout = 15000) + public async Task Connect(string ownerUri, ConnectParams connectParams, int timeout = 15000) { connectParams.OwnerUri = ownerUri; var connectResult = await Driver.SendRequest(ConnectionRequest.Type, connectParams); @@ -95,7 +86,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request a disconnect /// - protected async Task Disconnect(string ownerUri) + public async Task Disconnect(string ownerUri) { var disconnectParams = new DisconnectParams(); disconnectParams.OwnerUri = ownerUri; @@ -107,7 +98,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request a cancel connect /// - protected async Task CancelConnect(string ownerUri) + public async Task CancelConnect(string ownerUri) { var cancelParams = new CancelConnectParams(); cancelParams.OwnerUri = ownerUri; @@ -118,7 +109,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request a cancel connect /// - protected async Task ListDatabases(string ownerUri) + public async Task ListDatabases(string ownerUri) { var listParams = new ListDatabasesParams(); listParams.OwnerUri = ownerUri; @@ -129,7 +120,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request the active SQL script is parsed for errors /// - protected async Task RequestQueryExecuteSubset(QueryExecuteSubsetParams subsetParams) + public async Task RequestQueryExecuteSubset(QueryExecuteSubsetParams subsetParams) { return await Driver.SendRequest(QueryExecuteSubsetRequest.Type, subsetParams); } @@ -137,7 +128,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request the active SQL script is parsed for errors /// - protected async Task RequestOpenDocumentNotification(DidOpenTextDocumentNotification openParams) + public async Task RequestOpenDocumentNotification(DidOpenTextDocumentNotification openParams) { await Driver.SendEvent(DidOpenTextDocumentNotification.Type, openParams); } @@ -145,7 +136,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request a configuration change notification /// - protected async Task RequestChangeConfigurationNotification(DidChangeConfigurationParams configParams) + public async Task RequestChangeConfigurationNotification(DidChangeConfigurationParams configParams) { await Driver.SendEvent(DidChangeConfigurationNotification.Type, configParams); } @@ -153,7 +144,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// /// Request the active SQL script is parsed for errors /// - protected async Task RequestChangeTextDocumentNotification(DidChangeTextDocumentParams changeParams) + public async Task RequestChangeTextDocumentNotification(DidChangeTextDocumentParams changeParams) { await Driver.SendEvent(DidChangeTextDocumentNotification.Type, changeParams); } @@ -161,7 +152,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request completion item resolve to look-up additional info /// - protected async Task RequestResolveCompletion(CompletionItem item) + public async Task RequestResolveCompletion(CompletionItem item) { var result = await Driver.SendRequest(CompletionResolveRequest.Type, item); return result; @@ -170,7 +161,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request a Read Credential for given credential id /// - protected async Task ReadCredential(string credentialId) + public async Task ReadCredential(string credentialId) { var credentialParams = new Credential(); credentialParams.CredentialId = credentialId; @@ -181,7 +172,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Returns database connection parameters for given server type /// - protected async Task GetDatabaseConnectionAsync(TestServerType serverType) + public async Task GetDatabaseConnectionAsync(TestServerType serverType) { ConnectionProfile connectionProfile = null; TestServerIdentity serverIdentiry = ConnectionTestUtils.TestServers.FirstOrDefault(x => x.ServerType == serverType); @@ -212,7 +203,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request a list of completion items for a position in a block of text /// - protected async Task RequestCompletion(string ownerUri, string text, int line, int character) + public async Task RequestCompletion(string ownerUri, string text, int line, int character) { // Write the text to a backing file lock (fileLock) @@ -234,7 +225,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request a a hover tooltop /// - protected async Task RequestHover(string ownerUri, string text, int line, int character) + public async Task RequestHover(string ownerUri, string text, int line, int character) { // Write the text to a backing file lock (fileLock) @@ -242,12 +233,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests System.IO.File.WriteAllText(ownerUri, text); } - var completionParams = new TextDocumentPosition(); - completionParams.TextDocument = new TextDocumentIdentifier(); - completionParams.TextDocument.Uri = ownerUri; - completionParams.Position = new Position(); - completionParams.Position.Line = line; - completionParams.Position.Character = character; + var completionParams = new TextDocumentPosition + { + TextDocument = new TextDocumentIdentifier {Uri = ownerUri}, + Position = new Position + { + Line = line, + Character = character + } + }; var result = await Driver.SendRequest(HoverRequest.Type, completionParams); return result; @@ -256,14 +250,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Run a query using a given connection bound to a URI /// - protected async Task RunQuery(string ownerUri, string query, int timeoutMilliseconds = 5000) + public async Task RunQuery(string ownerUri, string query, int timeoutMilliseconds = 5000) { // Write the query text to a backing file WriteToFile(ownerUri, query); - var queryParams = new QueryExecuteParams(); - queryParams.OwnerUri = ownerUri; - queryParams.QuerySelection = null; + var queryParams = new QueryExecuteParams + { + OwnerUri = ownerUri, + QuerySelection = null + }; var result = await Driver.SendRequest(QueryExecuteRequest.Type, queryParams); if (result != null && string.IsNullOrEmpty(result.Messages)) @@ -280,10 +276,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request to cancel an executing query /// - protected async Task CancelQuery(string ownerUri) + public async Task CancelQuery(string ownerUri) { - var cancelParams = new QueryCancelParams(); - cancelParams.OwnerUri = ownerUri; + var cancelParams = new QueryCancelParams {OwnerUri = ownerUri}; var result = await Driver.SendRequest(QueryCancelRequest.Type, cancelParams); return result; @@ -292,14 +287,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request to save query results as CSV /// - protected async Task SaveAsCsv(string ownerUri, string filename, int batchIndex, int resultSetIndex) + public async Task SaveAsCsv(string ownerUri, string filename, int batchIndex, int resultSetIndex) { - var saveParams = new SaveResultsAsCsvRequestParams(); - saveParams.OwnerUri = ownerUri; - saveParams.BatchIndex = batchIndex; - saveParams.ResultSetIndex = resultSetIndex; - saveParams.FilePath = filename; - + var saveParams = new SaveResultsAsCsvRequestParams + { + OwnerUri = ownerUri, + BatchIndex = batchIndex, + ResultSetIndex = resultSetIndex, + FilePath = filename + }; + var result = await Driver.SendRequest(SaveResultsAsCsvRequest.Type, saveParams); return result; } @@ -307,14 +304,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request to save query results as JSON /// - protected async Task SaveAsJson(string ownerUri, string filename, int batchIndex, int resultSetIndex) + public async Task SaveAsJson(string ownerUri, string filename, int batchIndex, int resultSetIndex) { - var saveParams = new SaveResultsAsJsonRequestParams(); - saveParams.OwnerUri = ownerUri; - saveParams.BatchIndex = batchIndex; - saveParams.ResultSetIndex = resultSetIndex; - saveParams.FilePath = filename; - + var saveParams = new SaveResultsAsJsonRequestParams + { + OwnerUri = ownerUri, + BatchIndex = batchIndex, + ResultSetIndex = resultSetIndex, + FilePath = filename + }; + var result = await Driver.SendRequest(SaveResultsAsJsonRequest.Type, saveParams); return result; } @@ -322,7 +321,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Request a subset of results from a query /// - protected async Task ExecuteSubset(string ownerUri, int batchIndex, int resultSetIndex, int rowStartIndex, int rowCount) + public async Task ExecuteSubset(string ownerUri, int batchIndex, int resultSetIndex, int rowStartIndex, int rowCount) { var subsetParams = new QueryExecuteSubsetParams(); subsetParams.OwnerUri = ownerUri; @@ -335,7 +334,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests return result; } - protected void WriteToFile(string ownerUri, string query) + public void WriteToFile(string ownerUri, string query) { lock (fileLock) { diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/WorkspaceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/WorkspaceTests.cs index 0796dc44..59814534 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/WorkspaceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/WorkspaceTests.cs @@ -13,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests /// /// Language Service end-to-end integration tests /// - public class WorkspaceTests : TestBase + public class WorkspaceTests { /// /// Validate workspace lifecycle events @@ -21,7 +21,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests [Fact] public async Task InitializeRequestTest() { - try + using (TestHelper testHelper = new TestHelper()) { InitializeRequest initializeRequest = new InitializeRequest() { @@ -29,13 +29,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests Capabilities = new ClientCapabilities() }; - InitializeResult result = await Driver.SendRequest(InitializeRequest.Type, initializeRequest); + InitializeResult result = await testHelper.Driver.SendRequest(InitializeRequest.Type, initializeRequest); Assert.NotNull(result); } - finally - { - WaitForExit(); - } } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Utility/SelfCleaningTempFile.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Utility/SelfCleaningTempFile.cs new file mode 100644 index 00000000..c991e3ff --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Utility/SelfCleaningTempFile.cs @@ -0,0 +1,53 @@ +// +// 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; + +namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Utility +{ + public class SelfCleaningTempFile : IDisposable + { + private bool disposed; + + public SelfCleaningTempFile() + { + FilePath = Path.GetTempFileName(); + } + + public string FilePath { get; private set; } + + #region IDisposable Implementation + + public void Dispose() + { + if (!disposed) + { + Dispose(true); + GC.SuppressFinalize(this); + } + } + + public void Dispose(bool disposing) + { + if (!disposed && disposing) + { + try + { + File.Delete(FilePath); + } + catch + { + Console.WriteLine($"Failed to cleanup {FilePath}"); + } + } + + disposed = true; + } + + #endregion + + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Utility/TestRunner.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Utility/TestRunner.cs new file mode 100644 index 00000000..a3b6fc61 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Utility/TestRunner.cs @@ -0,0 +1,76 @@ +// +// 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.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Utility +{ + public class TestRunner + { + public static async Task RunTests(string[] tests, string testNamespace) + { + foreach (var test in tests) + { + try + { + var testName = test.Contains(testNamespace) ? test.Replace(testNamespace, "") : test; + bool containsTestName = testName.Contains("."); + var className = containsTestName ? testName.Substring(0, testName.LastIndexOf('.')) : testName; + var methodName = containsTestName ? testName.Substring(testName.LastIndexOf('.') + 1) : null; + + + var type = Type.GetType(testNamespace + className); + if (type == null) + { + Console.WriteLine("Invalid class name"); + } + else + { + if (string.IsNullOrEmpty(methodName)) + { + var methods = type.GetMethods().Where(x => x.CustomAttributes.Any(a => a.AttributeType == typeof(FactAttribute))); + foreach (var method in methods) + { + await RunTest(type, method, method.Name); + } + } + else + { + MethodInfo methodInfo = type.GetMethod(methodName); + await RunTest(type, methodInfo, test); + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + return -1; + } + } + return 0; + } + + private static async Task RunTest(Type type, MethodBase methodInfo, string testName) + { + if (methodInfo == null) + { + Console.WriteLine("Invalid method name"); + } + else + { + using (var typeInstance = (IDisposable)Activator.CreateInstance(type)) + { + Console.WriteLine("Running test " + testName); + await (Task)methodInfo.Invoke(typeInstance, null); + Console.WriteLine("Test ran successfully: " + testName); + } + } + } + } +}