Skip to content

Commit

Permalink
Add new test cases to cover fast-run diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
NipunaRanasinghe committed Jan 7, 2025
1 parent 6e1c967 commit 0abf156
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ private void logError(String message) {

@Override
public boolean stop(Path filePath) {
Optional<ProjectContext> projectPairOpt = projectContext(projectRoot(filePath));
Optional<ProjectContext> projectPairOpt = projectContext(projectRoot(filePath).toAbsolutePath());
if (projectPairOpt.isEmpty()) {
clientLogger.logWarning("Failed to stop process: Project not found");
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
* @since 2.0.0
*/
public class TestWorkspaceManager {

private static final Path RESOURCE_DIRECTORY = Path.of("src/test/resources/project");
private final String dummyContent = "function foo() {" + CommonUtil.LINE_SEPARATOR + "}";
private final String dummyDidChangeContent = "function foo1() {" + CommonUtil.LINE_SEPARATOR + "}";
Expand Down Expand Up @@ -558,16 +559,32 @@ public void testWSRunStopProject()
throws WorkspaceDocumentException, EventSyncException, LSCommandExecutorException {
Path projectPath = RESOURCE_DIRECTORY.resolve("long_running");
Path filePath = projectPath.resolve("main.bal");
ExecuteCommandContext execContext = runViaLs(filePath);
stopViaLs(execContext, projectPath);
RunResult runResult = executeRunCommand(filePath);
Assert.assertTrue(runResult.success());
Assert.assertEquals(runResult.programOutput[0], "Hello, World!\n");
executeStopCommand(projectPath);
}

@Test
public void testWSRunProjectWithCompilationErrors()
throws WorkspaceDocumentException, EventSyncException, LSCommandExecutorException {
Path projectPath = RESOURCE_DIRECTORY.resolve("pkg_with_compilation_errors");
Path filePath = projectPath.resolve("main.bal");
RunResult runResult = executeRunCommand(filePath);
Assert.assertFalse(runResult.success());
Assert.assertTrue(runResult.errorOutput().length > 0);
Assert.assertEquals(runResult.errorOutput()[0], "ERROR [main.bal:(5:1,5:1)] missing semicolon token");
Assert.assertEquals(runResult.errorOutput()[1], "error: compilation contains errors");
executeStopCommand(projectPath);
}

@Test
public void testSemanticApiAfterWSRun()
throws WorkspaceDocumentException, EventSyncException, LSCommandExecutorException {
Path projectPath = RESOURCE_DIRECTORY.resolve("hello_service");
Path filePath = projectPath.resolve("main.bal");
ExecuteCommandContext execContext = runViaLs(filePath);
RunResult runResult = executeRunCommand(filePath);
Assert.assertTrue(runResult.success());

// Test syntax tree api
JsonElement syntaxTreeJSON = DiagramUtil.getSyntaxTreeJSON(workspaceManager.document(filePath).orElseThrow(),
Expand All @@ -581,7 +598,7 @@ public void testSemanticApiAfterWSRun()
Assert.assertEquals(execPositions.getAsJsonArray().get(0).getAsJsonObject().get("name").getAsString(),
"hello");

stopViaLs(execContext, projectPath);
executeStopCommand(projectPath);
}

@Test
Expand All @@ -602,7 +619,8 @@ public void testSemanticApiAfterWSRunMultiMod()
workspaceManager.document(filePath).orElseThrow(),
semanticModelPreExec);

ExecuteCommandContext execContext = runViaLs(filePath);
RunResult runResult = executeRunCommand(filePath);
Assert.assertTrue(runResult.success());

SemanticModel semanticModelPostExec = workspaceManager.semanticModel(filePath).orElseThrow();
JsonElement syntaxTreeJSONPostExec = DiagramUtil.getSyntaxTreeJSON(
Expand All @@ -612,48 +630,53 @@ public void testSemanticApiAfterWSRunMultiMod()
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Assert.assertEquals(gson.toJson(syntaxTreeJSONPreExec), gson.toJson(syntaxTreeJSONPostExec));

stopViaLs(execContext, projectPath);
executeStopCommand(projectPath);
}


private ExecuteCommandContext runViaLs(Path filePath)
private RunResult executeRunCommand(Path filePath)
throws WorkspaceDocumentException, EventSyncException, LSCommandExecutorException {
System.setProperty("java.command", guessJavaPath());
System.setProperty(BALLERINA_HOME, "./build");
workspaceManager.loadProject(filePath);
RunExecutor runExecutor = new RunExecutor();
MockSettings mockSettings = Mockito.withSettings().stubOnly();
ExecuteCommandContext execContext = Mockito.mock(ExecuteCommandContext.class, mockSettings);
CommandArgument arg = CommandArgument.from("path", new JsonPrimitive(filePath.toString()));
Mockito.when(execContext.getArguments()).thenReturn(Collections.singletonList(arg));
Mockito.when(execContext.workspace()).thenReturn(workspaceManager);

ExecuteCommandContext execContext = createExecutionContextMock(filePath);
ExtendedLanguageClient languageClient = Mockito.mock(ExtendedLanguageClient.class, mockSettings);
ArgumentCaptor<LogTraceParams> logCaptor = ArgumentCaptor.forClass(LogTraceParams.class);
Mockito.doNothing().when(languageClient).logTrace(logCaptor.capture());
Mockito.when(execContext.getLanguageClient()).thenReturn(languageClient);
Boolean didRan = runExecutor.execute(execContext);
Assert.assertTrue(didRan);
Assert.assertEquals(reduceToOutString(logCaptor), "Hello, World!" + System.lineSeparator());
return execContext;

return new RunResult(didRan, extractLogs(logCaptor, "out"), extractLogs(logCaptor, "err"));
}

private static void stopViaLs(ExecuteCommandContext execContext, Path projectPath) {
private void executeStopCommand(Path projectPath) {
StopExecutor stopExecutor = new StopExecutor();
ExecuteCommandContext execContext = createExecutionContextMock(projectPath);
Boolean didStop = stopExecutor.execute(execContext);
Assert.assertTrue(didStop);

Path target = projectPath.resolve("target");
FileUtils.deleteQuietly(target.toFile());
}

private static String reduceToOutString(ArgumentCaptor<LogTraceParams> logCaptor) {
private ExecuteCommandContext createExecutionContextMock(Path filePath) {
MockSettings mockSettings = Mockito.withSettings().stubOnly();
ExecuteCommandContext execContext = Mockito.mock(ExecuteCommandContext.class, mockSettings);

CommandArgument arg = CommandArgument.from("path", new JsonPrimitive(filePath.toString()));
Mockito.when(execContext.getArguments()).thenReturn(Collections.singletonList(arg));
Mockito.when(execContext.workspace()).thenReturn(workspaceManager);
return execContext;
}

private static String[] extractLogs(ArgumentCaptor<LogTraceParams> logCaptor, String channel) {
List<LogTraceParams> params = waitGetAllValues(logCaptor);
StringBuilder sb = new StringBuilder();
for (LogTraceParams param : params) {
sb.append(param.getMessage());
Assert.assertEquals(param.getVerbose(), "out"); // not "err"
}
return sb.toString();
return params.stream()
.filter(param -> param.getVerbose().equals(channel))
.map(LogTraceParams::getMessage)
.toArray(String[]::new);
}

private static List<LogTraceParams> waitGetAllValues(ArgumentCaptor<LogTraceParams> logCaptor) {
Expand Down Expand Up @@ -742,4 +765,8 @@ public Object[] workspaceEventsTestDataProvider() {
RESOURCE_DIRECTORY.resolve("myproject").resolve("main.bal").toAbsolutePath()
};
}

private record RunResult(boolean success, String[] programOutput, String[] errorOutput) {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
org = "baltest"
name = "pkg_with_compilation_errors"
version = "0.1.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ballerina/lang.runtime;

public function main() {
runtime:sleep(20)
}

0 comments on commit 0abf156

Please sign in to comment.