diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/RetryPolicyFactory.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/RetryPolicyFactory.cs index 4ac025fb..8e42894a 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/RetryPolicyFactory.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ReliableConnection/RetryPolicyFactory.cs @@ -390,7 +390,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection return retryPolicy; } - private static void DataConnectionFailureRetry(RetryState retryState) + internal static void DataConnectionFailureRetry(RetryState retryState) { Logger.Write(LogLevel.Normal, string.Format(CultureInfo.InvariantCulture, "Connection retry number {0}. Delaying {1} ms before retry. Exception: {2}", @@ -401,7 +401,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection RetryPolicyUtils.RaiseAmbientRetryMessage(retryState, SqlSchemaModelErrorCodes.ServiceActions.ConnectionRetry); } - private static void CommandFailureRetry(RetryState retryState, string commandKeyword) + internal static void CommandFailureRetry(RetryState retryState, string commandKeyword) { Logger.Write(LogLevel.Normal, string.Format( CultureInfo.InvariantCulture, @@ -414,7 +414,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection RetryPolicyUtils.RaiseAmbientRetryMessage(retryState, SqlSchemaModelErrorCodes.ServiceActions.CommandRetry); } - private static void CommandFailureIgnore(RetryState retryState, string commandKeyword) + internal static void CommandFailureIgnore(RetryState retryState, string commandKeyword) { Logger.Write(LogLevel.Normal, string.Format( CultureInfo.InvariantCulture, @@ -426,32 +426,32 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection RetryPolicyUtils.RaiseAmbientIgnoreMessage(retryState, SqlSchemaModelErrorCodes.ServiceActions.CommandRetry); } - private static void CommandFailureRetry(RetryState retryState) + internal static void CommandFailureRetry(RetryState retryState) { CommandFailureRetry(retryState, "Command"); } - private static void CommandFailureIgnore(RetryState retryState) + internal static void CommandFailureIgnore(RetryState retryState) { CommandFailureIgnore(retryState, "Command"); } - private static void CreateDatabaseCommandFailureRetry(RetryState retryState) + internal static void CreateDatabaseCommandFailureRetry(RetryState retryState) { CommandFailureRetry(retryState, "Database Command"); } - private static void CreateDatabaseCommandFailureIgnore(RetryState retryState) + internal static void CreateDatabaseCommandFailureIgnore(RetryState retryState) { CommandFailureIgnore(retryState, "Database Command"); } - private static void ElementCommandFailureRetry(RetryState retryState) + internal static void ElementCommandFailureRetry(RetryState retryState) { CommandFailureRetry(retryState, "Element Command"); } - private static void ElementCommandFailureIgnore(RetryState retryState) + internal static void ElementCommandFailureIgnore(RetryState retryState) { CommandFailureIgnore(retryState, "Element Command"); } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs index 46ccbb94..631a2106 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ConnectionServiceTests.cs @@ -809,6 +809,33 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection Assert.True(callbackInvoked); } + /// + /// Test ConnectionSummaryComparer + /// + [Fact] + public void TestConnectionSummaryComparer() + { + var summary1 = new ConnectionSummary() + { + ServerName = "localhost", + DatabaseName = "master", + UserName = "user" + }; + + var summary2 = new ConnectionSummary() + { + ServerName = "localhost", + DatabaseName = "master", + UserName = "user" + }; + + var comparer = new ConnectionSummaryComparer(); + Assert.True(comparer.Equals(summary1, summary2)); + + summary2.DatabaseName = "tempdb"; + Assert.False(comparer.Equals(summary1, summary2)); + } + /// /// Verify when a connection is created that the URI -> Connection mapping is created in the connection service. /// diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ReliableConnectionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ReliableConnectionTests.cs index 18867612..816a4d38 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ReliableConnectionTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Connection/ReliableConnectionTests.cs @@ -10,9 +10,13 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Data.SqlClient; +using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection; using Microsoft.SqlTools.ServiceLayer.Test.Utility; +using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts; +using Microsoft.SqlTools.Test.Utility; using Xunit; +using static Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection.ReliableConnectionHelper; using static Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection.RetryPolicy; using static Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection.RetryPolicy.TimeBasedRetryPolicy; @@ -526,8 +530,133 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.Connection Dictionary settings = new Dictionary(); settings.Add("LockTimeoutMilliSeconds", 10000); data.PopulateSettings(settings); + settings["LockTimeoutMilliSeconds"] = 15000; + data.PopulateSettings(settings); data.TraceSettings(); } + + [Fact] + public void RetryPolicyFactoryTest() + { + Assert.NotNull(RetryPolicyFactory.NoRetryPolicy); + Assert.NotNull(RetryPolicyFactory.PrimaryKeyViolationRetryPolicy); + + RetryPolicy noRetyPolicy = RetryPolicyFactory.CreateDefaultSchemaCommandRetryPolicy(useRetry: false); + + var retryState = new RetryStateEx(); + retryState.LastError = new Exception(); + RetryPolicyFactory.DataConnectionFailureRetry(retryState); + RetryPolicyFactory.CommandFailureRetry(retryState, "command"); + RetryPolicyFactory.CommandFailureIgnore(retryState, "command"); + RetryPolicyFactory.ElementCommandFailureIgnore(retryState); + RetryPolicyFactory.ElementCommandFailureRetry(retryState); + RetryPolicyFactory.CreateDatabaseCommandFailureIgnore(retryState); + RetryPolicyFactory.CreateDatabaseCommandFailureRetry(retryState); + RetryPolicyFactory.CommandFailureIgnore(retryState); + RetryPolicyFactory.CommandFailureRetry(retryState); + + var transientPolicy = new RetryPolicyFactory.TransientErrorIgnoreStrategy(); + Assert.False(transientPolicy.CanRetry(new Exception())); + Assert.False(transientPolicy.ShouldIgnoreError(new Exception())); + } + + [Fact] + public void ReliableConnectionHelperTest() + { + ScriptFile scriptFile; + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfo(out scriptFile); + + Assert.True(ReliableConnectionHelper.IsAuthenticatingDatabaseMaster(connInfo.SqlConnection)); + + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + Assert.True(ReliableConnectionHelper.IsAuthenticatingDatabaseMaster(builder)); + ReliableConnectionHelper.TryAddAlwaysOnConnectionProperties(builder, new SqlConnectionStringBuilder()); + + Assert.NotNull(ReliableConnectionHelper.GetServerName(connInfo.SqlConnection)); + Assert.NotNull(ReliableConnectionHelper.ReadServerVersion(connInfo.SqlConnection)); + + Assert.NotNull(ReliableConnectionHelper.GetAsSqlConnection(connInfo.SqlConnection)); + + ServerInfo info = ReliableConnectionHelper.GetServerVersion(connInfo.SqlConnection); + Assert.NotNull(ReliableConnectionHelper.IsVersionGreaterThan2012RTM(info)); + } + + [Fact] + public void DataSchemaErrorTests() + { + var error = new DataSchemaError(); + Assert.NotNull(error); + var isOnDisplay = error.IsOnDisplay; + var isBuildErrorCodeDefined = error.IsBuildErrorCodeDefined; + var buildErrorCode = error.BuildErrorCode; + var isPriorityEditable = error.IsPriorityEditable; + var message = error.Message; + var exception = error.Exception; + var prefix = error.Prefix; + var column = error.Column; + var line =error.Line; + var errorCode =error.ErrorCode; + var severity = error.Severity; + var document = error.Document; + + Assert.NotNull(error.ToString()); + Assert.NotNull(DataSchemaError.FormatErrorCode("ex", 1)); + } + + [Fact] + public void InitReliableSqlConnectionTest() + { + ScriptFile scriptFile; + ConnectionInfo connInfo = TestObjects.InitLiveConnectionInfo(out scriptFile); + + var connection = connInfo.SqlConnection as ReliableSqlConnection; + var command = new ReliableSqlConnection.ReliableSqlCommand(connection); + Assert.NotNull(command.Connection); + + } + + [Fact] + public void ThrottlingReasonTests() + { + var reason = RetryPolicy.ThrottlingReason.Unknown; + Assert.NotNull(reason.ThrottlingMode); + Assert.NotNull(reason.ThrottledResources); + + try + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + builder.InitialCatalog = "master"; + builder.IntegratedSecurity = false; + builder.DataSource = "localhost"; + builder.UserID = "invalid"; + builder.Password = ".."; + SqlConnection conn = new SqlConnection(builder.ToString()); + conn.Open(); + } + catch (SqlException sqlException) + { + var exceptionReason = RetryPolicy.ThrottlingReason.FromException(sqlException); + Assert.NotNull(exceptionReason); + + var errorReason = RetryPolicy.ThrottlingReason.FromError(sqlException.Errors[0]); + Assert.NotNull(errorReason); + } + + var unknownCodeReason = RetryPolicy.ThrottlingReason.FromReasonCode(-1); + var codeReason = RetryPolicy.ThrottlingReason.FromReasonCode(2601); + Assert.NotNull(codeReason); + + Assert.NotNull(codeReason.IsThrottledOnDataSpace); + Assert.NotNull(codeReason.IsThrottledOnLogSpace); + Assert.NotNull(codeReason.IsThrottledOnLogWrite); + Assert.NotNull(codeReason.IsThrottledOnDataRead); + Assert.NotNull(codeReason.IsThrottledOnCPU); + Assert.NotNull(codeReason.IsThrottledOnDatabaseSize); + Assert.NotNull(codeReason.IsThrottledOnWorkerThreads); + Assert.NotNull(codeReason.IsUnknown); + Assert.NotNull(codeReason.ToString()); + } } } + #endif // LIVE_CONNECTION_TESTS diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/LongListTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/LongListTests.cs new file mode 100644 index 00000000..a28714bc --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.Test/Utility/LongListTests.cs @@ -0,0 +1,29 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.ServiceLayer.Utility; +using Xunit; + +namespace Microsoft.SqlTools.Test.Utility +{ + /// + /// Tests for the LongList class + /// + public class LongListTests + { + /// + /// Add and remove and item in a LongList + /// + [Fact] + public void LongListTest() + { + var longList = new LongList(); + longList.Add('.'); + Assert.True(longList.Count == 1); + longList.RemoveAt(0); + Assert.True(longList.Count == 0); + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/LanguageServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/LanguageServiceTests.cs index 48d4c118..6eb3e303 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/LanguageServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/LanguageServiceTests.cs @@ -30,15 +30,12 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task HoverTest() { try - { + { string ownerUri = System.IO.Path.GetTempFileName(); - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); - Assert.True(connected, "Connection is successful"); - - Thread.Sleep(500); - string query = "SELECT * FROM sys.objects"; + WriteToFile(ownerUri, query); + DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() { TextDocument = new TextDocumentItem() @@ -51,7 +48,14 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests }; await RequestOpenDocumentNotification(openParams); - + + Thread.Sleep(500); + + bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); + Assert.True(connected, "Connection is successful"); + + Thread.Sleep(10000); + Hover hover = await RequestHover(ownerUri, query, 0, 15); Assert.True(hover != null, "Hover tooltop is not null"); @@ -71,15 +75,12 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests public async Task CompletionTest() { try - { + { string ownerUri = System.IO.Path.GetTempFileName(); - bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); - Assert.True(connected, "Connection is successful"); - - Thread.Sleep(500); - string query = "SELECT * FROM sys.objects"; + WriteToFile(ownerUri, query); + DidOpenTextDocumentNotification openParams = new DidOpenTextDocumentNotification() { TextDocument = new TextDocumentItem() @@ -92,43 +93,20 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests }; await RequestOpenDocumentNotification(openParams); + + 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" - }; + bool connected = await Connect(ownerUri, ConnectionTestUtils.LocalhostConnection); + Assert.True(connected, "Connection is successful"); - DidChangeTextDocumentParams changeParams = new DidChangeTextDocumentParams() - { - ContentChanges = contentChanges, - TextDocument = new VersionedTextDocumentIdentifier() - { - Version = 2, - Uri = ownerUri - } - }; + Thread.Sleep(10000); - await RequestChangeTextDocumentNotification(changeParams); - CompletionItem[] completions = await RequestCompletion(ownerUri, query, 0, 15); Assert.True(completions != null && completions.Length > 0, "Completion items list is not null and not empty"); + Thread.Sleep(50); + CompletionItem item = await RequestResolveCompletion(completions[0]); Assert.True(completions != null && completions.Length > 0, "Completion items list is not null and not empty"); diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestBase.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestBase.cs index f6d10b33..c785c107 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestBase.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestBase.cs @@ -214,10 +214,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests protected async Task RunQuery(string ownerUri, string query) { // Write the query text to a backing file - lock (fileLock) - { - System.IO.File.WriteAllText(ownerUri, query); - } + WriteToFile(ownerUri, query); var queryParams = new QueryExecuteParams(); queryParams.OwnerUri = ownerUri; @@ -234,5 +231,13 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests return null; } } + + protected void WriteToFile(string ownerUri, string query) + { + lock (fileLock) + { + System.IO.File.WriteAllText(ownerUri, query); + } + } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/WorkspaceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/WorkspaceTests.cs new file mode 100644 index 00000000..0796dc44 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/WorkspaceTests.cs @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.IO; +using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.Hosting.Contracts; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests +{ + /// + /// Language Service end-to-end integration tests + /// + public class WorkspaceTests : TestBase + { + /// + /// Validate workspace lifecycle events + /// + [Fact] + public async Task InitializeRequestTest() + { + try + { + InitializeRequest initializeRequest = new InitializeRequest() + { + RootPath = Path.GetTempPath(), + Capabilities = new ClientCapabilities() + }; + + InitializeResult result = await Driver.SendRequest(InitializeRequest.Type, initializeRequest); + Assert.NotNull(result); + } + finally + { + WaitForExit(); + } + } + } +}