FIx intellisense cache not refreshing (#831)

* FIx intellisense cache not refreshing

* Remove extra newlines

* Output label to provide more useful information in case of error
This commit is contained in:
Charles Gagnon
2019-06-27 23:50:41 +00:00
committed by GitHub
parent a6450eb180
commit c1f2411b02
4 changed files with 112 additions and 31 deletions

View File

@@ -26,7 +26,7 @@ namespace Microsoft.SqlTools.Hosting.Protocol
this.messageWriter = messageWriter; this.messageWriter = messageWriter;
} }
public async Task SendEvent<TParams>( public virtual async Task SendEvent<TParams>(
EventType<TParams> eventType, EventType<TParams> eventType,
TParams eventParams) TParams eventParams)
{ {

View File

@@ -628,6 +628,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{ {
await Task.Run(() => await Task.Run(() =>
{ {
// Get the current ScriptInfo if one exists so we can lock it while we're rebuilding the cache
ScriptParseInfo scriptInfo = GetScriptParseInfo(connInfo.OwnerUri, createIfNotExists: false); ScriptParseInfo scriptInfo = GetScriptParseInfo(connInfo.OwnerUri, createIfNotExists: false);
if (scriptInfo != null && scriptInfo.IsConnected && if (scriptInfo != null && scriptInfo.IsConnected &&
Monitor.TryEnter(scriptInfo.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout)) Monitor.TryEnter(scriptInfo.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout))
@@ -635,6 +636,8 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
try try
{ {
this.BindingQueue.AddConnectionContext(connInfo, featureName: "LanguageService", overwrite: true); this.BindingQueue.AddConnectionContext(connInfo, featureName: "LanguageService", overwrite: true);
RemoveScriptParseInfo(rebuildParams.OwnerUri);
UpdateLanguageServiceOnConnection(connInfo).Wait();
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -3,6 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
// //
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility; using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
@@ -157,5 +158,63 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer
Assert.True(LanguageService.Instance.BindingQueue.BindingContextMap.ContainsKey(connectionKey)); Assert.True(LanguageService.Instance.BindingQueue.BindingContextMap.ContainsKey(connectionKey));
Assert.False(object.ReferenceEquals(LanguageService.Instance.BindingQueue.BindingContextMap[connectionKey].ServerConnection, orgServerConnection)); Assert.False(object.ReferenceEquals(LanguageService.Instance.BindingQueue.BindingContextMap[connectionKey].ServerConnection, orgServerConnection));
} }
/// <summary>
/// Verifies that clearing the Intellisense cache correctly refreshes the cache with new info from the DB.
/// </summary>
[Fact]
public async Task RebuildIntellisenseCacheClearsScriptParseInfoCorrectly()
{
var testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, null, null, "LangSvcTest");
try
{
var connectionInfoResult = LiveConnectionHelper.InitLiveConnectionInfo(testDb.DatabaseName);
var langService = LanguageService.Instance;
await langService.UpdateLanguageServiceOnConnection(connectionInfoResult.ConnectionInfo);
var queryText = "SELECT * FROM dbo.";
connectionInfoResult.ScriptFile.SetFileContents(queryText);
var textDocumentPosition =
connectionInfoResult.TextDocumentPosition ??
new TextDocumentPosition()
{
TextDocument = new TextDocumentIdentifier
{
Uri = connectionInfoResult.ScriptFile.ClientFilePath
},
Position = new Position
{
Line = 0,
Character = queryText.Length
}
};
// First check that we don't have any items in the completion list as expected
var initialCompletionItems = langService.GetCompletionItems(
textDocumentPosition, connectionInfoResult.ScriptFile, connectionInfoResult.ConnectionInfo);
Assert.True(initialCompletionItems.Length == 0, $"Should not have any completion items initially. Actual : [{string.Join(',', initialCompletionItems.Select(ci => ci.Label))}]");
// Now create a table that should show up in the completion list
testDb.RunQuery("CREATE TABLE dbo.foo(col1 int)");
// And refresh the cache
await langService.HandleRebuildIntelliSenseNotification(
new RebuildIntelliSenseParams() { OwnerUri = connectionInfoResult.ScriptFile.ClientFilePath },
new TestEventContext());
// Now we should expect to see the item show up in the completion list
var afterTableCreationCompletionItems = langService.GetCompletionItems(
textDocumentPosition, connectionInfoResult.ScriptFile, connectionInfoResult.ConnectionInfo);
Assert.True(afterTableCreationCompletionItems.Length == 1, $"Should only have a single completion item after rebuilding Intellisense cache. Actual : [{string.Join(',', initialCompletionItems.Select(ci => ci.Label))}]");
Assert.True(afterTableCreationCompletionItems[0].InsertText == "foo", $"Expected single completion item 'foo'. Actual : [{string.Join(',', initialCompletionItems.Select(ci => ci.Label))}]");
}
finally
{
testDb.Cleanup();
}
}
} }
} }

View File

@@ -0,0 +1,19 @@
using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.Test.Common
{
/// <summary>
/// Simple EventContext for testing that just swallows all events.
/// </summary>
public class TestEventContext : EventContext
{
public override async Task SendEvent<TParams>(
EventType<TParams> eventType,
TParams eventParams)
{
await Task.FromResult(0);
}
}
}