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