From 39fa1c4df08115c17c0b540c6b0d8dea691859fc Mon Sep 17 00:00:00 2001 From: Mark Vieira Date: Wed, 29 Jul 2020 10:45:11 -0700 Subject: [PATCH] Add compatibility testing for JDBC driver (#60409) This commit adds compatibility testing of our JDBC driver against different Elasticsearch versions. Although we are really testing the forwards compatibility nature of the JDBC driver we model the testing the same as we do existing BWC tests, that is, with the current branch fetching the earlier versions of the artifact that is to be tested. In this case, that's the JDBC driver itself. Because the tests include the JDBC driver jar on it's classpath we had to change the packaging of the driver jar in order to avoid jarhell and other conflicting dependency issues when using an old JDBC driver with later branches. For this we simply relocate all driver dependencies in the shadow jar under a "shadowed" package. This allows the JDBC driver to use the correct version of Elasticsearch libs classes, while the tests themselves use their versions. Since this required a change to the driver jar compatibility testing can only go back as far as that version which at the time of this commit is 7.8.1. --- buildSrc/build.gradle | 2 +- distribution/bwc/build.gradle | 5 + gradle/bwc-test.gradle | 2 +- x-pack/plugin/sql/jdbc/build.gradle | 11 +- x-pack/plugin/sql/qa/jdbc/build.gradle | 128 ++++++++++++------ .../sql/qa/jdbc/multi-node/build.gradle | 8 +- x-pack/plugin/sql/qa/jdbc/no-sql/build.gradle | 6 +- .../plugin/sql/qa/jdbc/security/build.gradle | 82 +++++------ .../qa/jdbc/security/with-ssl/build.gradle | 2 +- .../qa/jdbc/security/without-ssl/build.gradle | 10 +- .../sql/qa/jdbc/single-node/build.gradle | 2 +- 11 files changed, 158 insertions(+), 100 deletions(-) diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 93d5c49bb85..144a927cc4f 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -98,7 +98,7 @@ dependencies { api 'com.netflix.nebula:gradle-info-plugin:7.1.3' api 'org.apache.rat:apache-rat:0.11' api "org.elasticsearch:jna:5.5.0" - api 'com.github.jengelman.gradle.plugins:shadow:5.1.0' + api 'com.github.jengelman.gradle.plugins:shadow:6.0.0' api 'de.thetaphi:forbiddenapis:3.0' api 'com.avast.gradle:gradle-docker-compose-plugin:0.12.1' api 'org.apache.maven:maven-model:3.6.2' diff --git a/distribution/bwc/build.gradle b/distribution/bwc/build.gradle index 52ff834963f..eb9ac6cfd3d 100644 --- a/distribution/bwc/build.gradle +++ b/distribution/bwc/build.gradle @@ -293,6 +293,11 @@ BuildParams.bwcVersions.forPreviousUnreleased { BwcVersions.UnreleasedVersionInf createBuildBwcTask(projectName, "${baseDir}/${projectName}", projectArtifact) } + // Create build tasks for the JDBC driver used for compatibility testing + String jdbcProjectDir = 'x-pack/plugin/sql/jdbc' + File jdbcProjectArtifact = file("${checkoutDir}/${jdbcProjectDir}/build/distributions/x-pack-sql-jdbc-${bwcVersion}-SNAPSHOT.jar") + createBuildBwcTask('jdbc', jdbcProjectDir, jdbcProjectArtifact) + createRunBwcGradleTask("resolveAllBwcDependencies") { args 'resolveAllDependencies' } diff --git a/gradle/bwc-test.gradle b/gradle/bwc-test.gradle index a6de8906ce3..1b546d52313 100644 --- a/gradle/bwc-test.gradle +++ b/gradle/bwc-test.gradle @@ -28,4 +28,4 @@ tasks.named("check").configure { dependsOn(bwcTestSnapshots) } -test.enabled = false +tasks.findByName("test")?.enabled = false diff --git a/x-pack/plugin/sql/jdbc/build.gradle b/x-pack/plugin/sql/jdbc/build.gradle index 3677cd7d5bd..19c1adf4ee4 100644 --- a/x-pack/plugin/sql/jdbc/build.gradle +++ b/x-pack/plugin/sql/jdbc/build.gradle @@ -35,10 +35,19 @@ tasks.named("dependencyLicenses").configure { } shadowJar { - relocate 'com.fasterxml', 'org.elasticsearch.fasterxml' + relocate 'com.fasterxml', 'shadow.fasterxml' + relocate('org.elasticsearch', 'shadow.org.elasticsearch') { + // Don't relocate the JDBC driver classes themselves as that's (mostly) public API + exclude 'org.elasticsearch.xpack.sql.jdbc.*' + } } thirdPartyAudit.ignoreMissingClasses( 'com.fasterxml.jackson.databind.ObjectMapper', 'com.fasterxml.jackson.databind.cfg.MapperBuilder' ) + +tasks.named("test").configure { + // reset the unit test classpath as using the shadow jar won't work due to relocated packages + classpath = sourceSets.test.runtimeClasspath +} diff --git a/x-pack/plugin/sql/qa/jdbc/build.gradle b/x-pack/plugin/sql/qa/jdbc/build.gradle index 9808d8ad536..3196126c092 100644 --- a/x-pack/plugin/sql/qa/jdbc/build.gradle +++ b/x-pack/plugin/sql/qa/jdbc/build.gradle @@ -1,61 +1,103 @@ +import org.elasticsearch.gradle.BwcVersions.UnreleasedVersionInfo +import org.elasticsearch.gradle.Version +import org.elasticsearch.gradle.VersionProperties +import org.elasticsearch.gradle.info.BuildParams +import org.elasticsearch.gradle.test.RestIntegTestTask + description = 'Integration tests for SQL JDBC driver' -apply plugin: 'elasticsearch.build' +apply plugin: 'elasticsearch.java' // Avoid circular dependency -group = "org.elasticsearch.x-pack.qa.sql.jdbc" +group = 'org.elasticsearch.x-pack.qa.sql.jdbc' dependencies { - api project(":test:framework") + api project(':test:framework') + implementation xpackProject('plugin:sql:sql-proto') - // JDBC testing dependencies - api project(path: xpackModule('sql:jdbc')) + // Actual tests will use the shadow jar + compileOnly(project(path: xpackModule('sql:jdbc'))) { + // Since dependencies will be relocated in the shadow jar, don't attempt to compile against them + transitive = false + } } -/* disable unit tests because these are all integration tests used - * other qa projects. */ +// disable unit tests because these are all integration tests used other qa projects test.enabled = false -tasks.named("dependencyLicenses").configure { it.enabled = false } -dependenciesInfo.enabled = false - -// the main files are actually test files, so use the appropriate forbidden api sigs -tasks.named('forbiddenApisMain').configure { - replaceSignatureFiles 'es-all-signatures', 'es-test-signatures' -} - -// just a test fixture: we aren't using this jars in releases and H2GIS requires disabling a lot of checks -thirdPartyAudit.enabled = false - subprojects { - if (subprojects.isEmpty()) { - // leaf project - apply plugin: 'elasticsearch.standalone-rest-test' - } else { - apply plugin: 'elasticsearch.build' + if (subprojects.isEmpty()) { + // leaf project + apply plugin: 'elasticsearch.standalone-rest-test' + apply from: "$rootDir/gradle/bwc-test.gradle" + } else { + apply plugin: 'elasticsearch.java' + } + + repositories { + maven { + // Repository for downloading BWC compatible JDBC driver releases + url = 'https://artifacts.elastic.co/maven' + } + } + + configurations { + jdbcDriver + } + + dependencies { + testImplementation(xpackProject('plugin:sql:qa:jdbc')) + + // We use the shadowjar for testing since that's the actual artifact we deliver to users + testCompileOnly project(path: xpackModule('sql:jdbc'), configuration: 'shadow') + jdbcDriver project(path: xpackModule('sql:jdbc'), configuration: 'shadow') + } + + if (project.name != 'security') { + // The security project just configures its subprojects + apply plugin: 'elasticsearch.testclusters' + apply plugin: 'elasticsearch.rest-test' + + testClusters.all { + testDistribution = 'DEFAULT' + setting 'xpack.ml.enabled', 'false' + setting 'xpack.watcher.enabled', 'false' } - dependencies { - /* Since we're a standalone rest test we actually get transitive - * dependencies but we don't really want them because they cause - * all kinds of trouble with the jar hell checks. So we suppress - * them explicitly for non-es projects. */ - testImplementation(xpackProject('plugin:sql:qa:jdbc')) { - transitive = false + integTest { + runner { + classpath += configurations.jdbcDriver + systemProperty 'jdbc.driver.version', VersionProperties.elasticsearch + } + } + + // Configure compatibility testing tasks + for (Version bwcVersion : BuildParams.bwcVersions.indexCompatible) { + // Compatibility testing for JDBC driver started with version 7.9.0 + if (bwcVersion.onOrAfter(Version.fromString("7.9.0"))) { + String baseName = "v${bwcVersion}" + UnreleasedVersionInfo unreleasedVersion = BuildParams.bwcVersions.unreleasedInfo(bwcVersion) + Configuration driverConfiguration = configurations.create("jdbcDriver${baseName}") + Object driverDependency = null + + if (unreleasedVersion) { + // For unreleased snapshot versions, build them from source + driverDependency = files(project(unreleasedVersion.gradleProjectPath).tasks.named('buildBwcJdbc')) + } else { + // For released versions, download it + driverDependency = "org.elasticsearch.plugin:x-pack-sql-jdbc:${bwcVersion}" } - testImplementation project(":test:framework") - testRuntimeOnly project(path: xpackModule('sql:jdbc')) - } - - if (project.name != 'security') { - // The security project just configures its subprojects - apply plugin: 'elasticsearch.testclusters' - apply plugin: 'elasticsearch.rest-test' - - testClusters.integTest { - testDistribution = 'DEFAULT' - setting 'xpack.ml.enabled', 'false' - setting 'xpack.watcher.enabled', 'false' + dependencies { + "jdbcDriver${baseName}"(driverDependency) } + + tasks.create(bwcTaskName(bwcVersion), RestIntegTestTask) { + runner { + classpath += driverConfiguration + systemProperty 'jdbc.driver.version', bwcVersion.toString() + } + } + } } + } } diff --git a/x-pack/plugin/sql/qa/jdbc/multi-node/build.gradle b/x-pack/plugin/sql/qa/jdbc/multi-node/build.gradle index 4929fdffaee..24d23b31f7c 100644 --- a/x-pack/plugin/sql/qa/jdbc/multi-node/build.gradle +++ b/x-pack/plugin/sql/qa/jdbc/multi-node/build.gradle @@ -1,7 +1,7 @@ description = 'Run SQL JDBC tests against multiple nodes' -testClusters.integTest { - numberOfNodes = 2 - setting 'xpack.security.enabled', 'false' - setting 'xpack.license.self_generated.type', 'trial' +testClusters.all { + numberOfNodes = 2 + setting 'xpack.security.enabled', 'false' + setting 'xpack.license.self_generated.type', 'trial' } diff --git a/x-pack/plugin/sql/qa/jdbc/no-sql/build.gradle b/x-pack/plugin/sql/qa/jdbc/no-sql/build.gradle index a8c24dc974f..08a706b85e1 100644 --- a/x-pack/plugin/sql/qa/jdbc/no-sql/build.gradle +++ b/x-pack/plugin/sql/qa/jdbc/no-sql/build.gradle @@ -1,4 +1,4 @@ -testClusters.integTest { - setting 'xpack.security.enabled', 'false' - setting 'xpack.license.self_generated.type', 'trial' +testClusters.all { + setting 'xpack.security.enabled', 'false' + setting 'xpack.license.self_generated.type', 'trial' } diff --git a/x-pack/plugin/sql/qa/jdbc/security/build.gradle b/x-pack/plugin/sql/qa/jdbc/security/build.gradle index 16230b2434d..ddd68872796 100644 --- a/x-pack/plugin/sql/qa/jdbc/security/build.gradle +++ b/x-pack/plugin/sql/qa/jdbc/security/build.gradle @@ -1,5 +1,7 @@ +import org.elasticsearch.gradle.testclusters.RestTestRunnerTask + dependencies { - testImplementation project(':x-pack:plugin:core') + testImplementation project(':x-pack:plugin:core') } Project mainProject = project @@ -7,55 +9,53 @@ Project mainProject = project configurations.create('testArtifacts') TaskProvider testJar = tasks.register("testJar", Jar) { - appendix 'test' - from sourceSets.test.output + appendix 'test' + from sourceSets.test.output } artifacts { - testArtifacts testJar + testArtifacts testJar } -// Tests are pushed down to subprojects and will be checked there. -testingConventions.enabled = false - subprojects { - // Use tests from the root security qa project in subprojects - configurations.create('testArtifacts') + // Use tests from the root security qa project in subprojects + configurations.create('testArtifacts') - dependencies { - testImplementation project(":x-pack:plugin:core") - testArtifacts project(path: mainProject.path, configuration: 'testArtifacts') - } + dependencies { + testImplementation project(":x-pack:plugin:core") + testArtifacts project(path: mainProject.path, configuration: 'testArtifacts') + } - testClusters.integTest { - testDistribution = 'DEFAULT' - // Setup auditing so we can use it in some tests - setting 'xpack.security.audit.enabled', 'true' - setting 'xpack.security.enabled', 'true' - setting 'xpack.license.self_generated.type', 'trial' - // Setup roles used by tests - extraConfigFile 'roles.yml', mainProject.file('roles.yml') - /* Setup the one admin user that we run the tests as. - * Tests use "run as" to get different users. */ - user username: "test_admin", password: "x-pack-test-password" - } + testClusters.all { + testDistribution = 'DEFAULT' + // Setup auditing so we can use it in some tests + setting 'xpack.security.audit.enabled', 'true' + setting 'xpack.security.enabled', 'true' + setting 'xpack.license.self_generated.type', 'trial' + // Setup roles used by tests + extraConfigFile 'roles.yml', mainProject.file('roles.yml') + /* Setup the one admin user that we run the tests as. + * Tests use "run as" to get different users. */ + user username: "test_admin", password: "x-pack-test-password" + } - File testArtifactsDir = project.file("$buildDir/testArtifacts") - TaskProvider copyTestClasses = tasks.register("copyTestClasses", Copy) { - dependsOn configurations.testArtifacts - from { zipTree(configurations.testArtifacts.singleFile) } - into testArtifactsDir - } + File testArtifactsDir = project.file("$buildDir/testArtifacts") + TaskProvider copyTestClasses = tasks.register("copyTestClasses", Copy) { + dependsOn configurations.testArtifacts + from { zipTree(configurations.testArtifacts.singleFile) } + into testArtifactsDir + } - integTest.runner { - dependsOn copyTestClasses - testClassesDirs += project.files(testArtifactsDir) - classpath += configurations.testArtifacts - nonInputProperties.systemProperty 'tests.audit.logfile', - "${-> testClusters.integTest.singleNode().getAuditLog()}" - nonInputProperties.systemProperty 'tests.audit.yesterday.logfile', - "${-> testClusters.integTest.singleNode().getAuditLog().getParentFile()}/integTest_audit-${new Date().format('yyyy-MM-dd')}.json" - } - testingConventions.enabled = false + tasks.withType(RestTestRunnerTask).configureEach { + dependsOn copyTestClasses + testClassesDirs += project.files(testArtifactsDir) + classpath += configurations.testArtifacts + nonInputProperties.systemProperty 'tests.audit.logfile', + "${-> testClusters.integTest.singleNode().getAuditLog()}" + nonInputProperties.systemProperty 'tests.audit.yesterday.logfile', + "${-> testClusters.integTest.singleNode().getAuditLog().getParentFile()}/integTest_audit-${new Date().format('yyyy-MM-dd')}.json" + } + + testingConventions.enabled = false } diff --git a/x-pack/plugin/sql/qa/jdbc/security/with-ssl/build.gradle b/x-pack/plugin/sql/qa/jdbc/security/with-ssl/build.gradle index bf584e78c31..aa349e4e3c6 100644 --- a/x-pack/plugin/sql/qa/jdbc/security/with-ssl/build.gradle +++ b/x-pack/plugin/sql/qa/jdbc/security/with-ssl/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'elasticsearch.test-with-ssl' -testClusters.integTest { +testClusters.all { // The setup that we actually want setting 'xpack.license.self_generated.type', 'trial' setting 'xpack.security.http.ssl.enabled', 'true' diff --git a/x-pack/plugin/sql/qa/jdbc/security/without-ssl/build.gradle b/x-pack/plugin/sql/qa/jdbc/security/without-ssl/build.gradle index 9639b809f46..a80b52bd77a 100644 --- a/x-pack/plugin/sql/qa/jdbc/security/without-ssl/build.gradle +++ b/x-pack/plugin/sql/qa/jdbc/security/without-ssl/build.gradle @@ -1,7 +1,9 @@ -integTest.runner { - systemProperty 'tests.ssl.enabled', 'false' +import org.elasticsearch.gradle.testclusters.RestTestRunnerTask + +tasks.withType(RestTestRunnerTask).configureEach { + systemProperty 'tests.ssl.enabled', 'false' } -testClusters.integTest { - setting 'xpack.license.self_generated.type', 'trial' +testClusters.all { + setting 'xpack.license.self_generated.type', 'trial' } diff --git a/x-pack/plugin/sql/qa/jdbc/single-node/build.gradle b/x-pack/plugin/sql/qa/jdbc/single-node/build.gradle index a8c24dc974f..4222575cd94 100644 --- a/x-pack/plugin/sql/qa/jdbc/single-node/build.gradle +++ b/x-pack/plugin/sql/qa/jdbc/single-node/build.gradle @@ -1,4 +1,4 @@ -testClusters.integTest { +testClusters.all { setting 'xpack.security.enabled', 'false' setting 'xpack.license.self_generated.type', 'trial' }