How to pass args to JVM which runs tests with Gradle - java

I am a Gradle rookie and I am not sure whether Gradle will start the new JVM when it runs the test set.
Like Passing JVM arguments to Gradle test task I want to pass some parameters to the JVM running the test set.
I added the following lines to build.gradle:
...
test {
groovy {
jvmArgs '-agentpath:/usr/lib/code_dependency_capturer.so' // add line
srcDirs = ['src/test']
if (!JavaVersion.current().isJava8Compatible()) {
exclude '**/v8/*'
exclude '**/vm8/*'
}
}
resources {
srcDirs = ['src/test-resources']
}
}
...
But it tells me:
A problem occurred evaluating root project 'groovy'.
Could not find method jvmArgs() for arguments[-agentpath:/usr/lib/code_dependency_capturer.so] on source set 'test' of type org.gradle.api.internal.tasks.DefaultSourceSet.
I googled this error but failed to solve it.

Try setting the jvmArgs of the enclosing test task rather than trying to set them on groovy.
The error you are getting suggests that jvmArgs isn’t present on groovy.
Example:
...
test {
jvmArgs '-agentpath:/usr/lib/code_dependency_capturer.so' // add line
groovy {
srcDirs = ['src/test']
...
}
...
}
This is just a guess as I don’t have a gradle setup handy on which to confirm but worth a try as jvmArgs is documented as a property for test:
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html#org.gradle.api.tasks.testing.Test:jvmArgs
List<String> jvmArgs
The extra arguments to use to launch the JVM for the process. Does not include system properties and the minimum/maximum heap size.
Since jvmArgs is a list of String you can pass it multiple arguments, refer to:
http://docs.groovy-lang.org/next/html/documentation/working-with-collections.html#_list_literals
Example:
jvmArgs ["-Xarg1", "-Xarg2"]
For "-Dprop=value" system properties use the systemProperties of the test task instead:
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html#org.gradle.api.tasks.testing.Test:systemProperties

Related

Gradle: compile and run a single test

I have a separate task to run the test that generates open-api.yml specification for my application. Here is the Gradle configuration below:
task generateOpenApiYml(type: Test) {
group = 'verification'
useJUnitPlatform {
includeTags 'openApi'
}
testLogging {
showExceptions true
showStandardStreams = false
showCauses true
showStackTraces true
exceptionFormat "full"
events("skipped", "failed", "passed")
}
}
So, I have one test with openApi JUnit tag. It works very well, but there is a slight thing I want to approve.
The whole idea of this test is that the result open-api.yml file is used to generate Java client to invoke REST endpoints. This client is used in other tests in the project.
I want to put those generated Java classes to .gitgnore because they are generated anyway and there is no need to index those files. The problem is that the generateOpenApiYml task compiles all the tests in src/test/java directory. Therefore, some of them use generated classes. Which leads to compiling errors.
Is it possible to tune the generateOpenApiYml task to make it compile and run only the single test with openApi JUnit tag? Then I could easily put generated Java classes to .gitignore and don't bother about their temporary absence, because other tests won't be compiled.
I figured out the solution. Firstly, I installed the gradle-testsets-plugin.
Then I configured a separate source set like this:
testSets {
generateOpenApiYml
}
So, generateOpenApiYml is the new Gradle task that looks for sources in src/generatedOpenApiYml/java directory.
Afterwards, we need to tune all tasks of test type to bind them with JUnit 5 platform.
tasks.withType(Test) {
group = 'verification'
useJUnitPlatform()
testLogging {
showExceptions true
showStandardStreams = false
showCauses true
showStackTraces true
exceptionFormat "full"
events("skipped", "failed", "passed")
}
}
generateOpenApiYml.outputs.upToDateWhen { false }
I put the upToDateWhen option for convenience to make sure the generateOpenApiYml task is always run on demand and never cached.
Then I have the open-api-generator.
openApiGenerate {
inputSpec = "$buildDir/classes/java/generateOpenApiYml/open-api.json".toString()
outputDir = "$buildDir/generated/openapi".toString()
apiPackage = "..."
invokerPackage = "..."
modelPackage = "..."
configOptions = [
dateLibrary : "java8",
openApiNullable: "false",
]
generatorName = 'java'
groupId = "..."
globalProperties = [
modelDocs: "false"
]
additionalProperties = [
hideGenerationTimestamp: true
]
}
tasks.named('openApiGenerate') {
dependsOn generateOpenApiYml
}
Finally, I just need to run two commands to build and run tests for my whole project.
./gradlew openApiGenerate
./gradlew build
The first one creates the open-api.yml file and generates Java client according to the provided specification. The second one runs tests and build the project normally. The tests running during the build phase uses classes generated by openApiGenerate task. Therefore, I can put them to .gitignore safely.
Hope this will be helpful.

gradle javaexec error "'apiElements' directly is not allowed"- Gradle 5.4.1

I am new to Gradle and trying to migrate an existing system build from ant to Gradle.
As part of this I need to run a java program on every file in a directory. Directory contains xml files and the java code will parse and convert .xml to .java files (and these Java files would be build to generate class and package in final jar) after performing some business specific transformation.
below is a function I wrote in Gradle
private runJavaFile(String dirPath) {
FileTree tree = fileTree(dir: dirPath, include: '**/*.xml')
tree.each {
def xmlfile = it.path
def javaFile = it.path.replaceFirst(".xml", ".java")
javaexec { //// getting error on this line
classpath configurations.all
main = 'XmlToJavaParser'
args = ["$xmlfile", "$javaFile", 'Java']
}
}
}
I am calling this function from a Gradle task by passing the dir path which contains the xml files to be parsed.
While running the task, I am getting below error:
> Resolving configuration 'apiElements' directly is not allowed
Any help would be appreciated.
Let me know if any more information is needed.
In Gradle, a configuration represents a group of artifacts and their dependencies. You typically have several configurations depending on what you want to do. For instance, you could have one where you declare which dependencies are needed for compilation, which are only needed at runtime, or which are needed for running a particular Java application.
In your case, you are saying that the classpath to the XmlToJavaParser class is "all configurations combined" and that doesn't really make sense. You are also not allowed to do that as some configurations from the Java plugin are not resolvable like this, which is why you get an error.
So to fix it, you should declare your own configuration for XmlToJavaParser. You can then declare dependencies for it like you normally do. Example (using the Groovy DSL):
configurations {
xmlJavaParser {
canBeResolved = true
canBeConsumed = false
}
}
dependencies {
xmlJavaParser "org.example:xml-java-parser:1.0" // or whatever you need
}
private runJavaFile(String dirPath) {
// ...
javaexec {
classpath = configurations.xmlJavaParser // The configuration is referenced here
main = 'XmlToJavaParser'
args = ["$xmlfile", "$javaFile", 'Java']
}
}
There are also other ways to go about it. But the main point is to not use configurations.all as a classpath.

How to use BuildConfig.DEBUG as task variable in build.gradle on Android Studio 4.0?

I have a custom task that required to check if the current build is debug or release, and then use the corresponding classpath.
The normal task definition:
task custom_java_task(type: JavaExec) {
classpath "build/intermediates/javac/debug/classes/"
main = "com.testapp.JavaTaskTest"
args "test", "${projectDir}"
}
The task definition needs to check BuildConfig.DEBUG and set the different value for classpath:
task custom_java_task(type: JavaExec) {
classpath BuildConfig.DEBUG ? "build/intermediates/javac/debug/classes/" : "build/intermediates/javac/release/classes/"
main = "com.testapp.JavaTaskTest"
args "test", "${projectDir}"
}
The build will fail with the following error:
Could not get unknown property 'BuildConfig' for task ':app:custom_java_task' of type org.gradle.api.tasks.JavaExec.
Thanks.
BuildConfig is generated set of properties that cannot be used from within gradle scripts. It is actually generated based on your build.gradle
But there are some ways to achieve what you want for example like this:
First in project level build.gradle under buildscript you can define the function / method and name ti however you want (eg. doStuff)
buildscript {
...
ext.doStuff = { buildType ->
// do stuff based on buildType param
}
...
}
Than in your module level build.gradle, simply do
android {
...
buildTypes {
debug {
...
doStuff("debug")
}
release {
...
doStuff("release")
}
}
...
}
Now this is just to give you a hint on the abilities of build.gradle files, you can build further from this.
Cheers

Excluding a a folder from test runs with TestNG and Gradle

I'm trying to exclude a 'quarantine' folder that I set up for Selenium tests that need to be updated and I do not wish to have run. I know that one solution is to set up and assign test groups for the tests in these classes but given the sheer size and volume of tests that will be in here, I'd rather do it using an Ant-style filter.
Here is a snippet of my build.gradle file:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'
repositories {
mavenCentral()
}
dependencies {
compile "org.seleniumhq.selenium:selenium-java:2.35.0"
compile "org.testng:testng:5.14.10"
testCompile('org.uncommons:reportng:1.1.2') {
exclude group: 'org.testng'
}
testCompile "junit:junit:4.8.2"
compile "com.jayway.restassured:rest-assured:1.8.1"
}
//initialize thread count variable for parallel testing and default to 1
def threadCount = System.getProperty("MAXTHREADS", "1")
tasks.withType(Test) {
maxParallelForks = 1
forkEvery = 1000
ignoreFailures = false
// Pass all system properties to the tests
systemProperties = System.getProperties()
// Makes the standard streams (err and out) visible at console when running tests
testLogging.showStandardStreams = true
exclude '**/tasks/'
exclude '**/disabled/'
classpath += configurations.testCompile
}
task firefox(type: Test) {
maxParallelForks = Integer.valueOf(threadCount) //default is 1 if not specified
testLogging.events "started"
testLogging {
events "started", "passed", "skipped", "failed", "standardOut", "standardError"
exceptionFormat "full" // default is "short"
}
useTestNG() {
excludeGroups 'chrome'
useDefaultListeners = false
listeners << 'org.uncommons.reportng.HTMLReporter'
listeners << 'org.uncommons.reportng.JUnitXMLReporter'
listeners << 'com.xmatters.testng.Listener'
}
testResultsDir = file("${buildDir}/test-results/firefox")
testReportDir = file("${reporting.baseDir}/firefox")
systemProperties.BROWSER = System.getProperty('BROWSER', 'firefox')
exclude '**/selenium/'
exclude '**/setupscripts/'
}
task chrome(type: Test) {
maxParallelForks = Integer.valueOf(threadCount) //default is 1 if not specified
testLogging.events "started"
useTestNG() {
useDefaultListeners = false;
listeners << 'org.uncommons.reportng.HTMLReporter'
listeners << 'org.uncommons.reportng.JUnitXMLReporter'
listeners << 'com.xmatters.testng.Listener'
}
testResultsDir = file("${buildDir}/test-results/chrome")
testReportDir = file("${reporting.baseDir}/chrome")
systemProperties.BROWSER = System.getProperty('BROWSER', 'chrome')
exclude '**/selenium/'
exclude '**/setupscripts/'
}
On line 34 you can see exclude '**/disabled/' that I added. This folder is a couple levels up from the root folder. The preceding like with exclude '**/tasks/' was already in the build file and seems to work fine with a similar directory structure.
When I run the build, tests in the /disabled/ folder are still getting run. Is there something I'm doing wrong here? I'm assuming that with that syntax, a directory named 'exclude' a couple levels up would be ignored by scanForTestClasses which is true by default. Any idea what is up here?
One other thing I've noticed in Gradle test report is that the package name listed in the report is default-packagefor the excluded tests that are not 'excluding' whereas the other tests that are meant to be run are listing the correct package names. The package names in the Java files match their folder structure correctly so I'm not sure why this is being reported this way. I've checked for duplicates, typos, etc, and am not getting anywhere.
If anyone could shed some light on this that would be great as having these incomplete / broken test classes running is causing failures that should be ignored until these tests are updated.
These test are being run using the Gradle wrapper generated bash script on our test CI (Jenkins) box running on Linux.
Looks like the exclude pattern is applied to the relative path of the files (i.e. relative to your root folder), which explains why it works for folders under your root folder.
Using an excludeSpec (see Gradle Test task DSL) should work fine:
exclude { it.file.canonicalPath.contains('/disabled/')}
Of course, pay attention to / vs \ according to your OS.

How to execute a main class in a jar from gradle using the 'java' command

I have these files under the <project_root> folder:
./build.gradle
./build/libs/vh-1.0-SNAPSHOT.jar
./libs/groovy-all-2.1.7.jar
./src/main/groovy/vh/Main.groovy
In the build.gradle file, I have this task:
task vh( type:Exec ) {
commandLine 'java -cp libs/groovy-all-2.1.7.jar:build/libs/' +
project.name + '-' + version + '.jar vh.Main'
}
The Main.groovy file is simple:
package vh
class Main {
static void main( String[] args ) {
println 'Hello, World!'
}
}
After plugging in the string values, the command line is:
java -cp libs/groovy-all-2.1.7.jar:build/libs/vh-1.0-SNAPSHOT.jar vh.Main
If I run the command directly from shell, I get correct output. However, if I run gradle vh, it will fail. So, how do I make it work? Thank you very much.
Exec.commandLine expects a list of values: one value for the executable, and another value for each argument. To execute Java code, it's better to use the JavaExec task:
task vh(type: JavaExec) {
main = "vh.Main"
classpath = files("libs/groovy-all-2.1.7.jar", "build/libs/${project.name}-${version}.jar")
}
Typically, you wouldn't have to hardcode the class path like that. For example, if you are using the groovy plugin, and groovy-all is already declared as a compile dependency (and knowing that the second Jar is created from the main sources), you would rather do:
classpath = sourceSets.main.runtimeClasspath
To find out more about the Exec and JavaExec task types, consult the Gradle Build Language Reference.

Categories