Gradle, Test task and '-XstartOnFirstThread'

Hi,

I am trying to run my JUnit test for SWT components in my project on a Mac. They require the jvm parameter ‘-XstartOnFirstThread’. I am using jvmArgs as it described here: http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.testing.Test.html But JUnit fails the same way as it does when ‘-XstartOnFirstThread’ is not passed (“Display must be created on main thread…” error). When I run the same JUnit test from Eclipse/Idea with that parameter everything works fine.

Am I missing something with Gradle?

1 Like

I’m not familiar with that JVM argument, but you should be able to verify in the info (or at least debug) log that it’s being passed correctly. Have you checked if the same JRE is used when running the test from Gradle and Eclipse? Gradle will typically use the one shown in ‘gradle -v’.

Yes, I do have only one JDK on my Mac. This JDK is being used in IDEA when I run those test:

[]$ gradle -v

------------------------------------------------------------ Gradle 1.5 ------------------------------------------------------------

Gradle build time: Wednesday, March 27, 2013 1:51:06 o’clock PM UTC Groovy: 1.8.6 Ant: Apache Ant™ version 1.8.4 compiled on May 22 2012 Ivy: 2.2.0 JVM: 1.7.0_09 (Oracle Corporation 23.5-b02) OS: Mac OS X 10.7.5 x86_64

[]$ java -version java version “1.7.0_09” Java™ SE Runtime Environment (build 1.7.0_09-b05) Java HotSpot™ 64-Bit Server VM (build 23.5-b02, mixed mode)

Hi Peter,

Thank you for your reply. I have looked into the output from IDEA and from Gradle using --debug option. I have found that IDEA and Gradle use different approach to run JUnit Test:

  1. IDEA does (in my case): “java -ea -XstartOnFirstThread -Didea.launcher.port=7532 “-Didea.launcher.bin.path=/Applications/IntelliJ IDEA 12 CE.app/bin” -Dfile.encoding=UTF-8 -classpath “[skipped long classpath]” com.intellij.rt.execution.application.AppMaincom.intellij.rt.execution.junit.JUnitStarter -ideVersion5 [your test is here]”. Inside the JUnitStarter it creates a command String and runs it using Runtime.exec().

  2. Gradle does: “10:13:53.776 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process ‘Gradle Worker 1’. Working directory: [skipped]/java -Djava.security.manager=jarjar.org.gradle.process.internal.child.BootstrapSecurityManager -XstartOnFirstThread -Dfile.encoding=UTF-8 -ea -cp [skipped]/gradle-worker.jar jarjar.org.gradle.process.internal.launcher.GradleWorkerMain”

10:13:54.405 [QUIET] [system.out] 10:13:54.405 [DEBUG] [org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor] Executing test class [your test is here]

Inside that it uses JUnitTestClassExecuter which acquires the JUnit Runner and runs it. This makes my parameter ‘-XstartOnFirstThead’ completely meaningful I guess.

So, as far as I understood this issue without deep knowledge of Gradle architecture, my only option is to use the ant.junit task. This actually works for me:

mkdir(project.projectDir.path + '/build/tests')
            ant.junit(showoutput: true, fork: true, forkmode: "once", clonevm: true, haltonerror: true, haltonfailure: true) {
                jvmarg(value: '-XstartOnFirstThread')
                  batchtest(toDir: project.projectDir.path + '/build/tests') {
                    fileset (dir: project.sourceSets.test.output.classesDir) {
                        include(name: '**/*Test.class')
                    }
                }
                  classpath(location: project.sourceSets.main.output.classesDir)
                classpath(location: project.sourceSets.test.output.classesDir)
                classpath(path: project.sourceSets.test.compileClasspath.asPath)
                formatter(type:

Inside that it uses JUnitTestClassExecuter which acquires the JUnit Runner and runs it. This makes my parameter ‘-XstartOnFirstThead’ completely meaningful I guess.

You mean “meaningless”? Why? It’s a JVM parameter, and the log indicates that it’s set when starting the test JVM.

Hey Peter,

We are running into a similar issue on a test task for one of our open-source projects. The parameter is necessary for SWT to run on OSX: http://www.eclipse.org/swt/macosx/. It seems like the parameter is being passed to the JVM, but for some reason it is not working.

Here is our project: https://github.com/ReadyTalk/swt-bling/ Here is the issue: https://github.com/ReadyTalk/swt-bling/issues/4

You should be able to check out the project and reproduce the issue on OSX by running the ‘integTest’ task:

task integTest(type: Test, group: 'Verification') {
      doFirst {
        if(platform == "darwin") {
          jvmArgs '-XstartOnFirstThread'
        }
        if(proj.files(sourceSets.integTest.getAllSource()).isEmpty()) {
          logger.lifecycle("${proj.name} does not contain any integration tests")
        }
      }
        reports {
        html.destination = "${proj.testReportDir}/integTest"
        junitXml.destination = "${proj.testResultsDir}/integTest"
      }
      classpath = sourceSets.integTest.runtimeClasspath
      testClassesDir = sourceSets.integTest.output.classesDir
        beforeTest { testName ->
        logger.info("Running test: ${testName}")
      }
    }

Here is the relevant part of the output you will get when running with ‘–info’:

Executing task ':integTest' (up-to-date check took 0.091 secs) due to:
  No history is available.
Starting process 'Gradle Worker 1'. Working directory: /Users/douglasborg/ReadyTalk/swt-bling Command: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java -Djava.security.manager=jarjar.org.gradle.process.internal.child.BootstrapSecurityManager -XstartOnFirstThread -Dfile.encoding=MacRoman -ea -cp /Users/douglasborg/.gradle/caches/1.8/workerMain/gradle-worker.jar jarjar.org.gradle.process.internal.launcher.GradleWorkerMain
An attempt to initialize for well behaving parent process finished.
Successfully started process 'Gradle Worker 1'
Gradle Worker 1 executing tests.
Running test: test testTextSetting(com.readytalk.swt.widgets.buttons.SquareButtonTest)
  com.readytalk.swt.widgets.buttons.SquareButtonTest > testTextSetting STANDARD_OUT
    ***WARNING: Display must be created on main thread due to Cocoa restrictions.
Gradle Worker 1 finished executing tests.
  com.readytalk.swt.widgets.buttons.SquareButtonTest > testTextSetting FAILED
    org.eclipse.swt.SWTException: Invalid thread access
        at org.eclipse.swt.SWT.error(Unknown Source)
        at org.eclipse.swt.SWT.error(Unknown Source)
        at org.eclipse.swt.SWT.error(Unknown Source)
        at org.eclipse.swt.widgets.Display.error(Unknown Source)
        at org.eclipse.swt.widgets.Display.createDisplay(Unknown Source)
        at org.eclipse.swt.widgets.Display.create(Unknown Source)
        at org.eclipse.swt.graphics.Device.<init>(Unknown Source)
        at org.eclipse.swt.widgets.Display.<init>(Unknown Source)
        at org.eclipse.swt.widgets.Display.<init>(Unknown Source)
        at com.readytalk.swt.widgets.buttons.SquareButtonTest.testTextSetting(SquareButtonTest.java:16)
Process 'Gradle Worker 1' finished with exit value 0 (state: SUCCEEDED)
  1 test completed, 1 failed

As you can see, the ‘-XstartOnFirstThread’ is getting passed to the test JVM. Any ideas on what could be going on? Let me know if you need any more info.

Cheers,

Doug

Not sure. Perhaps the problem is related to Gradle not running the tests in the main thread of the JVM?