Skip to content

Commit b5e5537

Browse files
authored
feat(tests): Test against a matrix of Iceberg and Spark/Flink versions (#106)
This change introduces a "simple" way to play Spark and Flink tests against a matrix of Iceberg and Spark/Flink versions. It is "simple" because it may not work if different engine versions become so incompatible, that the test classes themselves need to be changed. Once that happens (and it may soon, with Spark 4.0) then we'll need to look for a more complex setup. But for now, this change at least allows testing against Iceberg 1.9.0 and 1.9.1, and against the two last versions of each engine. The versions to use are controlled by the following properties: * `authmgr.test.iceberg.versions`: 1.9.1, 1.9.0 * `authmgr.test.spark.versions`: 3.5.6, 3.5.5 * `authmgr.test.flink.versions`: 1.20.2, 1.20.1 Summary of tasks: * The `intTest` task runs the tests with the latest versions. * The `intTestMatrix` task runs the entire matrix. * The `intTest_iceberg190_spark355` task runs the tests with Iceberg 1.9.0 and Spark 3.5.5. There are similar tasks for each combination of iceberg/engine versions available. * The `printTestMatrix` task prints the different tasks available.
1 parent a762282 commit b5e5537

7 files changed

Lines changed: 377 additions & 84 deletions

File tree

.github/workflows/ci.yml

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@ jobs:
118118
path: |
119119
**/build/test-results/**
120120
121-
runtime-tests:
121+
spark-tests:
122122

123123
runs-on: ubuntu-latest
124-
name: Spark & Flink Tests
124+
name: Spark Tests
125125
permissions:
126126
contents: read
127127

@@ -143,16 +143,51 @@ jobs:
143143

144144
- name: Gradle Run Spark Tests
145145
run: |
146-
./gradlew --continue --scan :authmgr-oauth2-runtime-spark-tests:intTest
146+
./gradlew --continue --scan \
147+
:authmgr-oauth2-runtime-spark-tests:printTestMatrix \
148+
:authmgr-oauth2-runtime-spark-tests:intTestMatrix
149+
150+
- name: Archive Test Results
151+
uses: actions/upload-artifact@v4
152+
if: always()
153+
with:
154+
name: spark-tests-results
155+
path: |
156+
**/build/test-results/**
157+
158+
flink-tests:
159+
160+
runs-on: ubuntu-latest
161+
name: Flink Tests
162+
permissions:
163+
contents: read
164+
165+
steps:
166+
167+
- name: Checkout Project
168+
uses: actions/checkout@v4
169+
170+
- name: Set up JDK 21
171+
uses: actions/setup-java@v4
172+
with:
173+
java-version: '21'
174+
distribution: 'temurin'
175+
176+
- name: Setup Gradle
177+
uses: gradle/actions/setup-gradle@v4
178+
with:
179+
validate-wrappers: false
147180

148181
- name: Gradle Run Flink Tests
149182
run: |
150-
./gradlew --continue --scan :authmgr-oauth2-runtime-flink-tests:intTest
183+
./gradlew --continue --scan \
184+
:authmgr-oauth2-runtime-flink-tests:printTestMatrix \
185+
:authmgr-oauth2-runtime-flink-tests:intTestMatrix
151186
152187
- name: Archive Test Results
153188
uses: actions/upload-artifact@v4
154189
if: always()
155190
with:
156-
name: runtime-tests-results
191+
name: flink-tests-results
157192
path: |
158193
**/build/test-results/**

gradle.properties

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@ org.gradle.configuration-cache=false
2828
#org.gradle.configuration-cache-problems=warn
2929
# bump the Gradle daemon heap size (you can set bigger heap sizes as well)
3030
org.gradle.jvmargs=-Xms2g -Xmx4g -XX:MaxMetaspaceSize=768m
31+
32+
# Matrix testing configuration for integration tests
33+
# Comma-separated list of versions to test against
34+
# The last version in the list is the default and will be used for the main intTest task
35+
authmgr.test.iceberg.versions=1.9.0,1.9.2
36+
authmgr.test.spark.versions=3.5.5,3.5.6
37+
authmgr.test.flink.versions=1.20.1,1.20.2

gradle/libs.versions.toml

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@
1919

2020
[versions]
2121
errorprone = "2.36.0"
22-
flink = "1.20.1"
2322
hadoop = "3.4.1"
24-
iceberg = "1.9.1"
25-
immutables = "2.10.1"
23+
iceberg = "1.9.1" # When updating iceberg version, also update the iceberg test versions in gradle.properties
24+
immutables = "2.11.1"
2625
mockserver = "5.15.0"
27-
slf4j = "2.0.16"
28-
spark = "3.5.5"
26+
slf4j = "2.0.17"
2927

3028
[bundles]
3129

@@ -41,12 +39,6 @@ bouncycastle-bcpkix = { module = "org.bouncycastle:bcpkix-jdk15on", version = "1
4139
caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version = "3.2.0" }
4240
errorprone = { module = "com.google.errorprone:error_prone_core", version.ref = "errorprone" }
4341
errorprone-annotations = { module = "com.google.errorprone:error_prone_annotations", version.ref = "errorprone" }
44-
flink-table-api-java = { module = "org.apache.flink:flink-table-api-java", version.ref = "flink" }
45-
flink-table-runtime = { module = "org.apache.flink:flink-table-runtime", version.ref = "flink" }
46-
flink-table-planner-loader = { module = "org.apache.flink:flink-table-planner-loader", version.ref = "flink" }
47-
flink-clients = { module = "org.apache.flink:flink-clients", version.ref = "flink" }
48-
flink-connector-base = { module = "org.apache.flink:flink-connector-base", version.ref = "flink" }
49-
flink-connector-files = { module = "org.apache.flink:flink-connector-files", version.ref = "flink" }
5042
hadoop-common = { module = "org.apache.hadoop:hadoop-common", version.ref = "hadoop" }
5143
hadoop-hdfs-client = { module = "org.apache.hadoop:hadoop-hdfs-client", version.ref = "hadoop" }
5244
hadoop-mapreduce-client-core = { module = "org.apache.hadoop:hadoop-mapreduce-client-core", version.ref = "hadoop" }
@@ -65,7 +57,6 @@ mockserver-client-java = { module = "org.mock-server:mockserver-client-java", ve
6557
mockserver-netty = { module = "org.mock-server:mockserver-netty", version.ref = "mockserver" }
6658
s3mock-testcontainers = { module = "com.adobe.testing:s3mock-testcontainers", version = "4.3.0" }
6759
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
68-
spark-sql = { module = "org.apache.spark:spark-sql_2.12", version.ref = "spark" }
6960
spotbugs-annotations = { module = "com.github.spotbugs:spotbugs-annotations", version = "4.9.0" }
7061
testcontainers-bom = { module = "org.testcontainers:testcontainers-bom", version = "1.20.4" }
7162
testcontainers-keycloak = { module = "com.github.dasniko:testcontainers-keycloak", version = "3.6.0" }

oauth2/runtime-flink-tests/build.gradle.kts

Lines changed: 157 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17+
import org.gradle.api.plugins.jvm.JvmTestSuite
18+
import org.gradle.kotlin.dsl.register
19+
1720
plugins {
1821
id("authmgr-java")
1922
id("authmgr-java-testing")
@@ -23,72 +26,179 @@ description = "Flink tests for Dremio AuthManager for Apache Iceberg"
2326

2427
ext { set("mavenName", "Auth Manager for Apache Iceberg - OAuth2 - Flink Tests") }
2528

29+
// Matrix testing configuration
30+
val icebergVersions = project.findProperty("authmgr.test.iceberg.versions").toString().split(",")
31+
val flinkVersions = project.findProperty("authmgr.test.flink.versions").toString().split(",")
32+
33+
// Use the last combination as default for regular intTest
34+
val defaultIcebergVersion = icebergVersions.last()
35+
val defaultFlinkVersion = flinkVersions.last()
36+
37+
val intTestBase =
38+
configurations.create("intTestBase") {
39+
description = "Base configuration holding common dependencies for Flink integration tests"
40+
isCanBeResolved = false
41+
isCanBeConsumed = false
42+
}
43+
44+
// Make intTestImplementation extend from intTestBase
45+
configurations.intTestImplementation.get().extendsFrom(intTestBase)
46+
2647
dependencies {
2748

2849
// Note: iceberg-core will be provided by the iceberg-flink-runtime jar,
2950
// with shaded dependencies; it should not leak into this project unshaded.
3051

31-
intTestImplementation(project(":authmgr-oauth2-runtime"))
52+
intTestBase(project(":authmgr-oauth2-runtime"))
3253

33-
intTestImplementation(testFixtures(project(":authmgr-oauth2-core")) as ModuleDependency) {
54+
intTestBase(testFixtures(project(":authmgr-oauth2-core")) as ModuleDependency) {
3455
exclude(group = "org.apache.iceberg")
3556
}
3657

58+
intTestBase(libs.hadoop.common)
59+
intTestBase(libs.hadoop.hdfs.client)
60+
intTestBase(libs.hadoop.mapreduce.client.core)
61+
62+
intTestBase(platform(libs.testcontainers.bom))
63+
intTestBase("org.testcontainers:testcontainers")
64+
intTestBase(libs.s3mock.testcontainers)
65+
66+
intTestBase(platform(libs.junit.bom))
67+
intTestBase("org.junit.jupiter:junit-jupiter")
68+
intTestBase("org.junit.jupiter:junit-jupiter-api")
69+
intTestBase("org.junit.platform:junit-platform-launcher")
70+
71+
intTestBase(libs.assertj.core)
72+
intTestBase(libs.mockito.core)
73+
intTestBase(libs.logback.classic)
74+
75+
// Add to intTestImplementation all Iceberg/Flink dependencies (with default versions)
76+
// that are required for compilation of test classes
3777
intTestImplementation(platform(libs.iceberg.bom))
3878
intTestImplementation("org.apache.iceberg:iceberg-flink-runtime-1.20")
79+
intTestImplementation("org.apache.flink:flink-table-api-java:$defaultFlinkVersion")
80+
}
81+
82+
// Create matrix test tasks for each version combination
83+
val matrixTestTasks = mutableListOf<TaskProvider<Test>>()
84+
85+
icebergVersions.forEach { icebergVersion ->
86+
flinkVersions.forEach { flinkVersion ->
87+
val suiteName =
88+
"intTest_iceberg${icebergVersion.replace(".", "_")}_flink${flinkVersion.replace(".", "_")}"
3989

40-
intTestImplementation(libs.flink.table.api.java)
41-
intTestImplementation(libs.flink.table.runtime)
42-
intTestImplementation(libs.flink.table.planner.loader)
43-
intTestImplementation(libs.flink.clients)
44-
intTestImplementation(libs.flink.connector.base)
45-
intTestImplementation(libs.flink.connector.files)
90+
val runtimeConfig =
91+
configurations.create(suiteName) {
92+
extendsFrom(intTestBase)
93+
isCanBeResolved = true
94+
isCanBeConsumed = false
95+
}
4696

47-
intTestImplementation(libs.hadoop.common)
48-
intTestImplementation(libs.hadoop.hdfs.client)
49-
intTestImplementation(libs.hadoop.mapreduce.client.core)
97+
// Add version-specific dependencies
98+
dependencies {
99+
runtimeConfig(platform("org.apache.iceberg:iceberg-bom:$icebergVersion"))
100+
runtimeConfig("org.apache.iceberg:iceberg-flink-runtime-1.20:$icebergVersion")
101+
runtimeConfig("org.apache.flink:flink-table-api-java:$flinkVersion")
102+
runtimeConfig("org.apache.flink:flink-table-runtime:$flinkVersion")
103+
runtimeConfig("org.apache.flink:flink-table-planner-loader:$flinkVersion")
104+
runtimeConfig("org.apache.flink:flink-clients:$flinkVersion")
105+
runtimeConfig("org.apache.flink:flink-connector-base:$flinkVersion")
106+
runtimeConfig("org.apache.flink:flink-connector-files:$flinkVersion")
107+
runtimeConfig("org.apache.iceberg:iceberg-aws-bundle:$icebergVersion")
108+
}
50109

51-
intTestRuntimeOnly("org.apache.iceberg:iceberg-aws")
52-
intTestRuntimeOnly("org.apache.iceberg:iceberg-aws-bundle")
110+
testing {
111+
suites {
112+
register<JvmTestSuite>(suiteName) {
113+
targets.all {
114+
testTask.configure {
115+
shouldRunAfter("test")
53116

54-
intTestImplementation(platform(libs.testcontainers.bom))
55-
intTestImplementation("org.testcontainers:testcontainers")
56-
intTestImplementation(libs.s3mock.testcontainers)
117+
if (System.getenv("CI") == null) {
118+
maxParallelForks = 2
119+
}
57120

58-
intTestImplementation(platform(libs.junit.bom))
59-
intTestImplementation("org.junit.jupiter:junit-jupiter")
60-
intTestImplementation("org.junit.jupiter:junit-jupiter-api")
121+
description =
122+
"Runs Flink integration tests with Iceberg $icebergVersion and Flink $flinkVersion"
61123

62-
intTestImplementation(libs.assertj.core)
63-
intTestImplementation(libs.mockito.core)
124+
// Use shared test classes from src/intTest
125+
testClassesDirs = sourceSets.intTest.get().output.classesDirs
126+
classpath = runtimeConfig + sourceSets.intTest.get().output
127+
128+
dependsOn(":authmgr-oauth2-runtime:shadowJar")
129+
130+
environment("AWS_REGION", "us-west-2")
131+
environment("AWS_ACCESS_KEY_ID", "fake")
132+
environment("AWS_SECRET_ACCESS_KEY", "fake")
133+
134+
jvmArgs(
135+
"--add-exports",
136+
"java.base/sun.nio.ch=ALL-UNNAMED",
137+
"--add-opens",
138+
"java.base/java.util=ALL-UNNAMED",
139+
"--add-opens",
140+
"java.base/java.lang=ALL-UNNAMED",
141+
"--add-opens",
142+
"java.base/java.lang.reflect=ALL-UNNAMED",
143+
"--add-opens",
144+
"java.base/java.io=ALL-UNNAMED",
145+
"--add-opens",
146+
"java.base/java.net=ALL-UNNAMED",
147+
"--add-opens",
148+
"java.base/java.nio=ALL-UNNAMED",
149+
"--add-opens",
150+
"java.base/java.util.concurrent=ALL-UNNAMED",
151+
"--add-opens",
152+
"java.base/java.security=ALL-UNNAMED",
153+
)
154+
155+
// Set system properties to identify the versions being tested
156+
systemProperty("authmgr.test.iceberg.version", icebergVersion)
157+
systemProperty("authmgr.test.flink.version", flinkVersion)
158+
159+
inputs.property("icebergVersion", icebergVersion)
160+
inputs.property("flinkVersion", flinkVersion)
161+
}
162+
matrixTestTasks.add(testTask)
163+
}
164+
}
165+
}
166+
}
167+
}
64168
}
65169

66170
tasks.named<Test>("intTest").configure {
67-
if (System.getenv("CI") == null) {
68-
maxParallelForks = 2
69-
}
70-
dependsOn(":authmgr-oauth2-runtime:shadowJar")
71-
environment("AWS_REGION", "us-west-2")
72-
environment("AWS_ACCESS_KEY_ID", "fake")
73-
environment("AWS_SECRET_ACCESS_KEY", "fake")
74-
jvmArgs(
75-
"--add-exports",
76-
"java.base/sun.nio.ch=ALL-UNNAMED",
77-
"--add-opens",
78-
"java.base/java.util=ALL-UNNAMED",
79-
"--add-opens",
80-
"java.base/java.lang=ALL-UNNAMED",
81-
"--add-opens",
82-
"java.base/java.lang.reflect=ALL-UNNAMED",
83-
"--add-opens",
84-
"java.base/java.io=ALL-UNNAMED",
85-
"--add-opens",
86-
"java.base/java.net=ALL-UNNAMED",
87-
"--add-opens",
88-
"java.base/java.nio=ALL-UNNAMED",
89-
"--add-opens",
90-
"java.base/java.util.concurrent=ALL-UNNAMED",
91-
"--add-opens",
92-
"java.base/java.security=ALL-UNNAMED",
171+
dependsOn(
172+
tasks.named(
173+
"intTest_iceberg${defaultIcebergVersion.replace(".", "_")}_flink${defaultFlinkVersion.replace(".", "_")}"
174+
)
93175
)
176+
// the task itself should not run any tests
177+
enabled = false
178+
description =
179+
"Runs Flink integration tests with the default Iceberg version ($defaultIcebergVersion) and default Flink version ($defaultFlinkVersion)."
180+
}
181+
182+
// Create a task to run all matrix tests
183+
tasks.register("intTestMatrix") {
184+
group = "verification"
185+
description = "Runs all integration test matrix combinations."
186+
dependsOn(matrixTestTasks)
187+
}
188+
189+
// Helper task to print matrix configuration
190+
tasks.register("printTestMatrix") {
191+
group = "help"
192+
description = "Prints the test matrix configuration."
193+
doLast {
194+
println("Flink Integration Test Matrix:")
195+
println("Iceberg versions: ${icebergVersions.joinToString(", ")}")
196+
println("Flink versions: ${flinkVersions.joinToString(", ")}")
197+
println("Available tasks:")
198+
matrixTestTasks.forEach { task ->
199+
val icebergVersion = task.get().inputs.properties["icebergVersion"]
200+
val flinkVersion = task.get().inputs.properties["flinkVersion"]
201+
println(" - ${task.name} uses: Iceberg $icebergVersion, Flink $flinkVersion")
202+
}
203+
}
94204
}

oauth2/runtime-flink-tests/src/intTest/java/com/dremio/iceberg/authmgr/oauth2/test/flink/FlinkPolarisS3ITBase.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.concurrent.ExecutionException;
3232
import org.apache.flink.table.api.EnvironmentSettings;
3333
import org.apache.flink.table.api.TableEnvironment;
34+
import org.apache.iceberg.IcebergBuild;
3435
import org.junit.jupiter.api.AfterAll;
3536
import org.junit.jupiter.api.BeforeAll;
3637
import org.junit.jupiter.api.Test;
@@ -45,6 +46,20 @@ public abstract class FlinkPolarisS3ITBase {
4546
protected volatile PolarisContainer polaris;
4647
protected TableEnvironment flink;
4748

49+
@BeforeAll
50+
public void recordExpectedVersions() {
51+
var expectedIcebergVersion = System.getProperty("authmgr.test.iceberg.version");
52+
var actualIcebergVersion = IcebergBuild.version();
53+
if (actualIcebergVersion.equals("unspecified")) {
54+
// Iceberg 1.9.0 returns "unspecified" :shrug:
55+
var icebergTag = IcebergBuild.gitTags().get(0);
56+
assertThat(icebergTag).startsWith("apache-iceberg-" + expectedIcebergVersion);
57+
} else {
58+
assertThat(actualIcebergVersion).startsWith(expectedIcebergVersion);
59+
}
60+
// TODO how to check Flink version? GlobalConfiguration.loadConfiguration() doesn't work
61+
}
62+
4863
@BeforeAll
4964
public void setup() throws ExecutionException, InterruptedException {
5065
var network = Network.newNetwork();

0 commit comments

Comments
 (0)