private boolean sealed = false;
public NormalizedNodePruner(SchemaContext schemaContext) {
- validNamespaces = new HashSet<>(schemaContext.getModules().size());
- for(org.opendaylight.yangtools.yang.model.api.Module module : schemaContext.getModules()){
- validNamespaces.add(module.getNamespace());
- }
+ this(NormalizedNodePruner.namespaces(schemaContext));
}
+
+ public NormalizedNodePruner(Set<URI> validNamespaces) {
+ this.validNamespaces = validNamespaces;
+ }
+
@Override
public void leafNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, Object o) throws IOException, IllegalArgumentException {
return stack;
}
-
+ public static Set<URI> namespaces(SchemaContext schemaContext){
+ Set<URI> namespaces = new HashSet<>(schemaContext.getModules().size());
+ for(org.opendaylight.yangtools.yang.model.api.Module module : schemaContext.getModules()){
+ namespaces.add(module.getNamespace());
+ }
+ return namespaces;
+ }
}
@Override
protected void onRecoveryComplete() {
+ store.recoveryDone();
//notify shard manager
getContext().parent().tell(new ActorInitialized(), getSelf());
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
+import java.net.URI;
import java.util.AbstractMap.SimpleEntry;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.controller.cluster.datastore.node.utils.transformer.NormalizedNodePruner;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
* This class is not part of the API contract and is subject to change at any time.
*/
@NotThreadSafe
-@VisibleForTesting
public final class ShardDataTree extends ShardDataTreeTransactionParent {
private static final Logger LOG = LoggerFactory.getLogger(ShardDataTree.class);
private static final ShardDataTreeNotificationManager MANAGER = new ShardDataTreeNotificationManager();
private final ShardDataTreeChangePublisher treeChangePublisher = new ShardDataTreeChangePublisher();
private final ListenerTree listenerTree = ListenerTree.create();
private final TipProducingDataTree dataTree;
+ private Set<URI> validNamespaces;
+ private ShardDataTreeTransactionFactory transactionFactory = new RecoveryShardDataTreeTransactionFactory();
ShardDataTree(final SchemaContext schemaContext) {
dataTree = InMemoryDataTreeFactory.getInstance().create();
- if (schemaContext != null) {
- dataTree.setSchemaContext(schemaContext);
- }
+ updateSchemaContext(schemaContext);
+
}
TipProducingDataTree getDataTree() {
}
void updateSchemaContext(final SchemaContext schemaContext) {
+ Preconditions.checkNotNull(schemaContext);
dataTree.setSchemaContext(schemaContext);
+ validNamespaces = NormalizedNodePruner.namespaces(schemaContext);
}
private ShardDataTreeTransactionChain ensureTransactionChain(final String chainId) {
ReadOnlyShardDataTreeTransaction newReadOnlyTransaction(final String txId, final String chainId) {
if (Strings.isNullOrEmpty(chainId)) {
- return new ReadOnlyShardDataTreeTransaction(txId, dataTree.takeSnapshot());
+ return transactionFactory.newReadOnlyTransaction(txId, chainId);
}
return ensureTransactionChain(chainId).newReadOnlyTransaction(txId);
ReadWriteShardDataTreeTransaction newReadWriteTransaction(final String txId, final String chainId) {
if (Strings.isNullOrEmpty(chainId)) {
- return new ReadWriteShardDataTreeTransaction(this, txId, dataTree.takeSnapshot().newModification());
+ return transactionFactory.newReadWriteTransaction(txId, chainId);
}
return ensureTransactionChain(chainId).newReadWriteTransaction(txId);
return new SimpleShardDataTreeCohort(this, snapshot);
}
+ void recoveryDone(){
+ transactionFactory = new RegularShardDataTreeTransactionFactory();
+ }
+
+ @VisibleForTesting
+ ShardDataTreeTransactionFactory getTransactionFactory(){
+ return transactionFactory;
+ }
+
+ @VisibleForTesting
+ static interface ShardDataTreeTransactionFactory {
+ ReadOnlyShardDataTreeTransaction newReadOnlyTransaction(final String txId, final String chainId);
+
+ ReadWriteShardDataTreeTransaction newReadWriteTransaction(final String txId, final String chainId);
+ }
+
+ @VisibleForTesting
+ class RecoveryShardDataTreeTransactionFactory implements ShardDataTreeTransactionFactory {
+
+ @Override
+ public ReadOnlyShardDataTreeTransaction newReadOnlyTransaction(String txId, String chainId) {
+ return new ReadOnlyShardDataTreeTransaction(txId,
+ new ShardDataTreeSnapshot(dataTree.takeSnapshot(), validNamespaces));
+ }
+
+ @Override
+ public ReadWriteShardDataTreeTransaction newReadWriteTransaction(String txId, String chainId) {
+ return new ReadWriteShardDataTreeTransaction(ShardDataTree.this, txId,
+ new ShardDataTreeSnapshot(dataTree.takeSnapshot(), validNamespaces).newModification());
+ }
+ }
+
+ @VisibleForTesting
+ class RegularShardDataTreeTransactionFactory implements ShardDataTreeTransactionFactory {
+
+ @Override
+ public ReadOnlyShardDataTreeTransaction newReadOnlyTransaction(String txId, String chainId) {
+ return new ReadOnlyShardDataTreeTransaction(txId, dataTree.takeSnapshot());
+
+ }
+
+ @Override
+ public ReadWriteShardDataTreeTransaction newReadWriteTransaction(String txId, String chainId) {
+ return new ReadWriteShardDataTreeTransaction(ShardDataTree.this, txId, dataTree.takeSnapshot()
+ .newModification());
+ }
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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 com.google.common.base.Optional;
+import java.net.URI;
+import java.util.Set;
+import org.opendaylight.controller.cluster.datastore.utils.PruningDataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+
+class ShardDataTreeSnapshot implements DataTreeSnapshot {
+
+ private final DataTreeSnapshot dataTreeSnapshot;
+ private final Set<URI> validNamespaces;
+
+ public ShardDataTreeSnapshot(DataTreeSnapshot dataTreeSnapshot, Set<URI> validNamespaces) {
+ this.dataTreeSnapshot = dataTreeSnapshot;
+ this.validNamespaces = validNamespaces;
+ }
+
+ @Override
+ public Optional<NormalizedNode<?, ?>> readNode(YangInstanceIdentifier yangInstanceIdentifier) {
+ return this.dataTreeSnapshot.readNode(yangInstanceIdentifier);
+ }
+
+ @Override
+ public DataTreeModification newModification() {
+ return new PruningDataTreeModification(this.dataTreeSnapshot.newModification(), validNamespaces);
+ }
+
+
+}
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.cluster.datastore.utils.PruningDataTreeModification;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateTip;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
import org.slf4j.Logger;
@Override
public ListenableFuture<Boolean> canCommit() {
try {
- dataTree.getDataTree().validate(transaction);
+ dataTree.getDataTree().validate(dataTreeModification());
LOG.debug("Transaction {} validated", transaction);
return TRUE_FUTURE;
} catch (Exception e) {
@Override
public ListenableFuture<Void> preCommit() {
try {
- candidate = dataTree.getDataTree().prepare(transaction);
+ candidate = dataTree.getDataTree().prepare(dataTreeModification());
/*
* FIXME: this is the place where we should be interacting with persistence, specifically by invoking
* persist on the candidate (which gives us a Future).
}
}
+ private DataTreeModification dataTreeModification() {
+ DataTreeModification dataTreeModification = transaction;
+ if(transaction instanceof PruningDataTreeModification){
+ dataTreeModification = ((PruningDataTreeModification) transaction).getDelegate();
+ }
+ return dataTreeModification;
+ }
+
@Override
public ListenableFuture<Void> abort() {
// No-op, really
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.utils;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Set;
+import org.opendaylight.controller.cluster.datastore.node.utils.transformer.NormalizedNodePruner;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModificationCursor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The PruningDataTreeModification first removes all entries from the data which do not belong in the schemaContext
+ * before delegating it to the actual DataTreeModification
+ */
+public class PruningDataTreeModification implements DataTreeModification {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PruningDataTreeModification.class);
+ private final DataTreeModification delegate;
+ private final Set<URI> validNamespaces;
+
+ public PruningDataTreeModification(DataTreeModification delegate, Set<URI> validNamespaces) {
+ this.delegate = delegate;
+ this.validNamespaces = validNamespaces;
+ }
+
+ @Override
+ public void delete(YangInstanceIdentifier yangInstanceIdentifier) {
+ try {
+ delegate.delete(yangInstanceIdentifier);
+ } catch(IllegalArgumentException e){
+ LOG.warn("Node at path : {} does not exist ignoring delete", yangInstanceIdentifier);
+ }
+ }
+
+ @Override
+ public void merge(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
+ try {
+ delegate.merge(yangInstanceIdentifier, normalizedNode);
+ } catch (IllegalArgumentException e){
+ if(!isValidYangInstanceIdentifier(yangInstanceIdentifier)){
+ LOG.warn("Invalid node identifier {} ignoring merge", yangInstanceIdentifier);
+ return;
+ }
+
+ LOG.warn("Node at path : {} was pruned during merge", yangInstanceIdentifier);
+
+ NormalizedNode<?,?> pruned = pruneNormalizedNode(normalizedNode);
+
+ if(pruned != null) {
+ delegate.merge(yangInstanceIdentifier, pruned);
+ }
+ }
+
+ }
+
+ @Override
+ public void write(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
+ try {
+ delegate.write(yangInstanceIdentifier, normalizedNode);
+ } catch (IllegalArgumentException e){
+ if(!isValidYangInstanceIdentifier(yangInstanceIdentifier)){
+ LOG.warn("Invalid node identifier {} ignoring write", yangInstanceIdentifier);
+ return;
+ }
+
+ LOG.warn("Node at path : {} was pruned during write", yangInstanceIdentifier);
+
+ NormalizedNode<?,?> pruned = pruneNormalizedNode(normalizedNode);
+
+ if(pruned != null) {
+ delegate.write(yangInstanceIdentifier, pruned);
+ }
+ }
+ }
+
+ @Override
+ public void ready() {
+ delegate.ready();
+ }
+
+ @Override
+ public void applyToCursor(DataTreeModificationCursor dataTreeModificationCursor) {
+ delegate.applyToCursor(dataTreeModificationCursor);
+ }
+
+ @Override
+ public Optional<NormalizedNode<?, ?>> readNode(YangInstanceIdentifier yangInstanceIdentifier) {
+ return delegate.readNode(yangInstanceIdentifier);
+ }
+
+ @Override
+ public DataTreeModification newModification() {
+ return new PruningDataTreeModification(delegate.newModification(), validNamespaces);
+ }
+
+ @VisibleForTesting
+ NormalizedNode<?, ?> pruneNormalizedNode(NormalizedNode<?,?> input){
+ NormalizedNodePruner pruner = new NormalizedNodePruner(validNamespaces);
+ try {
+ NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+ } catch (IOException ioe) {
+ LOG.error("Unexpected IOException when pruning normalizedNode", ioe);
+ }
+
+ return pruner.normalizedNode();
+ }
+
+ public DataTreeModification getDelegate(){
+ return delegate;
+ }
+
+ private boolean isValidYangInstanceIdentifier(YangInstanceIdentifier instanceIdentifier){
+ for(YangInstanceIdentifier.PathArgument pathArgument : instanceIdentifier.getPathArguments()){
+ if(!validNamespaces.contains(pathArgument.getNodeType().getNamespace())){
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.cluster.datastore;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+import java.net.URI;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.cluster.datastore.utils.PruningDataTreeModification;
+import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+
+public class ShardDataTreeSnapshotTest {
+
+ @Mock
+ DataTreeSnapshot dataTreeSnapshot;
+
+ @Mock
+ Set<URI> validNamespaces;
+
+ @Before
+ public void setUp(){
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testNewModification(){
+ ShardDataTreeSnapshot snapshot1
+ = new ShardDataTreeSnapshot(dataTreeSnapshot, validNamespaces);
+
+ DataTreeModification dataTreeModification1 = snapshot1.newModification();
+
+ assertTrue(dataTreeModification1 instanceof PruningDataTreeModification);
+ }
+
+ @Test
+ public void testReadNode(){
+ ShardDataTreeSnapshot snapshot
+ = new ShardDataTreeSnapshot(dataTreeSnapshot, validNamespaces);
+
+ snapshot.readNode(CarsModel.BASE_PATH);
+
+ verify(dataTreeSnapshot).readNode(CarsModel.BASE_PATH);
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.cluster.datastore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import com.google.common.base.Optional;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+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.yangtools.yang.data.api.schema.NormalizedNode;
+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.model.api.SchemaContext;
+
+public class ShardDataTreeTest {
+
+ @Test
+ public void testWrite() throws ExecutionException, InterruptedException {
+
+ SchemaContext schemaContext = SchemaContextHelper.full();
+
+ modify(new ShardDataTree(schemaContext), false, true, true);
+ }
+
+ @Test
+ public void testWriteWithMissingSchema() throws ExecutionException, InterruptedException {
+
+ SchemaContext schemaContext = SchemaContextHelper.select(SchemaContextHelper.ODL_DATASTORE_TEST_YANG, SchemaContextHelper.PEOPLE_YANG);
+
+ modify(new ShardDataTree(schemaContext), false, false, true);
+ }
+
+ @Test
+ public void testMerge() throws ExecutionException, InterruptedException {
+
+ SchemaContext schemaContext = SchemaContextHelper.full();
+
+ modify(new ShardDataTree(schemaContext), true, true, true);
+ }
+
+ @Test
+ public void testMergeWithMissingSchema() throws ExecutionException, InterruptedException {
+
+ SchemaContext schemaContext = SchemaContextHelper.select(SchemaContextHelper.ODL_DATASTORE_TEST_YANG, SchemaContextHelper.PEOPLE_YANG);
+
+ modify(new ShardDataTree(schemaContext), true, false, true);
+ }
+
+ private void modify(ShardDataTree shardDataTree, boolean merge, boolean expectedCarsPresent, boolean expectedPeoplePresent) throws ExecutionException, InterruptedException {
+ ReadWriteShardDataTreeTransaction transaction = shardDataTree.newReadWriteTransaction("txn-1", null);
+
+ DataTreeModification snapshot = transaction.getSnapshot();
+
+ assertNotNull(snapshot);
+
+ if(merge){
+ snapshot.merge(CarsModel.BASE_PATH, CarsModel.create());
+ snapshot.merge(PeopleModel.BASE_PATH, PeopleModel.create());
+ } else {
+ snapshot.write(CarsModel.BASE_PATH, CarsModel.create());
+ snapshot.write(PeopleModel.BASE_PATH, PeopleModel.create());
+ }
+
+ ShardDataTreeCohort cohort = shardDataTree.finishTransaction(transaction);
+
+ cohort.preCommit().get();
+ cohort.commit().get();
+
+
+ ReadOnlyShardDataTreeTransaction readOnlyShardDataTreeTransaction = shardDataTree.newReadOnlyTransaction("txn-2", null);
+
+ DataTreeSnapshot snapshot1 = readOnlyShardDataTreeTransaction.getSnapshot();
+
+ Optional<NormalizedNode<?, ?>> optional = snapshot1.readNode(CarsModel.BASE_PATH);
+
+ assertEquals(expectedCarsPresent, optional.isPresent());
+
+ Optional<NormalizedNode<?, ?>> optional1 = snapshot1.readNode(PeopleModel.BASE_PATH);
+
+ assertEquals(expectedPeoplePresent, optional1.isPresent());
+
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAfterRecoveryDone() throws ExecutionException, InterruptedException {
+ SchemaContext schemaContext = SchemaContextHelper.select(SchemaContextHelper.ODL_DATASTORE_TEST_YANG, SchemaContextHelper.PEOPLE_YANG);
+ ShardDataTree shardDataTree = new ShardDataTree(schemaContext);
+ assertTrue("transaction factory must be the recovery transaction factory",
+ shardDataTree.getTransactionFactory() instanceof ShardDataTree.RecoveryShardDataTreeTransactionFactory);
+ shardDataTree.recoveryDone();
+ assertTrue("transaction factory must be the regular transaction factory",
+ shardDataTree.getTransactionFactory() instanceof ShardDataTree.RegularShardDataTreeTransactionFactory);
+
+ modify(shardDataTree, true, false, true);
+
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.cluster.datastore.utils;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import java.net.URI;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModificationCursor;
+
+public class PruningDataTreeModificationTest {
+
+ @Mock
+ DataTreeModification delegate;
+
+ @Mock
+ Set<URI> validNamespaces;
+
+ @Mock
+ NormalizedNode<?,?> prunedNormalizedNode;
+
+ PruningDataTreeModification pruningDataTreeModification;
+
+ @Before
+ public void setUp(){
+ MockitoAnnotations.initMocks(this);
+ pruningDataTreeModification = new PruningDataTreeModification(delegate, validNamespaces) {
+ @Override
+ NormalizedNode<?, ?> pruneNormalizedNode(NormalizedNode<?, ?> input) {
+ return prunedNormalizedNode;
+ }
+ };
+ }
+
+ @Test
+ public void testDelete(){
+ pruningDataTreeModification.delete(CarsModel.BASE_PATH);
+
+ verify(delegate).delete(CarsModel.BASE_PATH);
+ }
+
+ @Test
+ public void testDeleteOnException(){
+ YangInstanceIdentifier path = CarsModel.BASE_PATH;
+ doThrow(IllegalArgumentException.class).when(delegate).delete(path);
+
+ pruningDataTreeModification.delete(path);
+
+ verify(delegate, times(1)).delete(path);
+ }
+
+
+ @Test
+ public void testMerge(){
+ NormalizedNode<?, ?> normalizedNode = CarsModel.create();
+ YangInstanceIdentifier path = CarsModel.BASE_PATH;
+ pruningDataTreeModification.merge(path, normalizedNode);
+
+ verify(delegate, times(1)).merge(path, normalizedNode);
+ }
+
+ @Test
+ public void testMergeOnException(){
+ NormalizedNode<?, ?> normalizedNode = CarsModel.create();
+ YangInstanceIdentifier path = CarsModel.BASE_PATH;
+
+ doThrow(IllegalArgumentException.class).when(delegate).merge(path, normalizedNode);
+ doReturn(true).when(validNamespaces).contains(any(YangInstanceIdentifier.PathArgument.class));
+
+ pruningDataTreeModification.merge(path, normalizedNode);
+
+ verify(delegate, times(1)).merge(path, normalizedNode);
+ verify(delegate, times(1)).merge(path, prunedNormalizedNode);
+ }
+
+ @Test
+ public void testWrite(){
+ NormalizedNode<?, ?> normalizedNode = CarsModel.create();
+ YangInstanceIdentifier path = CarsModel.BASE_PATH;
+ pruningDataTreeModification.write(path, normalizedNode);
+
+ verify(delegate, times(1)).write(path, normalizedNode);
+ }
+
+ @Test
+ public void testWriteOnException(){
+ NormalizedNode<?, ?> normalizedNode = CarsModel.create();
+ YangInstanceIdentifier path = CarsModel.BASE_PATH;
+
+ doThrow(IllegalArgumentException.class).when(delegate).write(path, normalizedNode);
+ doReturn(true).when(validNamespaces).contains(any(YangInstanceIdentifier.PathArgument.class));
+
+ pruningDataTreeModification.write(path, normalizedNode);
+
+ verify(delegate, times(1)).write(path, normalizedNode);
+ verify(delegate, times(1)).write(path, prunedNormalizedNode);
+ }
+
+ @Test
+ public void testReady(){
+ pruningDataTreeModification.ready();
+
+ verify(delegate).ready();
+ }
+
+ @Test
+ public void testApplyToCursor(){
+ DataTreeModificationCursor dataTreeModificationCursor = mock(DataTreeModificationCursor.class);
+ pruningDataTreeModification.applyToCursor(dataTreeModificationCursor);
+
+ verify(delegate).applyToCursor(dataTreeModificationCursor);
+ }
+
+ @Test
+ public void testReadNode(){
+ pruningDataTreeModification.readNode(CarsModel.BASE_PATH);
+
+ verify(delegate).readNode(CarsModel.BASE_PATH);
+ }
+
+ @Test
+ public void testNewModification(){
+ DataTreeModification dataTreeModification = pruningDataTreeModification.newModification();
+
+ assertTrue("new modification not of type PruningDataTreeModification", dataTreeModification instanceof PruningDataTreeModification);
+ }
+}
\ No newline at end of file
package org.opendaylight.controller.md.cluster.datastore.model;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
-
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
public class SchemaContextHelper {
+ public static final String ODL_DATASTORE_TEST_YANG = "/odl-datastore-test.yang";
+ public static final String PEOPLE_YANG = "/people.yang";
+ public static final String CARS_YANG = "/cars.yang";
+
public static InputStream getInputStream(final String yangFileName) {
return TestModel.class.getResourceAsStream(yangFileName);
}
public static SchemaContext full(){
+ return select(ODL_DATASTORE_TEST_YANG, PEOPLE_YANG, CARS_YANG);
+ }
+
+ public static SchemaContext select(String... schemaFiles){
YangParserImpl parser = new YangParserImpl();
List<InputStream> streams = new ArrayList<>();
- streams.add(getInputStream("/odl-datastore-test.yang"));
- streams.add(getInputStream("/people.yang"));
- streams.add(getInputStream("/cars.yang"));
+
+ for(String schemaFile : schemaFiles){
+ streams.add(getInputStream(schemaFile));
+ }
Set<Module> modules = parser.parseYangModelsFromStreams(streams);
return parser.resolveSchemaContext(modules);
-
}
+
}