Skip to content

Commit 89cc292

Browse files
authored
Fix Flink runner tests on Java 21 (#39272)
* fix Flink runner tests on Java 21 * fix UnboundedSourceWrapperTest * resolve comments * Apply Spotless
1 parent 2c92949 commit 89cc292

4 files changed

Lines changed: 68 additions & 16 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"comment": "Modify this file in a trivial way to cause this test suite to run.",
3-
"modification": 1
3+
"modification": 9
44
}

runners/flink/flink_runner.gradle

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,30 @@ if (use_override) {
180180
}
181181
}
182182

183+
def flinkTestJvmArgs() {
184+
def testJavaVer = project.findProperty('testJavaVersion') ? (project.property('testJavaVersion') as int) : JavaVersion.current().majorVersion.toInteger()
185+
if (testJavaVer >= 17) {
186+
return [
187+
"--add-opens=java.base/sun.nio.ch=ALL-UNNAMED",
188+
"--add-opens=java.base/java.nio=ALL-UNNAMED",
189+
"--add-opens=java.base/java.util=ALL-UNNAMED",
190+
"--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
191+
"--add-opens=java.base/java.lang=ALL-UNNAMED",
192+
"-Djava.security.manager=allow",
193+
]
194+
} else {
195+
return []
196+
}
197+
}
198+
183199
test {
184200
systemProperty "log4j.configuration", "log4j-test.properties"
185201
// Change log level to debug:
186202
// systemProperty "org.slf4j.simpleLogger.defaultLogLevel", "debug"
187203
// Change log level to debug only for the package and nested packages:
188204
// systemProperty "org.slf4j.simpleLogger.log.org.apache.beam.runners.flink.translation.wrappers.streaming", "debug"
189205
jvmArgs "-XX:-UseGCOverheadLimit"
206+
jvmArgs += flinkTestJvmArgs()
190207
if (System.getProperty("beamSurefireArgline")) {
191208
jvmArgs System.getProperty("beamSurefireArgline")
192209
}

runners/flink/src/test/java/org/apache/beam/runners/flink/FlinkSubmissionTest.java

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

2020
import java.io.File;
2121
import java.lang.reflect.Field;
22-
import java.lang.reflect.Modifier;
22+
import java.lang.reflect.Method;
2323
import java.nio.charset.StandardCharsets;
2424
import java.nio.file.Files;
2525
import java.security.Permission;
2626
import java.util.Collection;
27+
import java.util.Locale;
2728
import java.util.Map;
2829
import java.util.concurrent.TimeUnit;
2930
import java.util.stream.Collectors;
@@ -230,21 +231,49 @@ private static void restoreEnvironment() throws Exception {
230231
* We modify the JVM's environment variables here. This is necessary for the end-to-end test
231232
* because Flink's CliFrontend requires a Flink configuration file for which the location can only
232233
* be set using the {@code ConfigConstants.ENV_FLINK_CONF_DIR} environment variable.
234+
*
235+
* <p>On Unix, {@code theEnvironment} uses {@code Variable}/{@code Value} keys; {@code putAll}
236+
* with {@code String} keys does not work for {@code System.getenv(String)} lookups.
233237
*/
238+
@SuppressWarnings("unchecked")
234239
private static void modifyEnv(Map<String, String> env) throws Exception {
235240
Class processEnv = Class.forName("java.lang.ProcessEnvironment");
236-
Field envField = processEnv.getDeclaredField("theUnmodifiableEnvironment");
241+
Field theEnvironmentField = processEnv.getDeclaredField("theEnvironment");
242+
theEnvironmentField.setAccessible(true);
243+
Map<Object, Object> envMap = (Map<Object, Object>) theEnvironmentField.get(null);
244+
envMap.clear();
237245

238-
Field modifiersField = Field.class.getDeclaredField("modifiers");
239-
modifiersField.setAccessible(true);
240-
modifiersField.setInt(envField, envField.getModifiers() & ~Modifier.FINAL);
241-
242-
envField.setAccessible(true);
243-
envField.set(null, env);
244-
envField.setAccessible(false);
246+
Class<?> variableClass = null;
247+
Class<?> valueClass = null;
248+
try {
249+
variableClass = Class.forName("java.lang.ProcessEnvironment$Variable");
250+
valueClass = Class.forName("java.lang.ProcessEnvironment$Value");
251+
} catch (ClassNotFoundException e) {
252+
// Windows: theEnvironment uses String keys.
253+
}
254+
if (variableClass != null && valueClass != null) {
255+
Method valueOfVariable = variableClass.getDeclaredMethod("valueOf", String.class);
256+
Method valueOfValue = valueClass.getDeclaredMethod("valueOf", String.class);
257+
valueOfVariable.setAccessible(true);
258+
valueOfValue.setAccessible(true);
259+
for (Map.Entry<String, String> entry : env.entrySet()) {
260+
envMap.put(
261+
valueOfVariable.invoke(null, entry.getKey()),
262+
valueOfValue.invoke(null, entry.getValue()));
263+
}
264+
} else {
265+
envMap.putAll(env);
266+
}
245267

246-
modifiersField.setInt(envField, envField.getModifiers() & Modifier.FINAL);
247-
modifiersField.setAccessible(false);
268+
if (System.getProperty("os.name", "").toLowerCase(Locale.ROOT).startsWith("windows")) {
269+
Field ciEnvField = processEnv.getDeclaredField("theCaseInsensitiveEnvironment");
270+
ciEnvField.setAccessible(true);
271+
Map<String, String> ciEnvMap = (Map<String, String>) ciEnvField.get(null);
272+
if (ciEnvMap != null) {
273+
ciEnvMap.clear();
274+
ciEnvMap.putAll(env);
275+
}
276+
}
248277
}
249278

250279
/** Prevents the CliFrontend from calling System.exit. */

runners/flink/src/test/java/org/apache/beam/runners/flink/translation/wrappers/streaming/io/UnboundedSourceWrapperTest.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -666,10 +666,7 @@ private static void testSourceDoesNotShutdown(boolean shouldHaveReaders) throws
666666
if (!shouldHaveReaders) {
667667
// The expected state is for finalizeSource to sleep instead of exiting
668668
while (true) {
669-
StackTraceElement[] callStack = thread.getStackTrace();
670-
if (callStack.length >= 2
671-
&& "sleep".equals(callStack[0].getMethodName())
672-
&& "finalizeSource".equals(callStack[1].getMethodName())) {
669+
if (isInFinalizeSource(thread.getStackTrace())) {
673670
break;
674671
}
675672
Thread.sleep(10);
@@ -694,6 +691,15 @@ private static void testSourceDoesNotShutdown(boolean shouldHaveReaders) throws
694691
assertThat(thread.isAlive(), is(false));
695692
}
696693

694+
private static boolean isInFinalizeSource(StackTraceElement[] callStack) {
695+
for (StackTraceElement frame : callStack) {
696+
if ("finalizeSource".equals(frame.getMethodName())) {
697+
return true;
698+
}
699+
}
700+
return false;
701+
}
702+
697703
@Test
698704
public void testSequentialReadingFromBoundedSource() throws Exception {
699705
UnboundedReadFromBoundedSource.BoundedToUnboundedSourceAdapter<Long> source =

0 commit comments

Comments
 (0)