diff --git a/test/functional/buildAndPackage/build.xml b/test/functional/buildAndPackage/build.xml new file mode 100644 index 000000000..8559411b0 --- /dev/null +++ b/test/functional/buildAndPackage/build.xml @@ -0,0 +1,71 @@ + + + + + + + + AdoptOpenJDK Functional tests + + + + + + + + + + + + + + + + + Ant version is ${ant.version} + ============COMPILER SETTINGS============ + ===fork: yes + ===executable: ${compiler.javac} + ===debug: on + ===destdir: ${DEST} + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/functional/buildAndPackage/playlist.xml b/test/functional/buildAndPackage/playlist.xml new file mode 100644 index 000000000..32ec8b7c7 --- /dev/null +++ b/test/functional/buildAndPackage/playlist.xml @@ -0,0 +1,74 @@ + + + + + + Adopt_HS_FeatureTests + + $(JAVA_COMMAND) $(JVM_OPTIONS) -cp \ + $(Q)$(RESOURCES_DIR)$(P)$(TESTNG)$(P)$(TEST_RESROOT)$(D)BuildAndPackagingTests.jar$(Q) org.testng.TestNG \ + $(Q)$(TEST_RESROOT)$(D)testng.xml$(Q) -d $(REPORTDIR) -testnames CommonFeatureTests,HotspotFeatureTests -groups $(TEST_GROUP) \ + -excludegroups $(DEFAULT_EXCLUDE); $(TEST_STATUS) + + + extended + + + functional + + + hotspot + + + adoptopenjdk + + + + Adopt_J9_FeatureTests + + $(JAVA_COMMAND) $(JVM_OPTIONS) -cp \ + $(Q)$(RESOURCES_DIR)$(P)$(TESTNG)$(P)$(TEST_RESROOT)$(D)BuildAndPackagingTests.jar$(Q) org.testng.TestNG \ + $(Q)$(TEST_RESROOT)$(D)testng.xml$(Q) -d $(REPORTDIR) -testnames CommonFeatureTests -groups $(TEST_GROUP) \ + -excludegroups $(DEFAULT_EXCLUDE); $(TEST_STATUS) + + + extended + + + functional + + + openj9 + + + + CudaEnabledTest + $(JAVA_COMMAND) $(JVM_OPTIONS) -cp $(Q)$(RESOURCES_DIR)$(P)$(TESTNG)$(P)$(TEST_RESROOT)$(D)BuildAndPackagingTests.jar$(Q) org.testng.TestNG $(Q)$(TEST_RESROOT)$(D)testng.xml$(Q) -d $(REPORTDIR) -testnames CudaEnabledTest -groups $(TEST_GROUP) -excludegroups $(DEFAULT_EXCLUDE); \ + $(TEST_STATUS) + + extended + + + functional + + os.linux + + openj9 + + + adoptopenjdk + + + \ No newline at end of file diff --git a/test/functional/buildAndPackage/src/net/adoptopenjdk/test/BundledFreetypeTest.java b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/BundledFreetypeTest.java new file mode 100644 index 000000000..1da72c267 --- /dev/null +++ b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/BundledFreetypeTest.java @@ -0,0 +1,64 @@ +/* + * Licensed 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 + * + * https://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 net.adoptopenjdk.test; + +import org.testng.annotations.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; +import java.util.logging.Logger; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static net.adoptopenjdk.test.JdkPlatform.OperatingSystem; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +/** + * Freetype needs to be bundled on Windows and macOS but should not be present on Linux or AIX. + * + * @see AdoptOpenJDK enhancement request + */ +@Test(groups = {"level.extended"}) +public class BundledFreetypeTest { + + private static final Logger LOGGER = Logger.getLogger(BundledFreetypeTest.class.getName()); + + private final JdkPlatform jdkPlatform = new JdkPlatform(); + + @Test + public void freetypeOnlyBundledOnWindowsAndMacOS() throws IOException { + String testJdkHome = System.getenv("TEST_JDK_HOME"); + if (testJdkHome == null) { + throw new AssertionError("TEST_JDK_HOME is not set"); + } + + Pattern freetypePattern = Pattern.compile("(.*)?libfreetype\\.(dll|dylib|so)$"); + Set freetypeFiles = Files.walk(Paths.get(testJdkHome)) + .map(Path::toString) + .filter(name -> freetypePattern.matcher(name).matches()) + .collect(Collectors.toSet()); + + if (jdkPlatform.runsOn(OperatingSystem.MACOS) || jdkPlatform.runsOn(OperatingSystem.WINDOWS)) { + assertTrue(freetypeFiles.size() > 0, "Expected libfreetype to be bundled but is not."); + } else { + LOGGER.info("Found freetype-related files: " + freetypeFiles.toString()); + assertEquals(freetypeFiles.size(), 0, "Expected libfreetype not to be bundled but it is."); + } + } +} \ No newline at end of file diff --git a/test/functional/buildAndPackage/src/net/adoptopenjdk/test/CudaEnabledTest.java b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/CudaEnabledTest.java new file mode 100644 index 000000000..9ca79bf79 --- /dev/null +++ b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/CudaEnabledTest.java @@ -0,0 +1,103 @@ +package net.adoptopenjdk.test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.Scanner; +import org.testng.Assert; +import org.testng.annotations.Test; +import org.testng.log4testng.Logger; + +/* + * Tests if the Cuda functionality is enabled in this build. + * Fit for OpenJ9 builds on Windows, xLinux and pLinux. + */ +@Test(groups={ "level.extended" }) +public class CudaEnabledTest { + + private static Logger logger = Logger.getLogger(CudaEnabledTest.class); + + public int getJDKVersion() { + String javaVersion = System.getProperty("java.version"); + if (javaVersion.startsWith("1.")) { + javaVersion = javaVersion.substring(2); + } + int dotIndex = javaVersion.indexOf('.'); + int dashIndex = javaVersion.indexOf('-'); + try { + return Integer.parseInt(javaVersion.substring(0, dotIndex > -1 ? dotIndex : dashIndex > -1 ? dashIndex : javaVersion.length())); + } catch (NumberFormatException e) { + System.out.println("Cannot determine System.getProperty('java.version')=" + javaVersion + "\n"); + return -1; + } + } + + @Test + public void testIfCudaIsEnabled() { + + logger.info("Starting test to see if CUDA functionality is enabled in this build."); + + //Stage 1: Find the location of the j9prt lib file. + String prtLibDirectory = System.getProperty("java.home"); + String jreSubdir = ""; + if((new File(prtLibDirectory + "/jre")).exists()) { + jreSubdir = "/jre"; + } + if("Linux".contains(System.getProperty("os.name").split(" ")[0])) { + if(getJDKVersion() == 8) { + prtLibDirectory += jreSubdir + "/lib/amd64/compressedrefs"; + } else { + prtLibDirectory += "/lib/compressedrefs"; + } + } + //windows + if("Windows".contains(System.getProperty("os.name").split(" ")[0])) { + if(getJDKVersion() == 8) { + //jdk8 32: + prtLibDirectory += jreSubdir + "/bin/compressedrefs"; + if(!(new File(prtLibDirectory)).exists()) { + //In case of a 32-bit build, or a non-cr build. + prtLibDirectory = System.getProperty("java.home") + jreSubdir + "/bin/default"; + } + } else { + prtLibDirectory += "/bin/compressedrefs"; + } + } + + File prtDirObject = new File(prtLibDirectory); + Assert.assertTrue(prtDirObject.exists(), "Can't find the predicted location of the j9prt lib file. Expected location: " + prtLibDirectory); + + String[] prtLibDirectoryFiles = prtDirObject.list(); + String prtFile = null; + for(int x = 0 ; x < prtLibDirectoryFiles.length ; x++) { + if(prtLibDirectoryFiles[x].contains("j9prt")) { + prtFile = prtLibDirectory + "/" + prtLibDirectoryFiles[x]; + break; + } + } + Assert.assertNotNull(prtFile,"Can't find the j9prt lib file in " + prtLibDirectory); + Assert.assertTrue((new File (prtFile)).exists(), "Found the prt file, but it doesn't exist. Tautology bug."); + Assert.assertTrue((new File (prtFile)).canRead(), "Found the prt file, but it can't be read. Likely a permissions bug."); + + //Stage 2: Iterate through the j9prt lib file to find "cudart". + //If we find it, then cuda functionality is enabled on this build. + try { + BufferedReader prtFileReader = new BufferedReader(new FileReader(prtFile)); + String oneLine = ""; + while ((oneLine = prtFileReader.readLine()) != null) { + if(oneLine.contains("cudart")) { + logger.info("Test completed successfully."); + return; //Success! + } + } + prtFileReader.close(); + } catch (FileNotFoundException e) { + Assert.fail("A file that exists could not be found. This should never happen."); + } catch (Exception e) { + throw new Error(e); + } + Assert.fail("Cuda should be enabled on this build, but we found no evidence that this was the case."); + } + +} \ No newline at end of file diff --git a/test/functional/buildAndPackage/src/net/adoptopenjdk/test/FeatureTests.java b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/FeatureTests.java new file mode 100644 index 000000000..f7070a20d --- /dev/null +++ b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/FeatureTests.java @@ -0,0 +1,183 @@ +/* + * Licensed 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 + * + * https://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 net.adoptopenjdk.test; + +import org.testng.annotations.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import static net.adoptopenjdk.test.JdkPlatform.Architecture; +import static net.adoptopenjdk.test.JdkPlatform.OperatingSystem; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +/** + * Tests the availability of various features like garbage collectors, flight recorder, that need to be enabled via + * command line flags. + */ +@Test(groups = {"level.extended"}) +public class FeatureTests { + + private static final Logger LOGGER = Logger.getLogger(FeatureTests.class.getName()); + + private final JdkVersion jdkVersion = new JdkVersion(); + + private final JdkPlatform jdkPlatform = new JdkPlatform(); + + /** + * Tests whether Shenandoah GC is available. + *

+ * Shenandoah GC was enabled by default with JDK 15 (JEP 379) and backported to 11.0.9. + * + * @see JEP 379: Shenandoah: A Low-Pause-Time Garbage + * Collector (Production) + * @see JDK-8250784 (Backport) + * @see Shenandoah Support + * Overview + */ + @Test + public void testShenandoahAvailable() { + String testJdkHome = System.getenv("TEST_JDK_HOME"); + if (testJdkHome == null) { + throw new AssertionError("TEST_JDK_HOME is not set"); + } + + boolean shouldBePresent = false; + if ((jdkVersion.isNewerOrEqual(15) || jdkVersion.isNewerOrEqualSameFeature(11, 0, 9))) { + if (jdkPlatform.runsOn(OperatingSystem.LINUX, Architecture.AARCH64) + || jdkPlatform.runsOn(OperatingSystem.LINUX, Architecture.X86) + || jdkPlatform.runsOn(OperatingSystem.LINUX, Architecture.X64) + || jdkPlatform.runsOn(OperatingSystem.MACOS, Architecture.X64) + || jdkPlatform.runsOn(OperatingSystem.MACOS, Architecture.AARCH64) + || jdkPlatform.runsOn(OperatingSystem.WINDOWS, Architecture.X64) + || jdkPlatform.runsOn(OperatingSystem.WINDOWS, Architecture.AARCH64) + ) { + shouldBePresent = true; + } + } + + LOGGER.info(String.format("Detected %s on %s, expect Shenandoah to be present: %s", + jdkVersion, jdkPlatform, shouldBePresent)); + + List command = new ArrayList<>(); + command.add(String.format("%s/bin/java", testJdkHome)); + command.add("-XX:+UseShenandoahGC"); + command.add("-version"); + + try { + ProcessBuilder processBuilder = new ProcessBuilder(command); + processBuilder.inheritIO(); + + int retCode = processBuilder.start().waitFor(); + if (shouldBePresent) { + assertEquals(retCode, 0, "Expected Shenandoah to be present but it is absent."); + } else { + assertTrue(retCode > 0, "Expected Shenandoah to be absent but it is present."); + } + } catch (InterruptedException | IOException e) { + throw new RuntimeException("Failed to launch JVM", e); + } + } + + /** + * Tests whether Z Garbage Collector is available. + *

+ * Z Garbage Collector was enabled by default with JDK 15 (JEP 377). + * + * @see JEP 377: ZGC: A Scalable Low-Latency Garbage Collector + * (Production) + */ + @Test + public void testZGCAvailable() { + String testJdkHome = System.getenv("TEST_JDK_HOME"); + if (testJdkHome == null) { + throw new AssertionError("TEST_JDK_HOME is not set"); + } + + boolean shouldBePresent = false; + if (jdkVersion.isNewerOrEqual(15)) { + if (jdkPlatform.runsOn(OperatingSystem.LINUX, Architecture.AARCH64) + || jdkPlatform.runsOn(OperatingSystem.LINUX, Architecture.X64) + || jdkPlatform.runsOn(OperatingSystem.MACOS, Architecture.X64) + || jdkPlatform.runsOn(OperatingSystem.WINDOWS, Architecture.X64) + ) { + shouldBePresent = true; + } + } + + LOGGER.info(String.format("Detected %s on %s, expect ZGC to be present: %s", + jdkVersion, jdkPlatform, shouldBePresent)); + + List command = new ArrayList<>(); + command.add(String.format("%s/bin/java", testJdkHome)); + command.add("-XX:+UseZGC"); + command.add("-version"); + + try { + ProcessBuilder processBuilder = new ProcessBuilder(command); + processBuilder.inheritIO(); + + int retCode = processBuilder.start().waitFor(); + if (shouldBePresent) { + assertEquals(retCode, 0, "Expected ZGC to be present but it is absent."); + } else { + assertTrue(retCode > 0, "Expected ZGC to be absent but it is present."); + } + } catch (InterruptedException | IOException e) { + throw new RuntimeException("Failed to launch JVM", e); + } + } + + /** + * Tests whether JDK Flight Recorder is available. + *

+ * JDK Flight recorder was added to JDK 11 (JEP 328) and backported to JDK 8u262. + * + * @see JEP 328: Flight Recorder + * @see command = new ArrayList<>(); + command.add(String.format("%s/bin/java", testJdkHome)); + command.add("-XX:StartFlightRecording"); + command.add("-version"); + try { + ProcessBuilder processBuilder = new ProcessBuilder(command); + processBuilder.inheritIO(); + int retCode = processBuilder.start().waitFor(); + if (shouldBePresent) { + assertEquals(retCode, 0, "Expected JFR to be present but it is absent."); + } else { + assertTrue(retCode > 0, "Expected JFR to be absent but it is present."); + } + } catch (InterruptedException | IOException e) { + throw new RuntimeException("Failed to launch JVM", e); + } + } +} \ No newline at end of file diff --git a/test/functional/buildAndPackage/src/net/adoptopenjdk/test/JdkPlatform.java b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/JdkPlatform.java new file mode 100644 index 000000000..dd9261637 --- /dev/null +++ b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/JdkPlatform.java @@ -0,0 +1,132 @@ +/* + * Licensed 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 + * + * https://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 net.adoptopenjdk.test; + +import java.util.Collection; +import java.util.Locale; + +public class JdkPlatform { + + private final Architecture architecture; + + private final OperatingSystem operatingSystem; + + public JdkPlatform() { + this.architecture = detectArchitecture(); + this.operatingSystem = detectOperatingSystem(); + } + + public boolean runsOn(Architecture architecture) { + return architecture == this.architecture; + } + + public boolean runsOnAnyArchitecture(Collection architectures) { + return architectures.contains(this.architecture); + } + + public boolean runsOn(OperatingSystem operatingSystem) { + return operatingSystem == this.operatingSystem; + } + + public boolean runsOn(OperatingSystem operatingSystem, Architecture architecture) { + return this.runsOn(operatingSystem) && this.runsOn(architecture); + } + + public boolean runsOnAnyOperatingSystem(Collection operatingSystems) { + return operatingSystems.contains(this.operatingSystem); + } + + @Override + public String toString() { + return this.operatingSystem.name() + "/" + this.architecture.name(); + } + + private static Architecture detectArchitecture() { + String arch = normalize(System.getProperty("os.arch")); + + if (arch.matches("^(arm|arm32)$")) { + return Architecture.ARM; + } + if (arch.equals("aarch64")) { + return Architecture.AARCH64; + } + if (arch.equals("ppc64le")) { + return Architecture.PPC64LE; + } + if (arch.equals("riscv")) { + return Architecture.RISCV; + } + if (arch.equals("riscv64")) { + return Architecture.RISCV64; + } + if (arch.matches("^(sparc|sparc32)$")) { + return Architecture.SPARC32; + } + if (arch.matches("^(sparcv9|sparc64)$")) { + return Architecture.SPARC64; + } + if (arch.equals("s390x")) { + return Architecture.S390X; + } + if (arch.matches("^(amd64|em64t|x64|x86_64)$")) { + return Architecture.X64; + } + if (arch.matches("^(x86|i[3-6]86|ia32|x32)$")) { + return Architecture.X86; + } + + throw new AssertionError("Unrecognized architecture: " + arch); + } + + private static OperatingSystem detectOperatingSystem() { + String osName = normalize(System.getProperty("os.name")); + + if (osName.contains("aix")) { + return OperatingSystem.AIX; + } + if (osName.contains("bsd")) { + return OperatingSystem.BSD; + } + if (osName.contains("linux")) { + return OperatingSystem.LINUX; + } + if (osName.contains("mac")) { + return OperatingSystem.MACOS; + } + if (osName.contains("solaris") || osName.contains("sunos")) { + return OperatingSystem.SOLARIS; + } + if (osName.contains("win")) { + return OperatingSystem.WINDOWS; + } + + throw new AssertionError("Unrecognized operating system: " + osName); + } + + private static String normalize(String str) { + if (str == null) { + return ""; + } + return str.trim().toLowerCase(Locale.US); + } + + enum Architecture { + ARM, AARCH64, PPC64LE, RISCV, RISCV64, SPARC32, SPARC64, S390X, X64, X86 + } + + enum OperatingSystem { + AIX, BSD, LINUX, MACOS, SOLARIS, WINDOWS + } +} \ No newline at end of file diff --git a/test/functional/buildAndPackage/src/net/adoptopenjdk/test/JdkVersion.java b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/JdkVersion.java new file mode 100644 index 000000000..7aba40b67 --- /dev/null +++ b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/JdkVersion.java @@ -0,0 +1,127 @@ +/* + * Licensed 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 + * + * https://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 net.adoptopenjdk.test; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class JdkVersion { + + /** + * Matches JDK version numbers that were used before JEP 223 came into effect (JDK 8 and earlier). + */ + private static final Pattern PRE_223_PATTERN = Pattern.compile( + "^(?1\\.(?[0-8]+)\\.0(_(?[0-9]+)))(-(?.*)?)?$" + ); + + private final int feature; + + private final int interim; + + private final int update; + + private final int patch; + + public JdkVersion() { + String versionString = System.getProperty("java.version"); + if (versionString.isEmpty()) { + throw new AssertionError("Property java.version is empty"); + } + + Matcher pre223Matcher = PRE_223_PATTERN.matcher(versionString); + if (pre223Matcher.matches()) { + // Handle 8 or earlier. + this.feature = Integer.parseInt(pre223Matcher.group("major")); + this.interim = 0; + this.update = Integer.parseInt(pre223Matcher.group("update")); + this.patch = 0; + return; + } + + // Handle 9 or newer. + Class runtimeClass = Runtime.class; + try { + Method versionMethod = runtimeClass.getDeclaredMethod("version", (Class[]) null); + Object versionObject = versionMethod.invoke(null, (Object[]) null); + Class versionClass = versionObject.getClass(); + + Method featureMethod; + Method interimMethod; + Method updateMethod; + Method patchMethod; + try { + // Java 10 or newer (https://openjdk.java.net/jeps/322) + featureMethod = versionClass.getDeclaredMethod("feature", (Class[]) null); + interimMethod = versionClass.getDeclaredMethod("interim", (Class[]) null); + updateMethod = versionClass.getDeclaredMethod("update", (Class[]) null); + patchMethod = versionClass.getDeclaredMethod("patch", (Class[]) null); + } catch (NoSuchMethodException e) { + // Java 9 (https://openjdk.java.net/jeps/223) + featureMethod = versionClass.getDeclaredMethod("major", (Class[]) null); + interimMethod = versionClass.getDeclaredMethod("minor", (Class[]) null); + updateMethod = versionClass.getDeclaredMethod("security", (Class[]) null); + patchMethod = null; + } + + feature = (int) featureMethod.invoke(versionObject, (Object[]) null); + interim = (int) interimMethod.invoke(versionObject, (Object[]) null); + update = (int) updateMethod.invoke(versionObject, (Object[]) null); + if (patchMethod != null) { + patch = (int) patchMethod.invoke(versionObject, (Object[]) null); + } else { + patch = 0; + } + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new AssertionError("Cannot determine JDK version", e); + } + } + + public int getFeature() { + return feature; + } + + public int getInterim() { + return interim; + } + + public int getUpdate() { + return update; + } + + public int getPatch() { + return patch; + } + + public boolean isNewerOrEqual(int feature) { + return this.feature >= feature; + } + + public boolean isNewerOrEqualSameFeature(int feature, int interim, int update) { + if (this.feature != feature) { + return false; + } + if (this.interim >= interim) { + return true; + } + return this.update >= update; + } + + @Override + public String toString() { + return feature + "." + interim + "." + update + "." + patch; + } +} \ No newline at end of file diff --git a/test/functional/buildAndPackage/src/net/adoptopenjdk/test/StreamUtils.java b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/StreamUtils.java new file mode 100644 index 000000000..85599746c --- /dev/null +++ b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/StreamUtils.java @@ -0,0 +1,45 @@ +/* + * Licensed 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 + * + * https://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 net.adoptopenjdk.test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public final class StreamUtils { + + private StreamUtils() { + // no instances + } + + /** + * Reads the entire {@link InputStream} into a string. + * + * @throws IOException If an I/O error occurs + */ + public static String consumeStream(InputStream inputStream) throws IOException { + String lineSeparator = System.getProperty("line.separator"); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line); + builder.append(lineSeparator); + } + return builder.toString(); + } + } +} \ No newline at end of file diff --git a/test/functional/buildAndPackage/src/net/adoptopenjdk/test/VendorPropertiesTest.java b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/VendorPropertiesTest.java new file mode 100644 index 000000000..78356f698 --- /dev/null +++ b/test/functional/buildAndPackage/src/net/adoptopenjdk/test/VendorPropertiesTest.java @@ -0,0 +1,223 @@ +/* + * Licensed 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 + * + * https://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 net.adoptopenjdk.test; + +import org.testng.annotations.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertTrue; + +/** + * Tests whether vendor names and correct URLs appear in all the places they are supposed to. + */ +@Test(groups = {"level.extended"}) +public class VendorPropertiesTest { + + private final VmPropertiesChecks vendorChecks; + + public VendorPropertiesTest() { + Set allPropertiesChecks = new LinkedHashSet<>(); + allPropertiesChecks.add(new AdoptOpenJDKPropertiesChecks()); + allPropertiesChecks.add(new CorrettoPropertiesChecks()); + + // TODO: Somehow obtain the vendor name from the outside. Using any JVM properties is not a solution + // because that's what we want to test here. + String vendor = "AdoptOpenJDK"; + this.vendorChecks = allPropertiesChecks.stream() + .filter(checks -> checks.supports(vendor)) + .findFirst() + .orElseThrow(() -> new AssertionError("No checks found for vendor: " + vendor)); + } + + @Test + public void javaVersionPrintsVendor() { + String testJdkHome = System.getenv("TEST_JDK_HOME"); + if (testJdkHome == null) { + throw new AssertionError("TEST_JDK_HOME is not set"); + } + + List command = new ArrayList<>(); + command.add(String.format("%s/bin/java", testJdkHome)); + command.add("-version"); + + try { + ProcessBuilder processBuilder = new ProcessBuilder(command); + Process process = processBuilder.start(); + + String stderr = StreamUtils.consumeStream(process.getErrorStream()); + + if (process.waitFor() != 0) { + throw new AssertionError("Could not run java -version"); + } + + this.vendorChecks.javaVersion(stderr); + } catch (InterruptedException | IOException e) { + throw new RuntimeException("Failed to launch JVM", e); + } + } + + @Test + public void vmPropertiesPointToVendor() { + this.vendorChecks.javaVendor(System.getProperty("java.vendor")); + this.vendorChecks.javaVendorUrl(System.getProperty("java.vendor.url")); + this.vendorChecks.javaVendorUrlBug(System.getProperty("java.vendor.url.bug")); + this.vendorChecks.javaVendorVersion(System.getProperty("java.vendor.version")); + this.vendorChecks.javaVmVendor(System.getProperty("java.vm.vendor")); + this.vendorChecks.javaVmVersion(System.getProperty("java.vm.version")); + } + + private interface VmPropertiesChecks { + /** + * Tests whether the implementation of {@linkplain VmPropertiesChecks} is suitable to verify a JDK. + * + * @param vendor Name identifying the vendor. + */ + boolean supports(String vendor); + + /** + * Checks whether the output of {@code java -version} is acceptable. + */ + void javaVersion(String value); + + /** + * Checks the value of {@code java.vendor}. + */ + void javaVendor(String value); + + /** + * Checks the value of {@code java.vendor.url}. + */ + void javaVendorUrl(String value); + + /** + * Checks the value of {@code java.vendor.url.bug}. + */ + void javaVendorUrlBug(String value); + + /** + * Checks the value of {@code java.vendor.version}. + */ + void javaVendorVersion(String value); + + /** + * Checks the value of {@code java.vm.vendor}. + */ + void javaVmVendor(String value); + + /** + * Checks the value of {@code java.vm.version}. + */ + void javaVmVersion(String value); + } + + private static class AdoptOpenJDKPropertiesChecks implements VmPropertiesChecks { + + @Override + public boolean supports(String vendor) { + return vendor.toLowerCase(Locale.US).equals("adoptopenjdk"); + } + + @Override + public void javaVersion(String value) { + assertTrue(value.contains("AdoptOpenJDK")); + } + + @Override + public void javaVendor(String value) { + assertEquals(value, "AdoptOpenJDK"); + } + + @Override + public void javaVendorUrl(String value) { + assertEquals(value, "https://adoptopenjdk.net/"); + } + + @Override + public void javaVendorUrlBug(String value) { + assertEquals(value, "https://github.com/AdoptOpenJDK/openjdk-support/issues"); + } + + @Override + public void javaVendorVersion(String value) { + assertNotEquals(value.replaceAll("[^0-9]", "").length(), 0, + "java.vendor.version contains no numbers: " + value); + } + + @Override + public void javaVmVendor(String value) { + assertEquals(value, "AdoptOpenJDK"); + } + + @Override + public void javaVmVersion(String value) { + assertNotEquals(value.replaceAll("[^0-9]", "").length(), 0, + "java.vm.version contains no numbers: " + value); + } + } + + private static class CorrettoPropertiesChecks implements VmPropertiesChecks { + + @Override + public boolean supports(String vendor) { + return vendor.toLowerCase(Locale.US).startsWith("amazon"); + } + + @Override + public void javaVersion(String value) { + assertTrue(value.contains("Corretto")); + } + + @Override + public void javaVendor(String value) { + assertEquals(value, "Amazon.com Inc."); + } + + @Override + public void javaVendorUrl(String value) { + assertEquals(value, "https://aws.amazon.com/corretto/"); + } + + @Override + public void javaVendorUrlBug(String value) { + assertTrue(value.startsWith("https://github.com/corretto/corretto")); + } + + @Override + public void javaVendorVersion(String value) { + assertTrue(value.startsWith("Corretto")); + assertNotEquals(value.replaceAll("[^0-9]", "").length(), 0, + "java.vendor.version contains no numbers: " + value); + } + + @Override + public void javaVmVendor(String value) { + assertEquals(value, "Amazon.com Inc."); + } + + @Override + public void javaVmVersion(String value) { + assertNotEquals(value.replaceAll("[^0-9]", "").length(), 0, + "java.vm.version contains no numbers: " + value); + } + } +} \ No newline at end of file diff --git a/test/functional/buildAndPackage/testng.xml b/test/functional/buildAndPackage/testng.xml new file mode 100644 index 000000000..35b24fdbf --- /dev/null +++ b/test/functional/buildAndPackage/testng.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file