| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF 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. |
| */ |
| |
| // |
| // Configure test randomization seeds and derived test properties. |
| // |
| |
| import java.nio.file.* |
| import com.carrotsearch.randomizedtesting.SeedUtils |
| import com.carrotsearch.randomizedtesting.generators.RandomPicks |
| |
| buildscript { |
| repositories { |
| mavenCentral() |
| } |
| |
| dependencies { |
| classpath 'com.carrotsearch.randomizedtesting:randomizedtesting-runner:2.7.2' |
| } |
| } |
| |
| def resources = scriptResources(buildscript) |
| |
| // Pick the "root" seed from which everything else is derived. |
| configure(rootProject) { |
| ext { |
| rootSeed = propertyOrDefault('tests.seed', String.format("%08X", new Random().nextLong())) |
| rootSeedUserProvided = (propertyOrDefault('tests.seed', null) != null) |
| rootSeedLong = SeedUtils.parseSeedChain(rootSeed)[0] |
| projectSeedLong = rootSeedLong ^ project.path.hashCode() |
| } |
| |
| task randomizationInfo() { |
| doFirst { |
| logger.lifecycle("Running tests with randomization seed: tests.seed=${rootSeed}") |
| } |
| } |
| } |
| |
| // Any test task will trigger display of randomization settings. |
| allprojects { |
| tasks.withType(Test) { task -> |
| task.dependsOn rootProject.randomizationInfo |
| } |
| } |
| |
| // Configure test property defaults and their descriptions. |
| allprojects { |
| plugins.withType(JavaPlugin) { |
| ext { |
| testOptions += [ |
| // seed, repetition and amplification. |
| [propName: 'tests.seed', value: { -> rootSeed }, description: "Sets the master randomization seed."], |
| [propName: 'tests.iters', value: null, description: "Duplicate (re-run) each test case N times."], |
| [propName: 'tests.multiplier', value: 1, description: "Value multiplier for randomized tests."], |
| [propName: 'tests.maxfailures', value: null, description: "Skip tests after a given number of failures."], |
| [propName: 'tests.timeoutSuite', value: null, description: "Timeout (in millis) for an entire suite."], |
| [propName: 'tests.failfast', value: "false", description: "Stop the build early on failure.", buildOnly: true], |
| // asserts, debug output. |
| [propName: 'tests.asserts', value: "true", description: "Enables or disables assertions mode."], |
| [propName: 'tests.infostream', value: false, description: "Enables or disables infostream logs."], |
| [propName: 'tests.leaveTemporary', value: false, description: "Leave temporary directories after tests complete."], |
| [propName: 'tests.useSecurityManager', value: true, description: "Control security manager in tests.", buildOnly: true], |
| // component randomization |
| [propName: 'tests.codec', value: "random", description: "Sets the codec tests should run with."], |
| [propName: 'tests.directory', value: "random", description: "Sets the Directory implementation tests should run with."], |
| [propName: 'tests.postingsformat', value: "random", description: "Sets the postings format tests should run with."], |
| [propName: 'tests.docvaluesformat', value: "random", description: "Sets the doc values format tests should run with."], |
| [propName: 'tests.locale', value: "random", description: "Sets the default locale tests should run with."], |
| [propName: 'tests.timezone', value: "random", description: "Sets the default time zone tests should run with."], |
| // filtering |
| [propName: 'tests.filter', value: null, description: "Applies a test filter (see :helpTests)."], |
| [propName: 'tests.slow', value: true, description: "Enables or disables @Slow tests."], |
| [propName: 'tests.nightly', value: false, description: "Enables or disables @Nightly tests."], |
| [propName: 'tests.weekly', value: false, description: "Enables or disables @Weekly tests."], |
| [propName: 'tests.monster', value: false, description: "Enables or disables @Monster tests."], |
| [propName: 'tests.awaitsfix', value: null, description: "Enables or disables @AwaitsFix tests."], |
| [propName: 'tests.badapples', value: null, description: "Enables or disables @BadApple tests."], |
| [propName: 'tests.file.encoding', |
| value: { -> |
| RandomPicks.randomFrom(new Random(projectSeedLong), ["US-ASCII", "ISO-8859-1", "UTF-8"]) |
| }, |
| description: "Sets the default file.encoding on test JVM.", buildOnly: true], |
| // test data |
| [propName: 'tests.linedocsfile', value: 'europarl.lines.txt.gz', description: "Test data file path."], |
| // miscellaneous; some of them very weird. |
| [propName: 'tests.LUCENE_VERSION', value: baseVersion, description: "Base Lucene version."], |
| [propName: 'tests.bwcdir', value: null, description: "Data for backward-compatibility indexes."], |
| ] |
| } |
| } |
| } |
| |
| // Add Solr-specific test configs settings. |
| configure(allprojects.findAll {project -> project.path.startsWith(":solr") }) { |
| plugins.withType(JavaPlugin) { |
| ext { |
| testOptions += [ |
| [propName: 'tests.luceneMatchVersion', value: baseVersion, description: "Base Lucene version."], |
| [propName: 'common-solr.dir', |
| value: { -> file("${commonDir}/../solr").path }, |
| description: "Solr base dir.", |
| includeInReproLine: false |
| ], |
| [propName: 'solr.directoryFactory', value: "org.apache.solr.core.MockDirectoryFactory", description: "Solr directory factory."], |
| [propName: 'tests.src.home', value: null, description: "See SOLR-14023."], |
| [propName: 'solr.tests.use.numeric.points', value: null, description: "Point implementation to use (true=numerics, false=trie)."], |
| ] |
| } |
| } |
| } |
| |
| // Resolve test option values after all evaluation is complete. |
| allprojects { |
| plugins.withType(JavaPlugin) { |
| afterEvaluate { |
| ext.testOptionsResolved = testOptions.findAll { opt -> |
| propertyOrDefault(opt.propName, opt.value) != null |
| }.collectEntries { opt -> |
| [(opt.propName): Objects.toString(resolvedTestOption(opt.propName))] |
| } |
| |
| // Compute the "reproduce with" string. |
| ext.testOptionsForReproduceLine = testOptions.findAll { opt -> |
| if (opt["includeInReproLine"] == false) { |
| return false |
| } |
| |
| def defValue = Objects.toString(opt.value, null) |
| def value = testOptionsResolved[opt.propName] |
| return defValue != value |
| }.collect { opt -> |
| "-P" + opt.propName + "=" + testOptionsResolved[opt.propName] |
| }.join(" ") |
| |
| // leaving temporary folder option has multiple aliases... |
| if ([ |
| "tests.leaveTemporary", |
| "tests.leavetemporary", |
| "tests.leavetmpdir", |
| "solr.test.leavetmpdir", |
| ].find { prop -> |
| def v = Boolean.parseBoolean(propertyOrDefault(prop, "false")) |
| if (v) { |
| logger.lifecycle("Update your code to use the official 'tests.leaveTemporary' option (you used '${prop}').") |
| } |
| return v |
| }) { |
| testOptionsResolved['tests.leaveTemporary'] = "true" |
| } |
| |
| // Append resolved test properties to the test task. |
| tasks.withType(Test) { task -> |
| // TODO: we could remove some options that are only relevant to the build environment |
| // and not the test JVM itself. |
| systemProperties testOptionsResolved |
| |
| if (Boolean.parseBoolean(testOptionsResolved['tests.asserts'])) { |
| jvmArgs("-ea", "-esa") |
| } else { |
| enableAssertions = false |
| } |
| |
| if (Boolean.parseBoolean(testOptionsResolved["tests.failfast"])) { |
| failFast true |
| } |
| |
| // Enable security manager, if requested. We could move the selection of security manager and security policy |
| // to each project's build/ configuration but it seems compact enough to keep it here for now. |
| if (Boolean.parseBoolean(testOptionsResolved["tests.useSecurityManager"])) { |
| if (project.path == ":lucene:replicator") { |
| systemProperty 'java.security.manager', "org.apache.lucene.util.TestSecurityManager" |
| systemProperty 'java.security.policy', file("${resources}/policies/replicator-tests.policy") |
| } else if (project.path.startsWith(":lucene")) { |
| systemProperty 'java.security.manager', "org.apache.lucene.util.TestSecurityManager" |
| systemProperty 'java.security.policy', file("${resources}/policies/tests.policy") |
| } else { |
| systemProperty 'common-solr.dir', commonSolrDir |
| systemProperty 'java.security.manager', "org.apache.lucene.util.TestSecurityManager" |
| systemProperty 'java.security.policy', file("${resources}/policies/solr-tests.policy") |
| } |
| |
| systemProperty 'common.dir', commonDir |
| |
| def gradleUserHome = project.gradle.getGradleUserHomeDir() |
| systemProperty 'gradle.lib.dir', Paths.get(project.class.location.toURI()).parent.toAbsolutePath().toString().replace('\\', '/') |
| systemProperty 'gradle.worker.jar', Paths.get("${gradleUserHome}/caches/${gradle.gradleVersion}/workerMain/gradle-worker.jar").toAbsolutePath().toString() |
| systemProperty 'gradle.user.home', gradleUserHome.toPath().toAbsolutePath().toString() |
| } |
| |
| doFirst { |
| logger.debug("Will use test opts:\n" + testOptionsResolved.collect {k,v -> "${k}: ${v}"}.sort().join("\n")) |
| } |
| } |
| } |
| } |
| } |
| |
| // Add a helper task to display resolved test property values with their defaults |
| // and descriptions. |
| allprojects { |
| plugins.withType(JavaPlugin) { |
| task testOpts() { |
| group = 'Help (developer guides and hints)' |
| description = "Display values of randomization settings for a given seed" |
| |
| doFirst { |
| println "Test options for project ${project.path} and seed \"${rootSeed}\":" |
| |
| testOptions.sort { a, b -> a.propName.compareTo(b.propName) }.each { opt -> |
| def defValue |
| def computedValue = false |
| if (opt.value instanceof Closure) { |
| defValue = Objects.toString(opt.value(), null) |
| computedValue = true |
| } else { |
| defValue = Objects.toString(opt.value, null) |
| } |
| |
| def value = testOptionsResolved[opt.propName] |
| println String.format(Locale.ROOT, |
| "%s%-24s = %-8s # %s", |
| (defValue != value ? "! " : computedValue ? "C " : " "), |
| opt.propName, |
| value, |
| (computedValue ? "(!= default: computed) " : (defValue != value ? "(!= default: ${defValue}) " : "")) + opt.description) |
| } |
| } |
| } |
| } |
| } |