Skip to content

Commit

Permalink
Refactor LegacyESVersion tests from Version tests (#1662)
Browse files Browse the repository at this point in the history
In preparation for removing all LegacyESVersion support by 3.0; this commit
largely refactors the LegacyESVersion test logic from the OpenSearch Version
test logic into an independent test class. This PR also updates Version.fromString
to ensure a proper legacy version is returned when major is > 3 (to support
legacy yaml test and build scripts).

Note that bwc w/ legacy versions are still supported so some cross compatibility
testing is retained in the Version test class.

Signed-off-by: Nicholas Walter Knize <[email protected]>
  • Loading branch information
nknize authored Dec 7, 2021
1 parent 7496f80 commit 33d8677
Show file tree
Hide file tree
Showing 6 changed files with 422 additions and 146 deletions.
3 changes: 2 additions & 1 deletion server/src/main/java/org/opensearch/LegacyESVersion.java
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ public static Version fromString(String version) {
return fromStringSlow(version);
}

private static Version fromStringSlow(String version) {
// pkg private for usage in Version (todo: remove in 3.0)
static Version fromStringSlow(String version) {
final boolean snapshot; // this is some BWC for 2.x and before indices
if (snapshot = version.endsWith("-SNAPSHOT")) {
version = version.substring(0, version.length() - 9);
Expand Down
13 changes: 13 additions & 0 deletions server/src/main/java/org/opensearch/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,19 @@ public static Version fromString(String version) {
if (cached != null) {
return cached;
}
{
// get major string; remove when creating OpenSearch 3.0
String[] parts = version.split("[.-]");
if (parts.length < 3 || parts.length > 4) {
throw new IllegalArgumentException(
"the version needs to contain major, minor, and revision, and optionally the build: " + version
);
}
int major = Integer.parseInt(parts[0]);
if (major > 3) {
return LegacyESVersion.fromStringSlow(version);
}
}
return fromStringSlow(version);
}

Expand Down
294 changes: 294 additions & 0 deletions server/src/test/java/org/opensearch/LegacyESVersionTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch;

import org.opensearch.cluster.metadata.IndexMetadata;
import org.opensearch.common.settings.Settings;
import org.opensearch.test.OpenSearchTestCase;
import org.opensearch.test.VersionUtils;

import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.sameInstance;
import static org.opensearch.LegacyESVersion.V_6_3_0;
import static org.opensearch.LegacyESVersion.V_7_0_0;
import static org.opensearch.test.VersionUtils.randomLegacyVersion;
import static org.opensearch.VersionTests.isCompatible;

/**
* tests LegacyESVersion utilities.
* note: legacy version compatibility is already tested by e predecessor
*/
public class LegacyESVersionTests extends OpenSearchTestCase {

public void testVersionComparison() {
assertThat(V_6_3_0.before(V_7_0_0), is(true));
assertThat(V_6_3_0.before(V_6_3_0), is(false));
assertThat(V_7_0_0.before(V_6_3_0), is(false));

assertThat(V_6_3_0.onOrBefore(V_7_0_0), is(true));
assertThat(V_6_3_0.onOrBefore(V_6_3_0), is(true));
assertThat(V_7_0_0.onOrBefore(V_6_3_0), is(false));

assertThat(V_6_3_0.after(V_7_0_0), is(false));
assertThat(V_6_3_0.after(V_6_3_0), is(false));
assertThat(V_7_0_0.after(V_6_3_0), is(true));

assertThat(V_6_3_0.onOrAfter(V_7_0_0), is(false));
assertThat(V_6_3_0.onOrAfter(V_6_3_0), is(true));
assertThat(V_7_0_0.onOrAfter(V_6_3_0), is(true));

assertTrue(LegacyESVersion.fromString("5.0.0-alpha2").onOrAfter(LegacyESVersion.fromString("5.0.0-alpha1")));
assertTrue(LegacyESVersion.fromString("5.0.0").onOrAfter(LegacyESVersion.fromString("5.0.0-beta2")));
assertTrue(LegacyESVersion.fromString("5.0.0-rc1").onOrAfter(LegacyESVersion.fromString("5.0.0-beta24")));
assertTrue(LegacyESVersion.fromString("5.0.0-alpha24").before(LegacyESVersion.fromString("5.0.0-beta0")));

assertThat(V_6_3_0, is(lessThan(V_7_0_0)));
assertThat(V_6_3_0.compareTo(V_6_3_0), is(0));
assertThat(V_7_0_0, is(greaterThan(V_6_3_0)));

// compare opensearch version to LegacyESVersion
assertThat(Version.V_1_0_0.compareMajor(LegacyESVersion.V_7_0_0), is(0));
assertThat(Version.V_1_0_0.compareMajor(LegacyESVersion.V_6_3_0), is(1));
assertThat(LegacyESVersion.V_6_3_0.compareMajor(Version.V_1_0_0), is(-1));
}

public void testMin() {
assertEquals(VersionUtils.getPreviousVersion(), LegacyESVersion.min(Version.CURRENT, VersionUtils.getPreviousVersion()));
assertEquals(LegacyESVersion.fromString("7.0.1"), LegacyESVersion.min(LegacyESVersion.fromString("7.0.1"), Version.CURRENT));
Version legacyVersion = VersionUtils.randomLegacyVersion(random());
Version opensearchVersion = VersionUtils.randomOpenSearchVersion(random());
assertEquals(legacyVersion, Version.min(opensearchVersion, legacyVersion));
}

public void testMax() {
assertEquals(Version.CURRENT, Version.max(Version.CURRENT, VersionUtils.randomLegacyVersion(random())));
assertEquals(Version.CURRENT, Version.max(LegacyESVersion.fromString("1.0.1"), Version.CURRENT));
Version legacyVersion = VersionUtils.randomOpenSearchVersion(random());
Version opensearchVersion = VersionUtils.randomLegacyVersion(random());
assertEquals(legacyVersion, Version.max(opensearchVersion, legacyVersion));
}

public void testMinimumIndexCompatibilityVersion() {
assertEquals(LegacyESVersion.fromId(5000099), LegacyESVersion.V_6_0_0_beta1.minimumIndexCompatibilityVersion());
assertEquals(LegacyESVersion.fromId(2000099), LegacyESVersion.fromId(5000099).minimumIndexCompatibilityVersion());
assertEquals(LegacyESVersion.fromId(2000099), LegacyESVersion.fromId(5010000).minimumIndexCompatibilityVersion());
assertEquals(LegacyESVersion.fromId(2000099), LegacyESVersion.fromId(5000001).minimumIndexCompatibilityVersion());
}

public void testVersionFromString() {
final int iters = scaledRandomIntBetween(100, 1000);
for (int i = 0; i < iters; i++) {
LegacyESVersion version = randomLegacyVersion(random());
assertThat(LegacyESVersion.fromString(version.toString()), sameInstance(version));
}
}

public void testTooLongVersionFromString() {
Exception e = expectThrows(IllegalArgumentException.class, () -> LegacyESVersion.fromString("1.0.0.1.3"));
assertThat(e.getMessage(), containsString("needs to contain major, minor, and revision"));
}

public void testTooShortVersionFromString() {
Exception e = expectThrows(IllegalArgumentException.class, () -> LegacyESVersion.fromString("1.0"));
assertThat(e.getMessage(), containsString("needs to contain major, minor, and revision"));
}

public void testWrongVersionFromString() {
Exception e = expectThrows(IllegalArgumentException.class, () -> LegacyESVersion.fromString("WRONG.VERSION"));
assertThat(e.getMessage(), containsString("needs to contain major, minor, and revision"));
}

public void testVersionNoPresentInSettings() {
Exception e = expectThrows(IllegalStateException.class, () -> LegacyESVersion.indexCreated(Settings.builder().build()));
assertThat(e.getMessage(), containsString("[index.version.created] is not present"));
}

public void testIndexCreatedVersion() {
// an actual index has a IndexMetadata.SETTING_INDEX_UUID
final LegacyESVersion version = (LegacyESVersion) LegacyESVersion.fromId(6000026);
assertEquals(
version,
LegacyESVersion.indexCreated(
Settings.builder().put(IndexMetadata.SETTING_INDEX_UUID, "foo").put(IndexMetadata.SETTING_VERSION_CREATED, version).build()
)
);
}

public void testMinCompatVersion() {
Version major = LegacyESVersion.fromString("6.8.0");
assertThat(LegacyESVersion.fromString("1.0.0").minimumCompatibilityVersion(), equalTo(major));
assertThat(LegacyESVersion.fromString("1.2.0").minimumCompatibilityVersion(), equalTo(major));
assertThat(LegacyESVersion.fromString("1.3.0").minimumCompatibilityVersion(), equalTo(major));

Version major5x = LegacyESVersion.fromString("5.0.0");
assertThat(LegacyESVersion.fromString("5.0.0").minimumCompatibilityVersion(), equalTo(major5x));
assertThat(LegacyESVersion.fromString("5.2.0").minimumCompatibilityVersion(), equalTo(major5x));
assertThat(LegacyESVersion.fromString("5.3.0").minimumCompatibilityVersion(), equalTo(major5x));

Version major56x = LegacyESVersion.fromString("5.6.0");
assertThat(LegacyESVersion.V_6_5_0.minimumCompatibilityVersion(), equalTo(major56x));
assertThat(LegacyESVersion.V_6_3_1.minimumCompatibilityVersion(), equalTo(major56x));

// from 7.0 on we are supporting the latest minor of the previous major... this might fail once we add a new version ie. 5.x is
// released since we need to bump the supported minor in Version#minimumCompatibilityVersion()
LegacyESVersion lastVersion = LegacyESVersion.V_6_8_0; // TODO: remove this once min compat version is a constant instead of method
assertEquals(lastVersion.major, LegacyESVersion.V_7_0_0.minimumCompatibilityVersion().major);
assertEquals(
"did you miss to bump the minor in Version#minimumCompatibilityVersion()",
lastVersion.minor,
LegacyESVersion.V_7_0_0.minimumCompatibilityVersion().minor
);
assertEquals(0, LegacyESVersion.V_7_0_0.minimumCompatibilityVersion().revision);
}

public void testToString() {
// with 2.0.beta we lowercase
assertEquals("2.0.0-beta1", LegacyESVersion.fromString("2.0.0-beta1").toString());
assertEquals("5.0.0-alpha1", LegacyESVersion.fromId(5000001).toString());
assertEquals("2.3.0", LegacyESVersion.fromString("2.3.0").toString());
assertEquals("0.90.0.Beta1", LegacyESVersion.fromString("0.90.0.Beta1").toString());
assertEquals("1.0.0.Beta1", LegacyESVersion.fromString("1.0.0.Beta1").toString());
assertEquals("2.0.0-beta1", LegacyESVersion.fromString("2.0.0-beta1").toString());
assertEquals("5.0.0-beta1", LegacyESVersion.fromString("5.0.0-beta1").toString());
assertEquals("5.0.0-alpha1", LegacyESVersion.fromString("5.0.0-alpha1").toString());
}

public void testIsRc() {
assertTrue(LegacyESVersion.fromString("2.0.0-rc1").isRC());
assertTrue(LegacyESVersion.fromString("1.0.0.RC1").isRC());

for (int i = 0; i < 25; i++) {
assertEquals(LegacyESVersion.fromString("5.0.0-rc" + i).id, LegacyESVersion.fromId(5000000 + i + 50).id);
assertEquals("5.0.0-rc" + i, LegacyESVersion.fromId(5000000 + i + 50).toString());

// legacy RC versioning
assertEquals(LegacyESVersion.fromString("1.0.0.RC" + i).id, LegacyESVersion.fromId(1000000 + i + 50).id);
assertEquals("1.0.0.RC" + i, LegacyESVersion.fromId(1000000 + i + 50).toString());
}
}

public void testIsBeta() {
assertTrue(LegacyESVersion.fromString("2.0.0-beta1").isBeta());
assertTrue(LegacyESVersion.fromString("1.0.0.Beta1").isBeta());
assertTrue(LegacyESVersion.fromString("0.90.0.Beta1").isBeta());

for (int i = 0; i < 25; i++) {
assertEquals(LegacyESVersion.fromString("5.0.0-beta" + i).id, LegacyESVersion.fromId(5000000 + i + 25).id);
assertEquals("5.0.0-beta" + i, LegacyESVersion.fromId(5000000 + i + 25).toString());
}
}

public void testIsAlpha() {
assertTrue(new LegacyESVersion(5000001, org.apache.lucene.util.Version.LUCENE_7_0_0).isAlpha());
assertFalse(new LegacyESVersion(4000002, org.apache.lucene.util.Version.LUCENE_7_0_0).isAlpha());
assertTrue(new LegacyESVersion(4000002, org.apache.lucene.util.Version.LUCENE_7_0_0).isBeta());
assertTrue(LegacyESVersion.fromString("5.0.0-alpha14").isAlpha());
assertEquals(5000014, LegacyESVersion.fromString("5.0.0-alpha14").id);
assertTrue(LegacyESVersion.fromId(5000015).isAlpha());

for (int i = 0; i < 25; i++) {
assertEquals(LegacyESVersion.fromString("5.0.0-alpha" + i).id, LegacyESVersion.fromId(5000000 + i).id);
assertEquals("5.0.0-alpha" + i, LegacyESVersion.fromId(5000000 + i).toString());
}
}

public void testParseVersion() {
final int iters = scaledRandomIntBetween(100, 1000);
for (int i = 0; i < iters; i++) {
LegacyESVersion version = randomLegacyVersion(random());
LegacyESVersion parsedVersion = (LegacyESVersion) LegacyESVersion.fromString(version.toString());
assertEquals(version, parsedVersion);
}

expectThrows(IllegalArgumentException.class, () -> { LegacyESVersion.fromString("5.0.0-alph2"); });
assertEquals(LegacyESVersion.fromString("2.0.0-SNAPSHOT"), LegacyESVersion.fromId(2000099));
expectThrows(IllegalArgumentException.class, () -> { LegacyESVersion.fromString("5.0.0-SNAPSHOT"); });
}

public void testAllVersionsMatchId() throws Exception {
final Set<Version> releasedVersions = new HashSet<>(VersionUtils.allReleasedVersions());
final Set<Version> unreleasedVersions = new HashSet<>(VersionUtils.allUnreleasedVersions());
Map<String, Version> maxBranchVersions = new HashMap<>();
for (java.lang.reflect.Field field : Version.class.getFields()) {
if (field.getName().matches("_ID")) {
assertTrue(field.getName() + " should be static", Modifier.isStatic(field.getModifiers()));
assertTrue(field.getName() + " should be final", Modifier.isFinal(field.getModifiers()));
int versionId = (Integer) field.get(Version.class);

String constantName = field.getName().substring(0, field.getName().indexOf("_ID"));
java.lang.reflect.Field versionConstant = Version.class.getField(constantName);
assertTrue(constantName + " should be static", Modifier.isStatic(versionConstant.getModifiers()));
assertTrue(constantName + " should be final", Modifier.isFinal(versionConstant.getModifiers()));

Version v = (Version) versionConstant.get(null);
logger.debug("Checking {}", v);
if (field.getName().endsWith("_UNRELEASED")) {
assertTrue(unreleasedVersions.contains(v));
} else {
assertTrue(releasedVersions.contains(v));
}
assertEquals("Version id " + field.getName() + " does not point to " + constantName, v, Version.fromId(versionId));
assertEquals("Version " + constantName + " does not have correct id", versionId, v.id);
if (v.major >= 2) {
String number = v.toString();
if (v.isBeta()) {
number = number.replace("-beta", "_beta");
} else if (v.isRC()) {
number = number.replace("-rc", "_rc");
} else if (v.isAlpha()) {
number = number.replace("-alpha", "_alpha");
}
assertEquals("V_" + number.replace('.', '_'), constantName);
} else {
assertEquals("V_" + v.toString().replace('.', '_'), constantName);
}

// only the latest version for a branch should be a snapshot (ie unreleased)
String branchName = "" + v.major + "." + v.minor;
Version maxBranchVersion = maxBranchVersions.get(branchName);
if (maxBranchVersion == null) {
maxBranchVersions.put(branchName, v);
} else if (v.after(maxBranchVersion)) {
if (v == Version.CURRENT) {
// Current is weird - it counts as released even though it shouldn't.
continue;
}
assertFalse(
"Version " + maxBranchVersion + " cannot be a snapshot because version " + v + " exists",
VersionUtils.allUnreleasedVersions().contains(maxBranchVersion)
);
maxBranchVersions.put(branchName, v);
}
}
}
}

public void testIsCompatible() {
assertTrue(isCompatible(LegacyESVersion.V_6_8_0, LegacyESVersion.V_7_0_0));
assertFalse(isCompatible(LegacyESVersion.V_6_6_0, LegacyESVersion.V_7_0_0));
assertFalse(isCompatible(LegacyESVersion.V_6_7_0, LegacyESVersion.V_7_0_0));

assertFalse(isCompatible(LegacyESVersion.fromId(5000099), LegacyESVersion.fromString("6.0.0")));
assertFalse(isCompatible(LegacyESVersion.fromId(5000099), LegacyESVersion.fromString("7.0.0")));

Version a = randomLegacyVersion(random());
Version b = randomLegacyVersion(random());
assertThat(a.isCompatible(b), equalTo(b.isCompatible(a)));
}
}
Loading

0 comments on commit 33d8677

Please sign in to comment.