// // 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.Threading.Tasks; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Connection.Contracts; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; using Microsoft.SqlTools.Test.Utility; using Moq; using Xunit; namespace Microsoft.SqlTools.ServiceLayer.Test.Connection { /// /// Tests for the ServiceHost Connection Service tests /// public class ConnectionServiceTests { /// /// Verify that when a connection is started for a URI with an already existing /// connection, we disconnect first before connecting. /// [Fact] public void ConnectingWhenConnectionExistCausesDisconnectThenConnect() { bool callbackInvoked = false; // first connect string ownerUri = "file://my/sample/file.sql"; var connectionService = TestObjects.GetTestConnectionService(); var connectionResult = connectionService .Connect(new ConnectParams() { OwnerUri = ownerUri, Connection = TestObjects.GetTestConnectionDetails() }); // verify that we are connected Assert.NotEmpty(connectionResult.ConnectionId); // register disconnect callback connectionService.RegisterOnDisconnectTask( (result) => { callbackInvoked = true; return Task.FromResult(true); } ); // send annother connect request connectionResult = connectionService .Connect(new ConnectParams() { OwnerUri = ownerUri, Connection = TestObjects.GetTestConnectionDetails() }); // verify that the event was fired (we disconnected first before connecting) Assert.True(callbackInvoked); // verify that we connected again Assert.NotEmpty(connectionResult.ConnectionId); } /// /// Verify that when connecting with invalid credentials, an error is thrown. /// [Fact] public void ConnectingWithInvalidCredentialsYieldsErrorMessage() { var testConnectionDetails = TestObjects.GetTestConnectionDetails(); var invalidConnectionDetails = new ConnectionDetails(); invalidConnectionDetails.ServerName = testConnectionDetails.ServerName; invalidConnectionDetails.DatabaseName = testConnectionDetails.DatabaseName; invalidConnectionDetails.UserName = "invalidUsername"; // triggers exception when opening mock connection invalidConnectionDetails.Password = "invalidPassword"; // Connect to test db with invalid credentials var connectionResult = TestObjects.GetTestConnectionService() .Connect(new ConnectParams() { OwnerUri = "file://my/sample/file.sql", Connection = invalidConnectionDetails }); // check that an error was caught Assert.NotNull(connectionResult.Messages); Assert.NotEqual(String.Empty, connectionResult.Messages); } /// /// Verify that when connecting with invalid parameters, an error is thrown. /// [Theory] [InlineDataAttribute(null, "my-server", "test", "sa", "123456")] [InlineDataAttribute("file://my/sample/file.sql", null, "test", "sa", "123456")] [InlineDataAttribute("file://my/sample/file.sql", "my-server", null, "sa", "123456")] [InlineDataAttribute("file://my/sample/file.sql", "my-server", "test", null, "123456")] [InlineDataAttribute("file://my/sample/file.sql", "my-server", "test", "sa", null)] [InlineDataAttribute("", "my-server", "test", "sa", "123456")] [InlineDataAttribute("file://my/sample/file.sql", "", "test", "sa", "123456")] [InlineDataAttribute("file://my/sample/file.sql", "my-server", "", "sa", "123456")] [InlineDataAttribute("file://my/sample/file.sql", "my-server", "test", "", "123456")] [InlineDataAttribute("file://my/sample/file.sql", "my-server", "test", "sa", "")] public void ConnectingWithInvalidParametersYieldsErrorMessage(string ownerUri, string server, string database, string userName, string password) { // Connect with invalid parameters var connectionResult = TestObjects.GetTestConnectionService() .Connect(new ConnectParams() { OwnerUri = ownerUri, Connection = new ConnectionDetails() { ServerName = server, DatabaseName = database, UserName = userName, Password = password } }); // check that an error was caught Assert.NotNull(connectionResult.Messages); Assert.NotEqual(String.Empty, connectionResult.Messages); } /// /// Verify that when connecting with a null parameters object, an error is thrown. /// [Fact] public void ConnectingWithNullParametersObjectYieldsErrorMessage() { // Connect with null parameters var connectionResult = TestObjects.GetTestConnectionService() .Connect(null); // check that an error was caught Assert.NotNull(connectionResult.Messages); Assert.NotEqual(String.Empty, connectionResult.Messages); } /// /// Verify that the SQL parser correctly detects errors in text /// [Fact] public void ConnectToDatabaseTest() { // connect to a database instance string ownerUri = "file://my/sample/file.sql"; var connectionResult = TestObjects.GetTestConnectionService() .Connect(new ConnectParams() { OwnerUri = ownerUri, Connection = TestObjects.GetTestConnectionDetails() }); // verify that a valid connection id was returned Assert.NotEmpty(connectionResult.ConnectionId); } /// /// Verify that we can disconnect from an active connection succesfully /// [Fact] public void DisconnectFromDatabaseTest() { // first connect string ownerUri = "file://my/sample/file.sql"; var connectionService = TestObjects.GetTestConnectionService(); var connectionResult = connectionService .Connect(new ConnectParams() { OwnerUri = ownerUri, Connection = TestObjects.GetTestConnectionDetails() }); // verify that we are connected Assert.NotEmpty(connectionResult.ConnectionId); // send disconnect request var disconnectResult = connectionService .Disconnect(new DisconnectParams() { OwnerUri = ownerUri }); Assert.True(disconnectResult); } /// /// Test that when a disconnect is performed, the callback event is fired /// [Fact] public void DisconnectFiresCallbackEvent() { bool callbackInvoked = false; // first connect string ownerUri = "file://my/sample/file.sql"; var connectionService = TestObjects.GetTestConnectionService(); var connectionResult = connectionService .Connect(new ConnectParams() { OwnerUri = ownerUri, Connection = TestObjects.GetTestConnectionDetails() }); // verify that we are connected Assert.NotEmpty(connectionResult.ConnectionId); // register disconnect callback connectionService.RegisterOnDisconnectTask( (result) => { callbackInvoked = true; return Task.FromResult(true); } ); // send disconnect request var disconnectResult = connectionService .Disconnect(new DisconnectParams() { OwnerUri = ownerUri }); Assert.True(disconnectResult); // verify that the event was fired Assert.True(callbackInvoked); } /// /// Test that disconnecting an active connection removes the Owner URI -> ConnectionInfo mapping /// [Fact] public void DisconnectRemovesOwnerMapping() { // first connect string ownerUri = "file://my/sample/file.sql"; var connectionService = TestObjects.GetTestConnectionService(); var connectionResult = connectionService .Connect(new ConnectParams() { OwnerUri = ownerUri, Connection = TestObjects.GetTestConnectionDetails() }); // verify that we are connected Assert.NotEmpty(connectionResult.ConnectionId); // check that the owner mapping exists ConnectionInfo info; Assert.True(connectionService.TryFindConnection(ownerUri, out info)); // send disconnect request var disconnectResult = connectionService .Disconnect(new DisconnectParams() { OwnerUri = ownerUri }); Assert.True(disconnectResult); // check that the owner mapping no longer exists Assert.False(connectionService.TryFindConnection(ownerUri, out info)); } /// /// Test that disconnecting validates parameters and doesn't succeed when they are invalid /// [Theory] [InlineDataAttribute(null)] [InlineDataAttribute("")] public void DisconnectValidatesParameters(string disconnectUri) { // first connect string ownerUri = "file://my/sample/file.sql"; var connectionService = TestObjects.GetTestConnectionService(); var connectionResult = connectionService .Connect(new ConnectParams() { OwnerUri = ownerUri, Connection = TestObjects.GetTestConnectionDetails() }); // verify that we are connected Assert.NotEmpty(connectionResult.ConnectionId); // send disconnect request var disconnectResult = connectionService .Disconnect(new DisconnectParams() { OwnerUri = disconnectUri }); // verify that disconnect failed Assert.False(disconnectResult); } /// /// Verify that the SQL parser correctly detects errors in text /// [Fact] public void OnConnectionCallbackHandlerTest() { bool callbackInvoked = false; // setup connection service with callback var connectionService = TestObjects.GetTestConnectionService(); connectionService.RegisterOnConnectionTask( (sqlConnection) => { callbackInvoked = true; return Task.FromResult(true); } ); // connect to a database instance var connectionResult = connectionService.Connect(TestObjects.GetTestConnectionParams()); // verify that a valid connection id was returned Assert.True(callbackInvoked); } /// /// Verify when a connection is created that the URI -> Connection mapping is created in the connection service. /// [Fact] public void TestConnectRequestRegistersOwner() { // Given a request to connect to a database var service = TestObjects.GetTestConnectionService(); var connectParams = TestObjects.GetTestConnectionParams(); // connect to a database instance var connectionResult = service.Connect(connectParams); // verify that a valid connection id was returned Assert.NotNull(connectionResult.ConnectionId); Assert.NotEqual(String.Empty, connectionResult.ConnectionId); Assert.NotNull(new Guid(connectionResult.ConnectionId)); // verify that the (URI -> connection) mapping was created ConnectionInfo info; Assert.True(service.TryFindConnection(connectParams.OwnerUri, out info)); } } }