[analysis_server] Switch LSP tests to use workspaceAnalysisComplete() instead of progress/status notifications Progress/status notifications for analysis are not a reliably indicator of analysis being complete. They might not be sent if there is no work, or may have multiple bursts in case of plugins. The new `dart/workspace/analysis/complete` request was added as a reliably signal that all pending work is complete. This change updates all tests that used the progress/status notifications to know analysis had completed (except tests that were specifically testing the notifications), removing concepts like "initialAnalysis" which could be unsound with plugins (or debouncing of status notifications). I also replaced some `await pumpEventQueue();` which followed calls to the server with `await workspaceAnalysisComplete();` because it should also be more reliable. However `pumpEventQueue` remains when it's after synchronous modifications to the resource provider, since otherwise the server might not have started processing the watch event before we called it. Change-Id: I342890c82e18848b9bffc00876141216fbbcd5c7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/526482 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Samuel Rawlins <srawlins@google.com>
diff --git a/pkg/analysis_server/benchmark/perf/memory_tests.dart b/pkg/analysis_server/benchmark/perf/memory_tests.dart index 0005e5f..e799695 100644 --- a/pkg/analysis_server/benchmark/perf/memory_tests.dart +++ b/pkg/analysis_server/benchmark/perf/memory_tests.dart
@@ -145,7 +145,7 @@ int _fileVersion = 1; @override - Future<void> get analysisFinished => _test.initialAnalysis; + Future<void> get analysisFinished => _test.workspaceAnalysisComplete(); @override Future<void> closeFile(String filePath) {
diff --git a/pkg/analysis_server/integration_test/lsp_server/analyzer_status_test.dart b/pkg/analysis_server/integration_test/lsp_server/analyzer_status_test.dart index 5f63c17..e82b51eb 100644 --- a/pkg/analysis_server/integration_test/lsp_server/analyzer_status_test.dart +++ b/pkg/analysis_server/integration_test/lsp_server/analyzer_status_test.dart
@@ -20,7 +20,7 @@ newFile(mainFilePath, initialContents); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); // Set up futures to wait for the new events. var startNotification = waitForAnalysisStart();
diff --git a/pkg/analysis_server/integration_test/server/message_scheduler_test.dart b/pkg/analysis_server/integration_test/server/message_scheduler_test.dart index 056a43b..0e09acc 100644 --- a/pkg/analysis_server/integration_test/server/message_scheduler_test.dart +++ b/pkg/analysis_server/integration_test/server/message_scheduler_test.dart
@@ -240,8 +240,7 @@ Future<void> test_initialize() async { await initialize(); - await initialAnalysis; - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); _assertLogContents(testView!, r''' Incoming RequestMessage: initialize:0 Entering process messages loop @@ -253,6 +252,10 @@ Start LspMessage: initialized Exit process messages loop Complete LspMessage: initialized +Incoming RequestMessage: dart/workspace/analysis/complete:1 +Entering process messages loop + Start LspMessage: dart/workspace/analysis/complete:1 +Exit process messages loop '''); }
diff --git a/pkg/analysis_server/test/lsp/analyzer_status_test.dart b/pkg/analysis_server/test/lsp/analyzer_status_test.dart index 64d0591..f48c3bc4 100644 --- a/pkg/analysis_server/test/lsp/analyzer_status_test.dart +++ b/pkg/analysis_server/test/lsp/analyzer_status_test.dart
@@ -46,7 +46,7 @@ newFile(mainFilePath, initialContents); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); // Set up futures to wait for the new events. var startNotification = waitForAnalysisStart();
diff --git a/pkg/analysis_server/test/lsp/cancel_request_test.dart b/pkg/analysis_server/test/lsp/cancel_request_test.dart index 0bf6441..79c294a 100644 --- a/pkg/analysis_server/test/lsp/cancel_request_test.dart +++ b/pkg/analysis_server/test/lsp/cancel_request_test.dart
@@ -28,7 +28,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); // Create a completion request that we'll cancel. var completionRequest = makeRequest(
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart index 994f754..c0293ac 100644 --- a/pkg/analysis_server/test/lsp/completion_dart_test.dart +++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -109,7 +109,7 @@ Future<void> initializeServer() async { await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); } Future<void> test_supported() async { @@ -183,7 +183,7 @@ Future<void> initializeServer() async { await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); } Future<void> test_abstract_class() async { @@ -1559,7 +1559,7 @@ await provideConfig(initialize, {'documentation': ?preference}); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completion = res.singleWhere((c) => c.label == 'A'); var resolved = await resolveCompletion(completion); // Resolve for docs @@ -1600,7 +1600,7 @@ await provideConfig(initialize, {'documentation': ?preference}); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completion = res.singleWhere((c) => c.label == 'InOtherFile'); @@ -1716,7 +1716,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completion = res.where((c) => c.label == 'MyClass').single; @@ -2226,7 +2226,7 @@ await provideConfig(initialize, {'completeFunctionCalls': true}); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var item = res.singleWhere((c) => c.label == 'myFunction(…)'); // Ensure the snippet comes through in the expected format with the expected @@ -2275,7 +2275,7 @@ await provideConfig(initialize, {'completeFunctionCalls': true}); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completion = res.singleWhere( @@ -2585,7 +2585,7 @@ // after the expectations are set up above, because otherwise if the // exceptions occur too quickly, they will be unhandled (whereas the // expectations attach error handlers to them). - await pumpEventQueue(times: 50000); + await pumpEventQueue(times: 5000); completer.complete(); await Future.wait(expectationFutures); } finally { @@ -3150,7 +3150,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletionList(mainFileUri, code.position.position); // Expect everything (hashCode etc. will take it over 500). @@ -3180,7 +3180,7 @@ await provideConfig(initialize, {'maxCompletionItems': 200}); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletionList(mainFileUri, code.position.position); // Should be capped at 200 and marked as incomplete. @@ -3318,7 +3318,7 @@ await provideConfig(initialize, {'maxCompletionItems': 10}); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletionList(mainFileUri, code.position.position); expect(res.items, hasLength(10)); @@ -3352,7 +3352,7 @@ setCompletionItemSnippetSupport(); await provideConfig(initialize, {'maxCompletionItems': 10}); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletionList(mainFileUri, code.position.position); // Should be capped at 10 and marked as incomplete. @@ -3707,7 +3707,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completion = res.singleWhere((c) => c.label.startsWith('foo')); @@ -3971,7 +3971,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); // Find the completion for the class in the other file. @@ -4086,7 +4086,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completions = res.where((c) => c.label == 'MyExportedClass').toList(); expect(completions, hasLength(1)); @@ -4117,7 +4117,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completions = res.where((c) => c.label == 'MyExportedClass').toList(); @@ -4148,7 +4148,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completions = res.where((c) => c.label == 'MyDuplicatedClass').toList(); @@ -4187,7 +4187,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var enumCompletions = res @@ -4268,7 +4268,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completions = res @@ -4305,7 +4305,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); // Expect only a single entry for the 'empty' extension member. @@ -4360,7 +4360,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completions = res.where((c) => c.label == 'MyExportedClass').toList(); @@ -4442,7 +4442,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completions = res.where((c) => c.label == 'MyExportedClass').toList(); @@ -4475,7 +4475,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); // Find the completion for the class in the other file. @@ -4573,7 +4573,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completion = res.singleWhere((c) => c.label == 'InOtherFile'); @@ -4629,7 +4629,7 @@ }, ); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletionList(mainFileUri, code.position.position); // Ensure we flagged that we returned everything. @@ -4656,7 +4656,7 @@ }, ); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletionList(mainFileUri, code.position.position); // Ensure we flagged that we did not return everything. @@ -4781,7 +4781,7 @@ content = 'MyOtherClass^'; await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); // Start with a blank file. newFile(otherFilePath, ''); @@ -4816,7 +4816,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); // Find the completion for the class in the other file. @@ -4890,7 +4890,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); var completion = res.singleWhere( @@ -5031,7 +5031,7 @@ ); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); // Ensure the item doesn't appear in the results (because we might not @@ -5056,7 +5056,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(mainFileUri, code.position.position); // Ensure the item doesn't appear in the results (because we might not @@ -5106,7 +5106,7 @@ ) async { await initialize(); await openFile(fileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getCompletion(fileUri, code.position.position); var completion = res.singleWhere((c) => c.label == completionLabel); @@ -5222,7 +5222,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); // Use a Completer to control when the completion handler starts computing. var completer = Completer<void>();
diff --git a/pkg/analysis_server/test/lsp/diagnostic_test.dart b/pkg/analysis_server/test/lsp/diagnostic_test.dart index 9024b686..eabbb01 100644 --- a/pkg/analysis_server/test/lsp/diagnostic_test.dart +++ b/pkg/analysis_server/test/lsp/diagnostic_test.dart
@@ -728,7 +728,7 @@ newFile(newFilePath, ''); // Allow server to catch up. - await waitForAnalysisComplete(); + await workspaceAnalysisComplete(); // Expect unused_import, not uri_does_not_exist. expect(diagnostics[mainFileUri]!.single.code, 'unused_import'); @@ -858,13 +858,11 @@ await provideConfig(initialize, {}); await openFile(mainFileUri, contents); - await initialAnalysis; + await workspaceAnalysisComplete(); expect(diagnostics[mainFileUri], isNull); - await Future.wait([ - updateConfig({'showTodos': true}), - waitForAnalysisComplete(), - ]); + await updateConfig({'showTodos': true}); + await workspaceAnalysisComplete(); expect(diagnostics[mainFileUri], hasLength(1)); } @@ -883,7 +881,7 @@ // either. 'showTodos': ['TODO', 'fixme'], }); - await initialAnalysis; + await workspaceAnalysisComplete(); var initialDiagnostics = diagnostics[mainFileUri]!; expect(initialDiagnostics, hasLength(2));
diff --git a/pkg/analysis_server/test/lsp/document_changes_test.dart b/pkg/analysis_server/test/lsp/document_changes_test.dart index ec8b76b..f1a7239 100644 --- a/pkg/analysis_server/test/lsp/document_changes_test.dart +++ b/pkg/analysis_server/test/lsp/document_changes_test.dart
@@ -138,10 +138,10 @@ newFile(mainFilePath, content); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); await openFile(mainFileUri, newContent); - await pumpEventQueue(times: 50000); + await workspaceAnalysisComplete(); // Expect diagnostics, because changing the content will have triggered // analysis. @@ -153,10 +153,10 @@ newFile(mainFilePath, content); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); await openFile(mainFileUri, content); - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); // Expect no diagnostics because the file didn't actually change content // when the overlay was created, so it should not have triggered analysis. @@ -210,7 +210,7 @@ ], openFile(mainFileUri, content), ]); - await pumpEventQueue(times: 50000); + await workspaceAnalysisComplete(); expect(server.resourceProvider.hasOverlay(mainFilePath), isTrue); } @@ -232,19 +232,19 @@ // Expect diagnostics after opening the file with the same contents. await openFile(mainFileUri, content); - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expect(diagnostics[mainFileUri], isNotEmpty); // Expect diagnostics after deleting the file because the overlay is still // active. deleteFile(mainFilePath); - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expect(diagnostics[mainFileUri], isNotEmpty); // Expect diagnostics to be removed after we close the file (which removes // the overlay). await closeFile(mainFileUri); - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expect(diagnostics[mainFileUri], isEmpty); } @@ -268,19 +268,19 @@ // Expect diagnostics after opening the file with the same contents. await openFile(mainFileUri, content); - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expect(diagnostics[mainFileUri], isNotEmpty); // Expect diagnostics after deleting the file because the overlay is still // active. deleteFile(mainFilePath); - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expect(diagnostics[mainFileUri], isNotEmpty); // Expect diagnostics remain after re-creating the file (the overlay is still // active). newFile(mainFilePath, content); - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expect(diagnostics[mainFileUri], isNotEmpty); // Expect diagnostics remain after we close the file because the file still @@ -331,7 +331,7 @@ newFile(binMainFilePath, binMainContent); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); // Expect diagnostics because 'foo.dart' doesn't exist. expect(diagnostics[binMainFileUri], isNotEmpty); @@ -339,10 +339,8 @@ // Create the file and _immediately_ open it, so the file exists when the // overlay is created, even though the watcher event has not been processed. newFile(fooFilePath, fooContent); - await Future.wait([ - openFile(fooUri, fooContent), - waitForAnalysisComplete(), - ]); + await openFile(fooUri, fooContent); + await workspaceAnalysisComplete(); // Expect the diagnostics have gone. expect(diagnostics[binMainFileUri], isEmpty);
diff --git a/pkg/analysis_server/test/lsp/hover_test.dart b/pkg/analysis_server/test/lsp/hover_test.dart index a6040a3..828b91e 100644 --- a/pkg/analysis_server/test/lsp/hover_test.dart +++ b/pkg/analysis_server/test/lsp/hover_test.dart
@@ -37,7 +37,7 @@ await provideConfig(initialize, {'documentation': ?preference}); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var hover = await getHover(mainFileUri, code.position.position); var hoverContents = _getStringContents(hover!); @@ -61,7 +61,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var hover = await getHover(mainFileUri, code.position.position); expect(hover, isNotNull); expect(hover!.range, equals(code.range.range)); @@ -78,14 +78,18 @@ }) async { var code = TestCode.parse(content); - var initialAnalysis = waitForAnalysis ? waitForAnalysisComplete() : null; await initialize(); if (withOpenFile) { await openFile(mainFileUri, code.code); } else { newFile(mainFilePath, code.code); + if (waitForAnalysis) { + await pumpEventQueue(times: 5000); // Allow server to see watch event. + } } - await initialAnalysis; + if (waitForAnalysis) { + await workspaceAnalysisComplete(); + } var hover = await getHover(mainFileUri, code.position.position); expect(hover, isNull); } @@ -96,7 +100,7 @@ await initialize(); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var hover = await getHover(mainFileUri, code.position.position); expect(hover, isNotNull); expect(hover!.range, equals(code.range.range)); @@ -117,14 +121,18 @@ var code = TestCode.parse(content); - var initialAnalysis = waitForAnalysis ? waitForAnalysisComplete() : null; await initialize(); if (withOpenFile) { await openFile(fileUri, code.code); } else { newFile(mainFilePath, code.code); + if (waitForAnalysis) { + await pumpEventQueue(times: 5000); // Allow server to see watch event. + } } - await initialAnalysis; + if (waitForAnalysis) { + await workspaceAnalysisComplete(); + } var hover = await getHover(fileUri, code.position.position); expect(hover, isNotNull); expect(hover!.range, equals(code.range.range));
diff --git a/pkg/analysis_server/test/lsp/import_test.dart b/pkg/analysis_server/test/lsp/import_test.dart index 63b8526..427abbd 100644 --- a/pkg/analysis_server/test/lsp/import_test.dart +++ b/pkg/analysis_server/test/lsp/import_test.dart
@@ -615,7 +615,7 @@ newFile(fromUri(fileUri ?? mainFileUri), code.code); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); var res = await getImports(fileUri ?? mainFileUri, code.position.position); expect(res ?? [], expectedLocations);
diff --git a/pkg/analysis_server/test/lsp/inline_value_test.dart b/pkg/analysis_server/test/lsp/inline_value_test.dart index b6c275e..cc8069d 100644 --- a/pkg/analysis_server/test/lsp/inline_value_test.dart +++ b/pkg/analysis_server/test/lsp/inline_value_test.dart
@@ -534,7 +534,7 @@ 'experimentalInlineValuesProperties': true, }); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var actualValues = await getInlineValues( mainFileUri,
diff --git a/pkg/analysis_server/test/lsp/migrate_test.dart b/pkg/analysis_server/test/lsp/migrate_test.dart index 787bb19..45cca73 100644 --- a/pkg/analysis_server/test/lsp/migrate_test.dart +++ b/pkg/analysis_server/test/lsp/migrate_test.dart
@@ -1561,7 +1561,7 @@ String? expectedEdit, bool apply = false, }) async { - await initialAnalysis; + await workspaceAnalysisComplete(); var request = makeRequest( CustomMethods.migrate, DartMigrateParams(
diff --git a/pkg/analysis_server/test/lsp/outline_test.dart b/pkg/analysis_server/test/lsp/outline_test.dart index 921101f..95709e8 100644 --- a/pkg/analysis_server/test/lsp/outline_test.dart +++ b/pkg/analysis_server/test/lsp/outline_test.dart
@@ -251,15 +251,12 @@ waitForOutline(mainFileUri).then((outline) => mainOutline = outline), ); - await Future.wait([ - initialize(initializationOptions: {'outline': true}), - waitForAnalysisComplete(), - ]); - await pumpEventQueue(times: 5000); + await initialize(initializationOptions: {'outline': true}); + await workspaceAnalysisComplete(); expect(mainOutline, isNull); // Shouldn't be sent yet, file is not open. await openFile(mainFileUri, content); - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expect(mainOutline, isNotNull); // Should have been sent now. } }
diff --git a/pkg/analysis_server/test/lsp/reanalyze_test.dart b/pkg/analysis_server/test/lsp/reanalyze_test.dart index d02e69b..1eeea09 100644 --- a/pkg/analysis_server/test/lsp/reanalyze_test.dart +++ b/pkg/analysis_server/test/lsp/reanalyze_test.dart
@@ -15,12 +15,21 @@ @reflectiveTest class ReanalyzeTest extends AbstractLspAnalysisServerTest { + @override + void setUp() { + super.setUp(); + + // We use progress notifications to verify analysis happened after executing + // the command. + setWorkDoneProgressSupport(); + } + Future<void> test_reanalyze() async { const initialContents = 'int a = 1;'; newFile(mainFilePath, initialContents); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); // Set up futures to wait for the new events. var startNotification = waitForAnalysisStart();
diff --git a/pkg/analysis_server/test/lsp/rename_test.dart b/pkg/analysis_server/test/lsp/rename_test.dart index d6df260..98ca7c4 100644 --- a/pkg/analysis_server/test/lsp/rename_test.dart +++ b/pkg/analysis_server/test/lsp/rename_test.dart
@@ -1629,7 +1629,7 @@ var code = TestCode.parse(content); await initialize(workspaceFolders: workspaceFolders); await openFile(fileUri, code.code, version: documentVersion); - await initialAnalysis; + await workspaceAnalysisComplete(); var result = await rename( fileUri,
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart index 763a482..ba20214 100644 --- a/pkg/analysis_server/test/lsp/server_abstract.dart +++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -908,26 +908,13 @@ /// server. bool failTestOnErrorDiagnostic = true; - /// A completer for [initialAnalysis]. - final Completer<void> _initialAnalysisCompleter = Completer<void>(); - - /// A completer for [currentAnalysis]. - Completer<void> _currentAnalysisCompleter = Completer<void>()..complete(); - /// [analysisOptionsPath] as a 'file:///' [Uri]. Uri get analysisOptionsUri => pathContext.toUri(analysisOptionsPath); - /// A [Future] that completes when the current analysis completes (or is - /// already completed if no analysis is in progress). - Future<void> get currentAnalysis => _currentAnalysisCompleter.future; - /// The experimental capabilities returned from the server during initialization. Map<String, Object?> get experimentalServerCapabilities => serverCapabilities.experimental as Map<String, Object?>? ?? {}; - /// A [Future] that completes with the first analysis after initialization. - Future<void> get initialAnalysis => _initialAnalysisCompleter.future; - bool get initialized => _clientCapabilities != null; /// The URI for an augmentation for [mainFileUri]. @@ -1146,16 +1133,6 @@ notificationsFromServer.listen((notification) async { if (notification.method == Method.progress) { await _handleProgress(notification); - } else if (notification.method == CustomMethods.analyzerStatus) { - var params = AnalyzerStatusParams.fromJson( - notification.params as Map<String, Object?>, - ); - - if (params.isAnalyzing) { - _handleAnalysisBegin(); - } else { - _handleAnalysisEnd(); - } } }); @@ -1608,19 +1585,6 @@ return outlineParams.outline; } - void _handleAnalysisBegin() { - assert(_currentAnalysisCompleter.isCompleted); - _currentAnalysisCompleter = Completer<void>(); - } - - void _handleAnalysisEnd() { - if (!_initialAnalysisCompleter.isCompleted) { - _initialAnalysisCompleter.complete(); - } - assert(!_currentAnalysisCompleter.isCompleted); - _currentAnalysisCompleter.complete(); - } - Future<void> _handleProgress(NotificationMessage request) async { var params = ProgressParams.fromJson( request.params as Map<String, Object?>, @@ -1636,15 +1600,6 @@ if (WorkDoneProgressEnd.canParse(params.value, nullLspJsonReporter)) { _validProgressTokens.remove(params.token); } - - if (params.token == analyzingProgressToken) { - if (WorkDoneProgressBegin.canParse(params.value, nullLspJsonReporter)) { - _handleAnalysisBegin(); - } - if (WorkDoneProgressEnd.canParse(params.value, nullLspJsonReporter)) { - _handleAnalysisEnd(); - } - } } Future<void> _handleWorkDoneProgressCreate(RequestMessage request) async { @@ -1683,7 +1638,7 @@ @override Future<void> initializeServer() async { await initialize(); - await currentAnalysis; + await workspaceAnalysisComplete(); } }
diff --git a/pkg/analysis_server/test/lsp/server_test.dart b/pkg/analysis_server/test/lsp/server_test.dart index e4ca003..e941045 100644 --- a/pkg/analysis_server/test/lsp/server_test.dart +++ b/pkg/analysis_server/test/lsp/server_test.dart
@@ -39,21 +39,19 @@ Future<void> test_trigger_afterInitialAnalysis() async { await initialize(); - await initialAnalysis; - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expect(promptManager.checksTriggered, 1); } Future<void> test_trigger_afterPackageConfigChange() async { await initialize(); - await initialAnalysis; - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expect(promptManager.checksTriggered, 1); // Expect that writing package config attempts to trigger another check. writeTestPackageConfig(); - await waitForAnalysisComplete(); - await pumpEventQueue(times: 5000); + await pumpEventQueue(times: 5000); // Allow server to pick up watcher event. + await workspaceAnalysisComplete(); expect(promptManager.checksTriggered, 2); } }
diff --git a/pkg/analysis_server/test/lsp/signature_help_test.dart b/pkg/analysis_server/test/lsp/signature_help_test.dart index a1184f3..711c1ef 100644 --- a/pkg/analysis_server/test/lsp/signature_help_test.dart +++ b/pkg/analysis_server/test/lsp/signature_help_test.dart
@@ -52,7 +52,7 @@ if (state == _FileState.open) { await openFile(mainFileUri, code.code); } - await initialAnalysis; + await workspaceAnalysisComplete(); var res = (await getSignatureHelp( mainFileUri, @@ -125,7 +125,7 @@ var code = TestCode.parse(content); await provideConfig(initialize, {'documentation': ?preference}); await openFile(mainFileUri, code.code); - await initialAnalysis; + await workspaceAnalysisComplete(); var signatureHelp = await getSignatureHelp( mainFileUri, code.position.position,
diff --git a/pkg/analysis_server/test/lsp/temporary_overlay_operation_test.dart b/pkg/analysis_server/test/lsp/temporary_overlay_operation_test.dart index b8c1984..c900c47 100644 --- a/pkg/analysis_server/test/lsp/temporary_overlay_operation_test.dart +++ b/pkg/analysis_server/test/lsp/temporary_overlay_operation_test.dart
@@ -32,7 +32,7 @@ Future<void> test_noIntermediateAnalysisResults() async { newFile(mainFilePath, ''); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); // Modify the overlays to have invalid code, which will then be reverted. // At no point should diagnostics or closing labels be transmitted for the @@ -48,7 +48,7 @@ Future<void> test_pausesRequestQueue() async { await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); await openFile(mainFileUri, '// ORIGINAL'); await _TestTemporaryOverlayOperation(server, () async { @@ -62,7 +62,7 @@ }).doWork(); // Ensure we processed the update afterwards. - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expectFsStateContent(mainFilePath, '// CHANGED'); expectOverlayContent(mainFilePath, '// CHANGED'); } @@ -70,7 +70,7 @@ Future<void> test_pausesWatcherEvents() async { var mainFile = newFile(mainFilePath, '// ORIGINAL'); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); await _TestTemporaryOverlayOperation(server, () async { // Modify the file to trigger watcher events @@ -89,7 +89,7 @@ Future<void> test_restoresOverlays() async { newFile(mainFilePath, '// DISK'); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); await openFile(mainFileUri, '// ORIGINAL OVERLAY'); late _TestTemporaryOverlayOperation operation; @@ -101,14 +101,14 @@ }); await operation.doWork(); - await pumpEventQueue(times: 5000); + await workspaceAnalysisComplete(); expectOverlayContent(mainFilePath, '// ORIGINAL OVERLAY'); } Future<void> test_temporarilyRemovesAddedFiles() async { newFile(mainFilePath, ''); await initialize(); - await initialAnalysis; + await workspaceAnalysisComplete(); expect(server.driverMap.values.single.addedFiles, isNotEmpty);
diff --git a/pkg/analysis_server/test/lsp/workspace_analysis_complete_test.dart b/pkg/analysis_server/test/lsp/workspace_analysis_complete_test.dart index 8be941a..0b197ff 100644 --- a/pkg/analysis_server/test/lsp/workspace_analysis_complete_test.dart +++ b/pkg/analysis_server/test/lsp/workspace_analysis_complete_test.dart
@@ -35,6 +35,15 @@ return super.sendRequestToServer(request); } + @override + void setUp() { + super.setUp(); + + // Enable progress notifications because we want to check the analysis + // occurs prior to this request completing. + setWorkDoneProgressSupport(); + } + Future<void> test_advertisedCapability() async { await initialize(); @@ -96,9 +105,10 @@ r'Response to initialize', r'Response to dart/workspace/analysis/complete', // When adding a new workspace folder that triggers analysis. - r'$/analyzerStatus notification', + 'window/workDoneProgress/create request', + r'$/progress notification', r'textDocument/publishDiagnostics notification', - r'$/analyzerStatus notification', + r'$/progress notification', r'Response to dart/workspace/analysis/complete', ]); } @@ -168,9 +178,10 @@ expect(messages, [ r'Response to initialize', - r'$/analyzerStatus notification', + 'window/workDoneProgress/create request', + r'$/progress notification', r'textDocument/publishDiagnostics notification', - r'$/analyzerStatus notification', + r'$/progress notification', r'Response to dart/workspace/analysis/complete', ]); } @@ -190,8 +201,9 @@ // Initial empty workspace. r'Response to initialize', // Analysis of empty workspace. - r'$/analyzerStatus notification', - r'$/analyzerStatus notification', + 'window/workDoneProgress/create request', + r'$/progress notification', + r'$/progress notification', r'Response to dart/workspace/analysis/complete', ]); }
diff --git a/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart b/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart index 5bbd151..9cf4cba 100644 --- a/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart +++ b/pkg/analysis_server/test/lsp_over_legacy/abstract_lsp_over_legacy.dart
@@ -402,9 +402,6 @@ final Set<String> _priorityFiles = {}; @override - Future<void> get currentAnalysis => waitForTasksFinished(); - - @override Future<void> closeFile(Uri uri) async { // closeFile should both remove the overlay and remove from priority files, // since that's equivalent of what the LSP document handlers do and shared @@ -461,6 +458,9 @@ await addOverlay(fromUri(uri), content); } + @override + Future<void> workspaceAnalysisComplete() => waitForTasksFinished(); + void _updatePriorityFiles() { setPriorityFiles(_priorityFiles.map(getFile).toList()); }
diff --git a/pkg/analysis_server/test/shared/shared_edit_argument_tests.dart b/pkg/analysis_server/test/shared/shared_edit_argument_tests.dart index 23b0e7b..b938535 100644 --- a/pkg/analysis_server/test/shared/shared_edit_argument_tests.dart +++ b/pkg/analysis_server/test/shared/shared_edit_argument_tests.dart
@@ -940,7 +940,7 @@ if (open) { await openFile(testFileUri, code.code); } - await currentAnalysis; + await workspaceAnalysisComplete(); var verifier = await executeForEdits( () => editArgument(testFileUri, code.position.position, edit), ); @@ -976,7 +976,7 @@ code = TestCode.parse(content); createFile(testFilePath, code.code); await initializeServer(); - await currentAnalysis; + await workspaceAnalysisComplete(); await expectLater( editArgument(testFileUri, code.position.position, edit),
diff --git a/pkg/analysis_server/test/shared/shared_editable_arguments_tests.dart b/pkg/analysis_server/test/shared/shared_editable_arguments_tests.dart index c8939ce..57ccdb1 100644 --- a/pkg/analysis_server/test/shared/shared_editable_arguments_tests.dart +++ b/pkg/analysis_server/test/shared/shared_editable_arguments_tests.dart
@@ -33,7 +33,7 @@ createFile(testFilePath, code.code); await initializeServer(); await open(testFileUri, code.code); - await currentAnalysis; + await workspaceAnalysisComplete(); return await getEditableArguments(testFileUri, code.position.position); } @@ -809,7 +809,7 @@ createFile(textFilePath, content); await initializeServer(); await openFile(textFileUri, content); - await currentAnalysis; + await workspaceAnalysisComplete(); var result = await getEditableArguments( textFileUri, Position(line: 0, character: 0),
diff --git a/pkg/analysis_server/test/shared/shared_test_interface.dart b/pkg/analysis_server/test/shared/shared_test_interface.dart index 72636c5..d19986f 100644 --- a/pkg/analysis_server/test/shared/shared_test_interface.dart +++ b/pkg/analysis_server/test/shared/shared_test_interface.dart
@@ -15,11 +15,6 @@ /// notification from [openFile] whereas when using the legacy server (even for /// LSP-over-Legacy tests) will send an `analysis.updateContent` request. abstract interface class SharedTestInterface { - /// A future that completes when the current analysis completes. - /// - /// If there is no analysis in progress, completes immediately. - Future<void> get currentAnalysis; - /// Sets whether the test should fail if error diagnostics are generated. /// /// This is used to avoid accidentally including invalid code in tests but can @@ -76,6 +71,11 @@ /// Converts [filePath] to a file:/// URI. Uri toUri(String filePath); + /// Returns when current analysis completes. + /// + /// If there is no analysis in progress, completes immediately. + Future<void> workspaceAnalysisComplete(); + /// Writes a package_config.json for the package under test (considered /// 'package:test'). void writeTestPackageConfig({