You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by tk...@apache.org on 2022/10/06 14:16:40 UTC
[ignite] branch master updated: IGNITE-17805 Fail a test if it tries to launch remote JVM with different major Java version (#10287)
This is an automated email from the ASF dual-hosted git repository.
tkalkirill pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 830e7315265 IGNITE-17805 Fail a test if it tries to launch remote JVM with different major Java version (#10287)
830e7315265 is described below
commit 830e73152652b6ddbf48b83a35acd7522445f0e4
Author: Roman Puchkovskiy <ro...@gmail.com>
AuthorDate: Thu Oct 6 18:16:30 2022 +0400
IGNITE-17805 Fail a test if it tries to launch remote JVM with different major Java version (#10287)
---
.../junits/IgniteCompatibilityAbstractTest.java | 2 +-
.../ignite/internal/util/GridJavaProcess.java | 22 ++++++-
.../testframework/junits/GridAbstractTest.java | 2 +-
.../junits/multijvm/IgniteProcessProxy.java | 49 ++++++++++----
.../junits/multijvm/JavaVersionCommand.java | 68 ++++++++++++++++++++
.../junits/multijvm/JavaVersionCommandParser.java | 48 ++++++++++++++
.../multijvm/JavaVersionCommandParserTest.java | 74 ++++++++++++++++++++++
.../ignite/testsuites/IgniteBasicTestSuite.java | 2 +
8 files changed, 249 insertions(+), 18 deletions(-)
diff --git a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
index 46e94db7c2e..384d17bde6f 100644
--- a/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
+++ b/modules/compatibility/src/test/java/org/apache/ignite/compatibility/testframework/junits/IgniteCompatibilityAbstractTest.java
@@ -145,7 +145,7 @@ public abstract class IgniteCompatibilityAbstractTest extends GridCommonAbstract
final ListeningTestLogger logger = new ListeningTestLogger(log);
- IgniteProcessProxy ignite = new IgniteProcessProxy(cfg, logger, locJvmInstance == null ? null : (x) -> locJvmInstance, true) {
+ IgniteProcessProxy ignite = new IgniteProcessProxy(cfg, logger, locJvmInstance == null ? null : () -> locJvmInstance, true) {
@Override protected IgniteLogger logger(IgniteLogger log, Object ctgr) {
return logger.getLogger(ctgr + "#" + ver.replaceAll("\\.", "_"));
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/GridJavaProcess.java b/modules/core/src/main/java/org/apache/ignite/internal/util/GridJavaProcess.java
index 30312e6f835..be2a6c275c9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/GridJavaProcess.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/GridJavaProcess.java
@@ -142,8 +142,7 @@ public final class GridJavaProcess {
List<String> procCommands = new ArrayList<>();
- String javaBin = (javaHome == null ? System.getProperty("java.home") : javaHome) +
- File.separator + "bin" + File.separator + "java";
+ String javaBin = resolveJavaBin(javaHome);
procCommands.add(javaBin);
procCommands.addAll(jvmArgs == null ? U.jvmArgs() : jvmArgs);
@@ -183,6 +182,25 @@ public final class GridJavaProcess {
return gjProc;
}
+ /**
+ * Resolves path to java binary (that can be executed using exec). Either the provided java home directory
+ * is used, or, if it's {@code null}, the java.home system property is consulted with.
+ *
+ * @param javaHome Java home directory where to look for bin/java; if {@code null}, then java.home property value is used.
+ * @return Path to Java executable.
+ */
+ public static String resolveJavaBin(@Nullable String javaHome) {
+ return resolveJavaHome(javaHome) + File.separator + "bin" + File.separator + "java";
+ }
+
+ /**
+ * Returns the provided java home path or, if it's {@code null}, falls back to the path obtained via 'java.home'
+ * system property.
+ */
+ private static String resolveJavaHome(@Nullable String javaHome) {
+ return javaHome == null ? System.getProperty("java.home") : javaHome;
+ }
+
/**
* Kills the java process.
*
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
index d61a62e982e..95b0ae37abe 100755
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java
@@ -1429,7 +1429,7 @@ public abstract class GridAbstractTest extends JUnitAssertAware {
}
}
- return new IgniteProcessProxy(cfg, cfg.getGridLogger(), (x) -> grid(0), resetDiscovery, additionalRemoteJvmArgs());
+ return new IgniteProcessProxy(cfg, cfg.getGridLogger(), () -> grid(0), resetDiscovery, additionalRemoteJvmArgs());
}
/**
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java
index 436fd8abd53..7080a59e817 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java
@@ -17,6 +17,7 @@
package org.apache.ignite.testframework.junits.multijvm;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -28,7 +29,7 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
+import java.util.function.Supplier;
import javax.cache.CacheException;
import org.apache.ignite.DataRegionMetrics;
import org.apache.ignite.DataRegionMetricsAdapter;
@@ -101,6 +102,8 @@ import org.apache.ignite.testframework.junits.IgniteTestResources;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import static org.junit.Assert.fail;
+
/**
* Ignite proxy for ignite instance at another JVM.
*/
@@ -122,7 +125,7 @@ public class IgniteProcessProxy implements IgniteEx {
private final transient IgniteConfiguration cfg;
/** Local JVM grid. */
- private final transient Function<Void, Ignite> locJvmGrid;
+ private final transient Supplier<Ignite> locJvmGrid;
/** Logger. */
private final transient IgniteLogger log;
@@ -138,7 +141,7 @@ public class IgniteProcessProxy implements IgniteEx {
*/
public IgniteProcessProxy(IgniteConfiguration cfg, IgniteLogger log, Ignite locJvmGrid)
throws Exception {
- this(cfg, log, (Function<Void, Ignite>)locJvmGrid, true);
+ this(cfg, log, locJvmGrid == null ? null : () -> locJvmGrid, true);
}
/**
@@ -147,7 +150,7 @@ public class IgniteProcessProxy implements IgniteEx {
* @param locJvmGrid Local JVM grid.
* @throws Exception On error.
*/
- public IgniteProcessProxy(IgniteConfiguration cfg, IgniteLogger log, Function<Void, Ignite> locJvmGrid, boolean discovery)
+ public IgniteProcessProxy(IgniteConfiguration cfg, IgniteLogger log, Supplier<Ignite> locJvmGrid, boolean discovery)
throws Exception {
this(cfg, log, locJvmGrid, discovery, Collections.emptyList());
}
@@ -162,7 +165,7 @@ public class IgniteProcessProxy implements IgniteEx {
public IgniteProcessProxy(
IgniteConfiguration cfg,
IgniteLogger log,
- Function<Void, Ignite> locJvmGrid,
+ Supplier<Ignite> locJvmGrid,
boolean resetDiscovery,
List<String> additionalArgs
)
@@ -172,6 +175,9 @@ public class IgniteProcessProxy implements IgniteEx {
this.locJvmGrid = locJvmGrid;
this.log = logger(log, "jvm-" + id.toString().substring(0, id.toString().indexOf('-')));
+ final String javaHome = System.getProperty(TEST_MULTIJVM_JAVA_HOME);
+ validateRemoteJre(javaHome);
+
String params = params(cfg, resetDiscovery);
Collection<String> filteredJvmArgs = filteredJvmArgs();
@@ -180,7 +186,7 @@ public class IgniteProcessProxy implements IgniteEx {
final CountDownLatch rmtNodeStartedLatch = new CountDownLatch(1);
if (locJvmGrid != null)
- locJvmGrid.apply(null).events()
+ locJvmGrid.get().events()
.localListen(new NodeStartedListener(id, rmtNodeStartedLatch), EventType.EVT_NODE_JOINED);
proc = GridJavaProcess.exec(
@@ -188,14 +194,10 @@ public class IgniteProcessProxy implements IgniteEx {
params,
this.log,
// Optional closure to be called each time wrapped process prints line to system.out or system.err.
- new IgniteInClosure<String>() {
- @Override public void apply(String s) {
- IgniteProcessProxy.this.log.info(s);
- }
- },
+ (IgniteInClosure<String>)this.log::info,
null,
- System.getProperty(TEST_MULTIJVM_JAVA_HOME),
- filteredJvmArgs, // JVM Args.
+ javaHome,
+ filteredJvmArgs,
System.getProperty("surefire.test.class.path")
);
@@ -212,6 +214,25 @@ public class IgniteProcessProxy implements IgniteEx {
}
}
+ /**
+ * Validates that the JRE corresponding to the given Java home is valid for use as a remote JVM.
+ * This currently means only checking that its major version matches the major version of the JRE we run on.
+ *
+ * @param javaHome Java home.
+ * @throws IOException If I/O fails when interacting with 'java' process.
+ * @throws InterruptedException If we get interrupted.
+ */
+ private static void validateRemoteJre(@Nullable String javaHome) throws IOException, InterruptedException {
+ int remoteMajorVersion = new JavaVersionCommand().majorVersion(javaHome);
+ int localMajorVersion = U.majorJavaVersion(System.getProperty("java.version"));
+
+ if (localMajorVersion != remoteMajorVersion) {
+ fail("Version of remote java with home at '" + javaHome + "' (" + remoteMajorVersion +
+ ") is different from local java version (" + localMajorVersion + "). " +
+ "Make sure test.multijvm.java.home property specifies a path to a correct Java installation");
+ }
+ }
+
/**
* Creates new logger instance based on given logger and given category.
*
@@ -432,7 +453,7 @@ public class IgniteProcessProxy implements IgniteEx {
* @return Local JVM grid instance.
*/
public Ignite localJvmGrid() {
- return locJvmGrid.apply(null);
+ return locJvmGrid.get();
}
/**
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/JavaVersionCommand.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/JavaVersionCommand.java
new file mode 100644
index 00000000000..c0ebf16df05
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/JavaVersionCommand.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.testframework.junits.multijvm;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.TimeUnit;
+import org.apache.commons.io.IOUtils;
+import org.apache.ignite.internal.util.GridJavaProcess;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Utility to work with 'java -version' command.
+ */
+class JavaVersionCommand {
+ /**
+ * Obtains major Java version for Java located at the given path.
+ *
+ * @param javaHome Java home path.
+ * @return Major Java version (like 8 or 11).
+ * @throws IOException If something goes wrong.
+ */
+ int majorVersion(String javaHome) throws IOException, InterruptedException {
+ Process process = new ProcessBuilder(GridJavaProcess.resolveJavaBin(javaHome), "-version").start();
+ assertTrue(process.waitFor(10, TimeUnit.SECONDS));
+
+ if (process.exitValue() != 0) {
+ throw new IllegalStateException("'java -version' failed, stdin '" +
+ readStream(process.getInputStream()) + "', stdout '" +
+ readStream(process.getErrorStream()) + "'");
+ }
+
+ String versionOutput = readStream(process.getErrorStream());
+
+ return JavaVersionCommandParser.extractMajorVersion(versionOutput);
+ }
+
+ /**
+ * Reads whole stream content and returns it as a string. UTF-8 is used to convert from bytes to string.
+ *
+ * @param inputStream Stream to read.
+ * @return Stream content as a string.
+ * @throws IOException If something goes wrong.
+ */
+ private String readStream(InputStream inputStream) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ IOUtils.copy(inputStream, baos);
+ return new String(baos.toByteArray(), UTF_8);
+ }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/JavaVersionCommandParser.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/JavaVersionCommandParser.java
new file mode 100644
index 00000000000..2ce890ca8d5
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/JavaVersionCommandParser.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.testframework.junits.multijvm;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Parses output of 'java -version'.
+ */
+class JavaVersionCommandParser {
+ /** Pattern for parsing 'java -version' command output. */
+ private static final Pattern versionPattern = Pattern.compile("java version \"([^\"]+)\".*", Pattern.DOTALL);
+
+ /**
+ * Extracts major java version (like '17' or '1.8') from 'java -version' output.
+ *
+ * @param versionCommandOutput Output to parse.
+ * @return Major java version.
+ */
+ static int extractMajorVersion(String versionCommandOutput) {
+ Matcher matcher = versionPattern.matcher(versionCommandOutput);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("Cannot parse the following as java version output: '" +
+ versionCommandOutput + "'");
+ }
+
+ String fullJavaVersion = matcher.group(1);
+
+ return U.majorJavaVersion(fullJavaVersion);
+ }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/JavaVersionCommandParserTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/JavaVersionCommandParserTest.java
new file mode 100644
index 00000000000..cbd12b910b4
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/JavaVersionCommandParserTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.testframework.junits.multijvm;
+
+import java.util.Arrays;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * Tests for {@link JavaVersionCommandParser}.
+ */
+@RunWith(Parameterized.class)
+public class JavaVersionCommandParserTest {
+ /** 'java -version' command output. */
+ @Parameterized.Parameter(0)
+ public String commandOutput;
+
+ /** Major version corresponding to the output. */
+ @Parameterized.Parameter(1)
+ public int majorVersion;
+
+ /** Returns dataset for testing major version extraction. */
+ @Parameterized.Parameters()
+ public static Collection<Object[]> dataset() {
+ return Arrays.asList(
+ new Object[]{
+ "java version \"1.8.0_311\"\n" +
+ "Java(TM) SE Runtime Environment (build 1.8.0_311-b11)\n" +
+ "Java HotSpot(TM) Server VM (build 25.311-b11, mixed mode)",
+ 8
+ },
+ new Object[]{
+ "java version \"11.0.6\" 2020-01-14 LTS\n" +
+ "Java(TM) SE Runtime Environment 18.9 (build 11.0.6+8-LTS)\n" +
+ "Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.6+8-LTS, mixed mode)",
+ 11
+ },
+ new Object[]{
+ "java version \"19\" 2022-09-20\n" +
+ "Java(TM) SE Runtime Environment (build 19+36-2238)\n" +
+ "Java HotSpot(TM) 64-Bit Server VM (build 19+36-2238, mixed mode, sharing)\n",
+ 19
+ }
+ );
+ }
+
+ /**
+ * Tests major version extraction.
+ */
+ @Test
+ public void extractsMajorVersion() {
+ assertThat(JavaVersionCommandParser.extractMajorVersion(commandOutput), is(majorVersion));
+ }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
index 6e2dd6c693b..3ae20c00739 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
@@ -67,6 +67,7 @@ import org.apache.ignite.messaging.IgniteMessagingSendAsyncTest;
import org.apache.ignite.messaging.IgniteMessagingWithClientTest;
import org.apache.ignite.spi.GridSpiLocalHostInjectionTest;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTestSelfTest;
+import org.apache.ignite.testframework.junits.multijvm.JavaVersionCommandParserTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -143,6 +144,7 @@ import org.junit.runners.Suite;
OdbcConfigurationValidationSelfTest.class,
OdbcEscapeSequenceSelfTest.class,
SqlListenerUtilsTest.class,
+ JavaVersionCommandParserTest.class
})
public class IgniteBasicTestSuite {
}