summaryrefslogtreecommitdiffstats
path: root/v3po/impl
diff options
context:
space:
mode:
Diffstat (limited to 'v3po/impl')
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java4
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java102
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java17
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java2
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java2
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java92
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java (renamed from v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationException.java)2
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java49
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/DefaultVppWriter.java43
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppInterfacesReader.java56
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppReader.java30
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppWriter.java27
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java71
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java54
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java5
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationExceptionTest.java (renamed from v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationExceptionTest.java)2
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContextTest.java122
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizerTest.java269
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainTestUtils.java64
-rw-r--r--v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java13
20 files changed, 750 insertions, 276 deletions
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java
index 4afd86099..931ecefd6 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java
@@ -22,6 +22,7 @@ import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.Futures;
import io.fd.honeycomb.v3po.impl.data.VppDataBrokerInitializationProvider;
import io.fd.honeycomb.v3po.impl.data.VppReaderRegistry;
+import io.fd.honeycomb.v3po.impl.data.VppWriterRegistry;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
@@ -196,9 +197,10 @@ public class V3poProvider implements BindingAwareProvider, AutoCloseable, Broker
startOperationalUpdateTimer();
final VppReaderRegistry readerRegistry = VppReaderRegistry.getInstance(api);
+ final VppWriterRegistry writerRegistry = VppWriterRegistry.getInstance(api);
// TODO make configurable:
- vppDataBrokerInitializationProvider = new VppDataBrokerInitializationProvider(db, readerRegistry);
+ vppDataBrokerInitializationProvider = new VppDataBrokerInitializationProvider(db, readerRegistry, writerRegistry);
// TODO pull the registration into Module
domBroker.registerProvider(vppDataBrokerInitializationProvider);
}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java
index 41a68e7bb..6fdeea348 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppConfigDataTree.java
@@ -16,12 +16,15 @@
package io.fd.honeycomb.v3po.impl.data;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Collections.singletonList;
+
import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.Futures;
-import io.fd.honeycomb.v3po.impl.trans0.VppApiInvocationException;
-import io.fd.honeycomb.v3po.impl.trans0.VppWriter;
+import io.fd.honeycomb.v3po.impl.trans.w.WriteContext;
+import io.fd.honeycomb.v3po.impl.trans.w.util.TransactionWriteContext;
+import io.fd.honeycomb.v3po.impl.trans.VppApiInvocationException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -31,6 +34,7 @@ import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -55,7 +59,14 @@ public final class VppConfigDataTree implements VppDataTree {
private final BindingNormalizedNodeSerializer serializer;
private final DataTree dataTree;
- private final VppWriter writer;
+ private final VppWriterRegistry writer;
+ public static final ReadableVppDataTree EMPTY_OPERATIONAL = new ReadableVppDataTree() {
+ @Override
+ public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
+ @Nonnull final YangInstanceIdentifier path) {
+ return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>>absent());
+ }
+ };
/**
* Creates configuration data tree instance.
@@ -66,10 +77,10 @@ public final class VppConfigDataTree implements VppDataTree {
* @param vppWriter service for translation between Java Binding Data and Vpp.
*/
public VppConfigDataTree(@Nonnull final BindingNormalizedNodeSerializer serializer,
- @Nonnull final DataTree dataTree, @Nonnull final VppWriter vppWriter) {
- this.serializer = Preconditions.checkNotNull(serializer, "serializer should not be null");
- this.dataTree = Preconditions.checkNotNull(dataTree, "dataTree should not be null");
- this.writer = Preconditions.checkNotNull(vppWriter, "vppWriter should not be null");
+ @Nonnull final DataTree dataTree, @Nonnull final VppWriterRegistry vppWriter) {
+ this.serializer = checkNotNull(serializer, "serializer should not be null");
+ this.dataTree = checkNotNull(dataTree, "dataTree should not be null");
+ this.writer = checkNotNull(vppWriter, "vppWriter should not be null");
}
@Override
@@ -78,7 +89,8 @@ public final class VppConfigDataTree implements VppDataTree {
}
@Override
- public void commit(final DataTreeModification modification) throws DataValidationFailedException, VppApiInvocationException {
+ public void commit(final DataTreeModification modification)
+ throws DataValidationFailedException, VppApiInvocationException {
dataTree.validate(modification);
final DataTreeCandidate candidate = dataTree.prepare(modification);
@@ -87,16 +99,22 @@ public final class VppConfigDataTree implements VppDataTree {
final YangInstanceIdentifier rootPath = candidate.getRootPath();
final Optional<NormalizedNode<?, ?>> normalizedDataBefore = rootNode.getDataBefore();
final Optional<NormalizedNode<?, ?>> normalizedDataAfter = rootNode.getDataAfter();
- LOG.debug("VppConfigDataProxy.commit() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}",
+ LOG.debug("VppConfigDataTree.commit() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}",
rootPath, rootNode, normalizedDataBefore, normalizedDataAfter);
final Map<InstanceIdentifier<?>, DataObject> nodesBefore = extractNetconfData(normalizedDataBefore);
- LOG.debug("VppConfigDataProxy.commit() extracted nodesBefore={}", nodesBefore.keySet());
+ LOG.debug("VppConfigDataTree.commit() extracted nodesBefore={}", nodesBefore.keySet());
final Map<InstanceIdentifier<?>, DataObject> nodesAfter = extractNetconfData(normalizedDataAfter);
- LOG.debug("VppConfigDataProxy.commit() extracted nodesAfter={}", nodesAfter.keySet());
+ LOG.debug("VppConfigDataTree.commit() extracted nodesAfter={}", nodesAfter.keySet());
- final ChangesProcessor processor = new ChangesProcessor(writer, nodesBefore, nodesAfter);
+
+ final DOMDataReadOnlyTransaction beforeTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, takeSnapshot());
+ final ConfigSnapshot modificationSnapshot = new ConfigSnapshot(modification);
+ final DOMDataReadOnlyTransaction afterTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, modificationSnapshot);
+ final WriteContext ctx = new TransactionWriteContext(serializer, beforeTx, afterTx);
+
+ final ChangesProcessor processor = new ChangesProcessor(writer, nodesBefore, nodesAfter, ctx);
try {
processor.applyChanges();
} catch (VppApiInvocationException e) {
@@ -118,9 +136,10 @@ public final class VppConfigDataTree implements VppDataTree {
dataTree.commit(candidate);
}
- private Map<InstanceIdentifier<?>, DataObject> extractNetconfData(final Optional<NormalizedNode<?, ?>> parentOptional) {
+ private Map<InstanceIdentifier<?>, DataObject> extractNetconfData(
+ final Optional<NormalizedNode<?, ?>> parentOptional) {
if (parentOptional.isPresent()) {
- final DataContainerNode parent = (DataContainerNode)parentOptional.get();
+ final DataContainerNode parent = (DataContainerNode) parentOptional.get();
return DataTreeUtils.childrenFromNormalized(parent, serializer);
}
return Collections.emptyMap();
@@ -135,7 +154,7 @@ public final class VppConfigDataTree implements VppDataTree {
@Override
public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
- final YangInstanceIdentifier path) {
+ @Nonnull final YangInstanceIdentifier path) {
final Optional<NormalizedNode<?, ?>> node = snapshot.readNode(path);
if (LOG.isTraceEnabled() && node.isPresent()) {
LOG.trace("ConfigSnapshot.read: {}", node.get());
@@ -150,57 +169,80 @@ public final class VppConfigDataTree implements VppDataTree {
}
private static final class ChangesProcessor {
- private final VppWriter writer;
+ private final VppWriterRegistry writer;
private final List<InstanceIdentifier<?>> processedNodes;
private final Map<InstanceIdentifier<?>, DataObject> nodesBefore;
private final Map<InstanceIdentifier<?>, DataObject> nodesAfter;
+ private final WriteContext ctx;
- ChangesProcessor(@Nonnull final VppWriter writer,
+ ChangesProcessor(@Nonnull final VppWriterRegistry writer,
final Map<InstanceIdentifier<?>, DataObject> nodesBefore,
- final Map<InstanceIdentifier<?>, DataObject> nodesAfter) {
- this.writer = Preconditions.checkNotNull(writer, "VppWriter is null!");
- this.nodesBefore = Preconditions.checkNotNull(nodesBefore, "nodesBefore is null!");
- this.nodesAfter = Preconditions.checkNotNull(nodesAfter, "nodesAfter is null!");
+ final Map<InstanceIdentifier<?>, DataObject> nodesAfter,
+ @Nonnull final WriteContext writeContext) {
+ this.ctx = checkNotNull(writeContext, "writeContext is null!");
+ this.writer = checkNotNull(writer, "VppWriter is null!");
+ this.nodesBefore = checkNotNull(nodesBefore, "nodesBefore is null!");
+ this.nodesAfter = checkNotNull(nodesAfter, "nodesAfter is null!");
processedNodes = new ArrayList<>();
}
void applyChanges() throws VppApiInvocationException {
// TODO we should care about the order of modified subtrees
+ // TODO maybe WriterRegistry could provide writeAll method and it will process the updates
+ // in order in which it child writers are registered
final Set<InstanceIdentifier<?>> allNodes = new HashSet<>();
allNodes.addAll(nodesBefore.keySet());
allNodes.addAll(nodesAfter.keySet());
- LOG.debug("VppConfigDataProxy.applyChanges() all extracted nodes: {}", allNodes);
+ LOG.debug("ChangesProcessor.applyChanges() all extracted nodes: {}", allNodes);
for (InstanceIdentifier<?> node : allNodes) {
- LOG.debug("VppConfigDataProxy.applyChanges() processing node={}", node);
+ LOG.debug("ChangesProcessor.applyChanges() processing node={}", node);
final DataObject dataBefore = nodesBefore.get(node);
final DataObject dataAfter = nodesAfter.get(node);
+ LOG.debug("ChangesProcessor.applyChanges() processing dataBefore={}, dataAfter={}", dataBefore,
+ dataAfter);
try {
- writer.process(dataBefore, dataAfter);
+ // TODO is List as input argument really necessary for writer ?
+ final List<DataObject> dataObjectsBefore = dataBefore == null
+ ? Collections.<DataObject>emptyList()
+ : singletonList(dataBefore);
+ final List<DataObject> dataObjectsAfter = dataAfter == null
+ ? Collections.<DataObject>emptyList()
+ : singletonList(dataAfter);
+ LOG.debug("ChangesProcessor.applyChanges() processing dataObjectsBefore={}, dataObjectsAfter={}",
+ dataObjectsBefore, dataObjectsAfter);
+ writer.update(node, dataObjectsBefore, dataObjectsAfter, ctx);
processedNodes.add(node);
- } catch (VppApiInvocationException e) {
+ } catch (RuntimeException e) {
LOG.error("Error while processing data change (before={}, after={})", dataBefore, dataAfter, e);
- throw e;
+ // FIXME ex handling
+ throw new VppApiInvocationException("", 1, -1);
}
}
}
void revertChanges() throws VppApiInvocationException {
- Preconditions.checkNotNull(writer, "VppWriter is null!");
+ checkNotNull(writer, "VppWriter is null!");
// revert changes in reverse order they were applied
final ListIterator<InstanceIdentifier<?>> iterator = processedNodes.listIterator(processedNodes.size());
while (iterator.hasPrevious()) {
final InstanceIdentifier<?> node = iterator.previous();
- LOG.debug("VppConfigDataProxy.revertChanges() processing node={}", node);
+ LOG.debug("ChangesProcessor.revertChanges() processing node={}", node);
final DataObject dataBefore = nodesBefore.get(node);
final DataObject dataAfter = nodesAfter.get(node);
// revert a change by invoking writer with reordered arguments
- writer.process(dataAfter, dataBefore);
+ try {
+ // TODO is List as input argument really necessary for writer ?
+ writer.update(node, singletonList(dataAfter), singletonList(dataBefore), ctx);
+ } catch (RuntimeException e) {
+ // FIXME ex handling
+ throw new VppApiInvocationException("", 1, -1);
+ }
}
}
}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java
index 129a1b84b..2a14f48b1 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProvider.java
@@ -16,6 +16,8 @@
package io.fd.honeycomb.v3po.impl.data;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.AsyncFunction;
@@ -23,7 +25,6 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.fd.honeycomb.v3po.impl.LoggingFuturesCallBack;
import io.fd.honeycomb.v3po.impl.trans.r.ReaderRegistry;
-import io.fd.honeycomb.v3po.impl.trans0.DefaultVppWriter;
import java.util.Collection;
import java.util.Collections;
import javassist.ClassPool;
@@ -84,12 +85,16 @@ public final class VppDataBrokerInitializationProvider implements Provider, Auto
private final DataBroker bindingBroker;
private final ReaderRegistry readerRegistry;
private final InstanceIdentifier<Node> mountPointPath;
+ private final VppWriterRegistry writerRegistry;
private ObjectRegistration<DOMMountPoint> mountPointRegistration;
private DOMDataBroker broker;
- public VppDataBrokerInitializationProvider(@Nonnull final DataBroker bindingBroker, final ReaderRegistry readerRegistry) {
- this.bindingBroker = Preconditions.checkNotNull(bindingBroker, "bindingBroker should not be null");
- this.readerRegistry = Preconditions.checkNotNull(readerRegistry, "readerRegistry should not be null");
+ public VppDataBrokerInitializationProvider(@Nonnull final DataBroker bindingBroker,
+ final ReaderRegistry readerRegistry,
+ final VppWriterRegistry writerRegistry) {
+ this.bindingBroker = checkNotNull(bindingBroker, "bindingBroker should not be null");
+ this.readerRegistry = checkNotNull(readerRegistry, "readerRegistry should not be null");
+ this.writerRegistry = checkNotNull(writerRegistry, "writerRegistry should not be null");
this.mountPointPath = getMountPointPath();
}
@@ -180,9 +185,7 @@ public final class VppDataBrokerInitializationProvider implements Provider, Auto
InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION); // TODO make configurable
dataTree.setSchemaContext(globalContext);
- // FIXME use the new writer API
- final VppDataTree configDataProxy = new VppConfigDataTree(serializer, dataTree,
- new DefaultVppWriter()); // TODO make configurable
+ final VppDataTree configDataProxy = new VppConfigDataTree(serializer, dataTree, writerRegistry); // TODO make configurable
return new VppDataBroker(operationalData, configDataProxy);
}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java
index 17d3b7149..a3a4fae65 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppDataTree.java
@@ -17,7 +17,7 @@
package io.fd.honeycomb.v3po.impl.data;
import com.google.common.annotations.Beta;
-import io.fd.honeycomb.v3po.impl.trans0.VppApiInvocationException;
+import io.fd.honeycomb.v3po.impl.trans.VppApiInvocationException;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java
index 8cdd10b7e..b7aa2f854 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriteTransaction.java
@@ -26,7 +26,7 @@ import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import io.fd.honeycomb.v3po.impl.trans0.VppApiInvocationException;
+import io.fd.honeycomb.v3po.impl.trans.VppApiInvocationException;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.NotThreadSafe;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java
new file mode 100644
index 000000000..67b45cfd2
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/data/VppWriterRegistry.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl.data;
+
+import io.fd.honeycomb.v3po.impl.trans.util.VppRWUtils;
+import io.fd.honeycomb.v3po.impl.trans.w.ChildVppWriter;
+import io.fd.honeycomb.v3po.impl.trans.w.VppWriter;
+import io.fd.honeycomb.v3po.impl.trans.w.WriteContext;
+import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeChildVppWriter;
+import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeListVppWriter;
+import io.fd.honeycomb.v3po.impl.trans.w.impl.CompositeRootVppWriter;
+import io.fd.honeycomb.v3po.impl.trans.w.util.DelegatingWriterRegistry;
+import io.fd.honeycomb.v3po.impl.trans.w.util.NoopWriterCustomizer;
+import io.fd.honeycomb.v3po.impl.trans.w.util.ReflexiveChildWriterCustomizer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.vppjapi.vppApi;
+
+// TODO use some DI framework instead of singleton
+public class VppWriterRegistry implements VppWriter<DataObject> {
+
+ private static VppWriterRegistry instance;
+
+ private final DelegatingWriterRegistry writer;
+
+ private VppWriterRegistry(@Nonnull final vppApi vppApi) {
+ final CompositeRootVppWriter<Vpp> vppWriter = initVppStateWriter(vppApi);
+ writer = new DelegatingWriterRegistry(Collections.<VppWriter<? extends DataObject>>singletonList(vppWriter));
+ }
+
+ private static CompositeRootVppWriter<Vpp> initVppStateWriter(@Nonnull final vppApi vppApi) {
+ final CompositeListVppWriter<BridgeDomain, BridgeDomainKey> bridgeDomainWriter = new CompositeListVppWriter<>(
+ BridgeDomain.class,
+ new io.fd.honeycomb.v3po.impl.vpp.BridgeDomainCustomizer(vppApi));
+
+ final ChildVppWriter<BridgeDomains> bridgeDomainsWriter = new CompositeChildVppWriter<>(
+ BridgeDomains.class,
+ VppRWUtils.singletonChildWriterList(bridgeDomainWriter),
+ new ReflexiveChildWriterCustomizer<BridgeDomains>());
+
+ final List<ChildVppWriter<? extends ChildOf<Vpp>>> childWriters = new ArrayList<>();
+ childWriters.add(bridgeDomainsWriter);
+
+ return new CompositeRootVppWriter<>(
+ Vpp.class,
+ childWriters,
+ new NoopWriterCustomizer<Vpp>());
+ }
+
+ public static synchronized VppWriterRegistry getInstance(@Nonnull final vppApi vppApi) {
+ if (instance == null) {
+ instance = new VppWriterRegistry(vppApi);
+ }
+ return instance;
+ }
+
+ @Nonnull
+ @Override
+ public InstanceIdentifier<DataObject> getManagedDataObjectType() {
+ return writer.getManagedDataObjectType();
+ }
+
+ @Override
+ public void update(@Nonnull final InstanceIdentifier<? extends DataObject> id,
+ @Nonnull final List<? extends DataObject> dataBefore,
+ @Nonnull final List<? extends DataObject> data, @Nonnull final WriteContext ctx) {
+ writer.update(id, dataBefore, data, ctx);
+ }
+}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationException.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java
index 119563bdd..b0076cd9c 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationException.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationException.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.fd.honeycomb.v3po.impl.trans0;
+package io.fd.honeycomb.v3po.impl.trans;
import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java
index 3a1fd2f57..7c1a63da6 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContext.java
@@ -22,29 +22,30 @@ import io.fd.honeycomb.v3po.impl.trans.util.Context;
import io.fd.honeycomb.v3po.impl.trans.w.WriteContext;
import java.util.Collections;
import java.util.List;
-import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import java.util.Map;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
public class TransactionWriteContext implements WriteContext, AutoCloseable {
- private final ReadOnlyTransaction beforeTx;
- private final ReadOnlyTransaction afterTx;
+ private final DOMDataReadOnlyTransaction beforeTx;
+ private final DOMDataReadOnlyTransaction afterTx;
private final Context ctx;
+ private final BindingNormalizedNodeSerializer serializer;
- public TransactionWriteContext(final ReadOnlyTransaction beforeTx, final ReadOnlyTransaction afterTx,
- final Context ctx) {
- super();
+ public TransactionWriteContext(final BindingNormalizedNodeSerializer serializer,
+ final DOMDataReadOnlyTransaction beforeTx,
+ final DOMDataReadOnlyTransaction afterTx) {
+ this.serializer = serializer;
this.beforeTx = beforeTx;
this.afterTx = afterTx;
- this.ctx = ctx;
- }
-
- public TransactionWriteContext(final ReadOnlyTransaction beforeTx,
- final ReadOnlyTransaction afterTx) {
- this(beforeTx, afterTx, new Context());
+ this.ctx = new Context();
}
@Override
@@ -53,16 +54,26 @@ public class TransactionWriteContext implements WriteContext, AutoCloseable {
}
private List<? extends DataObject> read(final InstanceIdentifier<? extends DataObject> currentId,
- final ReadOnlyTransaction tx) {
+ final DOMDataReadOnlyTransaction tx) {
// FIXME how to read all for list (using wildcarded ID) ?
- final CheckedFuture<? extends Optional<? extends DataObject>, ReadFailedException> read =
- tx.read(LogicalDatastoreType.CONFIGURATION, currentId);
+ final YangInstanceIdentifier path = serializer.toYangInstanceIdentifier(currentId);
+
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read =
+ tx.read(LogicalDatastoreType.CONFIGURATION, path);
+
try {
- final Optional<? extends DataObject> optional = read.checkedGet();
- return optional.isPresent()
- ? Collections.singletonList(optional.get())
- : Collections.<DataObject>emptyList();
+ final Optional<NormalizedNode<?, ?>> optional = read.checkedGet();
+
+ if (!optional.isPresent()) {
+ return Collections.<DataObject>emptyList();
+ }
+
+ final NormalizedNode<?, ?> data = optional.get();
+ final Map.Entry<InstanceIdentifier<?>, DataObject> entry =
+ serializer.fromNormalizedNode(path, data);
+
+ return Collections.singletonList(entry.getValue());
} catch (ReadFailedException e) {
throw new IllegalStateException("Unable to perform read", e);
}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/DefaultVppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/DefaultVppWriter.java
deleted file mode 100644
index 573353b55..000000000
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/DefaultVppWriter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.fd.honeycomb.v3po.impl.trans0;
-
-import java.util.Objects;
-import javax.annotation.Nullable;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DefaultVppWriter implements VppWriter {
- private static final Logger LOG = LoggerFactory.getLogger(DefaultVppWriter.class);
-
- @Override
- public void process(@Nullable final DataObject dataBefore, @Nullable final DataObject dataAfter)
- throws VppApiInvocationException {
- LOG.debug("Processing modification: dataBefore={}, dataAfter={}", dataBefore, dataAfter);
-
- if (Objects.equals(dataBefore, dataAfter)) {
- LOG.debug("No modification");
- } else if (dataBefore == null) {
- LOG.debug("modification type: CREATE");
- } else if (dataAfter == null) {
- LOG.debug("modification type: DELETE");
- } else {
- LOG.debug("modification type: UPDATE");
- }
- }
-}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppInterfacesReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppInterfacesReader.java
deleted file mode 100644
index 39b5f0208..000000000
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppInterfacesReader.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.fd.honeycomb.v3po.impl.trans0;
-
-import java.util.Collections;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class VppInterfacesReader implements VppReader<Interfaces> {
- private static final Logger LOG = LoggerFactory.getLogger(VppInterfacesReader.class);
-
- @Override
- public Interfaces read(final InstanceIdentifier<? extends DataObject> id) {
- LOG.info("VppInterfacesReader.read, id={}", id);
-
- InterfaceBuilder ifaceBuilder = new InterfaceBuilder();
- final String interfaceName = "eth0";
- ifaceBuilder.setName(interfaceName);
- ifaceBuilder.setDescription("eth0 description");
- ifaceBuilder.setEnabled(false);
- ifaceBuilder.setKey(new InterfaceKey(interfaceName));
- ifaceBuilder.setType(EthernetCsmacd.class);
- ifaceBuilder.setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Disabled);
-
- InterfacesBuilder ifacesBuilder = new InterfacesBuilder();
- ifacesBuilder.setInterface(Collections.singletonList(ifaceBuilder.build()));
- return ifacesBuilder.build();
- }
-
- @Override
- public Class<Interfaces> getManagedDataObjectType() {
- return null;
- }
-}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppReader.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppReader.java
deleted file mode 100644
index 5a4215edb..000000000
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppReader.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.fd.honeycomb.v3po.impl.trans0;
-
-import com.google.common.annotations.Beta;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-@Beta
-public interface VppReader<C extends DataObject> {
-
- C read(InstanceIdentifier<? extends DataObject> id);
-
- Class<C> getManagedDataObjectType();
-
-} \ No newline at end of file
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppWriter.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppWriter.java
deleted file mode 100644
index ee6e1f4be..000000000
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/trans0/VppWriter.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.fd.honeycomb.v3po.impl.trans0;
-
-import com.google.common.annotations.Beta;
-import javax.annotation.Nullable;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-
-@Beta
-public interface VppWriter<C extends DataObject> {
-
- void process(@Nullable C dataBefore, @Nullable C dataAfter) throws VppApiInvocationException;
-} \ No newline at end of file
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java
index f707164eb..c56ebb1a8 100644
--- a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizer.java
@@ -16,6 +16,8 @@
package io.fd.honeycomb.v3po.impl.vpp;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import io.fd.honeycomb.v3po.impl.trans.util.Context;
@@ -38,9 +40,9 @@ public class BridgeDomainCustomizer
private static final Logger LOG = LoggerFactory.getLogger(BridgeDomainCustomizer.class);
- static final byte ADD_BD = (byte) 1;
- static final int NO_RET_VAL = -77;
- static final int RELEASE = 1;
+ private static final byte ADD_OR_UPDATE_BD = (byte) 1;
+ private static final int RESPONSE_NOT_READY = -77;
+ private static final int RELEASE = 1;
public BridgeDomainCustomizer(final org.openvpp.vppjapi.vppApi api) {
super(api);
@@ -53,30 +55,37 @@ public class BridgeDomainCustomizer
return ((BridgeDomains) parentData).getBridgeDomain();
}
+ private int waitForResponse(final int ctxId) {
+ int rv;
+ while ((rv = getVppApi().getRetval(ctxId, RELEASE)) == RESPONSE_NOT_READY) {
+ // TODO limit attempts
+ }
+ return rv;
+ }
+
+ private int addOrUpdateBridgeDomain(final int bdId, @Nonnull final BridgeDomain bd) {
+ byte flood = booleanToByte(bd.isFlood());
+ byte forward = booleanToByte(bd.isForward());
+ byte learn = booleanToByte(bd.isLearn());
+ byte uuf = booleanToByte(bd.isUnknownUnicastFlood());
+ byte arpTerm = booleanToByte(bd.isArpTermination());
+
+ int ctxId = getVppApi().bridgeDomainAddDel(bdId, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD);
+ return waitForResponse(ctxId);
+ }
+
@Override
public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
@Nonnull final BridgeDomain current,
@Nonnull final Context ctx) {
+ LOG.debug("writeCurrentAttributes: id={}, current={}, ctx={}", id, current, ctx);
final String bdName = current.getName();
int bdId = getVppApi().findOrAddBridgeDomainId(bdName);
checkState(bdId > 0, "Unable to find or create bridge domain. Return code: %s", bdId);
- byte flood = booleanToByte(current.isFlood());
- byte forward = booleanToByte(current.isForward());
- byte learn = booleanToByte(current.isLearn());
- byte uuf = booleanToByte(current.isUnknownUnicastFlood());
- byte arpTerm = booleanToByte(current.isArpTermination());
-
- int ctxId = getVppApi().bridgeDomainAddDel(bdId, flood, forward, learn, uuf, arpTerm, ADD_BD);
-
- int rv = NO_RET_VAL;
- while (rv == -77) {
- rv = getVppApi().getRetval(ctxId, RELEASE /* release */);
- // TODO limit attempts
- }
- checkState(rv > 0, "Bridge domain %s(%s) write failed. Return code: %s", bdName, bdId, rv);
+ int rv = addOrUpdateBridgeDomain(bdId, current);
- bdId = getVppApi().bridgeDomainIdFromName(bdName);
+ checkState(rv >= 0, "Bridge domain %s(%s) write failed. Return code: %s", bdName, bdId, rv);
LOG.debug("Bridge domain {} written as {} successfully", bdName, bdId);
}
@@ -88,9 +97,10 @@ public class BridgeDomainCustomizer
public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
@Nonnull final BridgeDomain dataBefore,
@Nonnull final Context ctx) {
+ LOG.debug("deleteCurrentAttributes: id={}, dataBefore={}, ctx={}", id, dataBefore, ctx);
String bdName = id.firstKeyOf(BridgeDomain.class).getName();
- int bdId = getVppApi().findOrAddBridgeDomainId(bdName);
+ int bdId = getVppApi().bridgeDomainIdFromName(bdName);
checkState(bdId > 0, "Unable to delete bridge domain. Does not exist. Return code: %s", bdId);
int ctxId = getVppApi().bridgeDomainAddDel(bdId,
@@ -101,13 +111,9 @@ public class BridgeDomainCustomizer
(byte) 0 /* arpTerm */,
(byte) 0 /* isAdd */);
- int rv = NO_RET_VAL;
- while (rv == NO_RET_VAL) {
- rv = getVppApi().getRetval(ctxId, RELEASE /* release */);
- // TODO limit attempts
- }
+ int rv = waitForResponse(ctxId);
- checkState(rv > 0, "Bridge domain delete failed. Return code: %s", rv);
+ checkState(rv >= 0, "Bridge domain delete failed. Return code: %s", rv);
LOG.debug("Bridge domain {} deleted as {} successfully", bdName, bdId);
}
@@ -115,9 +121,18 @@ public class BridgeDomainCustomizer
public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<BridgeDomain> id,
@Nonnull final BridgeDomain dataBefore, @Nonnull final BridgeDomain dataAfter,
@Nonnull final Context ctx) {
- // Most basic update implementation: Delete + Write
- deleteCurrentAttributes(id, dataBefore, ctx);
- writeCurrentAttributes(id, dataAfter, ctx);
+ LOG.debug("updateCurrentAttributes: id={}, dataBefore={}, dataAfter={}, ctx={}", id, dataBefore, dataAfter, ctx);
+
+ final String bdName = checkNotNull(dataAfter.getName());
+ checkArgument(bdName.equals(dataBefore.getName()), "BridgeDomain name changed. It should be deleted and then created.");
+
+ int bdId = getVppApi().bridgeDomainIdFromName(bdName);
+ checkState(bdId > 0, "Unable to find bridge domain. Return code: %s", bdId);
+
+ final int rv = addOrUpdateBridgeDomain(bdId, dataAfter);
+
+ checkState(rv >= 0, "Bridge domain %s(%s) update failed. Return code: %s", bdName, bdId, rv);
+ LOG.debug("Bridge domain {}({}) updated successfully", bdName, bdId);
}
}
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java
index 4e855f447..6aa9da57c 100644
--- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VPPConfigDataTreeTest.java
@@ -16,10 +16,12 @@
package io.fd.honeycomb.v3po.impl.data;
+import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@@ -31,17 +33,17 @@ import static org.mockito.MockitoAnnotations.initMocks;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.CheckedFuture;
-import io.fd.honeycomb.v3po.impl.trans0.VppApiInvocationException;
-import io.fd.honeycomb.v3po.impl.trans0.VppWriter;
+import io.fd.honeycomb.v3po.impl.trans.w.WriteContext;
+import io.fd.honeycomb.v3po.impl.trans.VppApiInvocationException;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -67,7 +69,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailed
public class VPPConfigDataTreeTest {
@Mock
- private VppWriter<DataObject> vppWriter;
+ private VppWriterRegistry vppWriter;
@Mock
private BindingNormalizedNodeSerializer serializer;
@Mock
@@ -135,7 +137,8 @@ public class VPPConfigDataTreeTest {
proxy.commit(modification);
// Verify all changes were processed:
- verify(vppWriter).process(dataBefore, dataAfter);
+ verify(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(dataBefore)),
+ eq(singletonList(dataAfter)), any(WriteContext.class));
// Verify modification was validated
verify(dataTree).validate(modification);
@@ -155,8 +158,9 @@ public class VPPConfigDataTreeTest {
final List<Map.Entry<DataObject, DataObject>> processedChanges = new ArrayList<>();
// reject third applied change
- final Answer answer = new VppWriterAnswer(processedChanges, Arrays.asList(1,2), Collections.singletonList(3));
- doAnswer(answer).when(vppWriter).process(any(DataObject.class), any(DataObject.class));
+ final Answer answer = new VppWriterAnswer(processedChanges, Arrays.asList(1,2), singletonList(3));
+ doAnswer(answer).when(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), anyListOf(DataObject.class),
+ anyListOf(DataObject.class), any(WriteContext.class));
// Prepare modification:
final DataTreeCandidateNode rootNode = mockRootNode();
@@ -172,16 +176,20 @@ public class VPPConfigDataTreeTest {
proxy.commit(modification);
} catch (DataValidationFailedException | VppApiInvocationException e) {
// verify that all changes were processed:
- verify(vppWriter).process(dataBefore1, dataAfter1);
- verify(vppWriter).process(dataBefore2, dataAfter2);
- verify(vppWriter).process(dataBefore3, dataAfter3);
+ verify(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(dataBefore1)),
+ eq(singletonList(dataAfter1)), any(WriteContext.class));
+ verify(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(dataBefore2)),
+ eq(singletonList(dataAfter2)), any(WriteContext.class));
+ verify(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(dataBefore3)),
+ eq(singletonList(dataAfter3)), any(WriteContext.class));
// verify that only two changes were processed successfully:
assertEquals(2, processedChanges.size());
// verify that successful changes were undone
for (final Map.Entry<DataObject, DataObject> change : processedChanges) {
- verify(vppWriter).process(change.getValue(), change.getKey());
+ verify(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(change.getValue())),
+ eq(singletonList(change.getKey())), any(WriteContext.class));
}
return;
}
@@ -204,7 +212,8 @@ public class VPPConfigDataTreeTest {
// reject third applied change and fourth (first undo):
final List<Map.Entry<DataObject, DataObject>> processedChanges = new ArrayList<>();
final Answer answer = new VppWriterAnswer(processedChanges, Arrays.asList(1,2), Arrays.asList(3,4));
- doAnswer(answer).when(vppWriter).process(any(DataObject.class), any(DataObject.class));
+ doAnswer(answer).when(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), anyListOf(DataObject.class),
+ anyListOf(DataObject.class), any(WriteContext.class));
// Prepare modification:
final DataTreeCandidateNode rootNode = mockRootNode();
@@ -220,20 +229,25 @@ public class VPPConfigDataTreeTest {
proxy.commit(modification);
} catch (DataValidationFailedException | VppApiInvocationException e) {
// verify that all changes were processed:
- verify(vppWriter).process(dataBefore1, dataAfter1);
- verify(vppWriter).process(dataBefore2, dataAfter2);
- verify(vppWriter).process(dataBefore3, dataAfter3);
+ verify(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(dataBefore1)),
+ eq(singletonList(dataAfter1)), any(WriteContext.class));
+ verify(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(dataBefore2)),
+ eq(singletonList(dataAfter2)), any(WriteContext.class));
+ verify(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(dataBefore3)),
+ eq(singletonList(dataAfter3)), any(WriteContext.class));
// verify that only two changes were processed successfully:
assertEquals(2, processedChanges.size());
// verify we tried to undo the last successful change:
Map.Entry<DataObject, DataObject> change = processedChanges.get(1);
- verify(vppWriter).process(change.getValue(), change.getKey());
+ verify(vppWriter).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(change.getValue())),
+ eq(singletonList(change.getKey())), any(WriteContext.class));
// but failed, and did not try to undo the first:
change = processedChanges.get(0);
- verify(vppWriter, never()).process(change.getValue(), change.getKey());
+ verify(vppWriter, never()).update(Matchers.<InstanceIdentifier<?>>any(), eq(singletonList(change.getValue())),
+ eq(singletonList(change.getKey())), any(WriteContext.class));
return;
}
@@ -295,12 +309,12 @@ public class VPPConfigDataTreeTest {
public Object answer(final InvocationOnMock invocation) throws Throwable {
++count;
if (toCapture.contains(count)) {
- final DataObject dataBefore = (DataObject)invocation.getArguments()[0];
- final DataObject dataAfter = (DataObject)invocation.getArguments()[1];
+ final DataObject dataBefore = (DataObject) ((List)invocation.getArguments()[1]).get(0);
+ final DataObject dataAfter = (DataObject) ((List)invocation.getArguments()[2]).get(0);
capturedChanges.add(new AbstractMap.SimpleImmutableEntry<>(dataBefore, dataAfter));
}
if (toReject.contains(count)) {
- throw mock(VppApiInvocationException.class);
+ throw mock(RuntimeException.class);
}
return null;
}
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java
index 5ac1f0130..30cebf2f9 100644
--- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/data/VppDataBrokerInitializationProviderTest.java
@@ -44,14 +44,17 @@ public class VppDataBrokerInitializationProviderTest {
private WriteTransaction writeTx;
@Mock
private ReaderRegistry readerRegistry;
+ @Mock
+ private VppWriterRegistry writerRegistry;
private VppDataBrokerInitializationProvider provider;
+
@Before
public void setUp() throws Exception {
initMocks(this);
doReturn(writeTx).when(bindingBroker).newWriteOnlyTransaction();
- provider = new VppDataBrokerInitializationProvider(bindingBroker, readerRegistry);
+ provider = new VppDataBrokerInitializationProvider(bindingBroker, readerRegistry, writerRegistry);
}
@Test
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationExceptionTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationExceptionTest.java
index e83e541d1..fed792a3b 100644
--- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans0/VppApiInvocationExceptionTest.java
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/VppApiInvocationExceptionTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.fd.honeycomb.v3po.impl.trans0;
+package io.fd.honeycomb.v3po.impl.trans;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContextTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContextTest.java
new file mode 100644
index 000000000..1a6cf3a5b
--- /dev/null
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/trans/w/util/TransactionWriteContextTest.java
@@ -0,0 +1,122 @@
+package io.fd.honeycomb.v3po.impl.trans.w.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import io.fd.honeycomb.v3po.impl.trans.util.Context;
+import java.util.List;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class TransactionWriteContextTest {
+
+ @Mock
+ private BindingNormalizedNodeSerializer serializer;
+ @Mock
+ private DOMDataReadOnlyTransaction beforeTx;
+ @Mock
+ private DOMDataReadOnlyTransaction afterTx;
+ @Mock
+ private CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future;
+ @Mock
+ private Optional<org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode<?, ?>> optional;
+ @Mock
+ private Map.Entry entry;
+
+ private TransactionWriteContext transactionWriteContext;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+ transactionWriteContext = new TransactionWriteContext(serializer, beforeTx, afterTx);
+ }
+
+ @Test
+ public void testReadBeforeNoData() throws Exception {
+ when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future);
+ when(future.checkedGet()).thenReturn(optional);
+ when(optional.isPresent()).thenReturn(false);
+
+ final InstanceIdentifier<BridgeDomain> instanceId =
+ InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class);
+
+ final List<? extends DataObject> dataObjects = transactionWriteContext.readBefore(instanceId);
+ assertNotNull(dataObjects);
+ assertTrue(dataObjects.isEmpty());
+
+ verify(serializer).toYangInstanceIdentifier(instanceId);
+ verify(serializer, never()).fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class));
+ }
+
+
+ @Test
+ public void testReadBefore() throws Exception {
+ when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future);
+ when(future.checkedGet()).thenReturn(optional);
+ when(optional.isPresent()).thenReturn(true);
+
+ final InstanceIdentifier<BridgeDomain> instanceId =
+ InstanceIdentifier.create(Vpp.class).child(BridgeDomains.class).child(BridgeDomain.class);
+ final YangInstanceIdentifier yangId = YangInstanceIdentifier.builder().node(VppState.QNAME).node(
+ BridgeDomains.QNAME).node(BridgeDomain.QNAME).build();
+ when(serializer.toYangInstanceIdentifier(any(InstanceIdentifier.class))).thenReturn(yangId);
+ when(serializer.fromNormalizedNode(eq(yangId), any(NormalizedNode.class))).thenReturn(entry);
+
+ final List<? extends DataObject> dataObjects = transactionWriteContext.readBefore(instanceId);
+ assertNotNull(dataObjects);
+ assertFalse(dataObjects.isEmpty());
+
+ verify(serializer).toYangInstanceIdentifier(instanceId);
+ verify(serializer).fromNormalizedNode(eq(yangId), any(NormalizedNode.class));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testReadBeforeFailed() throws Exception {
+ when(beforeTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future);
+ when(future.checkedGet()).thenThrow(ReadFailedException.class);
+ transactionWriteContext.readBefore(mock(InstanceIdentifier.class));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testReadAfterFailed() throws Exception {
+ when(afterTx.read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(future);
+ when(future.checkedGet()).thenThrow(ReadFailedException.class);
+ transactionWriteContext.readAfter(mock(InstanceIdentifier.class));
+ }
+
+ @Test
+ public void testGetContext() throws Exception {
+ assertNotNull(transactionWriteContext.getContext());
+ }
+
+ @Test
+ public void testClose() throws Exception {
+ final Context context = transactionWriteContext.getContext();
+ transactionWriteContext.close();
+ // TODO verify context was closed
+ }
+} \ No newline at end of file
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizerTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizerTest.java
new file mode 100644
index 000000000..4614b875a
--- /dev/null
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainCustomizerTest.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl.vpp;
+
+import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.BD_NAME_TO_ID_ANSWER;
+import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.bdIdentifierForName;
+import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.bdNameToID;
+import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.booleanToByte;
+import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.intToBoolean;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import io.fd.honeycomb.v3po.impl.trans.util.Context;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.openvpp.vppjapi.vppApi;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+@SuppressStaticInitializationFor("org.openvpp.vppjapi.vppConn")
+@PrepareForTest(vppApi.class)
+public class BridgeDomainCustomizerTest {
+
+ private static final int RESPONSE_NOT_READY = -77;
+ private static final byte ADD_OR_UPDATE_BD = (byte) 1;
+ private static final byte ZERO = 0;
+ private vppApi api;
+
+ @Mock
+ private Context ctx;
+
+ private BridgeDomainCustomizer customizer;
+
+ @Before
+ public void setUp() throws Exception {
+ // TODO create base class for tests using vppApi
+ api = PowerMockito.mock(vppApi.class);
+ initMocks(this);
+ customizer = new BridgeDomainCustomizer(api);
+
+ PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).findOrAddBridgeDomainId(anyString());
+ PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).bridgeDomainIdFromName(anyString());
+ PowerMockito.when(api.getRetval(anyInt(), anyInt())).thenReturn(RESPONSE_NOT_READY).thenReturn(0);
+ PowerMockito.doReturn(0).when(api).getRetval(anyInt(), anyInt());
+ }
+
+ private BridgeDomain generateBridgeDomain(final String bdName) {
+ final byte arpTerm = 0;
+ final byte flood = 1;
+ final byte forward = 0;
+ final byte learn = 1;
+ final byte uuf = 0;
+ return generateBridgeDomain(bdName, arpTerm, flood, forward, learn, uuf);
+ }
+
+ private BridgeDomain generateBridgeDomain(final String bdName, final int arpTerm, final int flood,
+ final int forward, final int learn, final int uuf) {
+ return new BridgeDomainBuilder()
+ .setName(bdName)
+ .setArpTermination(intToBoolean(arpTerm))
+ .setFlood(intToBoolean(flood))
+ .setForward(intToBoolean(forward))
+ .setLearn(intToBoolean(learn))
+ .setUnknownUnicastFlood(intToBoolean(uuf))
+ .build();
+ }
+
+ private final int verifyBridgeDomainAddOrUpdateWasInvoked(final BridgeDomain bd) {
+ final int bdn1Id = bdNameToID(bd.getName());
+ final byte arpTerm = booleanToByte(bd.isArpTermination());
+ final byte flood = booleanToByte(bd.isFlood());
+ final byte forward = booleanToByte(bd.isForward());
+ final byte learn = booleanToByte(bd.isLearn());
+ final byte uuf = booleanToByte(bd.isUnknownUnicastFlood());
+ return verify(api).bridgeDomainAddDel(bdn1Id, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD);
+ }
+
+ private int verifyBridgeDomainAddOrUpdateWasNotInvoked(final BridgeDomain bd) {
+ final int bdn1Id = bdNameToID(bd.getName());
+ final byte arpTerm = booleanToByte(bd.isArpTermination());
+ final byte flood = booleanToByte(bd.isFlood());
+ final byte forward = booleanToByte(bd.isForward());
+ final byte learn = booleanToByte(bd.isLearn());
+ final byte uuf = booleanToByte(bd.isUnknownUnicastFlood());
+ return verify(api, never()).bridgeDomainAddDel(bdn1Id, flood, forward, learn, uuf, arpTerm, ADD_OR_UPDATE_BD);
+ }
+
+ private int verifyBridgeDomainDeletedWasInvoked(final BridgeDomain bd) {
+ final int bdn1Id = bdNameToID(bd.getName());
+ return verify(api).bridgeDomainAddDel(bdn1Id, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO);
+ }
+
+ private int verifyBridgeDomainDeletedWasNotInvoked(final BridgeDomain bd) {
+ final int bdn1Id = bdNameToID(bd.getName());
+ return verify(api, never()).bridgeDomainAddDel(bdn1Id, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO);
+ }
+
+ @Test
+ public void testAddBridgeDomain() {
+ final String bdName = "bd1";
+ final BridgeDomain bd = generateBridgeDomain("bd1");
+
+ customizer.writeCurrentAttributes(bdIdentifierForName(bdName), bd, ctx);
+
+ verifyBridgeDomainAddOrUpdateWasInvoked(bd);
+ }
+
+ @Test
+ public void testBridgeDomainNameCreateFailed() {
+ final String bdName = "bd1";
+ final BridgeDomain bd = generateBridgeDomain("bd1");
+
+ // make vpp api fail to create id for our bd name
+ PowerMockito.doReturn(-1).when(api).findOrAddBridgeDomainId(bdName);
+
+ try {
+ customizer.writeCurrentAttributes(bdIdentifierForName(bdName), bd, ctx);
+ } catch (IllegalStateException e) {
+ verifyBridgeDomainAddOrUpdateWasNotInvoked(bd);
+ return;
+ }
+ fail("IllegalStateException was expected");
+ }
+
+ @Test
+ public void testAddBridgeDomainFailed() {
+ // make any call to vpp fail
+ PowerMockito.doReturn(-1).when(api).getRetval(anyInt(), anyInt());
+
+ final String bdName = "bd1";
+ final BridgeDomain bd = generateBridgeDomain(bdName);
+
+ try {
+ customizer.writeCurrentAttributes(bdIdentifierForName(bdName), bd, ctx);
+ } catch (IllegalStateException e) {
+ verifyBridgeDomainAddOrUpdateWasInvoked(bd);
+ return;
+ }
+ fail("IllegalStateException was expected");
+ }
+
+ @Test
+ public void testDeleteBridgeDomain() {
+ final String bdName = "bd1";
+ final BridgeDomain bd = generateBridgeDomain("bd1");
+
+ customizer.deleteCurrentAttributes(bdIdentifierForName(bdName), bd, ctx);
+
+ verifyBridgeDomainDeletedWasInvoked(bd);
+ }
+
+ @Test
+ public void testDeleteUnknownBridgeDomain() {
+ final String bdName = "bd1";
+ final BridgeDomain bd = generateBridgeDomain("bd1");
+
+ // make vpp api not find our bd
+ PowerMockito.doReturn(-1).when(api).bridgeDomainIdFromName(bdName);
+
+ try {
+ customizer.deleteCurrentAttributes(bdIdentifierForName(bdName), bd, ctx);
+ } catch (IllegalStateException e) {
+ verifyBridgeDomainDeletedWasNotInvoked(bd);
+ return;
+ }
+ fail("IllegalStateException was expected");
+ }
+
+ @Test
+ public void testDeleteBridgeDomainFailed() {
+ // make any call to vpp fail
+ PowerMockito.doReturn(-1).when(api).getRetval(anyInt(), anyInt());
+
+ final String bdName = "bd1";
+ final BridgeDomain bd = generateBridgeDomain(bdName);
+
+ try {
+ customizer.deleteCurrentAttributes(bdIdentifierForName(bdName), bd, ctx);
+ } catch (IllegalStateException e) {
+ verifyBridgeDomainDeletedWasInvoked(bd);
+ return;
+ }
+ fail("IllegalStateException was expected");
+ }
+
+ @Test
+ public void testUpdateBridgeDomain() throws Exception {
+ final String bdName = "bd1";
+ final byte arpTermBefore = 1;
+ final byte floodBefore = 1;
+ final byte forwardBefore = 0;
+ final byte learnBefore = 1;
+ final byte uufBefore = 0;
+
+ final BridgeDomain dataBefore =
+ generateBridgeDomain(bdName, arpTermBefore, floodBefore, forwardBefore, learnBefore, uufBefore);
+ final BridgeDomain dataAfter =
+ generateBridgeDomain(bdName, arpTermBefore ^ 1, floodBefore ^ 1, forwardBefore ^ 1, learnBefore ^ 1,
+ uufBefore ^ 1);
+
+ final KeyedInstanceIdentifier<BridgeDomain, BridgeDomainKey> id = bdIdentifierForName(bdName);
+
+ customizer.updateCurrentAttributes(id, dataBefore, dataAfter, ctx);
+
+ verifyBridgeDomainAddOrUpdateWasInvoked(dataAfter);
+ }
+
+ @Test
+ public void testUpdateUnknownBridgeDomain() throws Exception {
+ final String bdName = "bd1";
+ final BridgeDomain bd = generateBridgeDomain("bd1");
+
+ // make vpp api not find our bd
+ PowerMockito.doReturn(-1).when(api).bridgeDomainIdFromName(bdName);
+
+ try {
+ customizer.updateCurrentAttributes(bdIdentifierForName(bdName), bd, bd, ctx);
+ } catch (IllegalStateException e) {
+ verifyBridgeDomainAddOrUpdateWasNotInvoked(bd);
+ return;
+ }
+ fail("IllegalStateException was expected");
+ }
+
+ @Test
+ public void testUpdateBridgeDomainFailed() {
+ // make any call to vpp fail
+ PowerMockito.doReturn(-1).when(api).getRetval(anyInt(), anyInt());
+
+ final String bdName = "bd1";
+ final BridgeDomain bd = generateBridgeDomain(bdName);
+
+ try {
+ customizer.updateCurrentAttributes(bdIdentifierForName(bdName), bd, bd, ctx);
+ } catch (IllegalStateException e) {
+ verifyBridgeDomainAddOrUpdateWasInvoked(bd);
+ return;
+ }
+ fail("IllegalStateException was expected");
+ }
+
+} \ No newline at end of file
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainTestUtils.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainTestUtils.java
new file mode 100644
index 000000000..6930493b6
--- /dev/null
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/BridgeDomainTestUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl.vpp;
+
+import javax.annotation.Nullable;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+final class BridgeDomainTestUtils {
+
+ private BridgeDomainTestUtils() {
+ throw new UnsupportedOperationException("Utility class cannot be instantiated.");
+ }
+
+ public static byte booleanToByte(@Nullable final Boolean value) {
+ return value != null && value ? (byte) 1 : (byte) 0;
+ }
+
+ @Nullable
+ public static Boolean intToBoolean(final int value) {
+ if (value == 0) {
+ return Boolean.FALSE;
+ }
+ if (value == 1) {
+ return Boolean.TRUE;
+ }
+ return null;
+ }
+
+ public static int bdNameToID(String bName) {
+ return Integer.parseInt(((Character)bName.charAt(bName.length() - 1)).toString());
+ }
+
+ public static KeyedInstanceIdentifier<BridgeDomain, BridgeDomainKey> bdIdentifierForName(
+ final String bdName) {
+ return InstanceIdentifier.create(BridgeDomains.class).child(BridgeDomain.class, new BridgeDomainKey(bdName));
+ }
+
+ public static final Answer<Integer> BD_NAME_TO_ID_ANSWER = new Answer<Integer>() {
+ @Override
+ public Integer answer(final InvocationOnMock invocationOnMock) throws Throwable {
+ return bdNameToID((String) invocationOnMock.getArguments()[0]);
+ }
+ };
+} \ No newline at end of file
diff --git a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java
index beec76ab1..bf7b9de4b 100644
--- a/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java
+++ b/v3po/impl/src/test/java/io/fd/honeycomb/v3po/impl/vpp/VppTest.java
@@ -16,6 +16,7 @@
package io.fd.honeycomb.v3po.impl.vpp;
+import static io.fd.honeycomb.v3po.impl.vpp.BridgeDomainTestUtils.BD_NAME_TO_ID_ANSWER;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
@@ -33,8 +34,6 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
@@ -71,14 +70,8 @@ public class VppTest {
public void setUp() throws Exception {
api = PowerMockito.mock(vppApi.class);
ctx = mock(WriteContext.class);
- PowerMockito.doAnswer(new Answer<Integer>() {
- @Override
- public Integer answer(final InvocationOnMock invocationOnMock) throws Throwable {
- final String bName = (String) invocationOnMock.getArguments()[0];
- return Integer.parseInt(((Character)bName.charAt(bName.length() - 1)).toString());
- }
- }).when(api).findOrAddBridgeDomainId(anyString());
- PowerMockito.doReturn(1).when(api).bridgeDomainIdFromName(anyString());
+ PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).findOrAddBridgeDomainId(anyString());
+ PowerMockito.doAnswer(BD_NAME_TO_ID_ANSWER).when(api).bridgeDomainIdFromName(anyString());
PowerMockito.doReturn(1).when(api).getRetval(anyInt(), anyInt());
vppWriter = VppUtils.getVppWriter(api);
rootRegistry = new DelegatingWriterRegistry(