Gradle: exclude specific directory from testRuntime classpath - gradle

One of the unit tests picks up a wrong resource file because there's another directory in the classpath where a file exists with the same name.
The unwelcome directory is part of 'rootProject.sourceSets.main.runtimeClasspath'. (there are many sub projects, with circular dependencies. Some of which these unit tests depend on hence the reason for using dependency this way)
How do I exclude such directory from testRuntime class path?

Here's something that worked.
Add 'runtimeClasspath -= ' entry in the build script.
sourceSets {
test {
java {
//...
}
resources {
//...
}
runtimeClasspath -= files("/dir/you/want/to/exclude")
}

Related

Using gradle to programmatically add resource folder to test compile/runtime classpath

We have a master build script for 60+ components. The individual components do not have build.gradle files. What I'm trying to do is programmatically (in the master build.gradle) add a resource folder to certain projects. This resource folder contains a file which must be in the classpath when unit tests are ran. I'm trying to add this in the subprojects block like this:
subprojects { proj ->
...
// this is the folder I need in the test task classpath
def resdir = sprintf("%s\\resources", project(':Common').projectDir)
sourceSets {
test {
java {
srcDir 'test'
}
resources {
srcDirs = [resdir]
}
}
}
}
...
if(proj.name == "APROJECT"){
proj.tasks['test'].getClasspath().each {
logger.info "COMPILE CLASSPATH: {}", it
}
}
}
However, if I query the classpath of the test task (see above) I do not see the folder in the classpath. Additionally, of course, the test is failing because the folder is not in the classpath.
If I put the sourceSet update in a build.gradle in the component folder, it works as expected.
Am I doing something wrong? How can I get this folder into the classpath for testing?
I wasn't able to get this to work by dynamically updating the sourceSet, however, I was able to get it to work by adding the necessary resource path to the testCompile dependency. See this for adding a class folder to a dependency.
Update: It's still not an ideal solution since the "solution" only adds the class folder to the compile path, it doesn't treat it as a resource (e.g., copy it to the runtime class folder).
Update #2: It's actually working as expected. It turns out that different tests were referencing slightly different resource paths. Adding all resource paths dynamically as noted above works fine!

Gradle: How to exclude an entire directory except one file?

I am trying to exclude all code in package foo.bar except for class MyClass for a certain Gradle subproject.
I tried to add this in build.gradle:
sourceSets {
main {
java {
exclude '**/foo/bar/**'
include '**/foo/bar/MyClass'
}
}
}
But it does not work.
The related question gradle: Exclude all - except one file also does not work, because I am not trying to exclude everything, but only the contents of a certain package.

Generate CLASSPATH from all multiproject gradle build dependencies

We're using an external testing tool (Squish) which runs after our main gradle build. This requires visibility of classes under test. Currently the CLASSPATH environment variable is built from various bash scripts and other string manipulation. I'm aiming to get gradle to do this automagically.
Since the build is done on a very slow source control system (clearcase) it is preferable for the tests to be run against the class files/JARs as left by the build rather than extra copies / compression into a single JAR etc.
The classpath needs to contain
Generated JAR files, typically in build/libs/project-x.jar
Test classes typically build/classes/test
Test resources typically build/resources/test
Any 3rd party jars any of the child projects depend upon, log4j, spring etc.
It's a complex multiproject build, but I've simplified to following example with parent and two children.
Parent settings.gradle
include ':child1'
include ':child2'
Parent build.gradle
allprojects {
apply plugin: 'java'
repositories {
mavenCentral()
}
}
Child 1 build.gradle
dependencies {
compile 'org.springframework:spring-context:4.1.2.RELEASE'
compile 'org.springframework:spring-beans:4.1.2.RELEASE'
}
Child 2 build.gradle
dependencies {
project (":child1")
}
What I've got so far. Is this the right approach? Can it be simplified or completely rewritten in a better way?
task createSquishClasspath << {
def paths = new LinkedHashSet()
paths.addAll(subprojects.configurations.compile.resolvedConfiguration.resolvedArtifacts.file.flatten())
paths.addAll(subprojects.jar.outputs.files.asPath)
paths.addAll(subprojects.sourceSets.test.output.resourcesDir)
paths.addAll(subprojects.sourceSets.test.output.classesDir)
paths.each {
println "${it}"
}
println paths.join(File.pathSeparator)
}
Output
C:\so-question\Parent\local-repo\spring\spring-context-4.1.2.RELEASE.jar
C:\so-question\Parent\local-repo\spring\spring-beans-4.1.2.RELEASE.jar
C:\so-question\Parent\child1\build\libs\child1.jar
C:\so-question\Parent\child2\build\libs\child2.jar
C:\so-question\Parent\child1\build\resources\test
C:\so-question\Parent\child2\build\resources\test
C:\so-question\Parent\child1\build\classes\test
C:\so-question\Parent\child2\build\classes\test
In summary the best answer so far is to join all the paths from the projects dependencies and all the test.output.resourcesDir and test.output.classesDir
task createSquishClasspath << {
def paths = new LinkedHashSet()
paths.addAll(subprojects.configurations.compile.resolvedConfiguration.resolvedArtifacts.file.flatten())
paths.addAll(subprojects.jar.outputs.files.asPath)
paths.addAll(subprojects.sourceSets.test.output.resourcesDir)
paths.addAll(subprojects.sourceSets.test.output.classesDir)
paths.each {
println "${it}"
}
println paths.join(File.pathSeparator)
}

Filter out resources from custom Test task in Gradle with goal of having one properties file for tests and a different one for production

So I have setup a way to just run integration tests using this configuration:
test {
exclude "**/*IntegrationTest*.class"
}
task integrationTest(type: Test, dependsOn: testClasses) {
include "**/*IntegrationTest*.class"
}
check.dependsOn integrationTest
Works great. But then for logging in my integration tests, I want to use a log4j.properties file from a specific directory instead of the one that is located in the src/main/resoures which is used for production.
I've tried this but didn't work:
integrationTest.classpath = files("$rootDir/test/src/main/resources/log4j.properties") + integrationTest.classpath
I also tried to just see if I could exclude the file, but could not find a way. Tried this:
processTestResources.exclude "**/*log4j.properties"
Any suggestions for including one properties file in production and another one for tests?
If you put the 'test' log4j.properties in the src/test/resources directory, it will actually come before anything in src/main/resources on the classpath of your tests/integration tests.
An alternative solution is to setup your bundling so that the log4j.properties for production is not in src/main/resources, but is added to the jar from a different directory...
jar {
from('production') {
include('log4j.properties')
}
}
If you want to keep the log4j.properties files in their current locations, you were almost there with what you tried. On the classpath you can have either jar files, or directories containing resources. So try doing this:
integrationTest.classpath = files("$rootDir/test/src/main/resources") + integrationTest.classpath
Seems like you could do something like this also so that the .jar task will include it later:
sourceSets {
main {
java {
srcDir 'src/main/java'
output.classesDir = 'build/classes/main'
}
resources {
srcDir 'src/main/resources'
include 'logback.xml'
output.resourcesDir = 'build/resources/main'
}
}
}

How to compile single class dependency in gradle outside the main project

I have a gradle project that contains only Selenium/TestNG test classes. They are executed against a deployed war application. All works fine and now I'm adding a java utility that will query the test base and print list of tests that belong to a given TestNG group. The utility should be compiled and executed separate from the main project, as users may want to query the test base before test execution.
I added the following to build.gradle:
task listgroups(dependsOn:'buildUtil' ) <<{
ant.java(classname: 'util.TestGroupScanner', fork: true,
classpath: "src/test/java")
}
task buildUtil {
compile {
source = "src/test/java/util"
}
}
However, when calling listgroups task, I'm getting the following error:
C:\console-bg1>g listgroups
FAILURE: Build failed with an exception.
(...)
* What went wrong:
A problem occurred evaluating root project 'console-bg1'.
> Could not find method compile() for arguments [build_4emu7duna2isgubc1k8uts8k9
8$_run_closure6_closure11#d210ab] on root project 'console-bg1'.
I'm not sure how to resolve this issue and needless to say, haven't found an answer online so far. Any pointers appreciated.
The problem is in the buildUtil task, as the error suggests. The buildUtil declares a compile closure, but such closure does not exist for the default task.
Let me try to clarify what your setup is. The util.TestGroupScanner source is in the src/test/java/util directory, which you want to compile separately from other source (presumably src/main/java and src/test/java). The buildUtil task is supposed to compile sources in src/test/java/util, and the listgroups task executes the scanner utility on sources src/test/java folder.
In this case, I'd suggest you declare a new source set for your utility sources, like this:
sourceSets {
util {
java {
srcDir 'src/test/java/util'
}
}
}
This will automatically create a compile task called compileUtilJava for you, that will compile those sources. I also think you'll want to include utility classes in the classpath when executing your tool, which can be retrieved by sourceSets.util.output.classesDir. So now your listgroups task will look like:
task listgroups(dependsOn: 'compileUtilJava' ) <<{
ant.java(classname: 'util.TestGroupScanner', fork: true,
classpath: "src/test/java:" + sourceSets.util.output.classesDir)
}
One thing I have noticed about your setup, is that src/test/java/util source folder is nested under src/test/java. Gradle will assume src/test/java to be the default folder for your project test, and will therefore automatically include it, and all of its children when running tests. Since you want to keep your utility folder separate from the default setup, I would recommend you put it in src/testutil/java, to avoid any clashes. If you do, don't forget to update the sourceSets setup above with the correct source path.
To solve this with gradle, I suggest to create a specific sourceset for your util class and add a task of type JavaExec that executes this class for printing your testng groups. Have a look at the following snippet:
apply plugin:'java'
...
...
configurations{
testUtilCompile.extendsFrom testCompile
}
...
...
sourceSets{
testUtil{
java {
srcDir "src/test/java"
include "util/**"
}
}
}
task printGroups(type:JavaExec){
main = "util.TestGroupScanner"
classpath = sourceSets.testUtil.runtimeClasspath
}
regards,
René

Resources