X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-distributed-datastore%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fdatastore%2FShardDataTreeTest.java;h=6a8635b2c2744ec606bcd9bf3bffe0a2b3f29ed5;hp=35cb8ed6294fc365f8fea4cbdfade63289b1c335;hb=817d0efe25becd8d457550b11bf985298e169954;hpb=baf24349053f1097e311de0b6632a7463bff7b1b diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardDataTreeTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardDataTreeTest.java index 35cb8ed629..6a8635b2c2 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardDataTreeTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardDataTreeTest.java @@ -5,7 +5,6 @@ * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ - package org.opendaylight.controller.cluster.datastore; import static org.junit.Assert.assertEquals; @@ -34,12 +33,13 @@ import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediatePreCommit; import com.google.common.base.Ticker; -import com.google.common.collect.Maps; import com.google.common.primitives.UnsignedLong; import com.google.common.util.concurrent.FutureCallback; +import java.io.IOException; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -49,21 +49,34 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mockito; -import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats; import org.opendaylight.controller.cluster.datastore.persisted.CommitTransactionPayload; +import org.opendaylight.controller.cluster.datastore.persisted.MetadataShardDataTreeSnapshot; +import org.opendaylight.controller.cluster.datastore.persisted.PayloadVersion; +import org.opendaylight.controller.cluster.datastore.persisted.ShardSnapshotState; import org.opendaylight.controller.md.cluster.datastore.model.CarsModel; import org.opendaylight.controller.md.cluster.datastore.model.PeopleModel; import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper; import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener; +import org.opendaylight.yangtools.yang.common.Uint64; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType; import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.api.SchemaContext; public class ShardDataTreeTest extends AbstractTest { @@ -71,12 +84,12 @@ public class ShardDataTreeTest extends AbstractTest { private final Shard mockShard = Mockito.mock(Shard.class); private ShardDataTree shardDataTree; - private SchemaContext fullSchema; + private EffectiveModelContext fullSchema; @Before public void setUp() { doReturn(Ticker.systemTicker()).when(mockShard).ticker(); - doReturn(mock(ShardStats.class)).when(mockShard).getShardMBean(); + doReturn(new ShardStats("shardName", "mxBeanType", mockShard)).when(mockShard).getShardMBean(); doReturn(DATASTORE_CONTEXT).when(mockShard).getDatastoreContext(); fullSchema = SchemaContextHelper.full(); @@ -199,7 +212,7 @@ public class ShardDataTreeTest extends AbstractTest { shardDataTree.applySnapshot(newDataTree.takeStateSnapshot()); - Map expChanges = Maps.newHashMap(); + Map expChanges = new HashMap<>(); expChanges.put(CarsModel.newCarPath("optima"), ModificationType.WRITE); expChanges.put(CarsModel.newCarPath("murano"), ModificationType.WRITE); expChanges.put(CarsModel.newCarPath("sportage"), ModificationType.DELETE); @@ -227,7 +240,7 @@ public class ShardDataTreeTest extends AbstractTest { snapshot.write(PeopleModel.BASE_PATH, peopleNode)); YangInstanceIdentifier carPath = CarsModel.newCarPath("optima"); - MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100")); + MapEntryNode carNode = CarsModel.newCarEntry("optima", Uint64.valueOf(100)); final ShardDataTreeCohort cohort4 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode)); immediateCanCommit(cohort1); @@ -318,7 +331,7 @@ public class ShardDataTreeTest extends AbstractTest { snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode())); YangInstanceIdentifier carPath = CarsModel.newCarPath("optima"); - MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100")); + MapEntryNode carNode = CarsModel.newCarEntry("optima", Uint64.valueOf(100)); final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode)); final FutureCallback commitCallback2 = immediate3PhaseCommit(cohort2); @@ -363,7 +376,7 @@ public class ShardDataTreeTest extends AbstractTest { snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode())); YangInstanceIdentifier carPath = CarsModel.newCarPath("optima"); - MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100")); + MapEntryNode carNode = CarsModel.newCarEntry("optima", Uint64.valueOf(100)); final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode)); final FutureCallback commitCallback1 = immediate3PhaseCommit(cohort1); @@ -393,7 +406,7 @@ public class ShardDataTreeTest extends AbstractTest { snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode())); YangInstanceIdentifier carPath = CarsModel.newCarPath("optima"); - MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100")); + MapEntryNode carNode = CarsModel.newCarEntry("optima", Uint64.valueOf(100)); final ShardDataTreeCohort cohort4 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode)); coordinatedCanCommit(cohort2); @@ -477,6 +490,117 @@ public class ShardDataTreeTest extends AbstractTest { assertEquals("People node", peopleNode, optional.get()); } + @Test + public void testUintCommitPayload() throws IOException { + shardDataTree.applyRecoveryPayload(CommitTransactionPayload.create(nextTransactionId(), + DataTreeCandidates.fromNormalizedNode(YangInstanceIdentifier.empty(), bigIntegerRoot()), + PayloadVersion.SODIUM_SR1)); + + assertCarsUint64(); + } + + @Test + public void testUintSnapshot() throws IOException, DataValidationFailedException { + shardDataTree.applyRecoverySnapshot(new ShardSnapshotState(new MetadataShardDataTreeSnapshot(bigIntegerRoot()), + true)); + + assertCarsUint64(); + } + + @Test + public void testUintReplay() throws DataValidationFailedException, IOException { + // Commit two writes and one merge, saving the data tree candidate for each. + // write(foo=1) + // write(foo=2) + // merge(foo=3) + final DataTree dataTree = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_OPERATIONAL, + fullSchema); + DataTreeModification mod = dataTree.takeSnapshot().newModification(); + mod.write(CarsModel.BASE_PATH, Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(CarsModel.BASE_QNAME)) + .withChild(Builders.mapBuilder() + .withNodeIdentifier(new NodeIdentifier(CarsModel.CAR_QNAME)) + .withChild(createCar("one", BigInteger.ONE)) + .build()) + .build()); + mod.ready(); + dataTree.validate(mod); + final DataTreeCandidate first = dataTree.prepare(mod); + dataTree.commit(first); + + mod = dataTree.takeSnapshot().newModification(); + mod.write(CarsModel.newCarPath("two"), createCar("two", BigInteger.TWO)); + mod.ready(); + dataTree.validate(mod); + final DataTreeCandidate second = dataTree.prepare(mod); + dataTree.commit(second); + + mod = dataTree.takeSnapshot().newModification(); + mod.merge(CarsModel.CAR_LIST_PATH, Builders.mapBuilder() + .withNodeIdentifier(new NodeIdentifier(CarsModel.CAR_QNAME)) + .withChild(createCar("three", BigInteger.TEN)) + .build()); + mod.ready(); + dataTree.validate(mod); + final DataTreeCandidate third = dataTree.prepare(mod); + dataTree.commit(third); + + // Apply first candidate as a snapshot + shardDataTree.applyRecoverySnapshot( + new ShardSnapshotState(new MetadataShardDataTreeSnapshot(first.getRootNode().getDataAfter().get()), true)); + // Apply the other two snapshots as transactions + shardDataTree.applyRecoveryPayload(CommitTransactionPayload.create(nextTransactionId(), second, + PayloadVersion.SODIUM_SR1)); + shardDataTree.applyRecoveryPayload(CommitTransactionPayload.create(nextTransactionId(), third, + PayloadVersion.SODIUM_SR1)); + + // Verify uint translation + final DataTreeSnapshot snapshot = shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot(); + final NormalizedNode cars = snapshot.readNode(CarsModel.CAR_LIST_PATH).get(); + + assertEquals(Builders.mapBuilder() + .withNodeIdentifier(new NodeIdentifier(CarsModel.CAR_QNAME)) + // Note: Uint64 + .withChild(createCar("one", Uint64.ONE)) + .withChild(createCar("two", Uint64.TWO)) + .withChild(createCar("three", Uint64.TEN)) + .build(), cars); + } + + private void assertCarsUint64() { + final DataTreeSnapshot snapshot = shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot(); + final NormalizedNode cars = snapshot.readNode(CarsModel.CAR_LIST_PATH).get(); + + assertEquals(Builders.mapBuilder() + .withNodeIdentifier(new NodeIdentifier(CarsModel.CAR_QNAME)) + // Note: Uint64 + .withChild(createCar("foo", Uint64.ONE)) + .build(), cars); + } + + private static ContainerNode bigIntegerRoot() { + return Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(SchemaContext.NAME)) + .withChild(Builders.containerBuilder() + .withNodeIdentifier(new NodeIdentifier(CarsModel.CARS_QNAME)) + .withChild(Builders.mapBuilder() + .withNodeIdentifier(new NodeIdentifier(CarsModel.CAR_QNAME)) + // Note: BigInteger + .withChild(createCar("foo", BigInteger.ONE)) + .build()) + .build()) + .build(); + } + + private static MapEntryNode createCar(final String name, final Object value) { + return Builders.mapEntryBuilder() + .withNodeIdentifier(NodeIdentifierWithPredicates.of(CarsModel.CAR_QNAME,CarsModel.CAR_NAME_QNAME, name)) + .withChild(ImmutableNodes.leafNode(CarsModel.CAR_NAME_QNAME, name)) + // Note: old BigInteger + .withChild(ImmutableNodes.leafNode(CarsModel.CAR_PRICE_QNAME, value)) + .build(); + } + private ShardDataTreeCohort newShardDataTreeCohort(final DataTreeOperation operation) { final ReadWriteShardDataTreeTransaction transaction = shardDataTree.newReadWriteTransaction(nextTransactionId()); @@ -519,7 +643,7 @@ public class ShardDataTreeTest extends AbstractTest { return doTransaction(shardDataTree, snapshot -> { snapshot.merge(CarsModel.BASE_PATH, CarsModel.emptyContainer()); snapshot.merge(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()); - snapshot.write(CarsModel.newCarPath(name), CarsModel.newCarEntry(name, new BigInteger("100"))); + snapshot.write(CarsModel.newCarPath(name), CarsModel.newCarEntry(name, Uint64.valueOf(100))); }); }