Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert Infinitest from a facet to a tool window #334

Merged
merged 32 commits into from
Oct 1, 2022

Conversation

gtoison
Copy link
Contributor

@gtoison gtoison commented Sep 4, 2022

Currentl Infinitest is a facet in the IntelliJ plugin, this requires users to add the facet to every module. It also creates a window per module so it is not user friendly for large multi module projects.

Add a project-level ToolWindow and initialise the InfinitestLauncher as
a project-level service.
Use the platform message bus for the communication between the
Infinitest runner and its listeners
Display the failed tests grouped by module (instead of showing a window
per module)

Fixes #29
Fixes #173
Fixes #193
Fixes #216
Fixes #237
Fixes #327
Add a project-level ToolWindow and initialise the InfinitestLauncher as
a project-level service.
Use the platform message bus for the communication between the
Infinitest runner and its listeners
Display the failed tests grouped by module (instead of showing a window
per module)

Fixes #29
Fixes #173
Fixes #193
Fixes #216
Fixes #237
Fixes #327
@gtoison gtoison added the comp:infinitest-intellij Issues related to Infintest for IntelliJ (and other Jetbrains IDEs) label Sep 4, 2022
@szpak
Copy link
Contributor

szpak commented Sep 4, 2022

When executed in the multi-module project - here infinitest itself - I've got the following error on project recompilation:

java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 0
*.exampletests.*
^
	at java.base/java.util.regex.Pattern.error(Pattern.java:2027)
	at java.base/java.util.regex.Pattern.sequence(Pattern.java:2202)
	at java.base/java.util.regex.Pattern.expr(Pattern.java:2068)
	at java.base/java.util.regex.Pattern.compile(Pattern.java:1782)
	at java.base/java.util.regex.Pattern.<init>(Pattern.java:1428)
	at java.base/java.util.regex.Pattern.compile(Pattern.java:1068)
	at java.base/java.util.regex.Pattern.matches(Pattern.java:1173)
	at java.base/java.lang.String.matches(String.java:2024)
	at org.infinitest.filter.RegexFileFilter.matchesAnyPattern(RegexFileFilter.java:69)
	at org.infinitest.filter.RegexFileFilter.match(RegexFileFilter.java:64)
	at org.infinitest.parser.ClassFileTestDetector.isATest(ClassFileTestDetector.java:107)
	at org.infinitest.parser.ClassFileTestDetector.getCurrentTests(ClassFileTestDetector.java:132)
	at org.infinitest.DefaultInfinitestCore.runOptimizedTestSet(DefaultInfinitestCore.java:120)
	at org.infinitest.DefaultInfinitestCore.update(DefaultInfinitestCore.java:82)
	at org.infinitest.DefaultInfinitestCore.update(DefaultInfinitestCore.java:92)
	at org.infinitest.intellij.idea.IdeaCompilationListener.doRunTests(IdeaCompilationListener.java:76)
	at org.infinitest.intellij.idea.IdeaCompilationListener.finished(IdeaCompilationListener.java:56)
	at com.intellij.util.messages.impl.MessageBusImpl.invokeMethod(MessageBusImpl.java:642)
...

What is strange, that error seems to break the ability to execute tests in a regular way. Steps to reproduce:

  1. Open Infinitest project in IDEA (here 2022.1 with the plugin version from this branch - ac05431)
  2. Run JUnit4RunnerTest (in a regular Idea way).

Excepted behavior:

  1. Tests are executed by IDEA (and probably also by Infinitest).
  2. I can re-execute that test (or the other)

Current behavior:

  1. IDEA does not execute tests.
  2. Infinitest executes tests
  3. The aforementioned exception is thrown.
  4. Run 'JUnit4RunnerTest' icon is not active - I cannot re-run that test class (in fact any other as well). Only "Debug" is available, but after its execution the another exception is thrown and Debug is also "broken".

@szpak
Copy link
Contributor

szpak commented Sep 4, 2022

Another perception. I wonder, how would it be best to exclude some modules from the run. Somehow in Idea? Or the Infinitest's configuration file should be used?

@gtoison
Copy link
Contributor Author

gtoison commented Sep 4, 2022

I think the issue you're seeing is because of this filter: https://github.com/infinitest/infinitest/blob/master/infinitest-runner/infinitest.filters
So the error is in the project you're testing, not in the plugin. I had all kind of errors when using Infinitest on the Infinitest project and I think I saw a comment somewhere saying it does not work, but I'm not sure why.

Another perception. I wonder, how would it be best to exclude some modules from the run. Somehow in Idea? Or the Infinitest's configuration file should be used?

Currently the results are displayed as a tree and the modules are the top-level elements, maybe I could add an action to enable/disable the tests there. Maybe right click -> disable/enable?

@szpak
Copy link
Contributor

szpak commented Sep 4, 2022

So the error is in the project you're testing, not in the plugin.

You are right. The Infinitest project itself has many infinitest.filters file in the Git repo. Are the not vailid any longer?

Anyway, it would be good to catch that kind of exceptions - re-running tests is globally broken for that project.

@szpak
Copy link
Contributor

szpak commented Sep 4, 2022

Currently the results are displayed as a tree and the modules are the top-level elements, maybe I could add an action to enable/disable the tests there. Maybe right click -> disable/enable?

Sounds good for me. Please do something that is easy to implement for you. There could be some "heavy" modules (e.g. acceptance tests) in some projects which are not intended to be executed with Infinitest.

@gtoison
Copy link
Contributor Author

gtoison commented Sep 5, 2022

Now it should be possible to disable/enable the tests by right-clicking on it in the results tree

@szpak
Copy link
Contributor

szpak commented Sep 5, 2022

I hit the following error on loading the infinitest project itself with the new version of the plugin (still IDEA 2022.1):

java.lang.NoClassDefFoundError: org/testng/collections/Lists
	at org.infinitest.intellij.idea.IdeaModuleSettings.listClasspathElements(IdeaModuleSettings.java:166)
	at org.infinitest.intellij.idea.IdeaModuleSettings.buildClasspathString(IdeaModuleSettings.java:143)
	at org.infinitest.intellij.idea.IdeaModuleSettings.getRuntimeEnvironment(IdeaModuleSettings.java:102)
	at org.infinitest.intellij.plugin.launcher.InfinitestLauncherImpl.<init>(InfinitestLauncherImpl.java:48)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at com.intellij.serviceContainer.ConstructorInjectionKt.instantiateUsingPicoContainer(constructorInjection.kt:52)
	at com.intellij.serviceContainer.ComponentManagerImpl.instantiateClassWithConstructorInjection(ComponentManagerImpl.kt:891)
	at com.intellij.serviceContainer.ServiceComponentAdapter.createAndInitialize(ServiceComponentAdapter.kt:51)
	at com.intellij.serviceContainer.ServiceComponentAdapter.doCreateInstance(ServiceComponentAdapter.kt:41)
	at com.intellij.serviceContainer.BaseComponentAdapter.getInstanceUncached(BaseComponentAdapter.kt:119)
	at com.intellij.serviceContainer.BaseComponentAdapter.getInstance(BaseComponentAdapter.kt:73)
	at com.intellij.serviceContainer.BaseComponentAdapter.getInstance$default(BaseComponentAdapter.kt:66)
	at com.intellij.serviceContainer.ComponentManagerImpl.doGetService(ComponentManagerImpl.kt:610)
	at com.intellij.serviceContainer.ComponentManagerImpl.getService(ComponentManagerImpl.kt:584)
	at org.infinitest.intellij.plugin.swingui.TreeModelAdapter.getChildCount(TreeModelAdapter.java:99)
	at org.infinitest.intellij.plugin.swingui.TreeModelAdapter.isLeaf(TreeModelAdapter.java:138)
	at com.intellij.ui.tree.ui.DefaultTreeUI.isLeaf(DefaultTreeUI.java:182)
	at com.intellij.ui.tree.ui.DefaultTreeUI$2.getNodeDimensions(DefaultTreeUI.java:501)
	at java.desktop/javax.swing.tree.AbstractLayoutCache.getNodeDimensions(AbstractLayoutCache.java:493)
...

Probably you confused the import in Lists.newArrayList().

@szpak
Copy link
Contributor

szpak commented Sep 5, 2022

After fixing that, I have:

java.lang.NoClassDefFoundError: org/testng/annotations/Test
	at org.infinitest.parser.JavaAssistClass.isTestNGTestClass(JavaAssistClass.java:277)
	at org.infinitest.parser.JavaAssistClass.hasTestNGTests(JavaAssistClass.java:265)
	at org.infinitest.parser.JavaAssistClass.hasTests(JavaAssistClass.java:232)
	at org.infinitest.parser.JavaAssistClass.<init>(JavaAssistClass.java:63)
	at org.infinitest.parser.JavaAssistClassParser.getClass(JavaAssistClassParser.java:104)
	at org.infinitest.parser.JavaClassBuilder.getClass(JavaClassBuilder.java:57)
	at org.infinitest.parser.ClassFileIndex.findJavaClass(ClassFileIndex.java:91)
	at org.infinitest.parser.ClassFileIndex.updateParentReferences(ClassFileIndex.java:132)
	at org.infinitest.parser.ClassFileIndex.addToIndex(ClassFileIndex.java:105)
	at org.infinitest.parser.ClassFileIndex.findClasses(ClassFileIndex.java:80)
	at org.infinitest.parser.ClassFileTestDetector.findTestsToRun(ClassFileTestDetector.java:68)
	at org.infinitest.DefaultInfinitestCore.runOptimizedTestSet(DefaultInfinitestCore.java:121)
	at org.infinitest.DefaultInfinitestCore.update(DefaultInfinitestCore.java:82)
	at org.infinitest.DefaultInfinitestCore.update(DefaultInfinitestCore.java:92)
	at org.infinitest.intellij.idea.IdeaCompilationListener.doRunTests(IdeaCompilationListener.java:76)
	at org.infinitest.intellij.idea.IdeaCompilationListener.finished(IdeaCompilationListener.java:56)
	at com.intellij.util.messages.impl.MessageBusImpl.invokeMethod(MessageBusImpl.java:642)
...

in the JUnit 5 project.

@szpak
Copy link
Contributor

szpak commented Sep 5, 2022

Btw, maybe it was a "case" also before, however, it seems that infinitest core is shared across many open projects. I one project, in the logging tab, I see changed files also from the other project(s).

@gtoison
Copy link
Contributor Author

gtoison commented Sep 6, 2022

Hum, I agree that this import is not the best and should be fixed but it has been there for 4 years, so I'm not sure why you got that error. TestNG should be on the classpath since it is a (transitive) dependency.
When building are you doing mvn package or mvn clean package? I'm not sure why but for the Infinitest project I had cases where I had to clean or I would get some missing dependencies in the final artifact.

For the logs currently there's one static logger for the entire application and every view is a listener, so indeed this should be fixed. I think it could be better to make this change in a separate PR, that one is quite big already.

Thanks a lot for testing, it is very much appreciated!

@szpak
Copy link
Contributor

szpak commented Sep 6, 2022

Sorry for suspicion. Seeing that error for the first time, I though I've just made that statement. What is strange, today I rebuild the project and it works...

Two spotted things:

  1. I'm not sure, if module exclusion works as expected. I disabled infinitest-lib, clicked "force rebuild of dependency graph" and still I see some warnings about tests in that module:
    image

  2. *.exampletests.* in infinitest.filters still raises an exception.

@szpak
Copy link
Contributor

szpak commented Sep 7, 2022

I'm not sure, if module exclusion works as expected. I disabled infinitest-lib, clicked "force rebuild of dependency graph" and still I see some warnings about tests in that module:

After your last commit, it is fixed. Thanks.

I don't know how would it be hard to implement, however, the enabled/disabled state is not kept across Idea restarts. Having many modules to disable, it would be inconvenient to do it every time the project is open.

@gtoison
Copy link
Contributor Author

gtoison commented Sep 7, 2022

Yes, I had the same thoughts
Reading the docs it shouldn't be to complicated to persist the enabled/disabled state but for now I can't seem to get it to work
I'll try again later

@gtoison
Copy link
Contributor Author

gtoison commented Sep 9, 2022

It should save the project-level and module-level enabled/disabled switches now

@gtoison
Copy link
Contributor Author

gtoison commented Sep 23, 2022

Hello @szpak, I was wondering if you had time to test the last changes (I just made a very minor tweak)
Do you think it's ok to merge this?

@szpak
Copy link
Contributor

szpak commented Sep 25, 2022

I gave it an another try and it seems to work :-).

Most likely it is a problem with Idea which doesn't recompile my test files after change (or on "Save all") and I have to hit "Build project" to have the new class file(s) written and discovered by Infinitest).

In addition, in the inifinitest project it self there are some failed. However, in some other "simple" projects it works nicely and definitely the new approach of the plugin in Idea i much more user friendly.

Btw, after Idea start the icon for Infinitest is:
image

Is it intended? After the first execution it changes to stylized Inifinitest "Yin i yang".

@szpak
Copy link
Contributor

szpak commented Sep 25, 2022

Btw, I created #343 to cover a problem with ".exampletests."

@gtoison
Copy link
Contributor Author

gtoison commented Sep 25, 2022

Right, Infinitest won't run the tests until a build is completed, this was already the case from what I've seen.
I think the issue with the icon is that the plugins are not fully loaded when the main windows shows up, so Infinitest is still initializing

@szpak
Copy link
Contributor

szpak commented Sep 26, 2022

It should save the project-level and module-level enabled/disabled switches now

Btw, what do you mean by "the project-level enabled/disabled switches"? How can I disable Infinitest completely for the project (to do not load at all) at the next project opening?

A sample use case. A big legacy project (with many modules) and slow integration tests. On the first rebuild, they would try to be executed. All the modules can be disabled (which is persisted!), but still it not very handy. If it is currently not possible, I can create a separate issue for it, just to remember about that limitation.

@gtoison
Copy link
Contributor Author

gtoison commented Sep 27, 2022

There are two flags controlling whether the tests are executed: one at module level (enabled/disabled by right-clicking the module in the Infinitest window) and one at project level here:
image

When the tests are disabled at project level, none are executed even if they might be enable for a module.
These settings (project and module level) are now persisted in the .idea/workspace.xml file
So when reopening the project Infinitest should pick up the settings from the last session.

I'm not sure how to address the case that on the first build all the tests (including some slow tests) will run unless the user disabled them beforehand

@szpak
Copy link
Contributor

szpak commented Sep 27, 2022

Thanks for the screenshots - I wasn't aware it works that way (and that it is persisted).

I'm not sure how to address the case that on the first build all the tests (including some slow tests) will run unless the user disabled them beforehand

It should not be a problem. After the project it open you have to hit "Build project" to generate classes, so when one will click "x" before, no tests should be executed by Infinitest.

@gtoison
Copy link
Contributor Author

gtoison commented Sep 27, 2022

It wasn't persisted before, but with the changes in that PR it should be ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp:infinitest-intellij Issues related to Infintest for IntelliJ (and other Jetbrains IDEs)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants