diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterConfiguration.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterConfiguration.groovy index 6a2375efc62..3b34b45df0d 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterConfiguration.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterConfiguration.groovy @@ -47,6 +47,14 @@ class ClusterConfiguration { @Input int transportPort = 0 + /** An override of the data directory. This may only be used with a single node. */ + @Input + File dataDir = null + + /** Optional override of the cluster name. */ + @Input + String clusterName = null + @Input boolean daemonize = true @@ -59,13 +67,15 @@ class ClusterConfiguration { " " + System.getProperty('tests.jvm.argline', '') /** - * The seed nodes port file. In the case the cluster has more than one node we use a seed node - * to form the cluster. The file is null if there is no seed node yet available. + * A uri that should be used for the unicast host list. * - * Note: this can only be null if the cluster has only one node or if the first node is not yet - * configured. All nodes but the first node should see a non null value. + * This allows multi node clusters, or a new cluster to connect to an existing cluster. + * The type is Object to allow lazy evaluation. Typically this would be set with a + * closure in a GString like: + * + * {@code "${-> node.transportUri()}"} */ - File seedNodePortsFile + Object unicastTransportUri = null /** * A closure to call before the cluster is considered ready. The closure is passed the node info, @@ -137,12 +147,4 @@ class ClusterConfiguration { } extraConfigFiles.put(path, sourceFile) } - - /** Returns an address and port suitable for a uri to connect to this clusters seed node over transport protocol*/ - String seedNodeTransportUri() { - if (seedNodePortsFile != null) { - return seedNodePortsFile.readLines("UTF-8").get(0) - } - return null; - } } diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy index 8819c63080a..5acf7fde55d 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/ClusterFormationTasks.groovy @@ -48,7 +48,7 @@ class ClusterFormationTasks { * * Returns a NodeInfo object for the first node in the cluster. */ - static NodeInfo setup(Project project, Task task, ClusterConfiguration config) { + static List setup(Project project, Task task, ClusterConfiguration config) { if (task.getEnabled() == false) { // no need to add cluster formation tasks if the task won't run! return @@ -110,7 +110,7 @@ class ClusterFormationTasks { task.dependsOn(wait) // delay the resolution of the uri by wrapping in a closure, so it is not used until read for tests - return nodes[0] + return nodes } /** Adds a dependency on the given distribution */ diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/NodeInfo.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/NodeInfo.groovy index 5d9961a0425..e1834e26fb1 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/NodeInfo.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/NodeInfo.groovy @@ -57,6 +57,9 @@ class NodeInfo { /** config directory */ File confDir + /** data directory */ + File dataDir + /** THE config file */ File configFile @@ -95,11 +98,23 @@ class NodeInfo { this.config = config this.nodeNum = nodeNum this.sharedDir = sharedDir - clusterName = "${task.path.replace(':', '_').substring(1)}" + if (config.clusterName != null) { + clusterName = config.clusterName + } else { + clusterName = "${task.path.replace(':', '_').substring(1)}" + } baseDir = new File(project.buildDir, "cluster/${task.name} node${nodeNum}") pidFile = new File(baseDir, 'es.pid') homeDir = homeDir(baseDir, config.distribution, nodeVersion) confDir = confDir(baseDir, config.distribution, nodeVersion) + if (config.dataDir != null) { + if (config.numNodes != 1) { + throw new IllegalArgumentException("Cannot set data dir for integ test with more than one node") + } + dataDir = config.dataDir + } else { + dataDir = new File(homeDir, "data") + } configFile = new File(confDir, 'elasticsearch.yml') // even for rpm/deb, the logs are under home because we dont start with real services File logsDir = new File(homeDir, 'logs') @@ -140,7 +155,7 @@ class NodeInfo { } } env.put('ES_JVM_OPTIONS', new File(confDir, 'jvm.options')) - args.addAll("-E", "path.conf=${confDir}") + args.addAll("-E", "path.conf=${confDir}", "-E", "path.data=${dataDir}") if (Os.isFamily(Os.FAMILY_WINDOWS)) { args.add('"') // end the entire command, quoted } diff --git a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/RestIntegTestTask.groovy b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/RestIntegTestTask.groovy index c6463d28811..d50937408e7 100644 --- a/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/RestIntegTestTask.groovy +++ b/buildSrc/src/main/groovy/org/elasticsearch/gradle/test/RestIntegTestTask.groovy @@ -34,6 +34,9 @@ public class RestIntegTestTask extends RandomizedTestingTask { ClusterConfiguration clusterConfig + /** Info about nodes in the integ test cluster. Note this is *not* available until runtime. */ + List nodes + /** Flag indicating whether the rest tests in the rest spec should be run. */ @Input boolean includePackaged = false @@ -52,6 +55,12 @@ public class RestIntegTestTask extends RandomizedTestingTask { parallelism = '1' include('**/*IT.class') systemProperty('tests.rest.load_packaged', 'false') + systemProperty('tests.rest.cluster', "${-> nodes[0].httpUri()}") + systemProperty('tests.config.dir', "${-> nodes[0].confDir}") + // TODO: our "client" qa tests currently use the rest-test plugin. instead they should have their own plugin + // that sets up the test cluster and passes this transport uri instead of http uri. Until then, we pass + // both as separate sysprops + systemProperty('tests.cluster', "${-> nodes[0].transportUri()}") // copy the rest spec/tests into the test resources RestSpecHack.configureDependencies(project) @@ -61,13 +70,7 @@ public class RestIntegTestTask extends RandomizedTestingTask { // this must run after all projects have been configured, so we know any project // references can be accessed as a fully configured project.gradle.projectsEvaluated { - NodeInfo node = ClusterFormationTasks.setup(project, this, clusterConfig) - systemProperty('tests.rest.cluster', "${-> node.httpUri()}") - systemProperty('tests.config.dir', "${-> node.confDir}") - // TODO: our "client" qa tests currently use the rest-test plugin. instead they should have their own plugin - // that sets up the test cluster and passes this transport uri instead of http uri. Until then, we pass - // both as separate sysprops - systemProperty('tests.cluster', "${-> node.transportUri()}") + nodes = ClusterFormationTasks.setup(project, this, clusterConfig) } } @@ -88,6 +91,10 @@ public class RestIntegTestTask extends RandomizedTestingTask { return clusterConfig } + public List getNodes() { + return nodes + } + @Override public Task dependsOn(Object... dependencies) { super.dependsOn(dependencies) diff --git a/qa/rolling-upgrade/build.gradle b/qa/rolling-upgrade/build.gradle new file mode 100644 index 00000000000..d15a76daa92 --- /dev/null +++ b/qa/rolling-upgrade/build.gradle @@ -0,0 +1,36 @@ + +import org.elasticsearch.gradle.test.RestIntegTestTask + +task oldClusterTest(type: RestIntegTestTask) { + mustRunAfter(precommit) + cluster { + distribution = 'zip' + bwcVersion = '2.4.0' // TODO: either randomize, or make this settable with sysprop + numBwcNodes = 2 + numNodes = 0 + clusterName = 'rolling-upgrade' + } + systemProperty 'tests.rest.suite', 'old_cluster' +} + +task mixedClusterTest(type: RestIntegTestTask) { + dependsOn(oldClusterTest, 'oldClusterTest.node1 + cluster { + distribution = 'zip' + clusterName = 'rolling-upgrade' + } + systemProperty 'tests.rest.suite', 'mixed_cluster' +} + +task upgradedClusterTest(type: RestIntegTestTask) { + cluster { + distribution = 'zip' + clusterName = 'rolling-upgrade' + } + systemProperty 'tests.rest.suite', 'upgraded_cluster' +} + +task integTest { + dependsOn = [upgradedClusterTest] +} +check.dependsOn(integTest) diff --git a/settings.gradle b/settings.gradle index 904fb69469d..b2ddae925a3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -55,6 +55,7 @@ List projects = [ 'plugins:store-smb', 'qa:backwards-5.0', 'qa:evil-tests', + 'qa:rolling-upgrade', 'qa:smoke-test-client', 'qa:smoke-test-ingest-with-all-dependencies', 'qa:smoke-test-ingest-disabled',