// // 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.Connection.Contracts; using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts; using Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts; using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; using Microsoft.SqlTools.ServiceLayer.SqlContext; using Microsoft.SqlTools.ServiceLayer.TestDriver.Driver; using Microsoft.SqlTools.ServiceLayer.TestDriver.Utility; using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests { /// /// Base class for all test suites run by the test driver /// public sealed class TestHelper : IDisposable { private bool isRunning = false; public TestHelper() { Driver = new ServiceTestDriver(); Driver.Start().Wait(); this.isRunning = true; } public void Dispose() { if (this.isRunning) { WaitForExit(); } } public void WaitForExit() { try { this.isRunning = false; Driver.Stop().Wait(); Console.WriteLine("Successfully killed process."); } catch(Exception e) { Console.WriteLine($"Exception while waiting for service exit: {e.Message}"); } } /// /// The driver object used to read/write data to the service /// public ServiceTestDriver Driver { get; private set; } private object fileLock = new Object(); /// /// Request a new connection to be created /// /// True if the connection completed successfully public async Task Connect(string ownerUri, ConnectParams connectParams, int timeout = 15000) { connectParams.OwnerUri = ownerUri; var connectResult = await Driver.SendRequest(ConnectionRequest.Type, connectParams); if (connectResult) { var completeEvent = await Driver.WaitForEvent(ConnectionCompleteNotification.Type, timeout); return !string.IsNullOrEmpty(completeEvent.ConnectionId); } else { return false; } } /// /// Request a disconnect /// public async Task Disconnect(string ownerUri) { var disconnectParams = new DisconnectParams(); disconnectParams.OwnerUri = ownerUri; var disconnectResult = await Driver.SendRequest(DisconnectRequest.Type, disconnectParams); return disconnectResult; } /// /// Request a cancel connect /// public async Task CancelConnect(string ownerUri) { var cancelParams = new CancelConnectParams(); cancelParams.OwnerUri = ownerUri; return await Driver.SendRequest(CancelConnectRequest.Type, cancelParams); } /// /// Request a cancel connect /// public async Task ListDatabases(string ownerUri) { var listParams = new ListDatabasesParams(); listParams.OwnerUri = ownerUri; return await Driver.SendRequest(ListDatabasesRequest.Type, listParams); } /// /// Request the active SQL script is parsed for errors /// public async Task RequestQueryExecuteSubset(QueryExecuteSubsetParams subsetParams) { return await Driver.SendRequest(QueryExecuteSubsetRequest.Type, subsetParams); } /// /// Request the active SQL script is parsed for errors /// public async Task RequestOpenDocumentNotification(DidOpenTextDocumentNotification openParams) { await Driver.SendEvent(DidOpenTextDocumentNotification.Type, openParams); } /// /// Request a configuration change notification /// public async Task RequestChangeConfigurationNotification(DidChangeConfigurationParams configParams) { await Driver.SendEvent(DidChangeConfigurationNotification.Type, configParams); } /// /// /// Request the active SQL script is parsed for errors /// public async Task RequestChangeTextDocumentNotification(DidChangeTextDocumentParams changeParams) { await Driver.SendEvent(DidChangeTextDocumentNotification.Type, changeParams); } /// /// Request completion item resolve to look-up additional info /// public async Task RequestResolveCompletion(CompletionItem item) { var result = await Driver.SendRequest(CompletionResolveRequest.Type, item); return result; } /// /// Request a Read Credential for given credential id /// public async Task ReadCredential(string credentialId) { var credentialParams = new Credential(); credentialParams.CredentialId = credentialId; return await Driver.SendRequest(ReadCredentialRequest.Type, credentialParams); } /// /// Returns database connection parameters for given server type /// public async Task GetDatabaseConnectionAsync(TestServerType serverType, string databaseName) { ConnectionProfile connectionProfile = null; TestServerIdentity serverIdentiry = ConnectionTestUtils.TestServers.FirstOrDefault(x => x.ServerType == serverType); if (serverIdentiry == null) { connectionProfile = ConnectionTestUtils.Setting.Connections.FirstOrDefault(x => x.ServerType == serverType); } else { connectionProfile = ConnectionTestUtils.Setting.GetConnentProfile(serverIdentiry.ProfileName, serverIdentiry.ServerName); } if (connectionProfile != null) { string password = connectionProfile.Password; if (string.IsNullOrEmpty(password)) { Credential credential = await ReadCredential(connectionProfile.formatCredentialId()); password = credential.Password; } ConnectParams conenctParam = ConnectionTestUtils.CreateConnectParams(connectionProfile.ServerName, connectionProfile.Database, connectionProfile.User, password); if (!string.IsNullOrEmpty(databaseName)) { conenctParam.Connection.DatabaseName = databaseName; } if (serverType == TestServerType.Azure) { conenctParam.Connection.ConnectTimeout = 30; conenctParam.Connection.Encrypt = true; conenctParam.Connection.TrustServerCertificate = false; } return conenctParam; } return null; } /// /// Request a list of completion items for a position in a block of text /// public async Task RequestCompletion(string ownerUri, string text, int line, int character) { // Write the text to a backing file lock (fileLock) { System.IO.File.WriteAllText(ownerUri, text); } var completionParams = new TextDocumentPosition(); completionParams.TextDocument = new TextDocumentIdentifier(); completionParams.TextDocument.Uri = ownerUri; completionParams.Position = new Position(); completionParams.Position.Line = line; completionParams.Position.Character = character; var result = await Driver.SendRequest(CompletionRequest.Type, completionParams); return result; } /// /// Request a a hover tooltop /// public async Task RequestHover(string ownerUri, string text, int line, int character) { // Write the text to a backing file lock (fileLock) { System.IO.File.WriteAllText(ownerUri, text); } var completionParams = new TextDocumentPosition { TextDocument = new TextDocumentIdentifier {Uri = ownerUri}, Position = new Position { Line = line, Character = character } }; var result = await Driver.SendRequest(HoverRequest.Type, completionParams); return result; } /// /// Request definition( peek definition/go to definition) for a sql object in a sql string /// public async Task RequestDefinition(string ownerUri, string text, int line, int character) { // Write the text to a backing file lock (fileLock) { System.IO.File.WriteAllText(ownerUri, text); } var definitionParams = new TextDocumentPosition(); definitionParams.TextDocument = new TextDocumentIdentifier(); definitionParams.TextDocument.Uri = ownerUri; definitionParams.Position = new Position(); definitionParams.Position.Line = line; definitionParams.Position.Character = character; // Send definition request var result = await Driver.SendRequest(DefinitionRequest.Type, definitionParams); return result; } /// /// Run a query using a given connection bound to a URI /// public async Task RunQuery(string ownerUri, string query, int timeoutMilliseconds = 5000) { // Write the query text to a backing file WriteToFile(ownerUri, query); var queryParams = new QueryExecuteParams { OwnerUri = ownerUri, QuerySelection = null }; var result = await Driver.SendRequest(QueryExecuteRequest.Type, queryParams); if (result != null) { var eventResult = await Driver.WaitForEvent(QueryExecuteCompleteEvent.Type, timeoutMilliseconds); return eventResult; } else { return null; } } /// /// Run a query using a given connection bound to a URI. This method only waits for the initial response from query /// execution (QueryExecuteResult). It is up to the caller to wait for the QueryExecuteCompleteEvent if they are interested. /// public async Task RunQueryAsync(string ownerUri, string query, int timeoutMilliseconds = 5000) { WriteToFile(ownerUri, query); var queryParams = new QueryExecuteParams { OwnerUri = ownerUri, QuerySelection = null }; return await Driver.SendRequest(QueryExecuteRequest.Type, queryParams); } /// /// Request to cancel an executing query /// public async Task CancelQuery(string ownerUri) { var cancelParams = new QueryCancelParams {OwnerUri = ownerUri}; var result = await Driver.SendRequest(QueryCancelRequest.Type, cancelParams); return result; } /// /// Request to save query results as CSV /// public async Task SaveAsCsv(string ownerUri, string filename, int batchIndex, int resultSetIndex) { var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = ownerUri, BatchIndex = batchIndex, ResultSetIndex = resultSetIndex, FilePath = filename }; var result = await Driver.SendRequest(SaveResultsAsCsvRequest.Type, saveParams); return result; } /// /// Request to save query results as JSON /// public async Task SaveAsJson(string ownerUri, string filename, int batchIndex, int resultSetIndex) { var saveParams = new SaveResultsAsJsonRequestParams { OwnerUri = ownerUri, BatchIndex = batchIndex, ResultSetIndex = resultSetIndex, FilePath = filename }; var result = await Driver.SendRequest(SaveResultsAsJsonRequest.Type, saveParams); return result; } /// /// Request a subset of results from a query /// public async Task ExecuteSubset(string ownerUri, int batchIndex, int resultSetIndex, int rowStartIndex, int rowCount) { var subsetParams = new QueryExecuteSubsetParams(); subsetParams.OwnerUri = ownerUri; subsetParams.BatchIndex = batchIndex; subsetParams.ResultSetIndex = resultSetIndex; subsetParams.RowsStartIndex = rowStartIndex; subsetParams.RowsCount = rowCount; var result = await Driver.SendRequest(QueryExecuteSubsetRequest.Type, subsetParams); return result; } /// /// Waits for a message to be returned by the service /// /// A message from the service layer public async Task WaitForMessage() { return await Driver.WaitForEvent(QueryExecuteMessageEvent.Type); } public void WriteToFile(string ownerUri, string query) { lock (fileLock) { System.IO.File.WriteAllText(ownerUri, query); } } } }