diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs index 9ef9a23c..8bd6ada7 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs @@ -370,7 +370,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection // Success return true; } - + /// /// List all databases on the server specified /// diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs index 435f2af2..46ccbb94 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs @@ -36,7 +36,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection var commandMockSetup = commandMock.Protected() .Setup("ExecuteDbDataReader", It.IsAny()); - commandMockSetup.Returns(new TestDbDataReader(data)); + commandMockSetup.Returns(() => new TestDbDataReader(data)); return commandMock.Object; } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ReliableConnectionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ReliableConnectionTests.cs new file mode 100644 index 00000000..24a2f39c --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ReliableConnectionTests.cs @@ -0,0 +1,343 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#if LIVE_CONNECTION_TESTS + +using System; +using System.Data; +using System.Data.Common; +using System.Data.SqlClient; +using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection; +using Microsoft.SqlTools.ServiceLayer.Test.Utility; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.Test.Connection +{ + /// + /// Tests for the ReliableConnection module. + /// These tests all assume a live connection to a database on localhost using integrated auth. + /// + public class ReliableConnectionTests + { + /// + /// Environment variable that stores the name of the test server hosting the SQL Server instance. + /// + public static string TestServerEnvironmentVariable + { + get { return "TEST_SERVER"; } + } + + private static Lazy testServerName = new Lazy(() => Environment.GetEnvironmentVariable(TestServerEnvironmentVariable)); + + /// + /// Name of the test server hosting the SQL Server instance. + /// + public static string TestServerName + { + get { return testServerName.Value; } + } + + /// + /// Helper method to create an integrated auth connection builder for testing. + /// + private SqlConnectionStringBuilder CreateTestConnectionStringBuilder() + { + SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder(); + csb.DataSource = TestServerName; + csb.IntegratedSecurity = true; + + return csb; + } + + /// + /// Helper method to create an integrated auth reliable connection for testing. + /// + private DbConnection CreateTestConnection() + { + SqlConnectionStringBuilder csb = CreateTestConnectionStringBuilder(); + + RetryPolicy connectionRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy(); + RetryPolicy commandRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy(); + + ReliableSqlConnection connection = new ReliableSqlConnection(csb.ConnectionString, connectionRetryPolicy, commandRetryPolicy); + return connection; + } + + /// + /// Test ReliableConnectionHelper.GetDefaultDatabaseFilePath() + /// + [Fact] + public void TestGetDefaultDatabaseFilePath() + { + TestUtils.RunIfWindows(() => + { + var connectionBuilder = CreateTestConnectionStringBuilder(); + Assert.NotNull(connectionBuilder); + + string filePath = string.Empty; + string logPath = string.Empty; + + ReliableConnectionHelper.OpenConnection( + connectionBuilder, + usingConnection: (conn) => + { + filePath = ReliableConnectionHelper.GetDefaultDatabaseFilePath(conn); + logPath = ReliableConnectionHelper.GetDefaultDatabaseLogPath(conn); + }, + catchException: null, + useRetry: false); + + Assert.False(string.IsNullOrWhiteSpace(filePath)); + Assert.False(string.IsNullOrWhiteSpace(logPath)); + }); + } + + /// + /// Test ReliableConnectionHelper.GetServerVersion() + /// + [Fact] + public void TestGetServerVersion() + { + TestUtils.RunIfWindows(() => + { + using (var connection = CreateTestConnection()) + { + Assert.NotNull(connection); + connection.Open(); + + ReliableConnectionHelper.ServerInfo serverInfo = ReliableConnectionHelper.GetServerVersion(connection); + ReliableConnectionHelper.ServerInfo serverInfo2; + using (var connection2 = CreateTestConnection()) + { + connection2.Open(); + serverInfo2 = ReliableConnectionHelper.GetServerVersion(connection); + } + + Assert.NotNull(serverInfo); + Assert.NotNull(serverInfo2); + Assert.True(serverInfo.ServerMajorVersion != 0); + Assert.True(serverInfo.ServerMajorVersion == serverInfo2.ServerMajorVersion); + Assert.True(serverInfo.ServerMinorVersion == serverInfo2.ServerMinorVersion); + Assert.True(serverInfo.ServerReleaseVersion == serverInfo2.ServerReleaseVersion); + Assert.True(serverInfo.ServerEdition == serverInfo2.ServerEdition); + Assert.True(serverInfo.IsCloud == serverInfo2.IsCloud); + Assert.True(serverInfo.AzureVersion == serverInfo2.AzureVersion); + } + }); + } + + /// + /// Tests ReliableConnectionHelper.GetCompleteServerName() + /// + [Fact] + public void TestGetCompleteServerName() + { + string name = ReliableConnectionHelper.GetCompleteServerName(@".\SQL2008"); + Assert.True(name.Contains(Environment.MachineName)); + + name = ReliableConnectionHelper.GetCompleteServerName(@"(local)"); + Assert.True(name.Contains(Environment.MachineName)); + } + + /// + /// Tests ReliableConnectionHelper.IsDatabaseReadonly() + /// + [Fact] + public void TestIsDatabaseReadonly() + { + var connectionBuilder = CreateTestConnectionStringBuilder(); + Assert.NotNull(connectionBuilder); + + bool isReadOnly = ReliableConnectionHelper.IsDatabaseReadonly(connectionBuilder); + Assert.False(isReadOnly); + } + + /// + /// Verify ANSI_NULL and QUOTED_IDENTIFIER settings can be set and retrieved for a session + /// + [Fact] + public void VerifyAnsiNullAndQuotedIdentifierSettingsReplayed() + { + TestUtils.RunIfWindows(() => + { + using (ReliableSqlConnection conn = (ReliableSqlConnection)ReliableConnectionHelper.OpenConnection(CreateTestConnectionStringBuilder(), useRetry: true)) + { + VerifySessionSettings(conn, true); + VerifySessionSettings(conn, false); + } + }); + } + + private void VerifySessionSettings(ReliableSqlConnection conn, bool expectedSessionValue) + { + Tuple[] settings = null; + using (IDbCommand cmd = conn.CreateCommand()) + { + if (expectedSessionValue) + { + cmd.CommandText = "SET ANSI_NULLS, QUOTED_IDENTIFIER ON"; + } + else + { + cmd.CommandText = "SET ANSI_NULLS, QUOTED_IDENTIFIER OFF"; + } + + cmd.ExecuteNonQuery(); + + //baseline assertion + AssertSessionValues(cmd, ansiNullsValue: expectedSessionValue, quotedIdentifersValue: expectedSessionValue); + + // verify the initial values are correct + settings = conn.CacheOrReplaySessionSettings(cmd, settings); + + // assert no change is session settings + AssertSessionValues(cmd, ansiNullsValue: expectedSessionValue, quotedIdentifersValue: expectedSessionValue); + + // assert cached settings are correct + Assert.Equal("ANSI_NULLS", settings[0].Item1); + Assert.Equal(expectedSessionValue, settings[0].Item2); + + Assert.Equal("QUOTED_IDENTIFIER", settings[1].Item1); + Assert.Equal(expectedSessionValue, settings[1].Item2); + + // invert session values and assert we reset them + + if (expectedSessionValue) + { + cmd.CommandText = "SET ANSI_NULLS, QUOTED_IDENTIFIER OFF"; + } + else + { + cmd.CommandText = "SET ANSI_NULLS, QUOTED_IDENTIFIER ON"; + } + cmd.ExecuteNonQuery(); + + // baseline assertion + AssertSessionValues(cmd, ansiNullsValue: !expectedSessionValue, quotedIdentifersValue: !expectedSessionValue); + + // replay cached value + settings = conn.CacheOrReplaySessionSettings(cmd, settings); + + // assert session settings correctly set + AssertSessionValues(cmd, ansiNullsValue: expectedSessionValue, quotedIdentifersValue: expectedSessionValue); + } + } + + private void AssertSessionValues(IDbCommand cmd, bool ansiNullsValue, bool quotedIdentifersValue) + { + // assert session was updated + cmd.CommandText = "SELECT SESSIONPROPERTY ('ANSI_NULLS'), SESSIONPROPERTY ('QUOTED_IDENTIFIER')"; + using (IDataReader reader = cmd.ExecuteReader()) + { + Assert.True(reader.Read(), "Missing session settings"); + bool actualAnsiNullsOnValue = ((int)reader[0] == 1); + bool actualQuotedIdentifierOnValue = ((int)reader[1] == 1); + Assert.Equal(ansiNullsValue, actualAnsiNullsOnValue); + Assert.Equal(quotedIdentifersValue, actualQuotedIdentifierOnValue); + } + + } + + /// + /// Test that the retry policy factory constructs all possible types of policies successfully. + /// + [Fact] + public void RetryPolicyFactoryConstructsPoliciesSuccessfully() + { + TestUtils.RunIfWindows(() => + { + Assert.NotNull(RetryPolicyFactory.CreateColumnEncryptionTransferRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateDatabaseCommandRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateDataScriptUpdateRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateDefaultConnectionRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateDefaultDataConnectionRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateDefaultDataSqlCommandRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateDefaultDataTransferRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateDefaultSchemaCommandRetryPolicy(true)); + Assert.NotNull(RetryPolicyFactory.CreateDefaultSchemaConnectionRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateElementCommandRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateFastDataRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateNoRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreatePrimaryKeyCommandRetryPolicy()); + Assert.NotNull(RetryPolicyFactory.CreateSchemaCommandRetryPolicy(6)); + Assert.NotNull(RetryPolicyFactory.CreateSchemaConnectionRetryPolicy(6)); + }); + } + + /// + /// ReliableConnectionHelper.IsCloud() should be false for a local server + /// + [Fact] + public void TestIsCloudIsFalseForLocalServer() + { + TestUtils.RunIfWindows(() => + { + using (var connection = CreateTestConnection()) + { + Assert.NotNull(connection); + + connection.Open(); + Assert.False(ReliableConnectionHelper.IsCloud(connection)); + } + }); + } + + /// + /// Tests that ReliableConnectionHelper.OpenConnection() opens a connection if it is closed + /// + [Fact] + public void TestOpenConnectionOpensConnection() + { + TestUtils.RunIfWindows(() => + { + using (var connection = CreateTestConnection()) + { + Assert.NotNull(connection); + + Assert.True(connection.State == ConnectionState.Closed); + ReliableConnectionHelper.OpenConnection(connection); + Assert.True(connection.State == ConnectionState.Open); + } + }); + } + + /// + /// Tests that ReliableConnectionHelper.ExecuteNonQuery() runs successfully + /// + [Fact] + public void TestExecuteNonQuery() + { + TestUtils.RunIfWindows(() => + { + var result = ReliableConnectionHelper.ExecuteNonQuery( + CreateTestConnectionStringBuilder(), + "SET NOCOUNT ON; SET NOCOUNT OFF;", + ReliableConnectionHelper.SetCommandTimeout, + null, + true + ); + Assert.NotNull(result); + }); + } + + /// + /// Test that TryGetServerVersion() gets server information + /// + [Fact] + public void TestTryGetServerVersion() + { + TestUtils.RunIfWindows(() => + { + ReliableConnectionHelper.ServerInfo info = null; + Assert.True(ReliableConnectionHelper.TryGetServerVersion(CreateTestConnectionStringBuilder().ConnectionString, out info)); + + Assert.NotNull(info); + Assert.NotNull(info.ServerVersion); + Assert.NotEmpty(info.ServerVersion); + }); + } + } +} +#endif // LIVE_CONNECTION_TESTS diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/project.json b/test/Microsoft.SqlTools.ServiceLayer.Test/project.json index 0557e1b9..c6c98156 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test/project.json +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/project.json @@ -4,6 +4,15 @@ "buildOptions": { "debugType": "portable" }, + "configurations": { + "Integration": { + "buildOptions": { + "define": [ + "LIVE_CONNECTION_TESTS" + ] + } + } + }, "dependencies": { "Newtonsoft.Json": "9.0.1", "System.Runtime.Serialization.Primitives": "4.1.1",