Fix OE and Binding Queue reliability bugs (#702)

This commit is contained in:
Matt Irvine
2018-10-05 14:14:36 -07:00
committed by GitHub
parent 6f69f7e303
commit f45155aa4a
11 changed files with 200 additions and 94 deletions

View File

@@ -141,7 +141,6 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
public void QueueWithUnhandledExceptionTest()
{
InitializeTestSettings();
ManualResetEvent mre = new ManualResetEvent(false);
bool isExceptionHandled = false;
object defaultReturnObject = new object();
var queueItem = this.bindingQueue.QueueBindingOperation(
@@ -150,11 +149,10 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
timeoutOperation: TestTimeoutOperation,
errorHandler: (exception) => {
isExceptionHandled = true;
mre.Set();
return defaultReturnObject;
});
mre.WaitOne(10000);
queueItem.ItemProcessed.WaitOne(10000);
this.bindingQueue.StopQueueProcessor(15000);
@@ -213,5 +211,58 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.LanguageServer
Assert.Equal(1, this.timeoutCallCount);
Assert.True(this.isCancelationRequested);
}
/// <summary>
/// Queue an task with a long operation causing a timeout and make sure subsequent tasks still execute
/// </summary>
[Fact]
public void QueueWithTimeoutRunsNextTask()
{
string operationKey = "testkey";
ManualResetEvent firstEventExecuted = new ManualResetEvent(false);
ManualResetEvent secondEventExecuted = new ManualResetEvent(false);
bool firstOperationCanceled = false;
bool secondOperationExecuted = false;
InitializeTestSettings();
this.bindCallbackDelay = 1000;
var totalTimeout = (this.bindCallbackDelay + this.bindingContext.BindingTimeout) * 2;
this.bindingQueue.QueueBindingOperation(
key: operationKey,
bindingTimeout: bindCallbackDelay / 2,
bindOperation: (bindingContext, cancellationToken) =>
{
secondEventExecuted.WaitOne();
if (cancellationToken.IsCancellationRequested)
{
firstOperationCanceled = true;
}
firstEventExecuted.Set();
return null;
},
timeoutOperation: TestTimeoutOperation);
this.bindingQueue.QueueBindingOperation(
key: operationKey,
bindingTimeout: bindCallbackDelay,
bindOperation: (bindingContext, cancellationToken) =>
{
secondOperationExecuted = true;
secondEventExecuted.Set();
return null;
},
waitForLockTimeout: totalTimeout
);
var result = firstEventExecuted.WaitOne(totalTimeout);
Assert.True(result);
this.bindingQueue.StopQueueProcessor(15000);
Assert.Equal(1, this.timeoutCallCount);
Assert.True(firstOperationCanceled);
Assert.True(secondOperationExecuted);
}
}
}

View File

@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Globalization;
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.Extensibility;
@@ -400,7 +401,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
ServerNode node = SetupServerNodeWithServer(smoServer);
// When I populate its children
IList<TreeNode> children = node.Expand();
IList<TreeNode> children = node.Expand(new CancellationToken());
// Then I expect it to contain server-level folders
Assert.Equal(3, children.Count);
@@ -409,7 +410,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
VerifyTreeNode<FolderNode>(children[2], "Folder", SR.SchemaHierarchy_ServerObjects);
// And the database is contained under it
TreeNode databases = children[0];
IList<TreeNode> dbChildren = databases.Expand();
IList<TreeNode> dbChildren = databases.Expand(new CancellationToken());
Assert.Equal(2, dbChildren.Count);
Assert.Equal(SR.SchemaHierarchy_SystemDatabases, dbChildren[0].NodeValue);

View File

@@ -6,6 +6,7 @@
using System;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Connection;
@@ -52,6 +53,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
connectedBindingContext.ServerConnection = new ServerConnection(new SqlConnection(fakeConnectionString));
connectedBindingQueue = new ConnectedBindingQueue(false);
connectedBindingQueue.BindingContextMap.Add($"{details.ServerName}_{details.DatabaseName}_{details.UserName}_NULL", connectedBindingContext);
connectedBindingQueue.BindingContextTasks.Add(connectedBindingContext, Task.Run(() => null));
mockConnectionOpener = new Mock<SqlConnectionOpener>();
connectedBindingQueue.SetConnectionOpener(mockConnectionOpener.Object);
service.ConnectedBindingQueue = connectedBindingQueue;
@@ -271,7 +273,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
public void FindNodeCanExpandParentNodes()
{
var mockTreeNode = new Mock<TreeNode>();
object[] populateChildrenArguments = { ItExpr.Is<bool>(x => x == false), ItExpr.IsNull<string>() };
object[] populateChildrenArguments = { ItExpr.Is<bool>(x => x == false), ItExpr.IsNull<string>(), new CancellationToken() };
mockTreeNode.Protected().Setup("PopulateChildren", populateChildrenArguments);
mockTreeNode.Object.IsAlwaysLeaf = false;