Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forcing Gradle to use an earlier dependency version for testing

Is there a way to construct a Gradle build file to force the test phase to use an earlier version of a dependency than the one used for compilation and and packaging?

I'm attempting to set up an HBase mini-cluster via HBaseTestingUtility to test my project; unfortunately, HBaseTestingUtility relies on an old version of Guava (14.0.1 seems to work), while the rest of my project uses 18.0. Here are excerpts of my build script, as-is (I'm also using the Gradle test-sets plugin by unbroken-dome to create two separate sets of tests):

plugins {
    id 'org.unbroken-dome.test-sets' version '1.2.0'
}

apply plugin: 'java'

ext.verGuava = '18.0'
ext.verGuavaTEST = '14.0.1'

testSets {
    testUnit { dirName = 'test/unit' }
    testIntegration { dirName = 'test/integration' }
}

configurations {
    provided
    provided {
        extendsFrom(compile)
    }
    testIntConf
    testIntConf {
        extendsFrom(provided)
        resolutionStrategy {
            force "com.google.guava:guava:${verGuavaTEST}"
            forcedModules = ["com.google.guava:guava:${verGuavaTEST}"]
        }
    }
}

sourceSets {
    main.compileClasspath += configurations.provided
    testUnit.compileClasspath += configurations.provided
    testUnit.runtimeClasspath += configurations.provided
    testIntegration.compileClasspath += configurations.testIntConf
    testIntegration.runtimeClasspath += configurations.testIntConf
}

dependencies {
    provided "org.apache.hbase:hbase-client:${verHBase}"
    provided "org.apache.hbase:hbase-common:${verHBase}"
    compile "org.testng:testng:${verTestNG}"
    testIntegrationCompile group:'org.apache.hadoop', name:'hadoop-common', version:"${verHadoop}", classifier: 'tests'
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-server', version:"${verHBase}"
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-server', version:"${verHBase}", classifier: 'tests'
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-hadoop-compat', version:"${verHBase}"
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-hadoop-compat', version:"${verHBase}", classifier: 'tests'
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-hadoop2-compat', version:"${verHBase}"
    testIntegrationCompile group:'org.apache.hbase', name:'hbase-hadoop2-compat', version:"${verHBase}", classifier: 'tests'
    testIntegrationCompile group:'org.apache.hadoop', name:'hadoop-hdfs', version:"${verHadoop}"
    testIntegrationCompile group:'org.apache.hadoop', name:'hadoop-hdfs', version:"${verHadoop}", classifier: 'tests'
}

testUnit {
    useTestNG()
    logger.info "@@@ Classpath (UNIT testing): ${classpath.getFiles().collect({it.toString()}).inject('\n') {acc, next -> acc + next + '\n'}}"
    logger.info "@@@ SystemProps (UNIT testing): ${System.getProperties().collect({it.toString()}).inject('\n') {acc, next -> acc + next + '\n'}}"
}

testIntegration {
    useTestNG()
    systemProperty "java.net.preferIPv4Stack", "true"
    logger.info "@@@ Classpath (INTEGRATION testing): ${classpath.getFiles().collect({it.toString()}).inject('\n') {acc, next -> acc + next + '\n'}}"
    logger.info "@@@ SysProps (INTEGRATION testing): ${System.getProperties().collect({it.toString()}).inject('\n') {acc, next -> acc + next + '\n'}}"
}

When I run a build via this script, I get the following output which seems to show that Guava 14.0.1 was added to the classpath for the testIntegration target, rather than replacing Guava 18.0:

@@@ Classpath (UNIT testing):
/home/user/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/18.0/cce0823396aa693798f8882e64213b1772032b09/guava-18.0.jar
@@@ Classpath (INTEGRATION testing):
/home/user/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/18.0/cce0823396aa693798f8882e64213b1772032b09/guava-18.0.jar
/home/user/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/14.0.1/69e12f4c6aeac392555f1ea86fab82b5e5e31ad4/guava-14.0.1.jar

This behavior is probably to be expected; the API indicates that ResolutionStrategy.force(...) appends artifacts to the list to be considered.

How can I direct Gradle to eliminate Guava 18.0 from the classpath for the testIntegration target entirely?

I have tried changing the sourceSets section to assign the classpaths using = rather than +=:

sourceSets {
    ...
    testIntegration.compileClasspath = configurations.testIntConf
    testIntegration.runtimeClasspath = configurations.testIntConf
}

This has the desired effect as far as eliminating Guava 18.0 (and retaining 14.0.1), but it seems to prevent Gradle from detecting the location of the testIntegration source files, for some reason, so the testIntegration tests are never compiled or executed.

I have also tried a few variations on purging Guava from the inherited configuration, such as the following:

configurations {
    provided
    provided {
        extendsFrom(compile)
    }
    testIntConf
    testIntConf {
        extendsFrom(provided.copy {
            exclude group:"com.google.guava", module:"guava"
        })
        resolutionStrategy {
            force "com.google.guava:guava:${verGuavaTEST}"
            forcedModules = ["com.google.guava:guava:${verGuavaTEST}"]
        }
    }
}

The above (and all other variations I've tried) do successfully eliminate the duplication of the Guava artifact in the classpath, but they seem to nullify the resolutionStrategy, as the resolved artifact is always the newer version (18.0) even in testIntegration.

like image 987
sumitsu Avatar asked Sep 09 '15 14:09

sumitsu


People also ask

How do you override a Gradle dependency?

To override the version of a transitive dependency in Gradle, exclude it from the declared dependency that pulls it in, and then explicitly declare the version that you prefer to use in your build.

How do you avoid transitive dependencies in Gradle?

When you specify a dependency in your build script, you can provide an exclude rule at the same time telling Gradle not to pull in the specified transitive dependency. For example, say we have a Gradle project that depends on Google's Guava library, or more specifically com.

Does Gradle dependencies order matter?

This isn't necessary. The order inside the dependencies { } block is preserved. You are kind of right. Dependency ordering is preserved, but for example all compile dependencies will be before testCompile dependencies no matter of how you order them.


1 Answers

I was facing the same problem but simpler version. cause I am not differentiate the integration test and unit test. using this seems give the right guava dependency for test

   configurations {
        all{
            resolutionStrategy {
                force 'com.fasterxml.jackson.core:jackson-databind:2.4.4'
            }
        }
        testCompile{
            resolutionStrategy {
                force 'com.google.guava:guava:14.0.1'
            }
        }
    }
dependencies {
 testCompile group: 'org.apache.hbase', name: 'hbase-testing-util', version: '1.2.4'
}
like image 193
Nan Avatar answered Sep 19 '22 12:09

Nan