Allow parsing the value of java.version sysprop (#44017)

We often start testing with early access versions of new Java
versions and this have caused minor issues in our tests
(i.e. #43141) because the version string that the JVM reports
cannot be parsed as it ends with the string -ea.

This commit changes how we parse and compare Java versions to
allow correct parsing and comparison of the output of java.version
system property that might include an additional alphanumeric
part after the version numbers
 (see [JEP 223[(https://openjdk.java.net/jeps/223)). In short it 
handles a version number part, like before, but additionally a 
PRE part that matches ([a-zA-Z0-9]+).

It also changes a number of tests that would attempt to parse
java.specification.version in order to get the full version
of Java. java.specification.version only contains the major
version and is thus inappropriate when trying to compare against
a version that might contain a minor, patch or an early access
part. We know parse java.version that can be consistently
parsed.

Resolves #43141
This commit is contained in:
Ioannis Kakavas 2019-07-22 20:13:32 +03:00
parent 2a4380e0aa
commit 3714cb63da
9 changed files with 115 additions and 23 deletions

View File

@ -134,7 +134,7 @@ public class RestClientBuilderIntegTests extends RestClientTestCase {
* 12.0.1 so we pin to TLSv1.2 when running on an earlier JDK.
*/
private static String getProtocol() {
String version = AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty("java.specification.version"));
String version = AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty("java.version"));
String[] components = version.split("\\.");
if (components.length > 0) {
final int major = Integer.valueOf(components[0]);

View File

@ -19,6 +19,7 @@
package org.elasticsearch.bootstrap;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -28,12 +29,14 @@ import java.util.stream.Collectors;
public class JavaVersion implements Comparable<JavaVersion> {
private final List<Integer> version;
private final String prePart;
public List<Integer> getVersion() {
return version;
}
private JavaVersion(List<Integer> version) {
private JavaVersion(List<Integer> version, String prePart) {
this.prePart = prePart;
if (version.size() >= 2 && version.get(0) == 1 && version.get(1) == 8) {
// for Java 8 there is ambiguity since both 1.8 and 8 are supported,
// so we rewrite the former to the latter
@ -42,23 +45,38 @@ public class JavaVersion implements Comparable<JavaVersion> {
this.version = Collections.unmodifiableList(version);
}
/**
* Parses the Java version as it can be retrieved as the value of java.version or
* java.specification.version according to JEP 223.
*
* @param value The version String
*/
public static JavaVersion parse(String value) {
Objects.requireNonNull(value);
String prePart = null;
if (!isValid(value)) {
throw new IllegalArgumentException("value");
throw new IllegalArgumentException("Java version string [" + value + "] could not be parsed.");
}
List<Integer> version = new ArrayList<>();
String[] parts = value.split("-");
String[] numericComponents;
if (parts.length == 1) {
numericComponents = value.split("\\.");
} else if (parts.length == 2) {
numericComponents = parts[0].split("\\.");
prePart = parts[1];
} else {
throw new IllegalArgumentException("Java version string [" + value + "] could not be parsed.");
}
List<Integer> version = new ArrayList<>();
String[] components = value.split("\\.");
for (String component : components) {
for (String component : numericComponents) {
version.add(Integer.valueOf(component));
}
return new JavaVersion(version);
return new JavaVersion(version, prePart);
}
public static boolean isValid(String value) {
return value.matches("^0*[0-9]+(\\.[0-9]+)*$");
return value.matches("^0*[0-9]+(\\.[0-9]+)*(-[a-zA-Z0-9]+)?$");
}
private static final JavaVersion CURRENT = parse(System.getProperty("java.specification.version"));
@ -78,9 +96,26 @@ public class JavaVersion implements Comparable<JavaVersion> {
if (s > d)
return -1;
}
if (prePart != null && o.prePart == null) {
return -1;
} else if (prePart == null && o.prePart != null) {
return 1;
} else if (prePart != null && o.prePart != null) {
return comparePrePart(prePart, o.prePart);
}
return 0;
}
private int comparePrePart(String prePart, String otherPrePart) {
if (prePart.matches("\\d+")) {
return otherPrePart.matches("\\d+") ?
(new BigInteger(prePart)).compareTo(new BigInteger(otherPrePart)) : -1;
} else {
return otherPrePart.matches("\\d+") ?
1 : prePart.compareTo(otherPrePart);
}
}
@Override
public boolean equals(Object o) {
if (o == null || o.getClass() != getClass()) {
@ -96,6 +131,7 @@ public class JavaVersion implements Comparable<JavaVersion> {
@Override
public String toString() {
return version.stream().map(v -> Integer.toString(v)).collect(Collectors.joining("."));
final String versionString = version.stream().map(v -> Integer.toString(v)).collect(Collectors.joining("."));
return prePart != null ? versionString + "-" + prePart : versionString;
}
}

View File

@ -282,7 +282,7 @@ public class AzureDiscoveryClusterFormationTests extends ESIntegTestCase {
} else {
JavaVersion full =
AccessController.doPrivileged(
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.specification.version")));
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) {
return "TLSv1.2";
}

View File

@ -23,16 +23,47 @@ import org.elasticsearch.test.ESTestCase;
import java.util.List;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
public class JavaVersionTests extends ESTestCase {
public void testParse() {
JavaVersion javaVersion = JavaVersion.parse("1.7.0");
List<Integer> version = javaVersion.getVersion();
assertThat(3, is(version.size()));
assertThat(1, is(version.get(0)));
assertThat(7, is(version.get(1)));
assertThat(0, is(version.get(2)));
assertThat(version.size(), is(3));
assertThat(version.get(0), is(1));
assertThat(version.get(1), is(7));
assertThat(version.get(2), is(0));
JavaVersion javaVersionEarlyAccess = JavaVersion.parse("14.0.1-ea");
List<Integer> version14 = javaVersionEarlyAccess.getVersion();
assertThat(version14.size(), is(3));
assertThat(version14.get(0), is(14));
assertThat(version14.get(1), is(0));
assertThat(version14.get(2), is(1));
JavaVersion javaVersionOtherPrePart = JavaVersion.parse("13.2.4-somethingElseHere");
List<Integer> version13 = javaVersionOtherPrePart.getVersion();
assertThat(version13.size(), is(3));
assertThat(version13.get(0), is(13));
assertThat(version13.get(1), is(2));
assertThat(version13.get(2), is(4));
JavaVersion javaVersionNumericPrePart = JavaVersion.parse("13.2.4-something124443");
List<Integer> version11 = javaVersionNumericPrePart.getVersion();
assertThat(version11.size(), is(3));
assertThat(version11.get(0), is(13));
assertThat(version11.get(1), is(2));
assertThat(version11.get(2), is(4));
}
public void testParseInvalidVersions() {
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> JavaVersion.parse("11.2-something-else"));
assertThat(e.getMessage(), equalTo("Java version string [11.2-something-else] could not be parsed."));
final IllegalArgumentException e1 = expectThrows(IllegalArgumentException.class, () -> JavaVersion.parse("11.0."));
assertThat(e1.getMessage(), equalTo("Java version string [11.0.] could not be parsed."));
final IllegalArgumentException e2 = expectThrows(IllegalArgumentException.class, () -> JavaVersion.parse("11.a.3"));
assertThat(e2.getMessage(), equalTo("Java version string [11.a.3] could not be parsed."));
}
public void testToString() {
@ -40,6 +71,12 @@ public class JavaVersionTests extends ESTestCase {
assertThat(javaVersion170.toString(), is("1.7.0"));
JavaVersion javaVersion9 = JavaVersion.parse("9");
assertThat(javaVersion9.toString(), is("9"));
JavaVersion javaVersion11 = JavaVersion.parse("11.0.1-something09random");
assertThat(javaVersion11.toString(), is("11.0.1-something09random"));
JavaVersion javaVersion12 = JavaVersion.parse("12.2-2019");
assertThat(javaVersion12.toString(), is("12.2-2019"));
JavaVersion javaVersion13ea = JavaVersion.parse("13.1-ea");
assertThat(javaVersion13ea.toString(), is("13.1-ea"));
}
public void testCompare() {
@ -50,6 +87,15 @@ public class JavaVersionTests extends ESTestCase {
JavaVersion onePointSevenPointTwo = JavaVersion.parse("1.7.2");
JavaVersion onePointSevenPointOnePointOne = JavaVersion.parse("1.7.1.1");
JavaVersion onePointSevenPointTwoPointOne = JavaVersion.parse("1.7.2.1");
JavaVersion thirteen = JavaVersion.parse("13");
JavaVersion thirteenPointTwoPointOne = JavaVersion.parse("13.2.1");
JavaVersion thirteenPointTwoPointOneTwoThousand = JavaVersion.parse("13.2.1-2000");
JavaVersion thirteenPointTwoPointOneThreeThousand = JavaVersion.parse("13.2.1-3000");
JavaVersion thirteenPointTwoPointOneA = JavaVersion.parse("13.2.1-aaa");
JavaVersion thirteenPointTwoPointOneB = JavaVersion.parse("13.2.1-bbb");
JavaVersion fourteen = JavaVersion.parse("14");
JavaVersion fourteenPointTwoPointOne = JavaVersion.parse("14.2.1");
JavaVersion fourteenPointTwoPointOneEarlyAccess = JavaVersion.parse("14.2.1-ea");
assertTrue(onePointSix.compareTo(onePointSeven) < 0);
assertTrue(onePointSeven.compareTo(onePointSix) > 0);
@ -57,17 +103,27 @@ public class JavaVersionTests extends ESTestCase {
assertTrue(onePointSeven.compareTo(onePointSevenPointZero) == 0);
assertTrue(onePointSevenPointOnePointOne.compareTo(onePointSevenPointOne) > 0);
assertTrue(onePointSevenPointTwo.compareTo(onePointSevenPointTwoPointOne) < 0);
assertTrue(thirteen.compareTo(thirteenPointTwoPointOne) < 0);
assertTrue(thirteen.compareTo(fourteen) < 0);
assertTrue(thirteenPointTwoPointOneThreeThousand.compareTo(thirteenPointTwoPointOneTwoThousand) > 0);
assertTrue(thirteenPointTwoPointOneThreeThousand.compareTo(thirteenPointTwoPointOneThreeThousand) == 0);
assertTrue(thirteenPointTwoPointOneA.compareTo(thirteenPointTwoPointOneA) == 0);
assertTrue(thirteenPointTwoPointOneA.compareTo(thirteenPointTwoPointOneB) < 0);
assertTrue(thirteenPointTwoPointOneA.compareTo(thirteenPointTwoPointOneThreeThousand) > 0);
assertTrue(fourteenPointTwoPointOneEarlyAccess.compareTo(fourteenPointTwoPointOne) < 0);
assertTrue(fourteenPointTwoPointOneEarlyAccess.compareTo(fourteen) > 0);
}
public void testValidVersions() {
String[] versions = new String[]{"1.7", "1.7.0", "0.1.7", "1.7.0.80"};
String[] versions = new String[]{"1.7", "1.7.0", "0.1.7", "1.7.0.80", "12-ea", "13.0.2.3-ea", "14-something", "11.0.2-21002"};
for (String version : versions) {
assertTrue(JavaVersion.isValid(version));
}
}
public void testInvalidVersions() {
String[] versions = new String[]{"", "1.7.0_80", "1.7."};
String[] versions = new String[]{"", "1.7.0_80", "1.7.", "11.2-something-else"};
for (String version : versions) {
assertFalse(JavaVersion.isValid(version));
}
@ -76,4 +132,4 @@ public class JavaVersionTests extends ESTestCase {
public void testJava8Compat() {
assertEquals(JavaVersion.parse("1.8"), JavaVersion.parse("8"));
}
}
}

View File

@ -206,7 +206,7 @@ public class HttpExporterSslIT extends MonitoringIntegTestCase {
} else {
JavaVersion full =
AccessController.doPrivileged(
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.specification.version")));
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) {
return Collections.singletonList("TLSv1.2");
}

View File

@ -734,7 +734,7 @@ public class SamlRealmTests extends SamlTestCase {
} else {
JavaVersion full =
AccessController.doPrivileged(
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.specification.version")));
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) {
return Collections.singletonList("TLSv1.2");
}

View File

@ -214,7 +214,7 @@ public class SSLClientAuthTests extends SecurityIntegTestCase {
}
JavaVersion full =
AccessController.doPrivileged(
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.specification.version")));
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
if (full.compareTo(JavaVersion.parse("11.0.3")) < 0) {
return Collections.singletonList("TLSv1.2");
}

View File

@ -152,7 +152,7 @@ public class WebhookHttpsIntegrationTests extends AbstractWatcherIntegrationTest
} else {
JavaVersion full =
AccessController.doPrivileged(
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.specification.version")));
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) {
return Collections.singletonList("TLSv1.2");
}

View File

@ -761,7 +761,7 @@ public class HttpClientTests extends ESTestCase {
} else {
JavaVersion full =
AccessController.doPrivileged(
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.specification.version")));
(PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) {
return Collections.singletonList("TLSv1.2");
}