/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.elasticsearch.gradle.FileContentsTask import org.elasticsearch.gradle.vagrant.BatsOverVagrantTask import org.elasticsearch.gradle.vagrant.VagrantCommandTask String testScripts = '*.bats' String testCommand = "cd \$TESTROOT && sudo bats --tap \$BATS/$testScripts" String smokeTestCommand = 'echo I work' // the images we allow testing with List availableBoxes = [ 'centos-6', 'centos-7', 'debian-8', 'fedora-24', 'oel-6', 'oel-7', 'opensuse-13', 'sles-12', 'ubuntu-1204', 'ubuntu-1404', 'ubuntu-1604' ] String vagrantBoxes = getProperties().get('vagrant.boxes', 'sample') List boxes = [] for (String box : vagrantBoxes.split(',')) { if (box == 'sample') { boxes.add('centos-7') boxes.add('ubuntu-1404') } else if (box == 'all') { boxes = availableBoxes break } else { if (availableBoxes.contains(box) == false) { throw new IllegalArgumentException("Unknown vagrant box '${box}'") } boxes.add(box) } } long seed String formattedSeed = null String[] upgradeFromVersions String upgradeFromVersion String maybeTestsSeed = System.getProperty("tests.seed", null); if (maybeTestsSeed != null) { List seeds = maybeTestsSeed.tokenize(':') if (seeds.size() != 0) { String masterSeed = seeds.get(0) seed = new BigInteger(masterSeed, 16).longValue() formattedSeed = maybeTestsSeed } } if (formattedSeed == null) { seed = new Random().nextLong() formattedSeed = String.format("%016X", seed) } String maybeUpdradeFromVersions = System.getProperty("tests.packaging.upgrade.from.versions", null) if (maybeUpdradeFromVersions != null) { upgradeFromVersions = maybeUpdradeFromVersions.split(",") } else { upgradeFromVersions = new File(project.projectDir, 'versions') } upgradeFromVersion = upgradeFromVersions[new Random(seed).nextInt(upgradeFromVersions.length)] configurations { test } repositories { mavenCentral() // Try maven central first, it'll have releases before 5.0.0 /* Setup a repository that tries to download from https://artifacts.elastic.co/downloads/elasticsearch/[module]-[revision].[ext] which should work for 5.0.0+. This isn't a real ivy repository but gradle is fine with that */ ivy { artifactPattern "https://artifacts.elastic.co/downloads/elasticsearch/[module]-[revision].[ext]" } } dependencies { test project(path: ':distribution:tar', configuration: 'archives') test project(path: ':distribution:rpm', configuration: 'archives') test project(path: ':distribution:deb', configuration: 'archives') // Collect all the plugins for (Project subproj : project.rootProject.subprojects) { if (subproj.path.startsWith(':plugins:')) { test project(path: "${subproj.path}", configuration: 'zip') } } // The version of elasticsearch that we upgrade *from* test "org.elasticsearch.distribution.deb:elasticsearch:$upgradeFromVersion@deb" test "org.elasticsearch.distribution.rpm:elasticsearch:$upgradeFromVersion@rpm" } task clean(type: Delete) { group 'Build' delete buildDir } task stop { group 'Verification' description 'Stop any tasks from tests that still may be running' } Set getVersions() { Node xml new URL('https://repo1.maven.org/maven2/org/elasticsearch/elasticsearch/maven-metadata.xml').openStream().withStream { s -> xml = new XmlParser().parse(s) } Set versions = new TreeSet<>(xml.versioning.versions.version.collect { it.text() }.findAll { it ==~ /[5]\.\d\.\d/ }) if (versions.isEmpty() == false) { return versions; } // If no version is found, we run the tests with the current version return Collections.singleton(project.version); } task updatePackagingTestUpgradeFromVersions { group 'Verification' description 'Update file containing options for the\n "starting" version in the "upgrade from" packaging tests.' doLast { Set versions = getVersions() new File(project.projectDir, 'versions').text = versions.join('\n') + '\n' } } task verifyPackagingTestUpgradeFromVersions { doLast { String maybeUpdateFromVersions = System.getProperty("tests.packaging.upgrade.from.versions", null) if (maybeUpdateFromVersions == null) { Set versions = getVersions() Set actualVersions = new TreeSet<>(Arrays.asList(upgradeFromVersions)) if (!versions.equals(actualVersions)) { throw new GradleException("out-of-date versions " + actualVersions + ", expected " + versions + "; run gradle updatePackagingTestUpgradeFromVersions") } } } } File testRoot = new File("$buildDir/testroot") task createTestRoot { dependsOn verifyPackagingTestUpgradeFromVersions outputs.dir testRoot doLast { testRoot.mkdirs() } } task createVersionFile(type: FileContentsTask) { dependsOn createTestRoot file "${testRoot}/version" contents = version } task createUpgradeFromFile(type: FileContentsTask) { dependsOn createTestRoot file "${testRoot}/upgrade_from_version" contents = upgradeFromVersion } task prepareTestRoot(type: Copy) { description 'Dump bats test dependencies into the $TESTROOT' into testRoot from configurations.test dependsOn createVersionFile, createUpgradeFromFile doFirst { gradle.addBuildListener new BuildAdapter() { @Override void buildFinished(BuildResult result) { if (result.failure) { println "Reproduce with: gradle packagingTest -Pvagrant.boxes=${vagrantBoxes} -Dtests.seed=${formattedSeed} -Dtests.packaging.upgrade.from.versions=${upgradeFromVersions.join(",")}" } } } } } task checkVagrantVersion(type: Exec) { commandLine 'vagrant', '--version' standardOutput = new ByteArrayOutputStream() doLast { String version = standardOutput.toString().trim() if ((version ==~ /Vagrant 1\.(8\.[6-9]|9\.[0-9])+/) == false) { throw new InvalidUserDataException("Illegal version of vagrant [${version}]. Need [Vagrant 1.8.6+]") } } } task checkVirtualBoxVersion(type: Exec) { commandLine 'vboxmanage', '--version' standardOutput = new ByteArrayOutputStream() doLast { String version = standardOutput.toString().trim() try { String[] versions = version.split('\\.') int major = Integer.parseInt(versions[0]) int minor = Integer.parseInt(versions[1]) if ((major < 5) || (major == 5 && minor < 1)) { throw new InvalidUserDataException("Illegal version of virtualbox [${version}]. Need [5.1+]") } } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { throw new InvalidUserDataException("Unable to parse version of virtualbox [${version}]. Required [5.1+]", e) } } } task vagrantSmokeTest { group 'Verification' description 'Smoke test the specified vagrant boxes' } task packagingTest { group 'Verification' description "Tests yum/apt packages using vagrant and bats.\n" + " Specify the vagrant boxes to test using the gradle property 'vagrant.boxes'.\n" + " 'sample' can be used to test a single yum and apt box. 'all' can be used to\n" + " test all available boxes. The available boxes are: \n" + " ${availableBoxes}" } // Each box gets it own set of tasks for (String box : availableBoxes) { String boxTask = box.capitalize().replace('-', '') // always add a halt task for all boxes, so clean makes sure they are all shutdown Task halt = tasks.create("vagrant${boxTask}#halt", VagrantCommandTask) { boxName box args 'halt', box } stop.dependsOn(halt) if (boxes.contains(box) == false) { // we only need a halt task if this box was not specified continue; } Task update = tasks.create("vagrant${boxTask}#update", VagrantCommandTask) { boxName box args 'box', 'update', box dependsOn checkVagrantVersion, checkVirtualBoxVersion } Task up = tasks.create("vagrant${boxTask}#up", VagrantCommandTask) { boxName box /* It's important that we try to reprovision the box even if it already exists. That way updates to the vagrant configuration take automatically. That isn't to say that the updates will always be compatible. Its ok to just destroy the boxes if they get busted but that is a manual step because its slow-ish. */ /* We lock the provider to virtualbox because the Vagrantfile specifies lots of boxes that only work properly in virtualbox. Virtualbox is vagrant's default but its possible to change that default and folks do. But the boxes that we use are unlikely to work properly with other virtualization providers. Thus the lock. */ args 'up', box, '--provision', '--provider', 'virtualbox' /* It'd be possible to check if the box is already up here and output SKIPPED but that would require running vagrant status which is slow! */ dependsOn update } Task smoke = tasks.create("vagrant${boxTask}#smoketest", Exec) { dependsOn up finalizedBy halt commandLine 'vagrant', 'ssh', box, '--command', "set -o pipefail && ${smokeTestCommand} | sed -ue 's/^/ ${box}: /'" } vagrantSmokeTest.dependsOn(smoke) Task packaging = tasks.create("packagingTest${boxTask}", BatsOverVagrantTask) { dependsOn up finalizedBy halt boxName box command testCommand dependsOn prepareTestRoot } packagingTest.dependsOn(packaging) }