szpak / gradle-pitest-plugin

Gradle plugin for PIT Mutation Testing
http://gradle-pitest-plugin.solidsoft.info/
213 stars 58 forks source link

Setting junit5PluginVersion doesn't work in my project #188

Closed Demonian closed 4 years ago

Demonian commented 4 years ago

Pitest could not recognise tests if --enable-preview feature flag is enabled in gradle. I have tested it with multiple gradle-pitest-plugin version:

6:31:27 PM PIT >> INFO : Sending 62 test classes to minion 6:31:27 PM PIT >> INFO : Sent tests to minion 6:31:27 PM PIT >> INFO : MINION : 6:31:27 PM PIT >> FINE : Expecting 62 tests classes from parent 6:31:27 PM PIT >> FINE : Tests classes received

6:31:27 PM PIT >> INFO : MINION : 6:31:27 PM PIT >> INFO : Checking environment

6:31:27 PM PIT >> INFO : MINION : 6:31:27 PM PIT >> WARNING : Could not load com.numbrs.admin.AdminPanelApplication Preview features are not enabled for com/numbrs/admin/AdminPanelApplication (class file version 57.65535). Try running with '--enable-preview' ...

In this version of plugin additional `jvmArgs` are not picked.

- **gradle-pitest-plugin** version: `1.4.7`(with junit5 plugin version `0.12`)
Gradle config:

pitest { ... jvmArgs.add("--enable-preview") ... }

Here is the relevant log output (verbose mode is enabled):

Running report with ReportOptions [...jvmArgs=[-Djava.awt.headless=true, --enable-preview], ...] 5:30:04 PM PIT >> FINE : Maximum available memory is 4096 mb 5:30:04 PM PIT >> FINE : MINION : Installing PIT agent

5:30:05 PM PIT >> INFO : Sending 62 test classes to minion 5:30:05 PM PIT >> INFO : Sent tests to minion 5:30:06 PM PIT >> INFO : MINION : 5:30:06 PM PIT >> FINE : Expecting 62 tests classes from parent 5:30:06 PM PIT >> FINE : Tests classes received 5:30:06 PM PIT >> INFO : Checking environment

5:30:07 PM PIT >> INFO : MINION : 5:30:07 PM PIT >> INFO : Found 0 tests

5:30:07 PM PIT >> INFO : MINION : 5:30:07 PM PIT >> INFO : Dependency analysis reduced number of potential tests by 0

5:30:07 PM PIT >> INFO : MINION : 5:30:07 PM PIT >> INFO : 0 tests received

5:30:07 PM PIT >> INFO : MINION : 5:30:07 PM PIT >> FINE : Running 0 units

5:30:07 PM PIT >> FINE : Coverage generator Minion exited ok 5:30:07 PM PIT >> INFO : Calculated coverage in 3 seconds. 5:30:07 PM PIT >> FINE : Used memory after coverage calculation 6 mb 5:30:07 PM PIT >> FINE : Free Memory after coverage calculation 251 mb


In this version of plugin additional `jvmArgs` are picked, but tests are still not recognised. There are no any additional warnings or errors in output from PIT MINIONS.

Is there any workaround for this?
szpak commented 4 years ago

Are you sure it is related to jvmArgs? Do the tests are properly executed with 1.4.7 (and 0.12) if --enable-preview is not specified? Please paste your pitest plugin configuration (and how you apply the plugin itself). There were changes in 1.4.7 regarding the JUnit 5 plugin which could affect your configuration.

Demonian commented 4 years ago

@szpak Thanks, for quick reply. You are right. I have tried to configure JUnit 5 plugin with new property junit5PluginVersion which probably haven't worked for me, but now I have reverted to the config with previous approach and it seems working. Working config (with buildscript):

buildscript {
    val pitest = configurations.maybeCreate("pitest")
    dependencies {
        pitest("org.pitest:pitest-junit5-plugin:0.12")
    }
}
pitest {
    testPlugin.set("junit5")
    mutators.set(listOf("DEFAULTS"))
    jvmArgs.add("--enable-preview")
    // Need to give mutated tests some additional time to avoid tons of TIMED_OUT tests (default 1.25 is not enough):
    timeoutFactor.set(BigDecimal.valueOf(50))
    timeoutConstInMillis.set(20000)
    excludedClasses.set(listOf(
            "*.configuration.*", // All our configs are usually here
            "*.model.*", // Json models, forming APIs of our services
            "*.data.*", // DB data models
            // ~ at the beginning is required to mark this string as a regex. It won't be part of it.
            // Kafka models (we have `v` and then number in the name. e.g. `<package name>.v1.<class name>`):
            "~^.*v[0-9]+.*\$"
    ))
    excludedTestClasses.set(listOf(
            // Component tests shouldn't be used to test business logic, only integration with third party
            // components, so excluding them from mutation testing:
            "**.*ApplicationTest", "**.*ComponentTest"
    ))
    outputFormats.set(listOf("XML", "HTML"))
    timestampedReports.set(false)
    verbose.set(if (System.getProperty("override.pitest.verbose") != null) java.lang.Boolean.getBoolean("override.pitest.verbose") else true)
    threads.set(Integer.getInteger("override.pitest.threads") ?: 1)
    setReportDir(File(System.getProperty("override.pitest.report.dir") ?: "${buildDir}/reports/pitest"))
    //setHistoryInputLocation(System.getProperty("override.pitest.history.input.location") ?: "${buildDir}/mutationHistory/history.txt")
    setHistoryOutputLocation(System.getProperty("override.pitest.history.output.location") ?: "${buildDir}/mutationHistory/history.txt")
}

Not working config (with junit5PluginVersion.set("0.12") property):

pitest {
    junit5PluginVersion.set("0.12")
    mutators.set(listOf("DEFAULTS"))
    jvmArgs.add("--enable-preview")
    // Need to give mutated tests some additional time to avoid tons of TIMED_OUT tests (default 1.25 is not enough):
    timeoutFactor.set(BigDecimal.valueOf(50))
    timeoutConstInMillis.set(20000)
    excludedClasses.set(listOf(
            "*.configuration.*", // All our configs are usually here
            "*.model.*", // Json models, forming APIs of our services
            "*.data.*", // DB data models
            // ~ at the beginning is required to mark this string as a regex. It won't be part of it.
            // Kafka models (we have `v` and then number in the name. e.g. `<package name>.v1.<class name>`):
            "~^.*v[0-9]+.*\$"
    ))
    excludedTestClasses.set(listOf(
            // Component tests shouldn't be used to test business logic, only integration with third party
            // components, so excluding them from mutation testing:
            "**.*ApplicationTest", "**.*ComponentTest"
    ))
    outputFormats.set(listOf("XML", "HTML"))
    timestampedReports.set(false)
    verbose.set(if (System.getProperty("override.pitest.verbose") != null) java.lang.Boolean.getBoolean("override.pitest.verbose") else true)
    threads.set(Integer.getInteger("override.pitest.threads") ?: 1)
    setReportDir(File(System.getProperty("override.pitest.report.dir") ?: "${buildDir}/reports/pitest"))
    //setHistoryInputLocation(System.getProperty("override.pitest.history.input.location") ?: "${buildDir}/mutationHistory/history.txt")
    setHistoryOutputLocation(System.getProperty("override.pitest.history.output.location") ?: "${buildDir}/mutationHistory/history.txt")
}

By the way as you can see I have commented setHistoryInputLocation(System.getProperty("override.pitest.history.input.location") ?: "${buildDir}/mutationHistory/history.txt") because when I am enabling it I see gradle errors like this:

Caused by: org.gradle.api.UncheckedIOException: Unable to store input properties for task ':pitest'. Property 'historyInputLocation' with value 'path/build/mutationHistory/history.txt' cannot be serialized.

Caused by: java.lang.ClassCastException: class java.io.File cannot be cast to class java.lang.String (java.io.File and java.lang.String are in module java.base of loader 'bootstrap')

Do you know some workarounds for this?=)

Demonian commented 4 years ago

@szpak Should I create separate issues for this two problems?

  1. Enabling Junit5 test plugin with a help of junit5PluginVersion.set("0.12") seems not working (maybe I am doing something wrong)
  2. Setting historyInputLocation property gives gradle errors during execution:
    * Exception is:
    org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':pitest'.
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:38)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
    at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
    at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
    at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:41)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:372)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:359)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:352)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:338)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
    at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    **Caused by: org.gradle.api.UncheckedIOException: Unable to store input properties for task ':pitest'. Property 'historyInputLocation' with value '/project/build/mutationHistory/history.txt' cannot be serialized.**
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.lambda$fingerprintInputProperties$2(CaptureStateBeforeExecutionStep.java:178)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.visitInputProperties(ExecuteActionsTaskExecuter.java:307)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.fingerprintInputProperties(CaptureStateBeforeExecutionStep.java:169)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.captureExecutionState(CaptureStateBeforeExecutionStep.java:149)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.lambda$captureExecutionStateOp$1(CaptureStateBeforeExecutionStep.java:104)
    at org.gradle.internal.execution.steps.BuildOperationStep$1.call(BuildOperationStep.java:40)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)
    at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)
    at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
    at org.gradle.internal.execution.steps.BuildOperationStep.operation(BuildOperationStep.java:37)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.captureExecutionStateOp(CaptureStateBeforeExecutionStep.java:103)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.lambda$execute$0(CaptureStateBeforeExecutionStep.java:78)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:78)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:53)
    at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:74)
    at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:78)
    at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:78)
    at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:34)
    at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:39)
    at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:40)
    at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:28)
    at org.gradle.internal.execution.impl.DefaultWorkExecutor.execute(DefaultWorkExecutor.java:33)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:192)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:184)
    at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:109)
    at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:62)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
    ... 23 more
    **Caused by: java.lang.ClassCastException: class java.io.File cannot be cast to class java.lang.String (java.io.File and java.lang.String are in module java.base of loader 'bootstrap')**
    at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter$ValueSnapshotVisitor.managedImmutableValue(DefaultValueSnapshotter.java:287)
    at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter$ValueSnapshotVisitor.managedImmutableValue(DefaultValueSnapshotter.java:228)
    at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter.processValue(DefaultValueSnapshotter.java:152)
    at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter.snapshot(DefaultValueSnapshotter.java:54)
    at org.gradle.internal.snapshot.impl.NullValueSnapshot.snapshot(NullValueSnapshot.java:37)
    at org.gradle.internal.snapshot.impl.DefaultValueSnapshotter.snapshot(DefaultValueSnapshotter.java:59)
    at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.lambda$fingerprintInputProperties$2(CaptureStateBeforeExecutionStep.java:175)
szpak commented 4 years ago

Enabling Junit5 test plugin with a help of junit5PluginVersion.set("0.12") seems not working (maybe I am doing something wrong)

How do you apply the GPP plugin? With plugins {} or buildscript {}? Is it consistent with that blog post? https://blog.solidsoft.pl/2020/02/27/pit-junit-5-and-gradle-with-just-one-extra-line-of-configuration/

ClassCastException: class java.io.File cannot be cast to class java.lang.String (java.io.File and java.lang.String are in module java.base of loader 'bootstrap')**

It seems to be https://github.com/gradle/gradle/issues/10690 I remember I had a discussion about that with some proposed workaround, but I don't remember where :-/. Please create a separate bug to do not forget about that.

Demonian commented 4 years ago

@szpak I am using plugins to apply GPP, BTW as far as I can see pitestVersion override is also not making any affect. Maybe something is wrong with phase in which they are evaluated, so the values that are passed by user in extension are not yet evaluated?

szpak commented 4 years ago

It works in the acceptance tests and some people confirmed it works for them: https://github.com/szpak/gradle-pitest-plugin/blob/master/src/funcTest/resources/testProjects/junit5simple/build.gradle

  1. Please paste the plugin section.
  2. Run the pitest task with --info. There should be displayed information that junit5 plugin is applied.
szpak commented 4 years ago

And what is the command line in PIT execution with (near exec in the log).

szpak commented 4 years ago

Have you been able to check the logs? I plan to make a new release soon, it the (potential) fix could be put there.

Demonian commented 4 years ago

@szpak I have tried to do this on the clean project and everything was working as expected. I think that the problem is that in our project we have the main gradle plugin from which all other plugins are installed, but I am still trying to figure out the root cause.

szpak commented 4 years ago

Thanks for your update. In a case you find anything that could be improved in my plugin please let me know.

szpak commented 4 years ago

@Demonian Maybe you are able to write an inline plugin in build.gradle which applies my plugin to reproduce the problem in some code that you can easily share?

szpak commented 4 years ago

Closing due to inactivity. Feel free to reopen with failing configuration provided.