/* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ import org.opensearch.gradle.test.RestIntegTestTask import java.util.concurrent.Callable import org.opensearch.gradle.testclusters.StandaloneRestIntegTestTask buildscript { ext { opensearch_group = "org.opensearch" isSnapshot = "true" == System.getProperty("build.snapshot", "true") opensearch_version = System.getProperty("opensearch.version", "3.0.0-SNAPSHOT") buildVersionQualifier = System.getProperty("build.version_qualifier", "") // 2.0.0-rc1-SNAPSHOT -> 2.0.0.0-rc1-SNAPSHOT version_tokens = opensearch_version.tokenize('-') opensearch_build = version_tokens[0] + '.0' if (buildVersionQualifier) { opensearch_build += "-${buildVersionQualifier}" } if (isSnapshot) { opensearch_build += "-SNAPSHOT" } common_utils_version = System.getProperty("common_utils.version", opensearch_build) job_scheduler_version = System.getProperty("job_scheduler.version", opensearch_build) kotlin_version = System.getProperty("kotlin.version", "1.8.21") jackson_version = "2.14.1" } repositories { mavenLocal() maven { url "https://aws.oss.sonatype.org/content/repositories/snapshots" } mavenCentral() maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath "${opensearch_group}.gradle:build-tools:${opensearch_version}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}" classpath "org.jetbrains.kotlin:kotlin-allopen:${kotlin_version}" classpath "io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.22.0" classpath "org.jacoco:org.jacoco.agent:0.8.8" } } plugins { id 'nebula.ospackage' version "8.3.0" id "com.dorongold.task-tree" version "1.5" id 'java-library' } apply plugin: 'java' apply plugin: 'jacoco' apply plugin: 'idea' apply plugin: 'opensearch.opensearchplugin' apply plugin: 'opensearch.pluginzip' apply plugin: 'opensearch.testclusters' apply plugin: 'io.gitlab.arturbosch.detekt' apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'org.jetbrains.kotlin.plugin.allopen' def usingRemoteCluster = System.properties.containsKey('tests.rest.cluster') || System.properties.containsKey('tests.cluster') def usingMultiNode = project.properties.containsKey('numNodes') check.dependsOn jacocoTestReport opensearchplugin { name 'opensearch-reports-scheduler' description 'Scheduler for Dashboards Reports Plugin' classname "org.opensearch.reportsscheduler.ReportsSchedulerPlugin" extendedPlugins = ['opensearch-job-scheduler'] } publishing { publications { pluginZip(MavenPublication) { publication -> pom { name = 'opensearch-reports-scheduler' description = 'Scheduler for Dashboards Reports Plugin' groupId = "org.opensearch.plugin" licenses { license { name = 'The Apache License, Version 2.0' url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' } } developers { developer { name = 'OpenSearch' url = 'https://github.com/opensearch-project/reporting' } } } } } repositories { maven { name = "Snapshots" // optional target repository name url = "https://aws.oss.sonatype.org/content/repositories/snapshots" credentials { username "$System.env.SONATYPE_USERNAME" password "$System.env.SONATYPE_PASSWORD" } } } } allOpen { annotation("org.opensearch.reportsscheduler.util.OpenForTesting") } configurations { ktlint testCompile testRuntime zipArchive } detekt { config = files("detekt.yml") buildUponDefaultConfig = true } configurations.testCompile { exclude module: "securemock" } configurations.all { if (it.state != Configuration.State.UNRESOLVED) return resolutionStrategy { force "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}" force "org.jetbrains.kotlin:kotlin-stdlib-common:${kotlin_version}" force "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.11.4" force "org.yaml:snakeyaml:2.0" } } ext { projectSubstitutions = [:] licenseFile = rootProject.file('LICENSE.txt') noticeFile = rootProject.file('NOTICE.txt') } plugins.withId('java') { sourceCompatibility = targetCompatibility = "11" } plugins.withId('org.jetbrains.kotlin.jvm') { compileKotlin.kotlinOptions.jvmTarget = compileTestKotlin.kotlinOptions.jvmTarget = "11" } allprojects { group = "org.opensearch" version = "${opensearch_build}" plugins.withId('java') { sourceCompatibility = targetCompatibility = "11" } } repositories { mavenLocal() maven { url "https://aws.oss.sonatype.org/content/repositories/snapshots" } mavenCentral() maven { url "https://plugins.gradle.org/m2/" } } dependencies { zipArchive group: 'org.opensearch.plugin', name:'opensearch-job-scheduler', version: "${opensearch_build}" implementation "org.opensearch:opensearch:${opensearch_version}" implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}" implementation "org.jetbrains.kotlin:kotlin-stdlib-common:${kotlin_version}" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9" implementation "${group}:common-utils:${common_utils_version}" compileOnly "${group}:opensearch-job-scheduler-spi:${job_scheduler_version}" implementation "org.json:json:20230227" implementation group: 'com.github.wnameless.json', name: 'json-flattener', version: '0.15.1' // json-base, jackson-databind, jackson-annotations are transitive dependencies by json-flattener implementation group: 'com.github.wnameless.json', name: 'json-base', version: '2.2.1' implementation "com.fasterxml.jackson.core:jackson-databind:${jackson_version}" implementation "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}" implementation 'org.jsoup:jsoup:1.15.3' implementation 'com.google.code.gson:gson:2.8.9' implementation "org.jetbrains.kotlin:kotlin-test:${kotlin_version}" testImplementation( 'org.assertj:assertj-core:3.16.1', 'org.junit.jupiter:junit-jupiter-api:5.6.2' ) testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.6.2') testImplementation "org.opensearch.test:framework:${opensearch_version}" testImplementation "org.jetbrains.kotlin:kotlin-test:${kotlin_version}" testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" testImplementation "org.mockito:mockito-core:${versions.mockito}" testImplementation "org.mockito:mockito-junit-jupiter:4.7.0" testImplementation 'com.google.code.gson:gson:2.8.9' ktlint "com.pinterest:ktlint:0.45.1" } javadoc.enabled = false // turn off javadoc as it barfs on Kotlin code licenseHeaders.enabled = true // no need to validate pom, as we do not upload to maven/sonatype validateNebulaPom.enabled = false dependencyLicenses.enabled = false thirdPartyAudit.enabled = false // Allow @Test to be used in test classes not inherited from LuceneTestCase. forbiddenApis.ignoreFailures = true // Allow test cases to be named Tests without having to be inherited from LuceneTestCase. testingConventions.enabled = false loggerUsageCheck.enabled = false test { systemProperty 'tests.security.manager', 'false' useJUnitPlatform() } File repo = file("$buildDir/testclusters/repo") def _numNodes = findProperty('numNodes') as Integer ?: 1 def opensearch_tmp_dir = rootProject.file('build/private/es_tmp').absoluteFile opensearch_tmp_dir.mkdirs() // As of ES 7.7 the sample-extension-plugin is being added to the list of plugins for the testCluster during build before // the job-scheduler plugin is causing build failures. // The job-scheduler zip is added explicitly above but the sample-extension-plugin is added implicitly at some time during evaluation. // Will need to do a deep dive to find out exactly what task adds the sample-extension-plugin and add job-scheduler there but a temporary hack is to // reorder the plugins list after evaluation but prior to task execution when the plugins are installed. afterEvaluate { testClusters.integTest.nodes.each { node -> def plugins = node.plugins def firstPlugin = plugins.get(0) plugins.remove(0) plugins.add(firstPlugin) } } tasks.withType(licenseHeaders.class) { additionalLicense 'AL ', 'Apache', 'Licensed under the Apache License, Version 2.0 (the "License")' } task integTest(type: RestIntegTestTask) { description = "Run tests against a cluster" testClassesDirs = sourceSets.test.output.classesDirs classpath = sourceSets.test.runtimeClasspath } tasks.named("check").configure { dependsOn(integTest) } integTest { dependsOn "bundlePlugin" systemProperty 'tests.security.manager', 'false' systemProperty 'java.io.tmpdir', opensearch_tmp_dir.absolutePath systemProperty "https", System.getProperty("https") systemProperty "user", System.getProperty("user") systemProperty "password", System.getProperty("password") // Tell the test JVM if the cluster JVM is running under a debugger so that tests can use longer timeouts for // requests. The 'doFirst' delays reading the debug setting on the cluster till execution time. doFirst { // Tell the test JVM if the cluster JVM is running under a debugger so that tests can // use longer timeouts for requests. def isDebuggingCluster = getDebug() || System.getProperty("test.debug") != null systemProperty 'cluster.debug', isDebuggingCluster // Set number of nodes system property to be used in tests systemProperty 'cluster.number_of_nodes', "${_numNodes}" // There seems to be an issue when running multi node run or integ tasks with unicast_hosts // not being written, the waitForAllConditions ensures it's written getClusters().forEach { cluster -> cluster.waitForAllConditions() } } // The -Dcluster.debug option makes the cluster debuggable; this makes the tests debuggable if (System.getProperty("test.debug") != null) { jvmArgs '-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=8000' } if (System.getProperty("tests.clustername") != null) { exclude 'org/opensearch/integTest/ReportsSchedulerPluginIT.class' } if (System.getProperty("tests.rest.bwcsuite") == null) { filter { excludeTestsMatching "org.opensearch.integTest.bwc.*IT" } } } Zip bundle = (Zip) project.getTasks().getByName("bundlePlugin"); integTest.dependsOn(bundle) integTest.getClusters().forEach{c -> c.plugin(project.getObjects().fileProperty().value(bundle.getArchiveFile()))} testClusters.integTest { testDistribution = "INTEG_TEST" // need to install job-scheduler first, need to assemble job-scheduler first plugin(provider(new Callable(){ @Override RegularFile call() throws Exception { return new RegularFile() { @Override File getAsFile() { return configurations.zipArchive.asFileTree.getSingleFile() } } } })) // Cluster shrink exception thrown if we try to set numberOfNodes to 1, so only apply if > 1 if (_numNodes > 1) numberOfNodes = _numNodes // When running integration tests it doesn't forward the --debug-jvm to the cluster anymore // i.e. we have to use a custom property to flag when we want to debug opensearch JVM // since we also support multi node integration tests we increase debugPort per node if (System.getProperty("cluster.debug") != null) { def debugPort = 5005 nodes.forEach { node -> node.jvmArgs("-agentlib:jdwp=transport=dt_socket,server=n,suspend=y,address=*:${debugPort}") debugPort += 1 } } setting 'path.repo', repo.absolutePath } // For job-scheduler and reports-scheduler, the latest opensearch releases appear to be 1.1.0.0. String baseVersion = "2.10.0" String bwcVersion = baseVersion + ".0" String baseName = "reportsSchedulerBwcCluster" String bwcFilePath = "src/test/resources/bwc" String bwcJobSchedulerURL = "https://aws.oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=org.opensearch.plugin&a=opensearch-job-scheduler&v=$bwcVersion-SNAPSHOT&p=zip" String bwcReportsSchedulerURL = "https://aws.oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=org.opensearch.plugin&a=opensearch-reports-scheduler&v=$bwcVersion-SNAPSHOT&p=zip" String bwcSnapshotVersion = baseVersion + "-SNAPSHOT" 2.times {i -> testClusters { "${baseName}$i" { testDistribution = "ARCHIVE" versions = [bwcSnapshotVersion, opensearch_version] numberOfNodes = 3 plugin(provider(new Callable(){ @Override RegularFile call() throws Exception { return new RegularFile() { @Override File getAsFile() { File dir = new File(bwcFilePath + "/job-scheduler/" + bwcVersion) if (!dir.exists()) { dir.mkdirs() } File file = new File(dir, "opensearch-job-scheduler-" + bwcVersion + ".zip") if (!file.exists()) { new URL(bwcJobSchedulerURL).withInputStream{ ins -> file.withOutputStream{ it << ins }} } return fileTree(bwcFilePath + "/job-scheduler/" + bwcVersion).getSingleFile() } } } })) plugin(provider(new Callable(){ @Override RegularFile call() throws Exception { return new RegularFile() { @Override File getAsFile() { File dir = new File(bwcFilePath + "/reports-scheduler/" + bwcVersion) if (!dir.exists()) { dir.mkdirs() } File file = new File(dir, "opensearch-reports-scheduler-" + bwcVersion + ".zip") if (!file.exists()) { new URL(bwcReportsSchedulerURL).withInputStream{ ins -> file.withOutputStream{ it << ins }} } return fileTree(bwcFilePath + "/reports-scheduler/" + bwcVersion).getSingleFile() } } } })) setting 'path.repo', "${buildDir}/cluster/shared/repo/${baseName}" setting 'http.content_type.required', 'true' } } } List> plugins = [] // Ensure the artifact for the current project version is available to be used for the bwc tests task prepareBwcTests { dependsOn bundle doLast { plugins = [ provider(new Callable(){ @Override RegularFile call() throws Exception { return new RegularFile() { @Override File getAsFile() { return configurations.zipArchive.asFileTree.getSingleFile() } } } }), project.getObjects().fileProperty().value(bundle.getArchiveFile()) ] } } // Create two test clusters with 3 nodes of the old version 2.times {i -> task "${baseName}#oldVersionClusterTask$i"(type: StandaloneRestIntegTestTask) { dependsOn 'prepareBwcTests' useCluster testClusters."${baseName}$i" filter { includeTestsMatching "org.opensearch.integTest.bwc.*IT" } systemProperty 'tests.rest.bwcsuite', 'old_cluster' systemProperty 'tests.rest.bwcsuite_round', 'old' systemProperty 'tests.plugin_bwc_version', bwcVersion nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}$i".allHttpSocketURI.join(",")}") nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}$i".getName()}") } } // Upgrade one node of the old cluster to new OpenSearch version with upgraded plugin version. // This results in a mixed cluster with 2 nodes on the old version and 1 upgraded node. // This is also used as a one third upgraded cluster for a rolling upgrade. task "${baseName}#mixedClusterTask"(type: StandaloneRestIntegTestTask) { useCluster testClusters."${baseName}0" dependsOn "${baseName}#oldVersionClusterTask0" doFirst { testClusters."${baseName}0".upgradeNodeAndPluginToNextVersion(plugins) } filter { includeTestsMatching "org.opensearch.integTest.bwc.*IT" } systemProperty 'tests.rest.bwcsuite', 'mixed_cluster' systemProperty 'tests.rest.bwcsuite_round', 'first' systemProperty 'tests.plugin_bwc_version', bwcVersion nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}0".allHttpSocketURI.join(",")}") nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}0".getName()}") } // Upgrade the second node to new OpenSearch version with upgraded plugin version after the first node is upgraded. // This results in a mixed cluster with 1 node on the old version and 2 upgraded nodes. // This is used for rolling upgrade. task "${baseName}#twoThirdsUpgradedClusterTask"(type: StandaloneRestIntegTestTask) { dependsOn "${baseName}#mixedClusterTask" useCluster testClusters."${baseName}0" doFirst { testClusters."${baseName}0".upgradeNodeAndPluginToNextVersion(plugins) } filter { includeTestsMatching "org.opensearch.integTest.bwc.*IT" } systemProperty 'tests.rest.bwcsuite', 'mixed_cluster' systemProperty 'tests.rest.bwcsuite_round', 'second' systemProperty 'tests.plugin_bwc_version', bwcVersion nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}0".allHttpSocketURI.join(",")}") nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}0".getName()}") } // Upgrade the third node to new OpenSearch version with upgraded plugin version after the second node is upgraded. // This results in a fully upgraded cluster. // This is used for rolling upgrade. task "${baseName}#rollingUpgradeClusterTask"(type: StandaloneRestIntegTestTask) { dependsOn "${baseName}#twoThirdsUpgradedClusterTask" useCluster testClusters."${baseName}0" doFirst { testClusters."${baseName}0".upgradeNodeAndPluginToNextVersion(plugins) } filter { includeTestsMatching "org.opensearch.integTest.bwc.*IT" } mustRunAfter "${baseName}#mixedClusterTask" systemProperty 'tests.rest.bwcsuite', 'mixed_cluster' systemProperty 'tests.rest.bwcsuite_round', 'third' systemProperty 'tests.plugin_bwc_version', bwcVersion nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}0".allHttpSocketURI.join(",")}") nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}0".getName()}") } // Upgrade all the nodes of the old cluster to new OpenSearch version with upgraded plugin version // at the same time resulting in a fully upgraded cluster. task "${baseName}#fullRestartClusterTask"(type: StandaloneRestIntegTestTask) { dependsOn "${baseName}#oldVersionClusterTask1" useCluster testClusters."${baseName}1" doFirst { testClusters."${baseName}1".upgradeAllNodesAndPluginsToNextVersion(plugins) } filter { includeTestsMatching "org.opensearch.integTest.bwc.*IT" } systemProperty 'tests.rest.bwcsuite', 'upgraded_cluster' systemProperty 'tests.plugin_bwc_version', bwcVersion nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}1".allHttpSocketURI.join(",")}") nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}1".getName()}") } // A bwc test suite which runs all the bwc tasks combined task bwcTestSuite(type: StandaloneRestIntegTestTask) { exclude '**/*Test*' exclude '**/*IT*' dependsOn tasks.named("${baseName}#mixedClusterTask") dependsOn tasks.named("${baseName}#rollingUpgradeClusterTask") dependsOn tasks.named("${baseName}#fullRestartClusterTask") } task integTestRemote(type: RestIntegTestTask) { testClassesDirs = sourceSets.test.output.classesDirs classpath = sourceSets.test.runtimeClasspath systemProperty 'tests.security.manager', 'false' systemProperty 'java.io.tmpdir', opensearch_tmp_dir.absolutePath systemProperty "https", System.getProperty("https") systemProperty "user", System.getProperty("user") systemProperty "password", System.getProperty("password") // Only rest case can run with remote cluster if (System.getProperty("tests.rest.cluster") != null) { filter { includeTestsMatching "org.opensearch.integTest.rest.*IT" } } } run { doFirst { // There seems to be an issue when running multi node run or integ tasks with unicast_hosts // not being written, the waitForAllConditions ensures it's written getClusters().forEach { cluster -> cluster.waitForAllConditions() } } useCluster testClusters.integTest } task ktlint(type: JavaExec, group: "verification") { description = "Check Kotlin code style." main = "com.pinterest.ktlint.Main" classpath = configurations.ktlint args "src/**/*.kt" // to generate report in checkstyle format prepend following args: // "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/ktlint.xml" // see https://github.com/pinterest/ktlint#usage for more } check.dependsOn ktlint task ktlintFormat(type: JavaExec, group: "formatting") { description = "Fix Kotlin code style deviations." main = "com.pinterest.ktlint.Main" classpath = configurations.ktlint args "-F", "src/**/*.kt" } compileKotlin { kotlinOptions.freeCompilerArgs = ['-Xjsr305=strict'] } // Only apply jacoco test coverage if we are running a local single node cluster if (!usingRemoteCluster && !usingMultiNode) { apply from: 'build-tools/esplugin-coverage.gradle' } apply from: 'build-tools/pkgbuild.gradle' // updateVersion: Task to auto increment to the next development iteration task updateVersion { onlyIf { System.getProperty('newVersion') } doLast { ext.newVersion = System.getProperty('newVersion') println "Setting version to ${newVersion}." // String tokenization to support -SNAPSHOT ant.replaceregexp(file:'build.gradle', match: '"opensearch.version", "\\d.*"', replace: '"opensearch.version", "' + newVersion.tokenize('-')[0] + '-SNAPSHOT"', flags:'g', byline:true) ant.replaceregexp(file:'./.github/workflows/draft-release-notes-workflow.yml', match:'version: \\d+.\\d+.\\d+.\\d+', replace:'version: ' + newVersion.tokenize('-')[0] + '.0', flags:'g', byline:true) } }