lsp-java icon indicating copy to clipboard operation
lsp-java copied to clipboard

How to set classpath in test?

Open goldfita opened this issue 3 years ago • 11 comments

Are we supposed to set the classpath ourselves when running unit tests? If I run dap-java-run-test-method, I get the following, indicating that JUNIT_CLASS_PATH is not set:

java -jar c:/Development/.emacs.d/eclipse.jdt.ls/test-runner/junit-platform-console-standalone.jar -cp %JUNIT_CLASS_PATH% -m MyTest#testMyTest Error parsing command-line arguments: Expected parameter for option '--class-path' but found '-m'

I have a multi-module project. Do I need to add the all the jars in every project target to the classpath? I couldn't find any mention of JUNIT_CLASS_PATH in the docs. Also, if I run from the gui (right click and 'run test'), I get a different error, but still appears to be a classpath issue:

LSP :: workspace/executeCommand' with vscode.java.test.runtime.classpath' failed.

(error "No delegateCommandHandler for vscode.java.test.runtime.classpath") Error running timer: (wrong-type-argument listp #("LSP :: workspace/executeCommand' with vscode.java.test.runtime.classpath' failed.

(error "No delegateCommandHandler for vscode.java.test.runtime.classpath")" 0 3 (face error)))

goldfita avatar Aug 25 '22 20:08 goldfita

Even if I set JUNIT_CLASS_PATH from windows and restart emacs, I still get the same error. I can run this myself from the command line, but in addition to dependencies on other modules, it's looking for spring test, logging, etc. So assembling the classpath myself will be quite complicated.

goldfita avatar Aug 25 '22 21:08 goldfita

The line that is failing for the latter method of running the test is in lsp-jt.el:

(lsp-send-execute-command "vscode.java.test.runtime.classpath" [["absolute path to test file"]])

It gives the suggestion to run lsp-describe-session, which I did. It looks as though this command is not supported??

vscode.java.checkProjectSettings vscode.java.isOnClasspath java.project.list vscode.java.fetchUsageData java.navigate.openTypeHierarchy vscode.java.test.search.items.all sts.java.hierarchy.supertypes java.edit.stringFormatting sts.java.hierarchy.subtypes vscode.java.resolveMainClass vscode.java.test.search.location vscode.java.buildWorkspace vscode.java.resolveJavaExecutable sts.java.type java.project.refreshDiagnostics vscode.java.resolveInlineVariables java.project.listSourcePaths sts.java.search.packages java.project.getClasspaths java.project.updateSourceAttachment vscode.java.resolveClasspath vscode.java.resolveBuildFiles vscode.java.resolveSourceUri vscode.java.test.search.items vscode.java.fetchPlatformSettings java.project.resolveSourceAttachment sts.java.removeClasspathListener java.project.addToSourcePath vscode.java.startDebugSession java.project.import vscode.java.validateLaunchConfig java.project.resolveStackTraceLocation vscode.java.test.junit.argument vscode.java.resolveMainMethod java.project.getSettings java.project.resolveWorkspaceSymbol sts.java.addClasspathListener java.project.upgradeGradle vscode.java.test.get.testpath java.resolvePath sts.java.javadoc vscode.java.resolveElementAtSelection vscode.java.test.search.codelens java.edit.organizeImports java.project.removeFromSourcePath sts.java.javadocHoverLink java.project.getAll java.project.isTestFile sts.java.search.types vscode.java.resolveClassFilters java.getPackageData java.navigate.resolveTypeHierarchy vscode.java.updateDebugSettings sts.java.location vscode.java.inferLaunchCommandLength

goldfita avatar Aug 25 '22 22:08 goldfita

The code was different in master. I updated to the latest on melpa from stable. When I run through the gui, it gets further now, but I have a mile long stack trace starting with:

[ERROR] org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@71e693fa] to prepare test instance [...] java.lang.IllegalStateException: Failed to load ApplicationContext

This does work in Intellij. I'll try again tomorrow.

goldfita avatar Aug 25 '22 23:08 goldfita

Where is that vscode.java.test.runtime.classpath coming from? I dont see it in the repo : https://github.com/emacs-lsp/lsp-java/search?q=vscode.java.test.runtime.classpath

yyoncho avatar Aug 26 '22 05:08 yyoncho

I found the problem causing the exception. The maven-surefire-plugin sets keystore/truststore properties which are then accessed in code through System.getProperty(). This works in intellij, but the result is null in lsp. I'm not sure how to diagnose the problem further. Is there a way I can manually pass the system properties I need?

It appears that this used to be an issue in intellij as well.

Where is that vscode.java.test.runtime.classpath coming from? I dont see it in the repo : https://github.com/emacs-lsp/lsp-java/search?q=vscode.java.test.runtime.classpath

It's on lsp-jt.el:395 in version 3.1. This was on melpa stable.

goldfita avatar Aug 26 '22 14:08 goldfita

I tried setting dap-debug-template-configurations. I don't know how you tell it which one to use, so I replaced the defaults with a single instance:

(setq dap-debug-template-configurations
 (list (list "Java Run Configuration (compile/attach)"
       :type "java"
       :request "compile_attach"
       :args ""
       :vmArgs "-Djavax.net.ssl.keyStore=..."
       :cwd nil
       :host "localhost"
       :request "launch"
       :modulePaths []
       :classPaths nil
       :name "Run"
       :projectName nil
       :mainClass nil)))

I also tried lsp-java-vmargs:

(setq lsp-java-vmargs '("-Djavax.net.ssl.keyStore=..."))

In either case, it doesn't seem to make a difference. The only io I see related to vmargs is this:

 "vmArguments": [
    "-ea"
  ],

goldfita avatar Aug 26 '22 18:08 goldfita

It looks like lsp-jt--create-launch-config is called with results vm-arguments coming from the language server. I don't see any way to override it.

goldfita avatar Aug 26 '22 18:08 goldfita

We should create a variable here.

yyoncho avatar Aug 26 '22 18:08 yyoncho

I took another crack at this. I was finally able to get a unit test to pass. First, I found a work around for passing options to the jvm.

(defun dap-debug-patch (orig-fun &rest args)
  (let* ((args (cl-copy-list args))
         (vmArgs (plist-get (car args) :vmArgs)))
    (plist-put (car args) :vmArgs
               (concat vmArgs " -Denvvar1=... -Denvvar2=..."))
    (apply orig-fun args)))
(advice-add 'dap-debug :around #'dap-debug-patch)

Is there any way to retrieve the environment variables from the language server? It's part of the pom (surefire plugin), so the LSP should know about them.

The next issue I ran into was that I'm using an old jdk 8. However, I think there was a reason lsp-java requires a newer one for running tests. There seems to be some differences in that the old jdk allows null to be passed to Path.get(). This was easily fixed for me by setting some additional environment variables to the string "null". Diagnosing the issue was quite challenging, though, for the following reasons:

  • Truncation.
    1. Debug session truncates strings. I don't know if there is a customization for this. I tried right clicking on the variable I wanted to examine and it gave the error "Invalid menu item in easy menu".
    2. Test output truncates long exceptions.
  • Debug session doesn't show some variables - just class variables I think.
  • Something related to LSP (probably lsp or dap-debug) is occasionally hanging. From looking at the cpu usage, it's probably stuck in a loop somewhere. Unfortunately I can't provide any more than this.
  • Breakpoints.
    1. Placing a breakpoint on inline field initialization does not seem to work.
    2. I can right click on the statement causing a problem and go to implementation, which shows up as workspace/.cache/java.nio.file.Paths.java. But placing a breakpoint here does not seem to work. Actually, I hit the breakpoint once, but not from where I was expecting, and it wasn't repeatable.
  • Is there a way to hot reload classes? I've gotten used to having this feature.
  • Is there a way to restart a test session? I have been deleting the session and running a new one; otherwise, it creates a new one, leaving the old one in the sessions window.

I can open new issues if any of these are actual issues. As far as the problem with passing arguments to the jdk is concerned, I have a working solution, though I have to hard code the values.

goldfita avatar Oct 02 '22 19:10 goldfita

I believe the hanging, in some cases, is caused by accessing the project files outside emacs. For example, I was just building using command line maven, and emacs suddenly froze. I wasn't actively using LSP, although the language server had been started. So it likely has something to do with lsp-java or the language server monitoring compiled files, which are suddenly deleted or overwritten.

If I wait 15 seconds, it usually comes back, but it's happening almost every time. In this particular case, it is being caused by the build changing pom files.

goldfita avatar Oct 03 '22 14:10 goldfita

Ignoring pom files seems to have helped somewhat, but it's still fully locking up even when not building outside emacs.

(add-to-list 'lsp-file-watch-ignored-files "[/\\\\]pom\\.xml\\'")

goldfita avatar Oct 04 '22 23:10 goldfita