"failed to create temp file to extract class from jar into" while executing JUnit tests with Hudson (Gradle plugin)

I’m using Gradle 1.0-milestone-7-20111222000018+0100. As the stacktrace says, the problem occurs in org.gradle.api.internal.tasks.testing.detection.ClassFileExtractionManager.tempFile(ClassFileExtractionManager.java:141), because “The system cannot find the path specified”.

Unfortunately I have no idea which file the ClassFileExtractionManager tries to create. How is the ClassFileExtractionManager’s tempdir defined? Maybe the ClassFileExtractionManager could write which file it tries to create in case of an error?

  • Running the build with debug output doesn’t provide more infos to the problem. - The hudson user can access the default temp directory (we have tests of other builds creating Files using File.createTempFile(prefix,suffix) - I found no issue or other question related to my problem.

Thank you for your Help!

Stefan


Here is the stacktrace I see:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':easy-r-scripting-engine:testJUnit'.
 at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:71)
 at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:48)
 at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:34)
 at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter$1.run(CacheLockHandlingTaskExecuter.java:34)
 at org.gradle.cache.internal.DefaultCacheAccess$2.create(DefaultCacheAccess.java:200)
 at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:172)
 at org.gradle.cache.internal.DefaultCacheAccess.longRunningOperation(DefaultCacheAccess.java:198)
 at org.gradle.cache.internal.DefaultPersistentDirectoryStore.longRunningOperation(DefaultPersistentDirectoryStore.java:111)
 at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCacheAccess.longRunningOperation(DefaultTaskArtifactStateCacheAccess.java:83)
 at org.gradle.api.internal.changedetection.CacheLockHandlingTaskExecuter.execute(CacheLockHandlingTaskExecuter.java:32)
 at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:55)
 at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:57)
 at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:41)
 at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
 at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:52)
 at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:42)
 at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:243)
 at org.gradle.execution.DefaultTaskGraphExecuter.executeTask(DefaultTaskGraphExecuter.java:192)
 at org.gradle.execution.DefaultTaskGraphExecuter.doExecute(DefaultTaskGraphExecuter.java:177)
 at org.gradle.execution.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:83)
 at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:36)
 at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
 at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
 at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:67)
 at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExecuter$1.run(TaskCacheLockHandlingBuildExecuter.java:31)
 at org.gradle.cache.internal.DefaultCacheAccess$1.create(DefaultCacheAccess.java:111)
 at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:126)
 at org.gradle.cache.internal.DefaultCacheAccess.useCache(DefaultCacheAccess.java:109)
 at org.gradle.cache.internal.DefaultPersistentDirectoryStore.useCache(DefaultPersistentDirectoryStore.java:103)
 at org.gradle.api.internal.changedetection.DefaultTaskArtifactStateCacheAccess.useCache(DefaultTaskArtifactStateCacheAccess.java:79)
 at org.gradle.api.internal.changedetection.TaskCacheLockHandlingBuildExecuter.execute(TaskCacheLockHandlingBuildExecuter.java:29)
 at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
 at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
 at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:67)
 at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
 at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:61)
 at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:54)
 at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:152)
 at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:108)
 at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:76)
 at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:42)
 at org.gradle.launcher.cli.RunBuildAction.execute(RunBuildAction.java:28)
 at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:32)
 at org.gradle.launcher.exec.ExceptionReportingAction.execute(ExceptionReportingAction.java:21)
 at org.gradle.launcher.cli.CommandLineActionFactory$WithLoggingAction.execute(CommandLineActionFactory.java:238)
 at org.gradle.launcher.cli.CommandLineActionFactory$WithLoggingAction.execute(CommandLineActionFactory.java:222)
 at org.gradle.launcher.Main.doAction(Main.java:48)
 at org.gradle.launcher.exec.EntryPoint$1.execute(EntryPoint.java:53)
 at org.gradle.launcher.exec.EntryPoint$1.execute(EntryPoint.java:51)
 at org.gradle.launcher.exec.Execution.execute(Execution.java:28)
 at org.gradle.launcher.exec.EntryPoint.run(EntryPoint.java:39)
 at org.gradle.launcher.Main.main(Main.java:39)
 at org.gradle.launcher.ProcessBootstrap.runNoExit(ProcessBootstrap.java:51)
 at org.gradle.launcher.ProcessBootstrap.run(ProcessBootstrap.java:33)
 at org.gradle.launcher.GradleMain.main(GradleMain.java:24)
Caused by: org.gradle.api.GradleException: failed to create temp file to extract class from jar into
 at org.gradle.api.internal.tasks.testing.detection.ClassFileExtractionManager.tempFile(ClassFileExtractionManager.java:141)
 at org.gradle.api.internal.tasks.testing.detection.ClassFileExtractionManager.extractClassFile(ClassFileExtractionManager.java:91)
 at org.gradle.api.internal.tasks.testing.detection.ClassFileExtractionManager.getLibraryClassFile(ClassFileExtractionManager.java:79)
 at org.gradle.api.internal.tasks.testing.detection.AbstractTestFrameworkDetector.getSuperTestClassFile(AbstractTestFrameworkDetector.java:80)
 at org.gradle.api.internal.tasks.testing.junit.JUnitDetector.processTestClass(JUnitDetector.java:52)
 at org.gradle.api.internal.tasks.testing.detection.AbstractTestFrameworkDetector.processTestClass(AbstractTestFrameworkDetector.java:120)
 at org.gradle.api.internal.tasks.testing.detection.DefaultTestClassScanner$1.visitClassFile(DefaultTestClassScanner.java:58)
 at org.gradle.api.internal.tasks.testing.detection.DefaultTestClassScanner$ClassFileVisitor.visitFile(DefaultTestClassScanner.java:78)
 at org.gradle.api.internal.file.collections.DirectoryFileTree.walkDir(DirectoryFileTree.java:151)
 at org.gradle.api.internal.file.collections.DirectoryFileTree.walkDir(DirectoryFileTree.java:166)
 at org.gradle.api.internal.file.collections.DirectoryFileTree.walkDir(DirectoryFileTree.java:166)
 at org.gradle.api.internal.file.collections.DirectoryFileTree.walkDir(DirectoryFileTree.java:166)
 at org.gradle.api.internal.file.collections.DirectoryFileTree.walkDir(DirectoryFileTree.java:166)
 at org.gradle.api.internal.file.collections.DirectoryFileTree.visit(DirectoryFileTree.java:119)
 at org.gradle.api.internal.file.collections.FileTreeAdapter.visit(FileTreeAdapter.java:96)
 at org.gradle.api.internal.file.CompositeFileTree.visit(CompositeFileTree.java:54)
 at org.gradle.api.internal.tasks.testing.detection.DefaultTestClassScanner.detectionScan(DefaultTestClassScanner.java:56)
 at org.gradle.api.internal.tasks.testing.detection.DefaultTestClassScanner.run(DefaultTestClassScanner.java:50)
 at org.gradle.api.internal.tasks.testing.processors.TestMainAction.run(TestMainAction.java:43)
 at org.gradle.api.internal.tasks.testing.detection.DefaultTestExecuter.execute(DefaultTestExecuter.java:75)
 at org.gradle.api.tasks.testing.Test.executeTests(Test.java:367)
 at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:158)
 at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:93)
 at org.gradle.api.tasks.testing.Test_Decorated.invokeMethod(Unknown Source)
 at org.gradle.util.ReflectionUtil.invoke(ReflectionUtil.groovy:23)
 at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$2.execute(AnnotationProcessingTaskFactory.java:129)
 at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$2.execute(AnnotationProcessingTaskFactory.java:127)
 at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:63)
 ... 54 more
Caused by: java.io.IOException: The system cannot find the path specified
 at org.gradle.api.internal.tasks.testing.detection.ClassFileExtractionManager.tempFile(ClassFileExtractionManager.java:137)
 ... 81 more

By using ProcessMonitor I found out that gradle tries to create a file in ./build/tmp/testJUnit. The directory testJUnit doesn’t exist.

This seems to happen because I run the build by invoking ‘gradle clean test’.When running the two tasks seperately, the build works. Is it possible that I’m using useJUnit() wrong in the following part? Or is it a Bug?

task testJUnit(type: Test, description: 'Runs JUnit tests in addition to TestNG tests') {
    dependsOn testClasses
    useJUnit()//<-------
    allJvmArgs = ["-Xmx1024M", "-XX:MaxPermSize=128M"]
    testReportDir = new File(test.testReportDir.path + '-junit')
    excludes << '**/*TestPart.class'
    excludes << '**/*_internal.class'
}

Anyway, I’ll invoke the two tasks (clean and test) separately which should solve my problem for the moment.

Does it work if you omit the useJUnit()?

Yes, it works if I omit useJUnit(). Shouldn’t it be used?

You can omit useJUnit() because JUnit is the default and Gradle doesn’t currently offer any JUnit-specific configuration options. But of course it should nevertheless work, so it is a bug.

Thank you for your answer Peter! Then I’ll omit useJUnit().

Let me add onto this, so that it can be filed as a real bug. (Please create a JIRA for it.)

useJUnit() is run during the configure phase, calling the JUnitTestFramework constructor. This passes testTask.getTemporaryDir() to ClassFileExtractionManager, which is why ClassFileExtractionManager is in the stack. The crux of the problem is that I’m running the clean task in the execution phase, which deletes the testTask.getTemporaryDir(). So that when it’s later used by ClassFileExtractionManager, it’s no longer there. TestNGTestFramework does the exact same thing, so I’d guess that this would break too.

This means if you run clean before test and use useJUnit(), the build will not work. Calling clean before running tests seems like a pretty common pattern.

The fix is to call dir.mkdirs(); somewhere. It could easily be pushed down to ClassFileExtractionManager.tempFile() which is plenty logical and is an easy fix. The alternative is create some “ProvidesTempDir” interface with a single method call .getTemporaryDir() which will call .mkdirs() when ever it’s called. This would mean that testTask would be passed to ClassFileExtractionManager instead of testTask.getTemporaryDir(). This would offer a more general solution to directories disappearing during the lifecycle.

Create a bug and I might be able to fix it myself.

Done, GRADLE-2313. Thanks.

Any opinions on which fix I should submit?

See the description on the issue ticket.

It’s great that this got accepted, but it’s marked for 1.1-rc1, which I don’t expect for some time. Why didn’t it make it into 1.0?

N.B. Systems like buildhive only let you run a single run of gradle, and without this fix, I can’t run clean as a task at the same time as test. Essentially, until this is fixed all gradle projects in buildhive can’t clean before they run. :frowning:

Most likely because 1.0 already had code freeze. 1.1-rc1 will be released four weeks after 1.0.