Skip to content

Commit

Permalink
fix: Better handle the workspace folder change event (#1264)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdneo authored Aug 5, 2021
1 parent 8ccbfe8 commit 6008834
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -76,12 +77,14 @@ public static List<JavaTestItem> findJavaProjects(List<Object> arguments, IProgr
return Collections.emptyList();
}
final String workspaceFolderUri = (String) arguments.get(0);
final IPath workspaceFolderPath = ResourceUtils.filePathFromURI(workspaceFolderUri);
final IPath workspaceFolderPath = ResourceUtils.canonicalFilePathFromURI(workspaceFolderUri);
if (workspaceFolderPath == null) {
JUnitPlugin.logError("Failed to parse workspace folder path from uri: " + workspaceFolderUri);
// todo: handle non-file scheme
return Collections.emptyList();
}

final String invisibleProjectName = ProjectUtils.getWorkspaceInvisibleProjectName(workspaceFolderPath);
final List<JavaTestItem> resultList = new LinkedList<>();
for (final IJavaProject project : ProjectUtils.getJavaProjects()) {
if (monitor != null && monitor.isCanceled()) {
Expand All @@ -92,6 +95,15 @@ public static List<JavaTestItem> findJavaProjects(List<Object> arguments, IProgr
continue;
}

// Ignore all the projects that's not contained in the workspace folder, except
// for the invisible project. This is to make sure in a multi-roots workspace, an
// out-of-date invisible project won't be listed in the result.
if ((!ResourceUtils.isContainedIn(project.getProject().getLocation(),
Collections.singletonList(workspaceFolderPath)) && !Objects.equals(project.getProject().getName(),
invisibleProjectName))) {
continue;
}

try {
resultList.add(TestItemUtils.constructJavaTestItem(project, TestLevel.PROJECT, TestKind.None));
} catch (JavaModelException e) {
Expand Down
9 changes: 7 additions & 2 deletions src/controller/testController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CancellationToken, DebugConfiguration, Disposable, FileSystemWatcher, R
import { instrumentOperation, sendError, sendInfo } from 'vscode-extension-telemetry-wrapper';
import { INVOCATION_PREFIX } from '../constants';
import { IProgressReporter } from '../debugger.api';
import { extensionContext, isStandardServerReady, progressProvider } from '../extension';
import { isStandardServerReady, progressProvider } from '../extension';
import { testSourceProvider } from '../provider/testSourceProvider';
import { IExecutionConfig } from '../runConfigs';
import { BaseRunner } from '../runners/baseRunner/BaseRunner';
Expand All @@ -19,6 +19,7 @@ import { dataCache, ITestItemData } from './testItemDataCache';
import { findDirectTestChildrenForClass, findTestPackagesAndTypes, findTestTypesAndMethods, loadJavaProjects, resolvePath, synchronizeItemsRecursively, updateItemForDocumentWithDebounce } from './utils';

export let testController: TestController | undefined;
export const watchers: Disposable[] = [];

export function createTestController(): void {
if (!isStandardServerReady()) {
Expand Down Expand Up @@ -67,11 +68,15 @@ async function startWatchingWorkspace(): Promise<void> {
return;
}

for (const disposable of watchers) {
disposable.dispose();
}

for (const workspaceFolder of workspace.workspaceFolders) {
const patterns: RelativePattern[] = await testSourceProvider.getTestSourcePattern(workspaceFolder);
for (const pattern of patterns) {
const watcher: FileSystemWatcher = workspace.createFileSystemWatcher(pattern);
extensionContext.subscriptions.push(
watchers.push(
watcher,
watcher.onDidCreate(async (uri: Uri) => {
const testTypes: IJavaTestItem[] = await findTestTypesAndMethods(uri.toString());
Expand Down
18 changes: 16 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
// Licensed under the MIT license.

import * as path from 'path';
import { commands, DebugConfiguration, Event, Extension, ExtensionContext, extensions, TestItem, TextDocument, TextDocumentChangeEvent, TextEditor, Uri, window, workspace } from 'vscode';
import { commands, DebugConfiguration, Event, Extension, ExtensionContext, extensions, TestItem, TextDocument, TextDocumentChangeEvent, TextEditor, Uri, window, workspace, WorkspaceFoldersChangeEvent } from 'vscode';
import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation, instrumentOperationAsVsCodeCommand } from 'vscode-extension-telemetry-wrapper';
import { generateTests, registerAdvanceAskForChoice, registerAskForChoiceCommand, registerAskForInputCommand } from './commands/generationCommands';
import { runTestsFromJavaProjectExplorer } from './commands/projectExplorerCommands';
import { refresh, runTestsFromTestExplorer } from './commands/testExplorerCommands';
import { openStackTrace } from './commands/testReportCommands';
import { Context, ExtensionName, JavaTestRunnerCommands, VSCodeCommands } from './constants';
import { createTestController, testController } from './controller/testController';
import { createTestController, testController, watchers } from './controller/testController';
import { updateItemForDocument, updateItemForDocumentWithDebounce } from './controller/utils';
import { IProgressProvider } from './debugger.api';
import { initExpService } from './experimentationService';
Expand All @@ -30,6 +30,9 @@ export async function deactivate(): Promise<void> {
disposeCodeActionProvider();
await disposeTelemetryWrapper();
testController?.dispose();
for (const disposable of watchers) {
disposable.dispose();
}
}

async function doActivate(_operationId: string, context: ExtensionContext): Promise<void> {
Expand Down Expand Up @@ -116,6 +119,17 @@ async function doActivate(_operationId: string, context: ExtensionContext): Prom
}
await updateItemForDocumentWithDebounce(e.document.uri);
}),
workspace.onDidChangeWorkspaceFolders(async (e: WorkspaceFoldersChangeEvent) => {
for (const deletedFolder of e.removed) {
testSourceProvider.delete(deletedFolder.uri);
}
// workaround to wait for Java Language Server to accept the workspace folder change event,
// otherwise we cannot find the projects in the new workspace folder.
// TODO: this event should be notified by onDidProjectsImport, we need to fix upstream
setTimeout(() => {
createTestController();
}, 1000);
}),
);

if (isStandardServerReady()) {
Expand Down
4 changes: 4 additions & 0 deletions src/provider/testSourceProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ class TestSourcePathProvider {
this.testSourceMapping.clear();
}

public delete(workspaceUri: Uri): boolean {
return this.testSourceMapping.delete(workspaceUri);
}

private async getTestPaths(workspaceFolder: WorkspaceFolder): Promise<ITestSourcePath[]> {
let testPaths: ITestSourcePath[] | undefined = this.testSourceMapping.get(workspaceFolder.uri);
if (!testPaths) {
Expand Down

0 comments on commit 6008834

Please sign in to comment.