From ca7660a289be7632dd0957324665e2fa93c46ac6 Mon Sep 17 00:00:00 2001 From: Jordan Halterman Date: Wed, 4 Apr 2018 23:43:23 -0700 Subject: [PATCH] Add rolling upgrade test. Change-Id: Id1b09361aa69f1665f19c312933798b5206d46ac --- .../cli/ConsistentMapTestCommand.java | 25 +++++- .../java/org/onosproject/core/Version.java | 32 ++++++-- .../java/org/onosproject/VersionTest.java | 15 ++-- .../upgrade/impl/UpgradeManager.java | 7 -- .../impl/AtomixConsistentMapTest.java | 50 +++++++++++ tools/test/scenarios/rolling-upgrade.xml | 82 +++++++++++++++++++ 6 files changed, 189 insertions(+), 22 deletions(-) create mode 100644 tools/test/scenarios/rolling-upgrade.xml diff --git a/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/ConsistentMapTestCommand.java b/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/ConsistentMapTestCommand.java index ac090843bc..3896830cb3 100644 --- a/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/ConsistentMapTestCommand.java +++ b/apps/test/distributed-primitives/src/main/java/org/onosproject/distributedprimitives/cli/ConsistentMapTestCommand.java @@ -18,6 +18,7 @@ package org.onosproject.distributedprimitives.cli; import org.apache.karaf.shell.commands.Argument; import org.apache.karaf.shell.commands.Command; import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.Version; import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.service.ConsistentMap; import org.onosproject.store.service.Serializer; @@ -62,9 +63,11 @@ public class ConsistentMapTestCommand extends AbstractShellCommand { protected void execute() { StorageService storageService = get(StorageService.class); map = storageService.consistentMapBuilder() - .withName(name) - .withSerializer(Serializer.using(KryoNamespaces.BASIC)) - .build(); + .withName(name) + .withSerializer(Serializer.using(KryoNamespaces.BASIC)) + .withVersion(Version.version("1.0.0")) + .withCompatibilityFunction((value, version) -> version + ":" + value) + .build(); if ("get".equals(operation)) { print(map.get(arg1)); } else if ("put".equals(operation)) { @@ -95,6 +98,22 @@ public class ConsistentMapTestCommand extends AbstractShellCommand { } else { print("%b", map.replace(arg1, arg2, arg3)); } + } else if ("compatiblePut".equals(operation)) { + ConsistentMap map = storageService.consistentMapBuilder() + .withName(name) + .withSerializer(Serializer.using(KryoNamespaces.BASIC)) + .withCompatibilityFunction((value, version) -> version + ":" + value) + .withVersion(Version.version("2.0.0")) + .build(); + print(map.put(arg1, arg2)); + } else if ("compatibleGet".equals(operation)) { + ConsistentMap map = storageService.consistentMapBuilder() + .withName(name) + .withSerializer(Serializer.using(KryoNamespaces.BASIC)) + .withCompatibilityFunction((value, version) -> version + ":" + value) + .withVersion(Version.version("2.0.0")) + .build(); + print(map.get(arg1)); } } diff --git a/core/api/src/main/java/org/onosproject/core/Version.java b/core/api/src/main/java/org/onosproject/core/Version.java index ec0ea6d5d6..379eda2c9f 100644 --- a/core/api/src/main/java/org/onosproject/core/Version.java +++ b/core/api/src/main/java/org/onosproject/core/Version.java @@ -100,8 +100,9 @@ public final class Version implements Comparable { public static Version fromInt(int version) { int major = (version >> 24) & 0xff; int minor = (version >> 16) & 0xff; - int patch = (version) & 0xffff; - return new Version(major, minor, String.valueOf(patch), null); + int patch = (version >> 8) & 0xff; + int build = version & 0xff; + return new Version(major, minor, String.valueOf(patch), String.valueOf(build)); } /** @@ -157,13 +158,30 @@ public final class Version implements Comparable { public int toInt() { byte major = (byte) this.major; byte minor = (byte) this.minor; - short patch; - try { - patch = (short) Integer.parseInt(this.patch); - } catch (NumberFormatException e) { + + byte patch; + if (this.patch != null) { + try { + patch = (byte) Integer.parseInt(this.patch.replaceAll("[^0-9]", "")); + } catch (NumberFormatException e) { + patch = 0; + } + } else { patch = 0; } - return major << 24 | (minor & 0xff) << 16 | (patch & 0xffff); + + byte build; + if (this.build != null) { + try { + build = (byte) Integer.parseInt(this.build.replaceAll("[^0-9]", "")); + } catch (NumberFormatException e) { + build = 0; + } + } else { + build = 0; + } + + return major << 24 | (minor & 0xff) << 16 | (patch & 0xff) << 8 | (build & 0xff); } @Override diff --git a/core/api/src/test/java/org/onosproject/VersionTest.java b/core/api/src/test/java/org/onosproject/VersionTest.java index 1c972ee65c..482d798978 100644 --- a/core/api/src/test/java/org/onosproject/VersionTest.java +++ b/core/api/src/test/java/org/onosproject/VersionTest.java @@ -83,25 +83,30 @@ public class VersionTest { version1 = version("1.2"); version2 = Version.fromInt(version1.toInt()); - assertEquals(version2, version(1, 2, "0", null)); + assertEquals(version2, version(1, 2, "0", "0")); version1 = version("1.2.foo.bar"); version2 = Version.fromInt(version1.toInt()); - assertEquals(version2, version(1, 2, "0", null)); + assertEquals(version2, version(1, 2, "0", "0")); version1 = version("1.2.3"); version2 = Version.fromInt(version1.toInt()); - assertEquals(version2, version(1, 2, "3", null)); + assertEquals(version2, version(1, 2, "3", "0")); - version1 = version("255.254.65535.252"); + version1 = version("1.2.3-SNAPSHOT"); version2 = Version.fromInt(version1.toInt()); - assertEquals(version2, version(255, 254, "65535", null)); + assertEquals(version2, version(1, 2, "3", "0")); + + version1 = version("255.254.253.252"); + version2 = Version.fromInt(version1.toInt()); + assertEquals(version2, version(255, 254, "253", "252")); assertTrue(version("0.0.2").toInt() > version("0.0.1").toInt()); assertTrue(version("0.1.0").toInt() > version("0.0.1").toInt()); assertTrue(version("1.0.0").toInt() > version("0.1.0").toInt()); assertTrue(version("1.1.0").toInt() > version("1.0.1").toInt()); assertTrue(version("2.1.1").toInt() > version("1.10.10").toInt()); + assertTrue(version("0.1.0-rc2").toInt() > version("0.1.0-rc1").toInt()); } @Test diff --git a/core/net/src/main/java/org/onosproject/upgrade/impl/UpgradeManager.java b/core/net/src/main/java/org/onosproject/upgrade/impl/UpgradeManager.java index 218a357589..3910f4bd58 100644 --- a/core/net/src/main/java/org/onosproject/upgrade/impl/UpgradeManager.java +++ b/core/net/src/main/java/org/onosproject/upgrade/impl/UpgradeManager.java @@ -105,13 +105,6 @@ public class UpgradeManager Upgrade upgrade = getState(); - // If the upgrade state is not initialized, ensure this node matches the version of the cluster. - if (!upgrade.status().active() && !Objects.equals(upgrade.source(), localVersion)) { - log.error("Node version {} inconsistent with cluster version {}", localVersion, upgrade.source()); - throw new IllegalStateException("Node version " + localVersion + - " inconsistent with cluster version " + upgrade.source()); - } - // If the upgrade state is initialized then check the node version. if (upgrade.status() == Upgrade.Status.INITIALIZED) { // If the source version equals the target version, attempt to update the target version. diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapTest.java index 23f9a1f160..3e7a8726c5 100644 --- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapTest.java +++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapTest.java @@ -19,11 +19,17 @@ import com.google.common.collect.Sets; import io.atomix.protocols.raft.proxy.RaftProxy; import io.atomix.protocols.raft.service.RaftService; import org.junit.Test; +import org.onlab.util.HexString; import org.onlab.util.Tools; import org.onosproject.store.primitives.MapUpdate; import org.onosproject.store.primitives.TransactionId; +import org.onosproject.store.primitives.impl.CompatibleValue; +import org.onosproject.store.primitives.impl.DistributedPrimitives; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.AsyncConsistentMap; import org.onosproject.store.service.MapEvent; import org.onosproject.store.service.MapEventListener; +import org.onosproject.store.service.Serializer; import org.onosproject.store.service.TransactionLog; import org.onosproject.store.service.Version; import org.onosproject.store.service.Versioned; @@ -584,6 +590,50 @@ public class AtomixConsistentMapTest extends AtomixTestBase assertTrue(Arrays.equals(value2, event.newValue().value())); } + @Test + public void testCompatibilityFunction() throws Throwable { + AtomixConsistentMap atomixMap = newPrimitive("testCompatibilityFunction"); + + Serializer rawSerializer = Serializer.using(KryoNamespaces.API, CompatibleValue.class); + Serializer valueSerializer = Serializer.using(KryoNamespaces.BASIC); + + // Convert the byte[] value to CompatibleValue + AsyncConsistentMap> rawMap = DistributedPrimitives.newTranscodingMap( + atomixMap, + key -> HexString.toHexString(rawSerializer.encode(key)), + string -> rawSerializer.decode(HexString.fromHexString(string)), + value -> value == null ? null : rawSerializer.encode(value), + bytes -> rawSerializer.decode(bytes)); + + // Convert the CompatibleValue value to CompatibleValue using the user-provided serializer. + AsyncConsistentMap> compatibleMap = + DistributedPrimitives.newTranscodingMap( + rawMap, + key -> key, + key -> key, + value -> value == null ? null : + new CompatibleValue(valueSerializer.encode(value.value()), value.version()), + value -> value == null ? null : + new CompatibleValue(valueSerializer.decode(value.value()), value.version())); + + AsyncConsistentMap map1 = DistributedPrimitives.newCompatibleMap( + compatibleMap, + (value, version) -> version + ":" + value, + org.onosproject.core.Version.version("1.0.0")); + AsyncConsistentMap map2 = DistributedPrimitives.newCompatibleMap( + compatibleMap, + (value, version) -> version + ":" + value, + org.onosproject.core.Version.version("1.0.1")); + + map1.put("foo", "Hello world!").join(); + assertEquals("Hello world!", map1.get("foo").join().value()); + assertEquals("1.0.0:Hello world!", map2.get("foo").join().value()); + + map2.put("bar", "Hello world again!").join(); + assertEquals("Hello world again!", map2.get("bar").join().value()); + assertEquals("1.0.1:Hello world again!", map1.get("bar").join().value()); + } + private static class TestMapEventListener implements MapEventListener { private final BlockingQueue> queue = new ArrayBlockingQueue<>(1); diff --git a/tools/test/scenarios/rolling-upgrade.xml b/tools/test/scenarios/rolling-upgrade.xml new file mode 100644 index 0000000000..3a4f88a05f --- /dev/null +++ b/tools/test/scenarios/rolling-upgrade.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +