Skip to content

Commit ad1c0e1

Browse files
committed
Introduce BWC testing infrastructure
This commit introduces necessary changes to enable BWC testing. Closes: #315 Signed-off-by: Lukáš Vlček <lukas.vlcek@aiven.io>
1 parent 1410181 commit ad1c0e1

File tree

7 files changed

+354
-0
lines changed

7 files changed

+354
-0
lines changed

.github/workflows/BWC.yml

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Build and Run BWC Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- "*"
7+
pull_request:
8+
branches:
9+
- "*"
10+
11+
jobs:
12+
build:
13+
strategy:
14+
matrix:
15+
os: [ubuntu-latest]
16+
java: [21]
17+
name: Build and Run BWC Tests
18+
runs-on: ${{ matrix.os }}
19+
permissions:
20+
contents: read
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
- name: Set up JDK ${{ matrix.java }}
25+
uses: actions/setup-java@v4
26+
with:
27+
distribution: "temurin"
28+
java-version: ${{ matrix.java }}
29+
30+
- name: Build and Run Tests
31+
run: |
32+
./gradlew --info bwcTestSuite -Dtests.security.manager=false

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
# https://discuss.elastic.co/t/leftovers-after-integtestrunner-in-root/152610
33
\.local*-integTestRunner-execution-times.log
44

5+
# This location is used by BWC test clusters to host older and actual versions of plugin ZIP files.
6+
src/test/resources/org/opensearch/prometheus-exporter/bwc/
7+
58
# intellij files
69
.idea/
710
*.iml

README.md

+15
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The [Prometheus® exporter](https://prometheus.io/docs/instrumenting/writing_exp
1212
- [Usage](#usage)
1313
- [Build from Source](#build-from-source)
1414
- [Testing](#testing)
15+
- [BWC Testing](#bwc-testing)
1516
- [License](#license)
1617
- [Trademarks & Attributions](#trademarks--attributions)
1718

@@ -279,6 +280,20 @@ To run individual integration rest test file use:
279280
-Dtests.method="test {yaml=/20_11_index_level_metrics_disabled/Dynamically disable index level metrics}"
280281
```
281282

283+
### BWC Testing
284+
285+
Backward Compatibility (BWC) Testing is run manually using provided shell script:
286+
287+
```
288+
./bwctest.sh
289+
```
290+
291+
It is not part of `./gradlew [build|check]` task(s), but it is included in the CI workflow.
292+
293+
OpenSearch versions used during BWC tests use determined by properties located in `gradle.properties` file. Specifically `project.version` and `project.BWCversion`. Version of plugin deployed into `project.BWCversion` cluster is specified by `project.BWCPluginVersion` property.
294+
295+
In the beginning of BWC tests the actual version of plugin (`project.version`) is build using `bundlePlugin` gradle task and the `project.BWCPluginVersion` plugin is downloaded from GitHub releases. Both ZIP files are placed into `src/test/resource/org/opensearch/prometheus-exrpoter/bwc/prometheus-exporter` folder (this folder is ignored by git).
296+
282297
## License
283298

284299
Licensed under the Apache License, Version 2.0 (the "License");

build.gradle

+197
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import org.opensearch.gradle.test.RestIntegTestTask
22

3+
import java.util.concurrent.Callable
34
import java.util.regex.Matcher
45
import java.util.regex.Pattern
56

@@ -36,6 +37,12 @@ buildscript {
3637
"opensearch": opensearch_version,
3738
"prometheus": "0.16.0"
3839
]
40+
41+
bwcPluginDownloadLink = 'https://github.com/Aiven-Open/prometheus-exporter-plugin-for-opensearch/releases/download/' +
42+
project.BWCPluginVersion + '/prometheus-exporter-' + project.BWCPluginVersion + '.zip'
43+
baseName = "bwcCluster"
44+
bwcFilePath = "src/test/resources/org/opensearch/prometheus-exporter/bwc/"
45+
bwcPrometheusExporterPath = bwcFilePath + "prometheus-exporter/"
3946
}
4047

4148
repositories {
@@ -46,7 +53,12 @@ buildscript {
4653
maven { url "https://plugins.gradle.org/m2/" }
4754
}
4855

56+
configurations {
57+
zipArchive
58+
}
59+
4960
dependencies {
61+
zipArchive group: 'org.opensearch.plugin.prometheus', name:'prometheus-exporter', version: "${versions.opensearch}"
5062
classpath "org.opensearch.gradle:build-tools:${versions.opensearch}"
5163
}
5264
}
@@ -56,6 +68,7 @@ apply plugin: 'idea'
5668
apply plugin: 'opensearch.opensearchplugin'
5769
apply plugin: 'opensearch.yaml-rest-test'
5870
//apply plugin: 'checkstyle'
71+
apply plugin: 'opensearch.pluginzip'
5972

6073
def pluginName = pluginName
6174
def pluginDescription = pluginDescription
@@ -118,6 +131,9 @@ task integTest(type: RestIntegTestTask) {
118131
description = "Run tests against a cluster"
119132
testClassesDirs = sourceSets.test.output.classesDirs
120133
classpath = sourceSets.test.runtimeClasspath
134+
filter {
135+
excludeTestsMatching "org.opensearch.plugin.bwc.*IT"
136+
}
121137
}
122138
tasks.named("check").configure { dependsOn(integTest) }
123139

@@ -146,6 +162,187 @@ testClusters.integTest {
146162
plugin(project.tasks.bundlePlugin.archiveFile)
147163
}
148164

165+
task copyZIPBundle {
166+
dependsOn(bundlePlugin)
167+
168+
// doFirst {
169+
// if (new File("$bwcPrometheusExporterPath/$project.version").exists()) {
170+
// project.delete(files("$bwcPrometheusExporterPath/$project.version"))
171+
// }
172+
// project.mkdir bwcPrometheusExporterPath + project.version
173+
// }
174+
175+
// from 'build/distributions/prometheus-exporter-' + project.version + '.zip'
176+
// into bwcPrometheusExporterPath + project.version
177+
doLast {
178+
// By using ant.copy we can "hack" around gradle check for other task's resources modification.
179+
// It seems like a dirty hack but some official plugins seem to use this practice;
180+
// for instance see https://github.com/opensearch-project/anomaly-detection/
181+
ant.copy(todir: bwcPrometheusExporterPath + project.version) {
182+
ant.fileset(dir: 'build/distributions/', includes: 'prometheus-exporter-' + project.version + '.zip')
183+
}
184+
}
185+
}
186+
187+
// Clusters for BWC tests
188+
2.times { i ->
189+
testClusters {
190+
"${baseName}$i" {
191+
versions = [project.BWCversion, "2.17.1"]
192+
numberOfNodes = 3
193+
plugin(provider(new Callable<RegularFile>() {
194+
@Override
195+
RegularFile call() throws Exception {
196+
return new RegularFile() {
197+
@Override
198+
File getAsFile() {
199+
if (new File("$project.rootDir/$bwcFilePath/prometheus-exporter/$project.BWCPluginVersion").exists()) {
200+
project.delete(files("$project.rootDir/$bwcFilePath/prometheus-exporter/$project.BWCPluginVersion"))
201+
}
202+
project.mkdir bwcPrometheusExporterPath + project.BWCPluginVersion
203+
ant.get(src: bwcPluginDownloadLink,
204+
dest: bwcPrometheusExporterPath + project.BWCPluginVersion,
205+
httpusecaches: false)
206+
return fileTree(bwcPrometheusExporterPath + project.BWCPluginVersion).getSingleFile()
207+
}
208+
}
209+
}
210+
}))
211+
setting 'path.repo', "${buildDir}/cluster/shared/repo/${baseName}"
212+
setting 'http.content_type.required', 'true'
213+
}
214+
}
215+
}
216+
217+
List<Provider<RegularFile>> plugins = [
218+
provider(new Callable<RegularFile>(){
219+
@Override
220+
RegularFile call() throws Exception {
221+
return new RegularFile() {
222+
@Override
223+
File getAsFile() {
224+
return fileTree(bwcPrometheusExporterPath + project.version).getSingleFile()
225+
}
226+
}
227+
}
228+
})
229+
]
230+
231+
// Creates 2 test clusters with 3 nodes of the old version.
232+
2.times {i ->
233+
task "${baseName}#oldVersionClusterTask$i"(type: RestIntegTestTask) {
234+
useCluster testClusters."${baseName}$i"
235+
filter {
236+
includeTestsMatching "org.opensearch.plugin.bwc.*IT"
237+
}
238+
systemProperty 'tests.rest.bwcsuite', 'old_cluster'
239+
systemProperty 'tests.rest.bwcsuite_round', 'old'
240+
systemProperty 'tests.plugin_bwc_version', project.BWCPluginVersion
241+
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}$i".allHttpSocketURI.join(",")}")
242+
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}$i".getName()}")
243+
}
244+
}
245+
246+
// Upgrades one node of the old cluster to new OpenSearch version with upgraded plugin version
247+
// This results in a mixed cluster with 2 nodes on the old version and 1 upgraded node.
248+
// This is also used as a one third upgraded cluster for a rolling upgrade.
249+
task "${baseName}#mixedClusterTask"(type: RestIntegTestTask) {
250+
dependsOn tasks.named("copyZIPBundle")
251+
useCluster testClusters."${baseName}0"
252+
dependsOn "${baseName}#oldVersionClusterTask0"
253+
doFirst {
254+
testClusters."${baseName}0".upgradeNodeAndPluginToNextVersion(plugins)
255+
}
256+
filter {
257+
includeTestsMatching "org.opensearch.plugin.bwc.*IT"
258+
}
259+
systemProperty 'tests.rest.bwcsuite', 'mixed_cluster'
260+
systemProperty 'tests.rest.bwcsuite_round', 'first'
261+
systemProperty 'tests.plugin_bwc_version', project.BWCPluginVersion
262+
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}0".allHttpSocketURI.join(",")}")
263+
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}0".getName()}")
264+
}
265+
266+
// Upgrades the second node to new OpenSearch version with upgraded plugin version after the first node is upgraded.
267+
// This results in a mixed cluster with 1 node on the old version and 2 upgraded nodes.
268+
// This is used for rolling upgrade.
269+
task "${baseName}#twoThirdsUpgradedClusterTask"(type: RestIntegTestTask) {
270+
dependsOn tasks.named("copyZIPBundle")
271+
dependsOn "${baseName}#mixedClusterTask"
272+
useCluster testClusters."${baseName}0"
273+
doFirst {
274+
testClusters."${baseName}0".upgradeNodeAndPluginToNextVersion(plugins)
275+
}
276+
filter {
277+
includeTestsMatching "org.opensearch.plugin.bwc.*IT"
278+
}
279+
systemProperty 'tests.rest.bwcsuite', 'mixed_cluster'
280+
systemProperty 'tests.rest.bwcsuite_round', 'second'
281+
systemProperty 'tests.plugin_bwc_version', project.BWCPluginVersion
282+
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}0".allHttpSocketURI.join(",")}")
283+
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}0".getName()}")
284+
}
285+
286+
// Upgrades the third node to new OpenSearch version with upgraded plugin version after the second node is upgraded.
287+
// This results in a fully upgraded cluster.
288+
// This is used for rolling upgrade.
289+
task "${baseName}#rollingUpgradeClusterTask"(type: RestIntegTestTask) {
290+
dependsOn tasks.named("copyZIPBundle")
291+
dependsOn "${baseName}#twoThirdsUpgradedClusterTask"
292+
useCluster testClusters."${baseName}0"
293+
doFirst {
294+
testClusters."${baseName}0".upgradeNodeAndPluginToNextVersion(plugins)
295+
}
296+
filter {
297+
includeTestsMatching "org.opensearch.plugin.bwc.*IT"
298+
}
299+
mustRunAfter "${baseName}#mixedClusterTask"
300+
systemProperty 'tests.rest.bwcsuite', 'mixed_cluster'
301+
systemProperty 'tests.rest.bwcsuite_round', 'third'
302+
systemProperty 'tests.plugin_bwc_version', project.BWCPluginVersion
303+
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}0".allHttpSocketURI.join(",")}")
304+
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}0".getName()}")
305+
}
306+
307+
// Upgrades all the nodes of the old cluster to new OpenSearch version with upgraded plugin version
308+
// at the same time resulting in a fully upgraded cluster.
309+
task "${baseName}#fullRestartClusterTask"(type: RestIntegTestTask) {
310+
dependsOn tasks.named("copyZIPBundle")
311+
dependsOn "${baseName}#oldVersionClusterTask1"
312+
useCluster testClusters."${baseName}1"
313+
doFirst {
314+
testClusters."${baseName}1".upgradeAllNodesAndPluginsToNextVersion(plugins)
315+
}
316+
filter {
317+
includeTestsMatching "org.opensearch.plugin.bwc.*IT"
318+
}
319+
systemProperty 'tests.rest.bwcsuite', 'upgraded_cluster'
320+
systemProperty 'tests.plugin_bwc_version', project.BWCPluginVersion
321+
nonInputProperties.systemProperty('tests.rest.cluster', "${-> testClusters."${baseName}1".allHttpSocketURI.join(",")}")
322+
nonInputProperties.systemProperty('tests.clustername', "${-> testClusters."${baseName}1".getName()}")
323+
}
324+
325+
// A BWC test suite which runs all the bwc tasks combined.
326+
task bwcTestSuite(type: RestIntegTestTask) {
327+
328+
// Delete all downloaded and built plugin ZIP files.
329+
// Again – we are using ant task to workaround gradle resources modification alert.
330+
doFirst {
331+
ant.delete(includeEmptyDirs: true, verbose: true, removeNotFollowedSymlinks: true) {
332+
ant.fileset(
333+
dir: 'src/test/resources/org/opensearch/prometheus-exporter/bwc/prometheus-exporter'
334+
)
335+
}
336+
}
337+
338+
exclude '**/*Test*'
339+
exclude '**/*IT*'
340+
341+
dependsOn tasks.named("${baseName}#mixedClusterTask")
342+
dependsOn tasks.named("${baseName}#rollingUpgradeClusterTask")
343+
dependsOn tasks.named("${baseName}#fullRestartClusterTask")
344+
}
345+
149346
run {
150347
useCluster testClusters.integTest
151348
}

bwctest.sh

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
function usage() {
6+
echo ""
7+
echo "This script is used to run Backwards Compatibility tests"
8+
echo "--------------------------------------------------------------------------"
9+
echo "Usage: $0 [args]"
10+
echo ""
11+
echo "Required arguments:"
12+
echo "None"
13+
echo ""
14+
echo -e "-h\tPrint this message."
15+
echo "--------------------------------------------------------------------------"
16+
}
17+
18+
while getopts ":h" arg; do
19+
case $arg in
20+
h)
21+
usage
22+
exit 1
23+
;;
24+
?)
25+
echo "Invalid option: -${OPTARG}"
26+
exit 1
27+
;;
28+
esac
29+
done
30+
31+
# Warning!
32+
# This should be done from gradle, see bwcTestSuite task, but that task is skipped.
33+
# TODO: Skipping task ':bwcTestSuite' as it has no source files and no previous output files.
34+
rm -rf src/test/resources/org/opensearch/prometheus-exporter/bwc/prometheus-exporter
35+
36+
./gradlew bwcTestSuite -Dtests.security.manager=false

gradle.properties

+7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
#group = org.opensearch.plugin.prometheus
22

3+
# An actual version of plugin
34
version = 2.17.1.0
45

6+
# A version of OpenSearch cluster to run BWC tests against
7+
BWCversion = 2.17.0
8+
9+
# A version of plugin to deploy to BWC clusters
10+
BWCPluginVersion = 2.17.0.0
11+
512
pluginName = prometheus-exporter
613
pluginClassname = org.opensearch.plugin.prometheus.PrometheusExporterPlugin
714
pluginDescription = Prometheus exporter plugin for OpenSearch

0 commit comments

Comments
 (0)