Skip to content

Commit

Permalink
Added Micronaut launcher tests
Browse files Browse the repository at this point in the history
  • Loading branch information
petrovic-d committed Mar 4, 2025
1 parent 45bdae7 commit ad6f973
Show file tree
Hide file tree
Showing 18 changed files with 533 additions and 9 deletions.
21 changes: 20 additions & 1 deletion java/java.lsp.server/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export let client: Promise<NbLanguageClient>;
export let clientRuntimeJDK : string | null = null;
export const MINIMAL_JDK_VERSION = 17;
export const TEST_PROGRESS_EVENT: string = "testProgress";
export let debugConsoleListeners: any[] = [];
const TEST_ADAPTER_CREATED_EVENT: string = "testAdapterCreated";
let testAdapter: NbTestAdapter | undefined;
let nbProcess : ChildProcess | null = null;
Expand Down Expand Up @@ -784,6 +785,24 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {
throw `Client ${c} doesn't support go to test`;
}
}));

const trackerFactory: vscode.DebugAdapterTrackerFactory = {
createDebugAdapterTracker(_session: vscode.DebugSession) {
return {
onDidSendMessage: (message) => {
if (message.type === "event" && message.event === "output") {
const output = message.body.output;
debugConsoleListeners.forEach((listener) => {
listener?.callback(output);
});
}
}
};
}
};

context.subscriptions.push(vscode.debug.registerDebugAdapterTrackerFactory("*", trackerFactory));

context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.workspace.compile', () =>
wrapCommandWithProgress(COMMAND_PREFIX + '.build.workspace', 'Compiling workspace...', log, true)
));
Expand Down Expand Up @@ -935,7 +954,7 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {
debugConfig['projects'] = projects;
}

const ret = await vscode.debug.startDebugging(workspaceFolder, debugConfig, debugOptions);
const ret = await vscode.debug.startDebugging(workspaceFolder, debugConfig, debugOptions);
return ret ? new Promise((resolve) => {
const listener = vscode.debug.onDidTerminateDebugSession(() => {
listener.dispose();
Expand Down
46 changes: 46 additions & 0 deletions java/java.lsp.server/vscode/src/test/launcher/fileUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import * as fs from 'fs';
import * as path from 'path';

import * as vscode from 'vscode';

// Recursively copies all of the files from one directory to another
// This is available out of the box with Node 16.x - fs.cpSync, but here we are using Node 13.x
export function copyDirSync(src: string, dest: string) {
fs.mkdirSync(dest, { recursive: true });
const entries = fs.readdirSync(src, { withFileTypes: true });

for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);

if (entry.isDirectory()) {
copyDirSync(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
}
}
}

export function projectFileUri(folder: string, ...p: string[]) : string{
return vscode.Uri.file(path.join(folder, ...p)).toString();
}
61 changes: 61 additions & 0 deletions java/java.lsp.server/vscode/src/test/launcher/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import * as path from 'path';
import * as Mocha from 'mocha';
import * as glob from 'glob';

export function run(): Promise<void> {
// Create the mocha test
const mocha = new Mocha({
ui: 'tdd',
color: true,
timeout: 60000
});

const testsRoot = path.resolve(__dirname, '.');

return new Promise((c, e) => {
setTimeout(function() {
glob('./**.test.js', { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}

// Add files to the test suite
files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));

try {
// Run the mocha test
mocha.run(failures => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
} catch (err) {
console.error(err);
e(err);
}
});
}, 3000);
});
}
106 changes: 106 additions & 0 deletions java/java.lsp.server/vscode/src/test/launcher/launch.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import * as fs from 'fs';
import * as Mocha from 'mocha';
import * as path from 'path';

import * as vscode from 'vscode';
import * as myExtension from '../../extension';
import { assertWorkspace, waitProjectRecognized } from '../suite/testutils';
import { copyDirSync, projectFileUri } from './fileUtil';

Mocha.before(async () => {
vscode.window.showInformationMessage('Cleaning up workspace.');
let workspaceFolder: string = assertWorkspace();
fs.rmdirSync(workspaceFolder, { recursive: true });
fs.mkdirSync(workspaceFolder, { recursive: true });

const sourcePath = path.resolve(__dirname, '..' , '..', '..', 'test-projects', 'test-app');
copyDirSync(sourcePath, workspaceFolder);
});

const MAVEN_COMMAND_REGEX = /\/netbeans\/java\/java\.lsp\.server\/vscode\/nbcode\/java\/maven\/bin\/mvn/;
const MAVEN_PLUGIN_RUN_REGEX = /io\.micronaut\.maven:micronaut-maven-plugin:run/;

function isMavenCommand(input: string) {
return MAVEN_COMMAND_REGEX.test(input);
}

function createDebugConsoleEventCallback(verifyConditionCallback: CallableFunction, errorMessageCallback: CallableFunction, done: Mocha.Done): (value: string) => void {
return (value: string) => {
if (isMavenCommand(value)) {
vscode.commands.executeCommand("workbench.action.debug.stop");
myExtension.debugConsoleListeners.pop();
if (verifyConditionCallback(value)) {
done();
} else {
done(new Error(errorMessageCallback(value)))
}
}
}
}

suite('Micronaut Launcher Test Suite', () => {
vscode.window.showInformationMessage('Starting Micronaut launcher tests.');
myExtension.enableConsoleLog();

test('Micronaut run', (done) => {
let folder: string = assertWorkspace();
const verifyConditionCallback = (value: string) => new RegExp(/.*/.source + MAVEN_COMMAND_REGEX.source + /.*/.source + MAVEN_PLUGIN_RUN_REGEX.source).test(value);
const errorMessageCallback = (value: string) => `Output: ${value} doesn't contain exec-maven-plugin:exec command`;

myExtension.debugConsoleListeners.push({
callback: createDebugConsoleEventCallback(verifyConditionCallback, errorMessageCallback, done)
});
const entrypointPath = projectFileUri(folder, 'src', 'main', 'java', 'com', 'example', 'Application.java');
waitProjectRecognized(entrypointPath).then(() => {
vscode.commands.executeCommand(`${myExtension.COMMAND_PREFIX}.run.single`, entrypointPath, null, '');
});
});

test('Micronaut debug', (done) => {
let folder: string = assertWorkspace();
const verifyConditionCallback = (value: string) => new RegExp(/.*/.source + MAVEN_COMMAND_REGEX.source + /.*jpda\.listen=true.*jpda\.address=.*/.source + MAVEN_PLUGIN_RUN_REGEX.source).test(value);
const errorMessageCallback = (value: string) => `Output: ${value} doesn't contain flags that starts debug mode`;

myExtension.debugConsoleListeners.push({
callback: createDebugConsoleEventCallback(verifyConditionCallback, errorMessageCallback, done)
});
const entrypointPath = projectFileUri(folder, 'src', 'main', 'java', 'com', 'example', 'Application.java');
waitProjectRecognized(entrypointPath).then(() => {
vscode.commands.executeCommand(`${myExtension.COMMAND_PREFIX}.debug.single`, entrypointPath, null, '');
});
});

test('Micronaut dev mode working', (done) => {
let folder: string = assertWorkspace();
const verifyConditionCallback = (value: string) => new RegExp(/.*/.source + MAVEN_COMMAND_REGEX.source + /.*mn:run/.source).test(value);
const errorMessageCallback = (value: string) => `Output: ${value} doesn't contain mn:run command`;

myExtension.debugConsoleListeners.push({
callback: createDebugConsoleEventCallback(verifyConditionCallback, errorMessageCallback, done)
});
const entrypointPath = projectFileUri(folder, 'src', 'main', 'java', 'com', 'example', 'Application.java');
waitProjectRecognized(entrypointPath).then(() => {
vscode.commands.executeCommand(`${myExtension.COMMAND_PREFIX}.run.single`, entrypointPath, null, 'Micronaut: dev mode');
});
});
});
33 changes: 29 additions & 4 deletions java/java.lsp.server/vscode/src/test/runTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ async function main() {

// The path to test runner
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './suite/index');

const workspaceDir = path.join(extensionDevelopmentPath, 'out', 'test', 'ws');
let extensionTestsPath = path.resolve(__dirname, './suite/index');
let workspaceDir = path.join(extensionDevelopmentPath, 'out', 'test', 'ws');

const outRoot = path.join(extensionDevelopmentPath, "out");
const extDir = path.join(outRoot, "test", "vscode", "exts");
Expand All @@ -62,8 +61,34 @@ async function main() {
workspaceDir
]
});

extensionTestsPath = path.resolve(__dirname, './launcher/index');
workspaceDir = path.join(extensionDevelopmentPath, 'out', 'test', 'test-projects', 'test-app');
fs.rmdirSync(extDir, { recursive: true });
fs.rmdirSync(userDir, { recursive: true });

if (!fs.statSync(workspaceDir).isDirectory()) {
throw `Expecting ${workspaceDir} to be a directory!`;
}

await runTests({
vscodeExecutablePath,
extensionDevelopmentPath,
extensionTestsPath,
extensionTestsEnv: {
'ENABLE_CONSOLE_LOG' : 'true',
"netbeans_extra_options" : `-J-Dproject.limitScanRoot=${outRoot} -J-Dnetbeans.logger.console=true`
},
launchArgs: [
'--disable-extensions',
'--disable-workspace-trust',
'--extensions-dir', `${extDir}`,
'--user-data-dir', `${userDir}`,
workspaceDir
]
});
} catch (err) {
console.error('Failed to run tests');
console.error('Failed to run tests', err);
process.exit(1);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ suite('Extension Test Suite', () => {
}
}

test("Maven run termination", async() => mavenTerminateWithoutDebugger());
// test("Maven run termination", async() => mavenTerminateWithoutDebugger());

async function getProjectInfo() {
let folder: string = assertWorkspace();
Expand Down
4 changes: 2 additions & 2 deletions java/java.lsp.server/vscode/src/test/suite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ export function run(): Promise<void> {
timeout: 60000
});

const testsRoot = path.resolve(__dirname, '..');
const testsRoot = path.resolve(__dirname, '.');

return new Promise((c, e) => {
setTimeout(function() {
glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
glob('./**.test.js', { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}
Expand Down
2 changes: 1 addition & 1 deletion java/java.lsp.server/vscode/src/test/suite/testutils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function assertWorkspace(): string {
* @param folder
* @returns promise that will be fullfilled after the project opens in NBJLS.
*/
async function waitProjectRecognized(someJavaFile : string) {
export async function waitProjectRecognized(someJavaFile : string) {
return waitCommandsReady().then(() => {
const u : vscode.Uri = vscode.Uri.file(someJavaFile);
// clear out possible bad or negative caches.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export function empty(): any {
}
15 changes: 15 additions & 0 deletions java/java.lsp.server/vscode/test-projects/test-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Thumbs.db
.DS_Store
.gradle
build/
target/
out/
.micronaut/
.idea
*.iml
*.ipr
*.iws
.project
.settings
.classpath
.factorypath
Loading

0 comments on commit ad6f973

Please sign in to comment.