Fix Code Coverage (#151)

This is another large code review. I want to make a few more changes, but since these changes will stand on their own, I'll hold back on making this change set any larger than it already is.
Changes in this request:
To address Microsoft/vscode-mssql#326, instead of doing taskkill on the service layer when WaitForExit is executed, we now make an educated guess at which service layer was spawned when the test starts and do a Process.Kill on it when we shut down the test.
All the perf tests have been moved into a new project. This was done to keep them easily separated from code coverage test runs. At the same time the perf tests were separated into separate classes for logical categorization. This process will likely be repeated on the stress tests. The tests can still easily be ran from Visual Studio Test Explorer
To address Microsoft/vscode-mssql#349, a new SelfCleaningFile class was created to allow for easy cleanup of temporary files generated for integration tests via using blocks.
Due to some of the refactoring done while moving the perf tests to a new project, the TestBase class had to be switched to more of a helper class style. As such, all tests that use inherit from TestBase now create a TestBase object on start via a using block. This also simplifies the cleanup at the end of the test.

* Solution for hanging code coverage runs

Code coverage runs would hang in certain scenarios if a test failed before
the service process could be spawned. The taskkill command would fail to
find the service process. The test would then wait for opencover to exit,
but it would not since the service process it had spawned would still be
running, causing the test run to hang indefinitely.

Solution was to capture the service process after it launched and
explicitly kill it when shutting down the test driver.

* Setting the test name in the propery in the class and removign the parameter from each method

* New project for perf tests

* Reworking integration tests to cleanup temp files

* Changes as per @llali review comments

* Adding copyright notices
* Renaming TestBase => TestHelper
* Renaming SelfCleaningFile => SelfCleaningTempFile
* Removing code that sets TestName property

* Fixing compilation error due to removed code
This commit is contained in:
Benjamin Russell
2016-11-18 17:46:56 -08:00
committed by GitHub
parent a54d081363
commit db1e4ae351
23 changed files with 1249 additions and 1051 deletions

View File

@@ -51,6 +51,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeCoverage", "CodeCoverag
test\CodeCoverage\runintegration.bat = test\CodeCoverage\runintegration.bat test\CodeCoverage\runintegration.bat = test\CodeCoverage\runintegration.bat
EndProjectSection EndProjectSection
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{CC785604-6277-4878-8DA9-360C47158E96}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -79,5 +85,6 @@ Global
{CC785604-6277-4878-8DA9-360C47158E96} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {CC785604-6277-4878-8DA9-360C47158E96} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4}
{B7D21727-2926-452B-9610-3ADB0BB6D789} = {F9978D78-78FE-4E92-A7D6-D436B7683EF6} {B7D21727-2926-452B-9610-3ADB0BB6D789} = {F9978D78-78FE-4E92-A7D6-D436B7683EF6}
{87D9C7D9-18F4-4AB9-B20D-66C02B6075E2} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {87D9C7D9-18F4-4AB9-B20D-66C02B6075E2} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4}
{7E5968AB-83D7-4738-85A2-416A50F13D2F} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>7e5968ab-83d7-4738-85a2-416a50f13d2f</ProjectGuid>
<RootNamespace>Microsoft.SqlTools.ServiceLayer.PerfTests</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@@ -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;
}
}
}

View File

@@ -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")]

View File

@@ -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<Task<bool>> 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<bool> 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<T> CalculateRunTime<T>(Func<Task<T>> testToRun, [CallerMemberName] string testName = "")
{
TestTimer timer = new TestTimer();
T result = await testToRun();
timer.EndAndPrint(testName);
return result;
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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"
]
}
}
}

View File

@@ -3,28 +3,13 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // 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;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.Credentials;
using Microsoft.SqlTools.ServiceLayer.LanguageServices; 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.ServiceLayer.Workspace.Contracts;
using Microsoft.SqlTools.Test.Utility; using Microsoft.SqlTools.Test.Utility;
using Moq;
using Moq.Protected;
using Xunit; using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServer
{ {
/// <summary> /// <summary>
/// Tests for the ServiceHost Language Service tests /// Tests for the ServiceHost Language Service tests
@@ -145,14 +130,32 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
#region "General Language Service tests" #region "General Language Service tests"
#if LIVE_CONNECTION_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);
}
/// <summary> /// <summary>
/// Test the service initialization code path and verify nothing throws /// Test the service initialization code path and verify nothing throws
/// </summary> /// </summary>
// Test is causing failures in build lab..investigating to reenable // Test is causing failures in build lab..investigating to reenable
[Fact] [Fact]
public void ServiceInitiailzation() public void ServiceInitialization()
{ {
try try
{ {
@@ -178,8 +181,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
ScriptFile scriptFile; ScriptFile scriptFile;
ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfo(out scriptFile); ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfo(out scriptFile);
ScriptParseInfo scriptInfo = new ScriptParseInfo(); ScriptParseInfo scriptInfo = new ScriptParseInfo {IsConnected = true};
scriptInfo.IsConnected = true;
AutoCompleteHelper.PrepopulateCommonMetadata(connInfo, scriptInfo, null); AutoCompleteHelper.PrepopulateCommonMetadata(connInfo, scriptInfo, null);
} }
@@ -193,7 +195,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
TextDocumentPosition textDocument; TextDocumentPosition textDocument;
ConnectionInfo connInfo; ConnectionInfo connInfo;
ScriptFile scriptFile; ScriptFile scriptFile;
Common.GetAutoCompleteTestObjects(out textDocument, out scriptFile, out connInfo); GetLiveAutoCompleteTestObjects(out textDocument, out scriptFile, out connInfo);
textDocument.Position.Character = 7; textDocument.Position.Character = 7;
scriptFile.Contents = "select "; scriptFile.Contents = "select ";
@@ -209,52 +211,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
#endif #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"
/// <summary>
/// Creates a mock db command that returns a predefined result set
/// </summary>
public static DbCommand CreateTestCommand(Dictionary<string, string>[][] data)
{
var commandMock = new Mock<DbCommand> { CallBase = true };
var commandMockSetup = commandMock.Protected()
.Setup<DbDataReader>("ExecuteDbDataReader", It.IsAny<CommandBehavior>());
commandMockSetup.Returns(new TestDbDataReader(data));
return commandMock.Object;
}
/// <summary>
/// Creates a mock db connection that returns predefined data when queried for a result set
/// </summary>
public DbConnection CreateMockDbConnection(Dictionary<string, string>[][] data)
{
var connectionMock = new Mock<DbConnection> { CallBase = true };
connectionMock.Protected()
.Setup<DbCommand>("CreateDbCommand")
.Returns(CreateTestCommand(data));
return connectionMock.Object;
}
#endregion #endregion
} }
} }

View File

@@ -9,7 +9,10 @@
// //
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts; using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
@@ -33,7 +36,11 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver
public const string ServiceHostEnvironmentVariable = "SQLTOOLSSERVICE_EXE"; public const string ServiceHostEnvironmentVariable = "SQLTOOLSSERVICE_EXE";
public bool IsCoverageRun { get; set; } public bool IsCoverageRun { get; set; }
private Process[] serviceProcesses;
private DateTime startTime;
public ServiceTestDriver() public ServiceTestDriver()
{ {
@@ -71,8 +78,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver
coverageOutput = "coverage.xml"; coverageOutput = "coverage.xml";
} }
serviceHostArguments = "-mergeoutput -target:" + serviceHostExecutable + " -targetargs:" + serviceHostArguments serviceHostArguments = $"-mergeoutput -target:{serviceHostExecutable} -targetargs:{serviceHostArguments} " +
+ " -register:user -oldstyle -filter:\"+[Microsoft.SqlTools.*]* -[xunit*]*\" -output:" + coverageOutput + " -searchdirs:" + serviceHostDirectory; $"-register:user -oldstyle -filter:\"+[Microsoft.SqlTools.*]* -[xunit*]*\" -output:{coverageOutput} " +
$"-searchdirs:{serviceHostDirectory};";
serviceHostExecutable = coverageToolPath; serviceHostExecutable = coverageToolPath;
this.IsCoverageRun = true; this.IsCoverageRun = true;
@@ -88,9 +96,28 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver
/// </summary> /// </summary>
public async Task Start() public async Task Start()
{ {
// Store the time we started
startTime = DateTime.Now;
// Launch the process
await this.protocolClient.Start(); await this.protocolClient.Start();
await Task.Delay(1000); // Wait for the service host to 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 // Setup events to queue for testing
this.QueueEventsForType(ConnectionCompleteNotification.Type); this.QueueEventsForType(ConnectionCompleteNotification.Type);
this.QueueEventsForType(IntelliSenseReadyNotification.Type); this.QueueEventsForType(IntelliSenseReadyNotification.Type);
@@ -103,7 +130,38 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver
/// </summary> /// </summary>
public async Task Stop() 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);
}
}
} }
} }
} }

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
@@ -15,5 +15,8 @@
<PropertyGroup> <PropertyGroup>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View File

@@ -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<string> ComplexQueryInstance = new Lazy<string>(() =>
{
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; } }
}
}

View File

@@ -13,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Language Service end-to-end integration tests /// Language Service end-to-end integration tests
/// </summary> /// </summary>
public class ConnectionTests : TestBase public class ConnectionTest
{ {
/// <summary> /// <summary>
/// Try to connect with invalid credentials /// Try to connect with invalid credentials
@@ -21,23 +21,19 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
[Fact] [Fact]
public async Task InvalidConnection() public async Task InvalidConnection()
{ {
try using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
{ using (TestHelper testHelper = new TestHelper())
string ownerUri = System.IO.Path.GetTempFileName(); {
bool connected = await Connect(ownerUri, ConnectionTestUtils.InvalidConnection, 300000); bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.InvalidConnection, 300000);
Assert.False(connected, "Invalid connection is failed to connect"); 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); Thread.Sleep(1000);
await CancelConnect(ownerUri); await testHelper.CancelConnect(queryTempFile.FilePath);
await Disconnect(ownerUri); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
WaitForExit();
} }
} }
@@ -47,22 +43,17 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
[Fact] [Fact]
public async Task ListDatabasesTest() public async Task ListDatabasesTest()
{ {
try 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 successful"); Assert.True(connected, "Connection successful");
var listDatabaseResult = await ListDatabases(ownerUri); var listDatabaseResult = await testHelper.ListDatabases(queryTempFile.FilePath);
Assert.True(listDatabaseResult.DatabaseNames.Length > 0); Assert.True(listDatabaseResult.DatabaseNames.Length > 0);
await Disconnect(ownerUri); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
WaitForExit();
} }
} }
} }
} }

View File

@@ -3,10 +3,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // 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;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts; using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts;
@@ -20,7 +16,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Language Service end-to-end integration tests /// Language Service end-to-end integration tests
/// </summary> /// </summary>
public class LanguageServiceTests : TestBase public class LanguageServiceTests
{ {
/// <summary> /// <summary>
@@ -29,42 +25,38 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
[Fact] [Fact]
public async Task HoverTest() 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"; 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", LanguageId = "enu",
Version = 1, Version = 1,
Text = query Text = query
} }
}; };
await RequestOpenDocumentNotification(openParams); await testHelper.RequestOpenDocumentNotification(openParams);
Thread.Sleep(500); 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"); Assert.True(connected, "Connection was not successful");
Thread.Sleep(10000); 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); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
WaitForExit();
} }
} }
@@ -74,48 +66,44 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
[Fact] [Fact]
public async Task CompletionTest() public async Task CompletionTest()
{ {
try using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
{ using (TestHelper testHelper = new TestHelper())
string ownerUri = System.IO.Path.GetTempFileName(); {
string query = "SELECT * FROM sys.objects"; 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", LanguageId = "enu",
Version = 1, Version = 1,
Text = query Text = query
} }
}; };
await RequestOpenDocumentNotification(openParams); await testHelper.RequestOpenDocumentNotification(openParams);
Thread.Sleep(500); 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"); Assert.True(connected, "Connection is successful");
Thread.Sleep(10000); 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); 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); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
WaitForExit();
} }
} }
@@ -125,42 +113,42 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
[Fact] [Fact]
public async Task DiagnosticsTests() public async Task DiagnosticsTests()
{ {
try 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"); Assert.True(connected, "Connection was not successful");
Thread.Sleep(500); Thread.Sleep(500);
string query = "SELECT *** FROM sys.objects"; 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", LanguageId = "enu",
Version = 1, Version = 1,
Text = query Text = query
} }
}; };
await RequestOpenDocumentNotification(openParams); await testHelper.RequestOpenDocumentNotification(openParams);
Thread.Sleep(100); Thread.Sleep(100);
var contentChanges = new TextDocumentChangeEvent[1]; 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, Line = 0,
Character = 5 Character = 5
}, },
End = new Position() End = new Position
{ {
Line = 0, Line = 0,
Character = 6 Character = 6
@@ -176,24 +164,24 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
TextDocument = new VersionedTextDocumentIdentifier() TextDocument = new VersionedTextDocumentIdentifier()
{ {
Version = 2, Version = 2,
Uri = ownerUri Uri = queryTempFile.FilePath
} }
}; };
await RequestChangeTextDocumentNotification(changeParams); await testHelper.RequestChangeTextDocumentNotification(changeParams);
Thread.Sleep(100); 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, Line = 0,
Character = 5 Character = 5
}, },
End = new Position() End = new Position
{ {
Line = 0, Line = 0,
Character = 6 Character = 6
@@ -203,25 +191,21 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
Text = "t" Text = "t"
}; };
changeParams = new DidChangeTextDocumentParams() changeParams = new DidChangeTextDocumentParams
{ {
ContentChanges = contentChanges, ContentChanges = contentChanges,
TextDocument = new VersionedTextDocumentIdentifier() TextDocument = new VersionedTextDocumentIdentifier
{ {
Version = 3, Version = 3,
Uri = ownerUri Uri = queryTempFile.FilePath
} }
}; };
await RequestChangeTextDocumentNotification(changeParams); await testHelper.RequestChangeTextDocumentNotification(changeParams);
Thread.Sleep(2500); Thread.Sleep(2500);
await Disconnect(ownerUri); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
WaitForExit();
} }
} }
@@ -231,11 +215,11 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
[Fact] [Fact]
public async Task ChangeConfigurationTest() public async Task ChangeConfigurationTest()
{ {
try 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"); Assert.True(connected, "Connection was not successful");
Thread.Sleep(500); Thread.Sleep(500);
@@ -246,37 +230,29 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
Settings = settings Settings = settings
}; };
await RequestChangeConfigurationNotification(configParams); await testHelper.RequestChangeConfigurationNotification(configParams);
Thread.Sleep(2000); Thread.Sleep(2000);
await Disconnect(ownerUri); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
WaitForExit();
} }
} }
[Fact] [Fact]
public async Task NotificationIsSentAfterOnConnectionAutoCompleteUpdate() public async Task NotificationIsSentAfterOnConnectionAutoCompleteUpdate()
{ {
try using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
using (TestHelper testHelper = new TestHelper())
{ {
// Connect // Connect
string ownerUri = System.IO.Path.GetTempFileName(); await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection);
await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection);
// An event signalling that IntelliSense is ready should be sent shortly thereafter // 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.NotNull(readyParams);
Assert.Equal(ownerUri, readyParams.OwnerUri); Assert.Equal(queryTempFile.FilePath, readyParams.OwnerUri);
await Disconnect(ownerUri); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
WaitForExit();
} }
} }
} }

View File

@@ -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<bool> 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<T> CalculateRunTime<T>(Func<Task<T>> testToRun, [CallerMemberName] string testName = "")
{
TestTimer timer = new TestTimer();
T result = await testToRun();
timer.EndAndPrint(testName);
return result;
}
}
}

View File

@@ -14,219 +14,243 @@ using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
{ {
public class QueryExecutionTests : TestBase public class QueryExecutionTests
{ {
[Fact] [Fact]
public async Task TestQueryCancelReliability() public async Task TestQueryCancelReliability()
{ {
string ownerUri = System.IO.Path.GetTempFileName(); const string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c";
string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c";
await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
using (TestHelper testHelper = new TestHelper())
// Run and cancel 100 queries
for (int i = 0; i < 100; i++)
{ {
var queryTask = RunQuery(ownerUri, query); await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.AzureTestServerConnection);
var cancelResult = await CancelQuery(ownerUri); // Run and cancel 100 queries
Assert.NotNull(cancelResult); for (int i = 0; i < 100; i++)
Assert.True(string.IsNullOrEmpty(cancelResult.Messages)); {
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] [Fact]
public async Task TestQueryDoesNotBlockOtherRequests() public async Task TestQueryDoesNotBlockOtherRequests()
{ {
string ownerUri = System.IO.Path.GetTempFileName(); const string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c";
string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c";
await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
using (TestHelper testHelper = new TestHelper())
// 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++)
{ {
string ownerUri2 = System.IO.Path.GetTempFileName(); await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.AzureTestServerConnection);
await Connect(ownerUri2, ConnectionTestUtils.AzureTestServerConnection); // Start a long-running query
Assert.NotNull(await RequestCompletion(ownerUri2, "SELECT * FROM sys.objects", 0, 10)); var queryTask = testHelper.RunQuery(queryTempFile.FilePath, query, 60000);
await Disconnect(ownerUri2);
// 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] [Fact]
public async Task TestParallelQueryExecution() public async Task TestParallelQueryExecution()
{ {
int queryCount = 10; const int queryCount = 10;
const string query = "SELECT * FROM sys.objects";
// Create n connections using (TestHelper testHelper = new TestHelper())
string[] ownerUris = new string[queryCount];
for (int i = 0; i < queryCount; i++)
{ {
ownerUris[i] = System.IO.Path.GetTempFileName(); // Create n connections
Assert.NotNull(await Connect(ownerUris[i], ConnectionTestUtils.AzureTestServerConnection)); 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 // Run n queries at once
string query = "SELECT * FROM sys.objects"; var queryTasks = new Task<QueryExecuteCompleteParams>[queryCount];
var queryTasks = new Task<QueryExecuteCompleteParams>[queryCount]; for (int i = 0; i < queryCount; i++)
for (int i = 0; i < queryCount; i++) {
{ queryTasks[i] = testHelper.RunQuery(ownerUris[i].FilePath, query);
queryTasks[i] = RunQuery(ownerUris[i], query); }
} await Task.WhenAll(queryTasks);
await Task.WhenAll(queryTasks);
// Verify that they all completed with results and Disconnect // Verify that they all completed with results and Disconnect
for (int i = 0; i < queryCount; i++) for (int i = 0; i < queryCount; i++)
{ {
Assert.NotNull(queryTasks[i].Result); Assert.NotNull(queryTasks[i].Result);
Assert.NotNull(queryTasks[i].Result.BatchSummaries); Assert.NotNull(queryTasks[i].Result.BatchSummaries);
await Disconnect(ownerUris[i]); await testHelper.Disconnect(ownerUris[i].FilePath);
ownerUris[i].Dispose();
}
} }
} }
[Fact] [Fact]
public async Task TestSaveResultsDoesNotBlockOtherRequests() public async Task TestSaveResultsDoesNotBlockOtherRequests()
{ {
string ownerUri = System.IO.Path.GetTempFileName(); const string query = "SELECT * FROM sys.objects";
string query = "SELECT * FROM sys.objects";
await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
using (TestHelper testHelper = new TestHelper())
// Execute a query
await RunQuery(ownerUri, query);
// Spawn several tasks to save results
var saveTasks = new Task<SaveResultRequestResult>[100];
for (int i = 0; i < 100; i++)
{ {
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<SaveResultRequestResult>[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] [Fact]
public async Task TestQueryingSubsetDoesNotBlockOtherRequests() public async Task TestQueryingSubsetDoesNotBlockOtherRequests()
{ {
string ownerUri = System.IO.Path.GetTempFileName(); const string query = "SELECT * FROM sys.objects";
string query = "SELECT * FROM sys.objects";
await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
using (TestHelper testHelper = new TestHelper())
// Execute a query
await RunQuery(ownerUri, query);
// Spawn several tasks for subset requests
var subsetTasks = new Task<QueryExecuteSubsetResult>[100];
for (int i = 0; i < 100; i++)
{ {
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<QueryExecuteSubsetResult>[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] [Fact]
public async Task TestCancelQueryWhileOtherOperationsAreInProgress() public async Task TestCancelQueryWhileOtherOperationsAreInProgress()
{ {
string ownerUri = System.IO.Path.GetTempFileName(); const string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b";
string query = "SELECT * FROM sys.objects a CROSS JOIN sys.objects b";
List<Task> tasks = new List<Task>();
await Connect(ownerUri, ConnectionTestUtils.AzureTestServerConnection); using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
using (TestHelper testHelper = new TestHelper())
// 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++)
{ {
string ownerUri2 = System.IO.Path.GetTempFileName(); List<Task> tasks = new List<Task>();
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); using (SelfCleaningTempFile queryFile2 = new SelfCleaningTempFile())
await RequestCompletion(ownerUri2, "SELECT * FROM sys.objects", 0, 10); {
await RunQuery(ownerUri2, "SELECT * FROM sys.objects"); tasks.Add(Task.Run(async () =>
await Disconnect(ownerUri2); {
})); 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] [Fact]
public async Task ExecuteBasicQueryTest() 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 testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection);
bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection);
Assert.True(connected, "Connection is successful"); Assert.True(connected, "Connection is successful");
Thread.Sleep(500); Thread.Sleep(500);
string query = "SELECT * FROM sys.all_columns c";
DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification()
{ {
TextDocument = new TextDocumentItem() TextDocument = new TextDocumentItem()
{ {
Uri = ownerUri, Uri = queryTempFile.FilePath,
LanguageId = "enu", LanguageId = "enu",
Version = 1, Version = 1,
Text = query 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);
Assert.NotNull(queryResult.BatchSummaries); Assert.NotNull(queryResult.BatchSummaries);
@@ -241,69 +265,62 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
var subsetRequest = new QueryExecuteSubsetParams() var subsetRequest = new QueryExecuteSubsetParams()
{ {
OwnerUri = ownerUri, OwnerUri = queryTempFile.FilePath,
BatchIndex = 0, BatchIndex = 0,
ResultSetIndex = 0, ResultSetIndex = 0,
RowsStartIndex = 0, RowsStartIndex = 0,
RowsCount = 100, RowsCount = 100,
}; };
var querySubset = await RequestQueryExecuteSubset(subsetRequest); var querySubset = await testHelper.RequestQueryExecuteSubset(subsetRequest);
Assert.NotNull(querySubset); Assert.NotNull(querySubset);
Assert.True(querySubset.ResultSubset.RowCount == 100); Assert.True(querySubset.ResultSubset.RowCount == 100);
await Disconnect(ownerUri); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
WaitForExit();
} }
} }
[Fact] [Fact]
public async Task TestQueryingAfterCompletionRequests() 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<Task> tasks = new List<Task>(); List<Task> tasks = new List<Task>();
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))); Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(testHelper.RequestCompletion(queryTempFile.FilePath, query, 0, 10)));
var queryTask = RunQuery(ownerUri, query); var queryTask = testHelper.RunQuery(queryTempFile.FilePath, query);
tasks.Add(queryTask); tasks.Add(queryTask);
await Task.WhenAll(tasks); await Task.WhenAll(tasks);
Assert.NotNull(queryTask.Result); Assert.NotNull(queryTask.Result);
Assert.NotNull(queryTask.Result.BatchSummaries); Assert.NotNull(queryTask.Result.BatchSummaries);
await Connect(ownerUri, ConnectionTestUtils.DataToolsTelemetryAzureConnection); await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.DataToolsTelemetryAzureConnection);
tasks.Clear(); tasks.Clear();
Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(RequestCompletion(ownerUri, query, 0, 10))); Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(testHelper.RequestCompletion(queryTempFile.FilePath, query, 0, 10)));
queryTask = RunQuery(ownerUri, query); queryTask = testHelper.RunQuery(queryTempFile.FilePath, query);
tasks.Add(queryTask); tasks.Add(queryTask);
await Task.WhenAll(tasks); await Task.WhenAll(tasks);
Assert.NotNull(queryTask.Result); Assert.NotNull(queryTask.Result);
Assert.NotNull(queryTask.Result.BatchSummaries); Assert.NotNull(queryTask.Result.BatchSummaries);
await Connect(ownerUri, ConnectionTestUtils.SqlDataToolsAzureConnection); await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.SqlDataToolsAzureConnection);
tasks.Clear(); tasks.Clear();
Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(RequestCompletion(ownerUri, query, 0, 10))); Enumerable.Range(0, 10).ToList().ForEach(arg => tasks.Add(testHelper.RequestCompletion(queryTempFile.FilePath, query, 0, 10)));
queryTask = RunQuery(ownerUri, query); queryTask = testHelper.RunQuery(queryTempFile.FilePath, query);
tasks.Add(queryTask); tasks.Add(queryTask);
await Task.WhenAll(tasks); await Task.WhenAll(tasks);
Assert.NotNull(queryTask.Result); Assert.NotNull(queryTask.Result);
Assert.NotNull(queryTask.Result.BatchSummaries); Assert.NotNull(queryTask.Result.BatchSummaries);
await Disconnect(ownerUri); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
WaitForExit();
} }
} }
} }

View File

@@ -13,7 +13,7 @@ using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
{ {
public class StressTests : TestBase public class StressTests
{ {
/// <summary> /// <summary>
/// Simulate typing by a user to stress test the language service /// Simulate typing by a user to stress test the language service
@@ -21,24 +21,24 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
//[Fact] //[Fact]
public async Task TestLanguageService() public async Task TestLanguageService()
{ {
string textToType = const string textToType = "SELECT * FROM sys.objects GO " +
"SELECT * FROM sys.objects GO " + "CREATE TABLE MyTable(" +
"CREATE TABLE MyTable(" + "FirstName CHAR," +
"FirstName CHAR," + "LastName CHAR," +
"LastName CHAR," + "DateOfBirth DATETIME," +
"DateOfBirth DATETIME," + "CONSTRAINT MyTableConstraint UNIQUE (FirstName, LastName, DateOfBirth)) GO " +
"CONSTRAINT MyTableConstraint UNIQUE (FirstName, LastName, DateOfBirth)) GO " + "INSERT INTO MyTable (FirstName, LastName, DateOfBirth) VALUES ('John', 'Doe', '19800101') GO " +
"INSERT INTO MyTable (FirstName, LastName, DateOfBirth) VALUES ('John', 'Doe', '19800101') GO " + "SELECT * FROM MyTable GO " +
"SELECT * FROM MyTable GO " + "ALTER TABLE MyTable DROP CONSTRAINT MyTableConstraint GO " +
"ALTER TABLE MyTable DROP CONSTRAINT MyTableConstraint GO " + "DROP TABLE MyTable GO ";
"DROP TABLE MyTable GO ";
var ownerUri = System.IO.Path.GetTempFileName();
try
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
using (TestHelper testHelper = new TestHelper())
{ {
// Connect // Connect
bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection);
Assert.True(connected, "Connection is successful"); Assert.True(connected, "Connection was not successful");
Thread.Sleep(10000); // Wait for intellisense to warm up 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++) 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]; var contentChanges = new TextDocumentChangeEvent[1];
contentChanges[0] = new TextDocumentChangeEvent() contentChanges[0] = new TextDocumentChangeEvent()
@@ -78,30 +78,30 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
TextDocument = new VersionedTextDocumentIdentifier() TextDocument = new VersionedTextDocumentIdentifier()
{ {
Version = ++version, Version = ++version,
Uri = ownerUri Uri = queryTempFile.FilePath
} }
}; };
await RequestChangeTextDocumentNotification(changeParams); await testHelper.RequestChangeTextDocumentNotification(changeParams);
Thread.Sleep(50); Thread.Sleep(50);
// If we just typed a space, request/resolve completion // If we just typed a space, request/resolve completion
if (textToType[i] == ' ') if (textToType[i] == ' ')
{ {
var completions = await RequestCompletion(ownerUri, textToType.Substring(0, i + 1), 0, i + 1); 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 is not null and not empty"); Assert.True(completions != null && completions.Length > 0, "Completion items list was null or empty");
Thread.Sleep(50); Thread.Sleep(50);
var item = await RequestResolveCompletion(completions[0]); var item = await testHelper.RequestResolveCompletion(completions[0]);
Assert.NotNull(item); Assert.NotNull(item);
} }
} }
// Clear the text document // Clear the text document
System.IO.File.WriteAllText(ownerUri, ""); System.IO.File.WriteAllText(queryTempFile.FilePath, "");
var contentChanges2 = new TextDocumentChangeEvent[1]; var contentChanges2 = new TextDocumentChangeEvent[1];
contentChanges2[0] = new TextDocumentChangeEvent() contentChanges2[0] = new TextDocumentChangeEvent()
@@ -129,23 +129,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
TextDocument = new VersionedTextDocumentIdentifier() TextDocument = new VersionedTextDocumentIdentifier()
{ {
Version = ++version, Version = ++version,
Uri = ownerUri Uri = queryTempFile.FilePath
} }
}; };
await RequestChangeTextDocumentNotification(changeParams2); await testHelper.RequestChangeTextDocumentNotification(changeParams2);
} }
await Disconnect(ownerUri); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
try
{
System.IO.File.Delete(ownerUri);
}
catch {}
WaitForExit();
} }
} }
@@ -155,13 +146,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
//[Fact] //[Fact]
public async Task TestQueryExecutionService() 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"; const string queryToRun = "SELECT * FROM sys.all_objects GO " +
var ownerUri = System.IO.Path.GetTempFileName(); "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 // Connect
bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); bool connected = await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection);
Assert.True(connected, "Connection is successful"); Assert.True(connected, "Connection is successful");
// Run queries repeatedly // Run queries repeatedly
@@ -169,7 +163,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
stopwatch.Start(); stopwatch.Start();
while (stopwatch.Elapsed < TimeSpan.FromMinutes(60)) 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);
Assert.NotNull(queryResult.BatchSummaries); Assert.NotNull(queryResult.BatchSummaries);
@@ -179,24 +173,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
Assert.NotNull(queryResult.BatchSummaries[2].ResultSetSummaries); Assert.NotNull(queryResult.BatchSummaries[2].ResultSetSummaries);
Assert.NotNull(queryResult.BatchSummaries[3].ResultSetSummaries); Assert.NotNull(queryResult.BatchSummaries[3].ResultSetSummaries);
Assert.NotNull(await ExecuteSubset(ownerUri, 0, 0, 0, 7)); Assert.NotNull(await testHelper.ExecuteSubset(queryTempFile.FilePath, 0, 0, 0, 7));
Assert.NotNull(await ExecuteSubset(ownerUri, 1, 0, 0, 7)); Assert.NotNull(await testHelper.ExecuteSubset(queryTempFile.FilePath, 1, 0, 0, 7));
Assert.NotNull(await ExecuteSubset(ownerUri, 2, 0, 0, 7)); Assert.NotNull(await testHelper.ExecuteSubset(queryTempFile.FilePath, 2, 0, 0, 7));
Assert.NotNull(await ExecuteSubset(ownerUri, 3, 0, 0, 1)); Assert.NotNull(await testHelper.ExecuteSubset(queryTempFile.FilePath, 3, 0, 0, 1));
Thread.Sleep(500); Thread.Sleep(500);
} }
await Disconnect(ownerUri); await testHelper.Disconnect(queryTempFile.FilePath);
}
finally
{
try
{
System.IO.File.Delete(ownerUri);
}
catch {}
WaitForExit();
} }
} }
@@ -211,7 +196,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
var connection = ConnectionTestUtils.LocalhostConnection; var connection = ConnectionTestUtils.LocalhostConnection;
connection.Connection.Pooling = false; connection.Connection.Pooling = false;
try using (TestHelper testHelper = new TestHelper())
{ {
// Connect/disconnect repeatedly // Connect/disconnect repeatedly
Stopwatch stopwatch = new Stopwatch(); Stopwatch stopwatch = new Stopwatch();
@@ -219,18 +204,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
while (stopwatch.Elapsed < TimeSpan.FromMinutes(60)) while (stopwatch.Elapsed < TimeSpan.FromMinutes(60))
{ {
// Connect // Connect
bool connected = await Connect(ownerUri, connection); bool connected = await testHelper.Connect(ownerUri, connection);
Assert.True(connected, "Connection is successful"); Assert.True(connected, "Connection is successful");
// Disconnect // Disconnect
bool disconnected = await Disconnect(ownerUri); bool disconnected = await testHelper.Disconnect(ownerUri);
Assert.True(disconnected, "Disconnect is successful"); Assert.True(disconnected, "Disconnect is successful");
} }
} }
finally
{
WaitForExit();
}
} }
} }
} }

View File

@@ -4,7 +4,6 @@
// //
using System; using System;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts; using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
@@ -21,11 +20,11 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Base class for all test suites run by the test driver /// Base class for all test suites run by the test driver
/// </summary> /// </summary>
public class TestBase : IDisposable public sealed class TestHelper : IDisposable
{ {
private bool isRunning = false; private bool isRunning = false;
public TestBase() public TestHelper()
{ {
Driver = new ServiceTestDriver(); Driver = new ServiceTestDriver();
Driver.Start().Wait(); Driver.Start().Wait();
@@ -44,21 +43,13 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
{ {
try try
{ {
this.isRunning = false; this.isRunning = false;
Driver.Stop().Wait();
if (!Driver.IsCoverageRun) Console.WriteLine("Successfully killed process.");
{
Driver.Stop().Wait();
}
else
{
var p = Process.Start("taskkill", "/IM Microsoft.SqlTools.ServiceLayer.exe /F");
p.WaitForExit();
Driver.ServiceProcess?.WaitForExit();
}
} }
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 /// Request a new connection to be created
/// </summary> /// </summary>
/// <returns>True if the connection completed successfully</returns> /// <returns>True if the connection completed successfully</returns>
protected async Task<bool> Connect(string ownerUri, ConnectParams connectParams, int timeout = 15000) public async Task<bool> Connect(string ownerUri, ConnectParams connectParams, int timeout = 15000)
{ {
connectParams.OwnerUri = ownerUri; connectParams.OwnerUri = ownerUri;
var connectResult = await Driver.SendRequest(ConnectionRequest.Type, connectParams); var connectResult = await Driver.SendRequest(ConnectionRequest.Type, connectParams);
@@ -95,7 +86,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request a disconnect /// Request a disconnect
/// </summary> /// </summary>
protected async Task<bool> Disconnect(string ownerUri) public async Task<bool> Disconnect(string ownerUri)
{ {
var disconnectParams = new DisconnectParams(); var disconnectParams = new DisconnectParams();
disconnectParams.OwnerUri = ownerUri; disconnectParams.OwnerUri = ownerUri;
@@ -107,7 +98,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request a cancel connect /// Request a cancel connect
/// </summary> /// </summary>
protected async Task<bool> CancelConnect(string ownerUri) public async Task<bool> CancelConnect(string ownerUri)
{ {
var cancelParams = new CancelConnectParams(); var cancelParams = new CancelConnectParams();
cancelParams.OwnerUri = ownerUri; cancelParams.OwnerUri = ownerUri;
@@ -118,7 +109,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request a cancel connect /// Request a cancel connect
/// </summary> /// </summary>
protected async Task<ListDatabasesResponse> ListDatabases(string ownerUri) public async Task<ListDatabasesResponse> ListDatabases(string ownerUri)
{ {
var listParams = new ListDatabasesParams(); var listParams = new ListDatabasesParams();
listParams.OwnerUri = ownerUri; listParams.OwnerUri = ownerUri;
@@ -129,7 +120,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request the active SQL script is parsed for errors /// Request the active SQL script is parsed for errors
/// </summary> /// </summary>
protected async Task<QueryExecuteSubsetResult> RequestQueryExecuteSubset(QueryExecuteSubsetParams subsetParams) public async Task<QueryExecuteSubsetResult> RequestQueryExecuteSubset(QueryExecuteSubsetParams subsetParams)
{ {
return await Driver.SendRequest(QueryExecuteSubsetRequest.Type, subsetParams); return await Driver.SendRequest(QueryExecuteSubsetRequest.Type, subsetParams);
} }
@@ -137,7 +128,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request the active SQL script is parsed for errors /// Request the active SQL script is parsed for errors
/// </summary> /// </summary>
protected async Task RequestOpenDocumentNotification(DidOpenTextDocumentNotification openParams) public async Task RequestOpenDocumentNotification(DidOpenTextDocumentNotification openParams)
{ {
await Driver.SendEvent(DidOpenTextDocumentNotification.Type, openParams); await Driver.SendEvent(DidOpenTextDocumentNotification.Type, openParams);
} }
@@ -145,7 +136,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request a configuration change notification /// Request a configuration change notification
/// </summary> /// </summary>
protected async Task RequestChangeConfigurationNotification(DidChangeConfigurationParams<SqlToolsSettings> configParams) public async Task RequestChangeConfigurationNotification(DidChangeConfigurationParams<SqlToolsSettings> configParams)
{ {
await Driver.SendEvent(DidChangeConfigurationNotification<SqlToolsSettings>.Type, configParams); await Driver.SendEvent(DidChangeConfigurationNotification<SqlToolsSettings>.Type, configParams);
} }
@@ -153,7 +144,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// /// Request the active SQL script is parsed for errors /// /// Request the active SQL script is parsed for errors
/// </summary> /// </summary>
protected async Task RequestChangeTextDocumentNotification(DidChangeTextDocumentParams changeParams) public async Task RequestChangeTextDocumentNotification(DidChangeTextDocumentParams changeParams)
{ {
await Driver.SendEvent(DidChangeTextDocumentNotification.Type, changeParams); await Driver.SendEvent(DidChangeTextDocumentNotification.Type, changeParams);
} }
@@ -161,7 +152,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request completion item resolve to look-up additional info /// Request completion item resolve to look-up additional info
/// </summary> /// </summary>
protected async Task<CompletionItem> RequestResolveCompletion(CompletionItem item) public async Task<CompletionItem> RequestResolveCompletion(CompletionItem item)
{ {
var result = await Driver.SendRequest(CompletionResolveRequest.Type, item); var result = await Driver.SendRequest(CompletionResolveRequest.Type, item);
return result; return result;
@@ -170,7 +161,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request a Read Credential for given credential id /// Request a Read Credential for given credential id
/// </summary> /// </summary>
protected async Task<Credential> ReadCredential(string credentialId) public async Task<Credential> ReadCredential(string credentialId)
{ {
var credentialParams = new Credential(); var credentialParams = new Credential();
credentialParams.CredentialId = credentialId; credentialParams.CredentialId = credentialId;
@@ -181,7 +172,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Returns database connection parameters for given server type /// Returns database connection parameters for given server type
/// </summary> /// </summary>
protected async Task<ConnectParams> GetDatabaseConnectionAsync(TestServerType serverType) public async Task<ConnectParams> GetDatabaseConnectionAsync(TestServerType serverType)
{ {
ConnectionProfile connectionProfile = null; ConnectionProfile connectionProfile = null;
TestServerIdentity serverIdentiry = ConnectionTestUtils.TestServers.FirstOrDefault(x => x.ServerType == serverType); TestServerIdentity serverIdentiry = ConnectionTestUtils.TestServers.FirstOrDefault(x => x.ServerType == serverType);
@@ -212,7 +203,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request a list of completion items for a position in a block of text /// Request a list of completion items for a position in a block of text
/// </summary> /// </summary>
protected async Task<CompletionItem[]> RequestCompletion(string ownerUri, string text, int line, int character) public async Task<CompletionItem[]> RequestCompletion(string ownerUri, string text, int line, int character)
{ {
// Write the text to a backing file // Write the text to a backing file
lock (fileLock) lock (fileLock)
@@ -234,7 +225,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request a a hover tooltop /// Request a a hover tooltop
/// </summary> /// </summary>
protected async Task<Hover> RequestHover(string ownerUri, string text, int line, int character) public async Task<Hover> RequestHover(string ownerUri, string text, int line, int character)
{ {
// Write the text to a backing file // Write the text to a backing file
lock (fileLock) lock (fileLock)
@@ -242,12 +233,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
System.IO.File.WriteAllText(ownerUri, text); System.IO.File.WriteAllText(ownerUri, text);
} }
var completionParams = new TextDocumentPosition(); var completionParams = new TextDocumentPosition
completionParams.TextDocument = new TextDocumentIdentifier(); {
completionParams.TextDocument.Uri = ownerUri; TextDocument = new TextDocumentIdentifier {Uri = ownerUri},
completionParams.Position = new Position(); Position = new Position
completionParams.Position.Line = line; {
completionParams.Position.Character = character; Line = line,
Character = character
}
};
var result = await Driver.SendRequest(HoverRequest.Type, completionParams); var result = await Driver.SendRequest(HoverRequest.Type, completionParams);
return result; return result;
@@ -256,14 +250,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Run a query using a given connection bound to a URI /// Run a query using a given connection bound to a URI
/// </summary> /// </summary>
protected async Task<QueryExecuteCompleteParams> RunQuery(string ownerUri, string query, int timeoutMilliseconds = 5000) public async Task<QueryExecuteCompleteParams> RunQuery(string ownerUri, string query, int timeoutMilliseconds = 5000)
{ {
// Write the query text to a backing file // Write the query text to a backing file
WriteToFile(ownerUri, query); WriteToFile(ownerUri, query);
var queryParams = new QueryExecuteParams(); var queryParams = new QueryExecuteParams
queryParams.OwnerUri = ownerUri; {
queryParams.QuerySelection = null; OwnerUri = ownerUri,
QuerySelection = null
};
var result = await Driver.SendRequest(QueryExecuteRequest.Type, queryParams); var result = await Driver.SendRequest(QueryExecuteRequest.Type, queryParams);
if (result != null && string.IsNullOrEmpty(result.Messages)) if (result != null && string.IsNullOrEmpty(result.Messages))
@@ -280,10 +276,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request to cancel an executing query /// Request to cancel an executing query
/// </summary> /// </summary>
protected async Task<QueryCancelResult> CancelQuery(string ownerUri) public async Task<QueryCancelResult> CancelQuery(string ownerUri)
{ {
var cancelParams = new QueryCancelParams(); var cancelParams = new QueryCancelParams {OwnerUri = ownerUri};
cancelParams.OwnerUri = ownerUri;
var result = await Driver.SendRequest(QueryCancelRequest.Type, cancelParams); var result = await Driver.SendRequest(QueryCancelRequest.Type, cancelParams);
return result; return result;
@@ -292,14 +287,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request to save query results as CSV /// Request to save query results as CSV
/// </summary> /// </summary>
protected async Task<SaveResultRequestResult> SaveAsCsv(string ownerUri, string filename, int batchIndex, int resultSetIndex) public async Task<SaveResultRequestResult> SaveAsCsv(string ownerUri, string filename, int batchIndex, int resultSetIndex)
{ {
var saveParams = new SaveResultsAsCsvRequestParams(); var saveParams = new SaveResultsAsCsvRequestParams
saveParams.OwnerUri = ownerUri; {
saveParams.BatchIndex = batchIndex; OwnerUri = ownerUri,
saveParams.ResultSetIndex = resultSetIndex; BatchIndex = batchIndex,
saveParams.FilePath = filename; ResultSetIndex = resultSetIndex,
FilePath = filename
};
var result = await Driver.SendRequest(SaveResultsAsCsvRequest.Type, saveParams); var result = await Driver.SendRequest(SaveResultsAsCsvRequest.Type, saveParams);
return result; return result;
} }
@@ -307,14 +304,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request to save query results as JSON /// Request to save query results as JSON
/// </summary> /// </summary>
protected async Task<SaveResultRequestResult> SaveAsJson(string ownerUri, string filename, int batchIndex, int resultSetIndex) public async Task<SaveResultRequestResult> SaveAsJson(string ownerUri, string filename, int batchIndex, int resultSetIndex)
{ {
var saveParams = new SaveResultsAsJsonRequestParams(); var saveParams = new SaveResultsAsJsonRequestParams
saveParams.OwnerUri = ownerUri; {
saveParams.BatchIndex = batchIndex; OwnerUri = ownerUri,
saveParams.ResultSetIndex = resultSetIndex; BatchIndex = batchIndex,
saveParams.FilePath = filename; ResultSetIndex = resultSetIndex,
FilePath = filename
};
var result = await Driver.SendRequest(SaveResultsAsJsonRequest.Type, saveParams); var result = await Driver.SendRequest(SaveResultsAsJsonRequest.Type, saveParams);
return result; return result;
} }
@@ -322,7 +321,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Request a subset of results from a query /// Request a subset of results from a query
/// </summary> /// </summary>
protected async Task<QueryExecuteSubsetResult> ExecuteSubset(string ownerUri, int batchIndex, int resultSetIndex, int rowStartIndex, int rowCount) public async Task<QueryExecuteSubsetResult> ExecuteSubset(string ownerUri, int batchIndex, int resultSetIndex, int rowStartIndex, int rowCount)
{ {
var subsetParams = new QueryExecuteSubsetParams(); var subsetParams = new QueryExecuteSubsetParams();
subsetParams.OwnerUri = ownerUri; subsetParams.OwnerUri = ownerUri;
@@ -335,7 +334,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
return result; return result;
} }
protected void WriteToFile(string ownerUri, string query) public void WriteToFile(string ownerUri, string query)
{ {
lock (fileLock) lock (fileLock)
{ {

View File

@@ -13,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
/// <summary> /// <summary>
/// Language Service end-to-end integration tests /// Language Service end-to-end integration tests
/// </summary> /// </summary>
public class WorkspaceTests : TestBase public class WorkspaceTests
{ {
/// <summary> /// <summary>
/// Validate workspace lifecycle events /// Validate workspace lifecycle events
@@ -21,7 +21,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
[Fact] [Fact]
public async Task InitializeRequestTest() public async Task InitializeRequestTest()
{ {
try using (TestHelper testHelper = new TestHelper())
{ {
InitializeRequest initializeRequest = new InitializeRequest() InitializeRequest initializeRequest = new InitializeRequest()
{ {
@@ -29,13 +29,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
Capabilities = new ClientCapabilities() Capabilities = new ClientCapabilities()
}; };
InitializeResult result = await Driver.SendRequest(InitializeRequest.Type, initializeRequest); InitializeResult result = await testHelper.Driver.SendRequest(InitializeRequest.Type, initializeRequest);
Assert.NotNull(result); Assert.NotNull(result);
} }
finally
{
WaitForExit();
}
} }
} }
} }

View File

@@ -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
}
}

View File

@@ -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<int> 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);
}
}
}
}
}