From abd7814ef36ed9135c6e80b79ece76238d50a39c Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Tue, 12 Apr 2016 10:13:25 +0200 Subject: HONEYCOMB-8: Remove references to VPP from data layer Change-Id: Ia8ceb1f6e16c5148514ee2add55ff78533d8fe1e Signed-off-by: Marek Gradzki Signed-off-by: Maros Marsalek --- .../honeycomb/v3po/data/impl/ConfigDataTree.java | 171 +++++++++++++ .../io/fd/honeycomb/v3po/data/impl/DataBroker.java | 99 ++++++++ .../fd/honeycomb/v3po/data/impl/DataTreeUtils.java | 2 +- .../v3po/data/impl/OperationalDataTree.java | 210 ++++++++++++++++ .../v3po/data/impl/ReadOnlyTransaction.java | 105 ++++++++ .../v3po/data/impl/VppConfigDataTree.java | 172 ------------- .../fd/honeycomb/v3po/data/impl/VppDataBroker.java | 98 -------- .../v3po/data/impl/VppOperationalDataTree.java | 210 ---------------- .../v3po/data/impl/VppReadOnlyTransaction.java | 105 -------- .../v3po/data/impl/VppWriteTransaction.java | 147 ----------- .../honeycomb/v3po/data/impl/WriteTransaction.java | 147 +++++++++++ .../v3po/data/impl/ConfigDataTreeTest.java | 271 +++++++++++++++++++++ .../honeycomb/v3po/data/impl/DataBrokerTest.java | 111 +++++++++ .../v3po/data/impl/OperationalDataTreeTest.java | 171 +++++++++++++ .../v3po/data/impl/ReadOnlyTransactionTest.java | 68 ++++++ .../v3po/data/impl/VPPConfigDataTreeTest.java | 270 -------------------- .../v3po/data/impl/VppDataBrokerTest.java | 111 --------- .../v3po/data/impl/VppOperationalDataTreeTest.java | 171 ------------- .../v3po/data/impl/VppReadOnlyTransactionTest.java | 68 ------ .../v3po/data/impl/VppWriteTransactionTest.java | 136 ----------- .../v3po/data/impl/WriteTransactionTest.java | 136 +++++++++++ 21 files changed, 1490 insertions(+), 1489 deletions(-) create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTree.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTree.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java delete mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppConfigDataTree.java delete mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppDataBroker.java delete mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTree.java delete mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransaction.java delete mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransaction.java create mode 100644 v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTreeTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTreeTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java delete mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VPPConfigDataTreeTest.java delete mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppDataBrokerTest.java delete mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTreeTest.java delete mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransactionTest.java delete mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransactionTest.java create mode 100644 v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java (limited to 'v3po/data-impl') diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTree.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTree.java new file mode 100644 index 000000000..84a1d27e3 --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTree.java @@ -0,0 +1,171 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.honeycomb.v3po.data.impl.DataTreeUtils.childrenFromNormalized; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import io.fd.honeycomb.v3po.data.DataTreeSnapshot; +import io.fd.honeycomb.v3po.data.ModifiableDataTree; +import io.fd.honeycomb.v3po.data.ReadableDataTree; +import io.fd.honeycomb.v3po.translate.TranslationException; +import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext; +import io.fd.honeycomb.v3po.translate.write.WriteContext; +import io.fd.honeycomb.v3po.translate.write.WriterRegistry; +import java.util.Collections; +import java.util.Map; +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; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * DataTree implementation for configuration data. + */ +public final class ConfigDataTree implements ModifiableDataTree { + + private static final Logger LOG = LoggerFactory.getLogger(ConfigDataTree.class); + + private final BindingNormalizedNodeSerializer serializer; + private final DataTree dataTree; + private final WriterRegistry writer; + public static final ReadableDataTree EMPTY_OPERATIONAL = new ReadableDataTree() { + @Override + public CheckedFuture>, ReadFailedException> read( + @Nonnull final YangInstanceIdentifier path) { + return Futures.immediateCheckedFuture(Optional.>absent()); + } + }; + + /** + * Creates configuration data tree instance. + * + * @param serializer service for serialization between Java Binding Data representation and NormalizedNode + * representation. + * @param dataTree data tree for configuration data representation + * @param writer service for translation between Java Binding Data and data provider. + */ + public ConfigDataTree(@Nonnull final BindingNormalizedNodeSerializer serializer, + @Nonnull final DataTree dataTree, @Nonnull final WriterRegistry writer) { + this.serializer = checkNotNull(serializer, "serializer should not be null"); + this.dataTree = checkNotNull(dataTree, "dataTree should not be null"); + this.writer = checkNotNull(writer, "writer should not be null"); + } + + @Override + public DataTreeSnapshot takeSnapshot() { + return new ConfigSnapshot(dataTree.takeSnapshot()); + } + + @Override + public void modify(final DataTreeModification modification) + throws DataValidationFailedException, TranslationException { + dataTree.validate(modification); + + final DataTreeCandidate candidate = dataTree.prepare(modification); + + final DataTreeCandidateNode rootNode = candidate.getRootNode(); + final YangInstanceIdentifier rootPath = candidate.getRootPath(); + final Optional> normalizedDataBefore = rootNode.getDataBefore(); + final Optional> normalizedDataAfter = rootNode.getDataAfter(); + LOG.debug("ConfigDataTree.modify() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}", + rootPath, rootNode, normalizedDataBefore, normalizedDataAfter); + + final Map, DataObject> nodesBefore = extractNetconfData(normalizedDataBefore); + LOG.debug("ConfigDataTree.modify() extracted nodesBefore={}", nodesBefore.keySet()); + + final Map, DataObject> nodesAfter = extractNetconfData(normalizedDataAfter); + LOG.debug("ConfigDataTree.modify() extracted nodesAfter={}", nodesAfter.keySet()); + + + final DOMDataReadOnlyTransaction beforeTx = new ReadOnlyTransaction(EMPTY_OPERATIONAL, takeSnapshot()); + final ConfigSnapshot modificationSnapshot = new ConfigSnapshot(modification); + final DOMDataReadOnlyTransaction afterTx = new ReadOnlyTransaction(EMPTY_OPERATIONAL, modificationSnapshot); + try(final WriteContext ctx = new TransactionWriteContext(serializer, beforeTx, afterTx)) { + writer.update(nodesBefore, nodesAfter, ctx); + } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) { + LOG.warn("Failed to apply all changes", e); + LOG.info("Trying to revert successful changes for current transaction"); + + try { + e.revertChanges(); + LOG.info("Changes successfully reverted"); + } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException) { + // fail with failed revert + LOG.error("Failed to revert successful changes", revertFailedException); + throw revertFailedException; + } + + throw e; // fail with success revert + } catch (TranslationException e) { + LOG.error("Error while processing data change (before={}, after={})", nodesBefore, nodesAfter, e); + throw e; + } + + dataTree.commit(candidate); + } + + private Map, DataObject> extractNetconfData( + final Optional> parentOptional) { + if (parentOptional.isPresent()) { + final DataContainerNode parent = (DataContainerNode) parentOptional.get(); + return childrenFromNormalized(parent, serializer); + } + return Collections.emptyMap(); + } + + private final static class ConfigSnapshot implements DataTreeSnapshot { + private final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot snapshot; + + ConfigSnapshot(@Nonnull final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot snapshot) { + this.snapshot = snapshot; + } + + @Override + public CheckedFuture>, ReadFailedException> read( + @Nonnull final YangInstanceIdentifier path) { + final Optional> node = snapshot.readNode(path); + if (LOG.isTraceEnabled() && node.isPresent()) { + LOG.trace("ConfigSnapshot.read: {}", node.get()); + } + return Futures.immediateCheckedFuture(node); + } + + @Override + public DataTreeModification newModification() { + return snapshot.newModification(); + } + } +} + + + diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java new file mode 100644 index 000000000..7b4d93baa --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataBroker.java @@ -0,0 +1,99 @@ +/* + * 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.data.impl; + +import com.google.common.base.Preconditions; +import io.fd.honeycomb.v3po.data.ReadableDataTree; +import io.fd.honeycomb.v3po.data.ModifiableDataTree; +import io.fd.honeycomb.v3po.data.DataTreeSnapshot; +import java.util.Collections; +import java.util.Map; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +/** + * Data Broker which provides data transaction functionality for YANG capable data provider + * using {@link NormalizedNode} data format. + */ +public class DataBroker implements DOMDataBroker { + + private final ReadableDataTree operationalData; + private final ModifiableDataTree configDataTree; + + /** + * Creates DataBroker instance. + * + * @param operationalData operational data + * @param configDataTree configuration data + */ + public DataBroker(@Nonnull final ReadableDataTree operationalData, + @Nonnull final ModifiableDataTree configDataTree) { + this.operationalData = Preconditions.checkNotNull(operationalData, "operationalData should not be null"); + this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataProxy should not be null"); + } + + @Override + public DOMDataReadOnlyTransaction newReadOnlyTransaction() { + return new ReadOnlyTransaction(operationalData, configDataTree.takeSnapshot()); + } + + @Override + public DOMDataReadWriteTransaction newReadWriteTransaction() { + // todo use the same snapshot + final DataTreeSnapshot configSnapshot = configDataTree.takeSnapshot(); + final DOMDataReadOnlyTransaction readOnlyTx = new ReadOnlyTransaction(operationalData, configSnapshot); + final DOMDataWriteTransaction writeOnlyTx = new WriteTransaction(configDataTree, configSnapshot); + return new ReadWriteTransaction(readOnlyTx, writeOnlyTx); + } + + @Override + public DOMDataWriteTransaction newWriteOnlyTransaction() { + return new WriteTransaction(configDataTree); + } + + @Override + public ListenerRegistration registerDataChangeListener(final LogicalDatastoreType store, + final YangInstanceIdentifier path, + final DOMDataChangeListener listener, + final DataChangeScope triggeringScope) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) { + throw new UnsupportedOperationException("Not supported"); + } + + @Nonnull + @Override + public Map, DOMDataBrokerExtension> getSupportedExtensions() { + return Collections.emptyMap(); + } +} + + diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java index 83ed0f263..39e841f9a 100644 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/DataTreeUtils.java @@ -62,7 +62,7 @@ final class DataTreeUtils { for (final DataContainerChild child : children) { final YangInstanceIdentifier.PathArgument pathArgument = child.getIdentifier(); final YangInstanceIdentifier identifier = YangInstanceIdentifier.create(pathArgument); - LOG.debug("VppConfigDataProxy.extractDataObject() child={}, pathArgument={}, identifier={}", child, + LOG.debug("DataTreeUtils.childrenFromNormalized() child={}, pathArgument={}, identifier={}", child, pathArgument, identifier); final Map.Entry, DataObject> entry = serializer.fromNormalizedNode(identifier, child); diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTree.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTree.java new file mode 100644 index 000000000..21672b48b --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTree.java @@ -0,0 +1,210 @@ +/* + * 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.data.impl; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.getOnlyElement; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Collections2; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import io.fd.honeycomb.v3po.data.ReadableDataTree; +import io.fd.honeycomb.v3po.translate.Context; +import io.fd.honeycomb.v3po.translate.read.ReadContext; +import io.fd.honeycomb.v3po.translate.read.ReadFailedException; +import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; +import java.util.Collection; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ReadableDataTree implementation for operational data. + */ +public final class OperationalDataTree implements ReadableDataTree { + private static final Logger LOG = LoggerFactory.getLogger(OperationalDataTree.class); + + private final BindingNormalizedNodeSerializer serializer; + private final ReaderRegistry readerRegistry; + private final SchemaContext globalContext; + + /** + * Creates operational data tree instance. + * + * @param serializer service for serialization between Java Binding Data representation and NormalizedNode + * representation. + * @param globalContext service for obtaining top level context data from all yang modules. + * @param readerRegistry service responsible for translation between DataObjects and data provider. + */ + public OperationalDataTree(@Nonnull BindingNormalizedNodeSerializer serializer, + @Nonnull final SchemaContext globalContext, @Nonnull ReaderRegistry readerRegistry) { + this.globalContext = checkNotNull(globalContext, "serializer should not be null"); + this.serializer = checkNotNull(serializer, "serializer should not be null"); + this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null"); + } + + @Override + public CheckedFuture>, + org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read( + @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) { + + try(ReadContext ctx = new ReadContextImpl()) { + if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) { + return Futures.immediateCheckedFuture(readRoot(ctx)); + } else { + return Futures.immediateCheckedFuture(readNode(yangInstanceIdentifier, ctx)); + } + } catch (ReadFailedException e) { + return Futures.immediateFailedCheckedFuture( + new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException( + "Failed to read VPP data", e)); + } + } + + private Optional> readNode(final YangInstanceIdentifier yangInstanceIdentifier, + final ReadContext ctx) + throws ReadFailedException { + LOG.debug("OperationalDataTree.readNode(), yangInstanceIdentifier={}", yangInstanceIdentifier); + final InstanceIdentifier path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier); + checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier); + LOG.debug("OperationalDataTree.readNode(), path={}", path); + + final Optional dataObject; + + dataObject = readerRegistry.read(path, ctx); + if (dataObject.isPresent()) { + final NormalizedNode value = toNormalizedNodeFunction(path).apply(dataObject.get()); + return Optional.>fromNullable(value); + } else { + return Optional.absent(); + } + } + + private Optional> readRoot(final ReadContext ctx) throws ReadFailedException { + LOG.debug("OperationalDataTree.readRoot()"); + + final DataContainerNodeAttrBuilder dataNodeBuilder = + Builders.containerBuilder() + .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME)); + + final Multimap, ? extends DataObject> dataObjects = + readerRegistry.readAll(ctx); + + for (final InstanceIdentifier instanceIdentifier : dataObjects.keySet()) { + final YangInstanceIdentifier rootElementId = serializer.toYangInstanceIdentifier(instanceIdentifier); + final NormalizedNode node = + wrapDataObjects(rootElementId, instanceIdentifier, dataObjects.get(instanceIdentifier)); + dataNodeBuilder.withChild((DataContainerChild) node); + } + + return Optional.>of(dataNodeBuilder.build()); + } + + private NormalizedNode wrapDataObjects(final YangInstanceIdentifier yangInstanceIdentifier, + final InstanceIdentifier instanceIdentifier, + final Collection dataObjects) { + final Collection> normalizedRootElements = Collections2 + .transform(dataObjects, toNormalizedNodeFunction(instanceIdentifier)); + + final DataSchemaNode schemaNode = + globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType()); + if (schemaNode instanceof ListSchemaNode) { + // In case of a list, wrap all the values in a Mixin parent node + final ListSchemaNode listSchema = (ListSchemaNode) schemaNode; + return wrapListIntoMixinNode(normalizedRootElements, listSchema); + } else { + Preconditions.checkState(dataObjects.size() == 1, "Singleton list was expected"); + return getOnlyElement(normalizedRootElements); + } + } + + private static DataContainerChild wrapListIntoMixinNode( + final Collection> normalizedRootElements, final ListSchemaNode listSchema) { + if (listSchema.getKeyDefinition().isEmpty()) { + final CollectionNodeBuilder listBuilder = + Builders.unkeyedListBuilder(); + for (NormalizedNode normalizedRootElement : normalizedRootElements) { + listBuilder.withChild((UnkeyedListEntryNode) normalizedRootElement); + } + return listBuilder.build(); + } else { + final CollectionNodeBuilder listBuilder = + listSchema.isUserOrdered() + ? Builders.orderedMapBuilder() + : Builders.mapBuilder(); + + for (NormalizedNode normalizedRootElement : normalizedRootElements) { + listBuilder.withChild((MapEntryNode) normalizedRootElement); + } + return listBuilder.build(); + } + } + + @SuppressWarnings("unchecked") + private Function> toNormalizedNodeFunction(final InstanceIdentifier path) { + return new Function>() { + @Override + public NormalizedNode apply(@Nullable final DataObject dataObject) { + LOG.trace("OperationalDataTree.toNormalizedNode(), path={}, dataObject={}", path, dataObject); + final Map.Entry> entry = + serializer.toNormalizedNode(path, dataObject); + + LOG.trace("OperationalDataTree.toNormalizedNode(), normalizedNodeEntry={}", entry); + return entry.getValue(); + } + }; + } + + private static final class ReadContextImpl implements ReadContext { + public final Context ctx = new Context(); + + @Nonnull + @Override + public Context getContext() { + return ctx; + } + + @Override + public void close() { + // Make sure to clear the storage in case some customizer stored it to prevent memory leaks + ctx.close(); + } + } +} diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java new file mode 100644 index 000000000..83c9e30bd --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransaction.java @@ -0,0 +1,105 @@ +/* + * 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.data.impl; + +import com.google.common.base.Function; +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 com.google.common.util.concurrent.ListenableFuture; +import io.fd.honeycomb.v3po.data.ReadableDataTree; +import io.fd.honeycomb.v3po.data.DataTreeSnapshot; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class ReadOnlyTransaction implements DOMDataReadOnlyTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyTransaction.class); + private volatile ReadableDataTree operationalData; + private volatile DataTreeSnapshot configSnapshot; + + ReadOnlyTransaction(@Nonnull final ReadableDataTree operationalData, + @Nonnull final DataTreeSnapshot configSnapshot) { + this.operationalData = Preconditions.checkNotNull(operationalData, "operationalData should not be null"); + this.configSnapshot = Preconditions.checkNotNull(configSnapshot, "config should not be null"); + } + + @Override + public void close() { + configSnapshot = null; + operationalData = null; + } + + @Override + public CheckedFuture>, ReadFailedException> read( + final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + LOG.debug("ReadOnlyTransaction.read(), store={}, path={}", store, path); + + Preconditions.checkState(configSnapshot != null, "Transaction was closed"); + + if (store == LogicalDatastoreType.OPERATIONAL) { + return operationalData.read(path); + } else { + return configSnapshot.read(path); + } + } + + @Override + public CheckedFuture exists(final LogicalDatastoreType store, + final YangInstanceIdentifier path) { + LOG.debug("ReadOnlyTransaction.exists() store={}, path={}", store, path); + + ListenableFuture listenableFuture = Futures.transform(read(store, path), IS_NODE_PRESENT); + + return Futures.makeChecked(listenableFuture, ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER); + } + + @Nonnull + @Override + public Object getIdentifier() { + return this; + } + + + private static final Function>, ? extends Boolean> IS_NODE_PRESENT = + new Function>, Boolean>() { + @Nullable + @Override + public Boolean apply(@Nullable final Optional> input) { + return input == null + ? Boolean.FALSE + : input.isPresent(); + } + }; + + private static final Function ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER = + new Function() { + @Override + public ReadFailedException apply(@Nullable final Exception e) { + return new ReadFailedException("Exists failed", e); + } + }; +} \ No newline at end of file diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppConfigDataTree.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppConfigDataTree.java deleted file mode 100644 index 6e01306b0..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppConfigDataTree.java +++ /dev/null @@ -1,172 +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.data.impl; - -import static com.google.common.base.Preconditions.checkNotNull; -import static io.fd.honeycomb.v3po.data.impl.DataTreeUtils.childrenFromNormalized; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.data.ReadableVppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.util.write.TransactionWriteContext; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriterRegistry; -import java.util.Collections; -import java.util.Map; -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; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * VppDataTree implementation for configuration data. - */ -public final class VppConfigDataTree implements VppDataTree { - - private static final Logger LOG = LoggerFactory.getLogger(VppConfigDataTree.class); - - private final BindingNormalizedNodeSerializer serializer; - private final DataTree dataTree; - private final WriterRegistry writer; - public static final ReadableVppDataTree EMPTY_OPERATIONAL = new ReadableVppDataTree() { - @Override - public CheckedFuture>, ReadFailedException> read( - @Nonnull final YangInstanceIdentifier path) { - return Futures.immediateCheckedFuture(Optional.>absent()); - } - }; - - /** - * Creates configuration data tree instance. - * - * @param serializer service for serialization between Java Binding Data representation and NormalizedNode - * representation. - * @param dataTree data tree for configuration data representation - * @param vppWriter service for translation between Java Binding Data and Vpp. - */ - public VppConfigDataTree(@Nonnull final BindingNormalizedNodeSerializer serializer, - @Nonnull final DataTree dataTree, @Nonnull final WriterRegistry 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 - public VppDataTreeSnapshot takeSnapshot() { - return new ConfigSnapshot(dataTree.takeSnapshot()); - } - - @Override - public void commit(final DataTreeModification modification) - throws DataValidationFailedException, TranslationException { - dataTree.validate(modification); - - final DataTreeCandidate candidate = dataTree.prepare(modification); - - final DataTreeCandidateNode rootNode = candidate.getRootNode(); - final YangInstanceIdentifier rootPath = candidate.getRootPath(); - final Optional> normalizedDataBefore = rootNode.getDataBefore(); - final Optional> normalizedDataAfter = rootNode.getDataAfter(); - LOG.debug("VppConfigDataTree.commit() rootPath={}, rootNode={}, dataBefore={}, dataAfter={}", - rootPath, rootNode, normalizedDataBefore, normalizedDataAfter); - - final Map, DataObject> nodesBefore = extractNetconfData(normalizedDataBefore); - LOG.debug("VppConfigDataTree.commit() extracted nodesBefore={}", nodesBefore.keySet()); - - final Map, DataObject> nodesAfter = extractNetconfData(normalizedDataAfter); - LOG.debug("VppConfigDataTree.commit() extracted nodesAfter={}", nodesAfter.keySet()); - - - final DOMDataReadOnlyTransaction beforeTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, takeSnapshot()); - final ConfigSnapshot modificationSnapshot = new ConfigSnapshot(modification); - final DOMDataReadOnlyTransaction afterTx = new VppReadOnlyTransaction(EMPTY_OPERATIONAL, modificationSnapshot); - try(final WriteContext ctx = new TransactionWriteContext(serializer, beforeTx, afterTx)) { - writer.update(nodesBefore, nodesAfter, ctx); - } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) { - LOG.warn("Failed to apply all changes", e); - LOG.info("Trying to revert successful changes for current transaction"); - - try { - e.revertChanges(); - LOG.info("Changes successfully reverted"); - } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException) { - // fail with failed revert - LOG.error("Failed to revert successful changes", revertFailedException); - throw revertFailedException; - } - - throw e; // fail with success revert - } catch (TranslationException e) { - LOG.error("Error while processing data change (before={}, after={})", nodesBefore, nodesAfter, e); - throw e; - } - - dataTree.commit(candidate); - } - - private Map, DataObject> extractNetconfData( - final Optional> parentOptional) { - if (parentOptional.isPresent()) { - final DataContainerNode parent = (DataContainerNode) parentOptional.get(); - return childrenFromNormalized(parent, serializer); - } - return Collections.emptyMap(); - } - - private final static class ConfigSnapshot implements VppDataTreeSnapshot { - private final DataTreeSnapshot snapshot; - - ConfigSnapshot(@Nonnull final DataTreeSnapshot snapshot) { - this.snapshot = snapshot; - } - - @Override - public CheckedFuture>, ReadFailedException> read( - @Nonnull final YangInstanceIdentifier path) { - final Optional> node = snapshot.readNode(path); - if (LOG.isTraceEnabled() && node.isPresent()) { - LOG.trace("ConfigSnapshot.read: {}", node.get()); - } - return Futures.immediateCheckedFuture(node); - } - - @Override - public DataTreeModification newModification() { - return snapshot.newModification(); - } - } -} - - - diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppDataBroker.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppDataBroker.java deleted file mode 100644 index 5c5248cea..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppDataBroker.java +++ /dev/null @@ -1,98 +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.data.impl; - -import com.google.common.base.Preconditions; -import io.fd.honeycomb.v3po.data.ReadableVppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; -import java.util.Collections; -import java.util.Map; -import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -/** - * Data Broker which provides data transaction functionality for VPP using {@link NormalizedNode} data format. - */ -public class VppDataBroker implements DOMDataBroker { - - private final ReadableVppDataTree operationalData; - private final VppDataTree configDataTree; - - /** - * Creates VppDataBroker instance. - * - * @param operationalData VPP operational data - * @param configDataTree VPP configuration data - */ - public VppDataBroker(@Nonnull final ReadableVppDataTree operationalData, - @Nonnull final VppDataTree configDataTree) { - this.operationalData = Preconditions.checkNotNull(operationalData, "operationalData should not be null"); - this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataProxy should not be null"); - } - - @Override - public DOMDataReadOnlyTransaction newReadOnlyTransaction() { - return new VppReadOnlyTransaction(operationalData, configDataTree.takeSnapshot()); - } - - @Override - public DOMDataReadWriteTransaction newReadWriteTransaction() { - // todo use the same snapshot - final VppDataTreeSnapshot configSnapshot = configDataTree.takeSnapshot(); - final DOMDataReadOnlyTransaction readOnlyTx = new VppReadOnlyTransaction(operationalData, configSnapshot); - final DOMDataWriteTransaction writeOnlyTx = new VppWriteTransaction(configDataTree, configSnapshot); - return new ReadWriteTransaction(readOnlyTx, writeOnlyTx); - } - - @Override - public DOMDataWriteTransaction newWriteOnlyTransaction() { - return new VppWriteTransaction(configDataTree); - } - - @Override - public ListenerRegistration registerDataChangeListener(final LogicalDatastoreType store, - final YangInstanceIdentifier path, - final DOMDataChangeListener listener, - final DataChangeScope triggeringScope) { - throw new UnsupportedOperationException("Not supported"); - } - - @Override - public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) { - throw new UnsupportedOperationException("Not supported"); - } - - @Nonnull - @Override - public Map, DOMDataBrokerExtension> getSupportedExtensions() { - return Collections.emptyMap(); - } -} - - diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTree.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTree.java deleted file mode 100644 index fc13606e6..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTree.java +++ /dev/null @@ -1,210 +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.data.impl; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Iterables.getOnlyElement; - -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.Collections2; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import com.google.common.util.concurrent.Futures; -import io.fd.honeycomb.v3po.data.ReadableVppDataTree; -import io.fd.honeycomb.v3po.translate.Context; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReadFailedException; -import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; -import java.util.Collection; -import java.util.Map; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.MapNode; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; -import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode; -import org.opendaylight.yangtools.yang.data.impl.schema.Builders; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder; -import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * ReadableVppDataTree implementation for operational data. - */ -public final class VppOperationalDataTree implements ReadableVppDataTree { - private static final Logger LOG = LoggerFactory.getLogger(VppOperationalDataTree.class); - - private final BindingNormalizedNodeSerializer serializer; - private final ReaderRegistry readerRegistry; - private final SchemaContext globalContext; - - /** - * Creates operational data tree instance. - * - * @param serializer service for serialization between Java Binding Data representation and NormalizedNode - * representation. - * @param globalContext service for obtaining top level context data from all yang modules. - * @param readerRegistry service responsible for translation between DataObjects and VPP APIs. - */ - public VppOperationalDataTree(@Nonnull BindingNormalizedNodeSerializer serializer, - @Nonnull final SchemaContext globalContext, @Nonnull ReaderRegistry readerRegistry) { - this.globalContext = checkNotNull(globalContext, "serializer should not be null"); - this.serializer = checkNotNull(serializer, "serializer should not be null"); - this.readerRegistry = checkNotNull(readerRegistry, "reader should not be null"); - } - - @Override - public CheckedFuture>, - org.opendaylight.controller.md.sal.common.api.data.ReadFailedException> read( - @Nonnull final YangInstanceIdentifier yangInstanceIdentifier) { - - try(ReadContext ctx = new ReadContextImpl()) { - if (checkNotNull(yangInstanceIdentifier).equals(YangInstanceIdentifier.EMPTY)) { - return Futures.immediateCheckedFuture(readRoot(ctx)); - } else { - return Futures.immediateCheckedFuture(readNode(yangInstanceIdentifier, ctx)); - } - } catch (ReadFailedException e) { - return Futures.immediateFailedCheckedFuture( - new org.opendaylight.controller.md.sal.common.api.data.ReadFailedException( - "Failed to read VPP data", e)); - } - } - - private Optional> readNode(final YangInstanceIdentifier yangInstanceIdentifier, - final ReadContext ctx) - throws ReadFailedException { - LOG.debug("VppOperationalDataTree.readNode(), yangInstanceIdentifier={}", yangInstanceIdentifier); - final InstanceIdentifier path = serializer.fromYangInstanceIdentifier(yangInstanceIdentifier); - checkNotNull(path, "Invalid instance identifier %s. Cannot create BA equivalent.", yangInstanceIdentifier); - LOG.debug("VppOperationalDataTree.readNode(), path={}", path); - - final Optional dataObject; - - dataObject = readerRegistry.read(path, ctx); - if (dataObject.isPresent()) { - final NormalizedNode value = toNormalizedNodeFunction(path).apply(dataObject.get()); - return Optional.>fromNullable(value); - } else { - return Optional.absent(); - } - } - - private Optional> readRoot(final ReadContext ctx) throws ReadFailedException { - LOG.debug("VppOperationalDataTree.readRoot()"); - - final DataContainerNodeAttrBuilder dataNodeBuilder = - Builders.containerBuilder() - .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(SchemaContext.NAME)); - - final Multimap, ? extends DataObject> dataObjects = - readerRegistry.readAll(ctx); - - for (final InstanceIdentifier instanceIdentifier : dataObjects.keySet()) { - final YangInstanceIdentifier rootElementId = serializer.toYangInstanceIdentifier(instanceIdentifier); - final NormalizedNode node = - wrapDataObjects(rootElementId, instanceIdentifier, dataObjects.get(instanceIdentifier)); - dataNodeBuilder.withChild((DataContainerChild) node); - } - - return Optional.>of(dataNodeBuilder.build()); - } - - private NormalizedNode wrapDataObjects(final YangInstanceIdentifier yangInstanceIdentifier, - final InstanceIdentifier instanceIdentifier, - final Collection dataObjects) { - final Collection> normalizedRootElements = Collections2 - .transform(dataObjects, toNormalizedNodeFunction(instanceIdentifier)); - - final DataSchemaNode schemaNode = - globalContext.getDataChildByName(yangInstanceIdentifier.getLastPathArgument().getNodeType()); - if (schemaNode instanceof ListSchemaNode) { - // In case of a list, wrap all the values in a Mixin parent node - final ListSchemaNode listSchema = (ListSchemaNode) schemaNode; - return wrapListIntoMixinNode(normalizedRootElements, listSchema); - } else { - Preconditions.checkState(dataObjects.size() == 1, "Singleton list was expected"); - return getOnlyElement(normalizedRootElements); - } - } - - private static DataContainerChild wrapListIntoMixinNode( - final Collection> normalizedRootElements, final ListSchemaNode listSchema) { - if (listSchema.getKeyDefinition().isEmpty()) { - final CollectionNodeBuilder listBuilder = - Builders.unkeyedListBuilder(); - for (NormalizedNode normalizedRootElement : normalizedRootElements) { - listBuilder.withChild((UnkeyedListEntryNode) normalizedRootElement); - } - return listBuilder.build(); - } else { - final CollectionNodeBuilder listBuilder = - listSchema.isUserOrdered() - ? Builders.orderedMapBuilder() - : Builders.mapBuilder(); - - for (NormalizedNode normalizedRootElement : normalizedRootElements) { - listBuilder.withChild((MapEntryNode) normalizedRootElement); - } - return listBuilder.build(); - } - } - - @SuppressWarnings("unchecked") - private Function> toNormalizedNodeFunction(final InstanceIdentifier path) { - return new Function>() { - @Override - public NormalizedNode apply(@Nullable final DataObject dataObject) { - LOG.trace("VppOperationalDataTree.toNormalizedNode(), path={}, dataObject={}", path, dataObject); - final Map.Entry> entry = - serializer.toNormalizedNode(path, dataObject); - - LOG.trace("VppOperationalDataTree.toNormalizedNode(), normalizedNodeEntry={}", entry); - return entry.getValue(); - } - }; - } - - private static final class ReadContextImpl implements ReadContext { - public final Context ctx = new Context(); - - @Nonnull - @Override - public Context getContext() { - return ctx; - } - - @Override - public void close() { - // Make sure to clear the storage in case some customizer stored it to prevent memory leaks - ctx.close(); - } - } -} diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransaction.java deleted file mode 100644 index db01591b9..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransaction.java +++ /dev/null @@ -1,105 +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.data.impl; - -import com.google.common.base.Function; -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 com.google.common.util.concurrent.ListenableFuture; -import io.fd.honeycomb.v3po.data.ReadableVppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class VppReadOnlyTransaction implements DOMDataReadOnlyTransaction { - - private static final Logger LOG = LoggerFactory.getLogger(VppReadOnlyTransaction.class); - private volatile ReadableVppDataTree operationalData; - private volatile VppDataTreeSnapshot configSnapshot; - - VppReadOnlyTransaction(@Nonnull final ReadableVppDataTree operationalData, - @Nonnull final VppDataTreeSnapshot configSnapshot) { - this.operationalData = Preconditions.checkNotNull(operationalData, "operationalData should not be null"); - this.configSnapshot = Preconditions.checkNotNull(configSnapshot, "config should not be null"); - } - - @Override - public void close() { - configSnapshot = null; - operationalData = null; - } - - @Override - public CheckedFuture>, ReadFailedException> read( - final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - LOG.debug("VppReadOnlyTransaction.read(), store={}, path={}", store, path); - - Preconditions.checkState(configSnapshot != null, "Transaction was closed"); - - if (store == LogicalDatastoreType.OPERATIONAL) { - return operationalData.read(path); - } else { - return configSnapshot.read(path); - } - } - - @Override - public CheckedFuture exists(final LogicalDatastoreType store, - final YangInstanceIdentifier path) { - LOG.debug("VppReadOnlyTransaction.exists() store={}, path={}", store, path); - - ListenableFuture listenableFuture = Futures.transform(read(store, path), IS_NODE_PRESENT); - - return Futures.makeChecked(listenableFuture, ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER); - } - - @Nonnull - @Override - public Object getIdentifier() { - return this; - } - - - private static final Function>, ? extends Boolean> IS_NODE_PRESENT = - new Function>, Boolean>() { - @Nullable - @Override - public Boolean apply(@Nullable final Optional> input) { - return input == null - ? Boolean.FALSE - : input.isPresent(); - } - }; - - private static final Function ANY_EX_TO_READ_FAILED_EXCEPTION_MAPPER = - new Function() { - @Override - public ReadFailedException apply(@Nullable final Exception e) { - return new ReadFailedException("Exists failed", e); - } - }; -} \ No newline at end of file diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransaction.java deleted file mode 100644 index c9766eb21..000000000 --- a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransaction.java +++ /dev/null @@ -1,147 +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.data.impl; - -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.CANCELED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.COMMITED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.FAILED; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW; -import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.SUBMITED; - -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.data.VppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; -import io.fd.honeycomb.v3po.translate.TranslationException; -import javax.annotation.Nonnull; -import javax.annotation.concurrent.NotThreadSafe; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.common.RpcResult; -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.DataValidationFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@NotThreadSafe -final class VppWriteTransaction implements DOMDataWriteTransaction { - - private static final Logger LOG = LoggerFactory.getLogger(VppWriteTransaction.class); - private final VppDataTree configDataTree; - private DataTreeModification modification; - private TransactionStatus status; - - VppWriteTransaction(@Nonnull final VppDataTree configDataTree, - @Nonnull final VppDataTreeSnapshot configSnapshot) { - this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataTree should not be null"); - Preconditions.checkNotNull(configSnapshot, "configSnapshot should not be null"); - // initialize transaction state: - modification = configSnapshot.newModification(); - status = NEW; - } - - VppWriteTransaction(@Nonnull final VppDataTree configDataTree) { - this(configDataTree, configDataTree.takeSnapshot()); - } - - private static void checkConfigurationWrite(final LogicalDatastoreType store) { - Preconditions.checkArgument(LogicalDatastoreType.CONFIGURATION == store, "Write is not supported for operational data store"); - } - - private void checkIsNew() { - Preconditions.checkState(status == NEW, "Transaction was submitted or canceled"); - Preconditions.checkState(modification != null, "VPPDataTree modification should not be null"); - } - - @Override - public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - LOG.debug("VppWriteTransaction.put() store={}, path={}, data={}", store, path, data); - checkIsNew(); - checkConfigurationWrite(store); - modification.write(path, data); - } - - @Override - public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, - final NormalizedNode data) { - LOG.debug("VppWriteTransaction.merge() store={}, path={}, data={}", store, path, data); - checkIsNew(); - checkConfigurationWrite(store); - modification.merge(path, data); - } - - @Override - public boolean cancel() { - if (status != NEW) { - // only NEW transactions can be cancelled - return false; - } else { - status = CANCELED; - modification = null; - return true; - } - } - - @Override - public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) { - LOG.debug("VppWriteTransaction.delete() store={}, path={}", store, path); - checkIsNew(); - checkConfigurationWrite(store); - modification.delete(path); - } - - @Override - public CheckedFuture submit() { - LOG.debug("VppWriteTransaction.submit()"); - checkIsNew(); - - // seal transaction: - modification.ready(); - status = SUBMITED; - - try { - configDataTree.commit(modification); - status = COMMITED; - } catch (DataValidationFailedException | TranslationException e) { - status = FAILED; - LOG.error("Failed to commit VPP state modification", e); - return Futures.immediateFailedCheckedFuture( - new TransactionCommitFailedException("Failed to validate DataTreeModification", e)); - } finally { - modification = null; - } - return Futures.immediateCheckedFuture(null); - } - - @Override - @Deprecated - public ListenableFuture> commit() { - throw new UnsupportedOperationException("deprecated"); - } - - @Override - public Object getIdentifier() { - return this; - } -} diff --git a/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java new file mode 100644 index 000000000..fbeba7e07 --- /dev/null +++ b/v3po/data-impl/src/main/java/io/fd/honeycomb/v3po/data/impl/WriteTransaction.java @@ -0,0 +1,147 @@ +/* + * 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.data.impl; + +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.CANCELED; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.COMMITED; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.FAILED; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW; +import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.SUBMITED; + +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.data.ModifiableDataTree; +import io.fd.honeycomb.v3po.data.DataTreeSnapshot; +import io.fd.honeycomb.v3po.translate.TranslationException; +import javax.annotation.Nonnull; +import javax.annotation.concurrent.NotThreadSafe; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.common.RpcResult; +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.DataValidationFailedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@NotThreadSafe +final class WriteTransaction implements DOMDataWriteTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(WriteTransaction.class); + private final ModifiableDataTree configDataTree; + private DataTreeModification modification; + private TransactionStatus status; + + WriteTransaction(@Nonnull final ModifiableDataTree configDataTree, + @Nonnull final DataTreeSnapshot configSnapshot) { + this.configDataTree = Preconditions.checkNotNull(configDataTree, "configDataTree should not be null"); + Preconditions.checkNotNull(configSnapshot, "configSnapshot should not be null"); + // initialize transaction state: + modification = configSnapshot.newModification(); + status = NEW; + } + + WriteTransaction(@Nonnull final ModifiableDataTree configDataTree) { + this(configDataTree, configDataTree.takeSnapshot()); + } + + private static void checkConfigurationWrite(final LogicalDatastoreType store) { + Preconditions.checkArgument(LogicalDatastoreType.CONFIGURATION == store, "Write is not supported for operational data store"); + } + + private void checkIsNew() { + Preconditions.checkState(status == NEW, "Transaction was submitted or canceled"); + Preconditions.checkState(modification != null, "DataTree modification should not be null"); + } + + @Override + public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + LOG.debug("WriteTransaction.put() store={}, path={}, data={}", store, path, data); + checkIsNew(); + checkConfigurationWrite(store); + modification.write(path, data); + } + + @Override + public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, + final NormalizedNode data) { + LOG.debug("WriteTransaction.merge() store={}, path={}, data={}", store, path, data); + checkIsNew(); + checkConfigurationWrite(store); + modification.merge(path, data); + } + + @Override + public boolean cancel() { + if (status != NEW) { + // only NEW transactions can be cancelled + return false; + } else { + status = CANCELED; + modification = null; + return true; + } + } + + @Override + public void delete(LogicalDatastoreType store, final YangInstanceIdentifier path) { + LOG.debug("WriteTransaction.delete() store={}, path={}", store, path); + checkIsNew(); + checkConfigurationWrite(store); + modification.delete(path); + } + + @Override + public CheckedFuture submit() { + LOG.debug("WriteTransaction.submit()"); + checkIsNew(); + + // seal transaction: + modification.ready(); + status = SUBMITED; + + try { + configDataTree.modify(modification); + status = COMMITED; + } catch (DataValidationFailedException | TranslationException e) { + status = FAILED; + LOG.error("Failed modify data tree", e); + return Futures.immediateFailedCheckedFuture( + new TransactionCommitFailedException("Failed to validate DataTreeModification", e)); + } finally { + modification = null; + } + return Futures.immediateCheckedFuture(null); + } + + @Override + @Deprecated + public ListenableFuture> commit() { + throw new UnsupportedOperationException("deprecated"); + } + + @Override + public Object getIdentifier() { + return this; + } +} diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTreeTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTreeTest.java new file mode 100644 index 000000000..b7f8b9d2c --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ConfigDataTreeTest.java @@ -0,0 +1,271 @@ +/* + * 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.data.impl; + +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.anyMap; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +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.data.DataTreeSnapshot; +import io.fd.honeycomb.v3po.translate.TranslationException; +import io.fd.honeycomb.v3po.translate.write.WriteContext; +import io.fd.honeycomb.v3po.translate.write.WriterRegistry; +import java.util.ArrayList; +import java.util.Collections; +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.ReadFailedException; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; + +public class ConfigDataTreeTest { + + @Mock + private WriterRegistry writer; + @Mock + private BindingNormalizedNodeSerializer serializer; + @Mock + private DataTree dataTree; + @Mock + private DataTreeModification modification; + + private ConfigDataTree configDataTree; + + @Before + public void setUp() { + initMocks(this); + configDataTree = new ConfigDataTree(serializer, dataTree, writer); + } + + @Test + public void testRead() throws Exception { + final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot + snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class); + when(dataTree.takeSnapshot()).thenReturn(snapshot); + + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + final Optional node = mock(Optional.class); + doReturn(node).when(snapshot).readNode(path); + + final DataTreeSnapshot dataTreeSnapshot = configDataTree.takeSnapshot(); + final CheckedFuture>, ReadFailedException> future = + dataTreeSnapshot.read(path); + + verify(dataTree).takeSnapshot(); + verify(snapshot).readNode(path); + + assertTrue(future.isDone()); + assertEquals(node, future.get()); + } + + @Test + public void testNewModification() throws Exception { + final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot + snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class); + when(dataTree.takeSnapshot()).thenReturn(snapshot); + + when(snapshot.newModification()).thenReturn(modification); + + final DataTreeSnapshot dataTreeSnapshot = configDataTree.takeSnapshot(); + final DataTreeModification newModification = dataTreeSnapshot.newModification(); + verify(dataTree).takeSnapshot(); + verify(snapshot).newModification(); + + assertEquals(modification, newModification); + } + + @Test + public void testCommitSuccessful() throws Exception { + final DataObject dataBefore = mockDataObject("before", Ethernet.class); + final DataObject dataAfter = mockDataObject("after", Ethernet.class); + + // Prepare modification: + final DataTreeCandidateNode rootNode = mockRootNode(); + // data before: + final ContainerNode nodeBefore = mockContainerNode(dataBefore); + when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); + // data after: + final ContainerNode nodeAfter = mockContainerNode(dataAfter); + when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); + + // Run the test + configDataTree.modify(modification); + + // Verify all changes were processed: + verify(writer).update( + mapOf(dataBefore, Ethernet.class), + mapOf(dataAfter, Ethernet.class), + any(WriteContext.class)); + + // Verify modification was validated + verify(dataTree).validate(modification); + } + + private Map, DataObject> mapOf(final DataObject dataBefore, final Class type) { + return eq( + Collections., DataObject>singletonMap(InstanceIdentifier.create(type), + dataBefore)); + } + + private DataObject mockDataObject(final String name, final Class classToMock) { + final DataObject dataBefore = mock(classToMock, name); + doReturn(classToMock).when(dataBefore).getImplementedInterface(); + return dataBefore; + } + + @Test + public void testCommitUndoSuccessful() throws Exception { + // Prepare data changes: + final DataObject dataBefore = mockDataObject("before", Ethernet.class); + final DataObject dataAfter = mockDataObject("after", Ethernet.class); + + final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock( + io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class); + + // Fail on update: + final TranslationException failedOnUpdateException = new TranslationException("update failed"); + doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter, + failedOnUpdateException)).when(writer).update(anyMap(), anyMap(), any(WriteContext.class)); + + // Prepare modification: + final DataTreeCandidateNode rootNode = mockRootNode(); + // data before: + final ContainerNode nodeBefore = mockContainerNode(dataBefore); + when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); + // data after: + final ContainerNode nodeAfter = mockContainerNode(dataAfter); + when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); + + // Run the test + try { + configDataTree.modify(modification); + } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) { + verify(writer).update(anyMap(), anyMap(), any(WriteContext.class)); + verify(reverter).revert(); + assertEquals(failedOnUpdateException, e.getCause()); + return; + } + + fail("WriterRegistry.BulkUpdateException was expected"); + } + + @Test + public void testCommitUndoFailed() throws Exception { + // Prepare data changes: + final DataObject dataBefore = mockDataObject("before", Ethernet.class); + final DataObject dataAfter = mockDataObject("after", Ethernet.class); + + final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock( + io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class); + + // Fail on update: + doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter, + new TranslationException("update failed"))).when(writer).update(anyMap(), anyMap(), any(WriteContext.class)); + + // Fail on revert: + final TranslationException failedOnRevertException = new TranslationException("update failed"); + final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException = + new io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException(Collections.>emptyList(), + failedOnRevertException); + doThrow(revertFailedException).when(reverter).revert(); + + // Prepare modification: + final DataTreeCandidateNode rootNode = mockRootNode(); + // data before: + final ContainerNode nodeBefore = mockContainerNode(dataBefore); + when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); + // data after: + final ContainerNode nodeAfter = mockContainerNode(dataAfter); + when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); + + // Run the test + try { + configDataTree.modify(modification); + } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException e) { + verify(writer).update(anyMap(), anyMap(), any(WriteContext.class)); + verify(reverter).revert(); + assertEquals(failedOnRevertException, e.getCause()); + return; + } + + fail("RevertFailedException was expected"); + } + + private DataTreeCandidateNode mockRootNode() { + final DataTreeCandidate candidate = mock(DataTreeCandidate.class); + when(dataTree.prepare(modification)).thenReturn(candidate); + + final DataTreeCandidateNode rootNode = mock(DataTreeCandidateNode.class); + when(candidate.getRootNode()).thenReturn(rootNode); + + return rootNode; + } + + private ContainerNode mockContainerNode(DataObject... modifications) { + final int numberOfChildren = modifications.length; + + final YangInstanceIdentifier.NodeIdentifier identifier = + YangInstanceIdentifier.NodeIdentifier.create(QName.create("/")); + + final ContainerNode node = mock(ContainerNode.class); + when(node.getIdentifier()).thenReturn(identifier); + + final List list = new ArrayList<>(numberOfChildren); + doReturn(list).when(node).getValue(); + + for (DataObject modification : modifications) { + final DataContainerChild child = mock(DataContainerChild.class); + when(child.getIdentifier()).thenReturn(mock(YangInstanceIdentifier.PathArgument.class)); + list.add(child); + + final Map.Entry entry = mock(Map.Entry.class); + final Class implementedInterface = + (Class) modification.getImplementedInterface(); + final InstanceIdentifier id = InstanceIdentifier.create(implementedInterface); + + doReturn(id).when(entry).getKey(); + doReturn(modification).when(entry).getValue(); + doReturn(entry).when(serializer).fromNormalizedNode(any(YangInstanceIdentifier.class), eq(child)); + } + return node; + } +} diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java new file mode 100644 index 000000000..a2908d591 --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/DataBrokerTest.java @@ -0,0 +1,111 @@ +/* + * 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.data.impl; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.honeycomb.v3po.data.ReadableDataTree; +import io.fd.honeycomb.v3po.data.ModifiableDataTree; +import io.fd.honeycomb.v3po.data.DataTreeSnapshot; +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.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; +import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; + +public class DataBrokerTest { + + @Mock + private ReadableDataTree operationalData; + @Mock + private ModifiableDataTree confiDataTree; + @Mock + private DataTreeSnapshot configSnapshot; + private DataBroker broker; + + @Before + public void setUp() { + initMocks(this); + when(confiDataTree.takeSnapshot()).thenReturn(configSnapshot); + broker = new DataBroker(operationalData, confiDataTree); + } + + @Test + public void testNewReadWriteTransaction() { + final DOMDataReadWriteTransaction readWriteTx = broker.newReadWriteTransaction(); + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + readWriteTx.read(LogicalDatastoreType.CONFIGURATION, path); + + // verify that read and write transactions use the same config snapshot + verify(configSnapshot).read(path); + verify(configSnapshot).newModification(); + } + + @Test + public void testNewWriteOnlyTransaction() { + final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction(); + + // verify that write transactions use config snapshot + verify(configSnapshot).newModification(); + } + + @Test + public void testNewReadOnlyTransaction() { + final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction(); + + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + readTx.read(LogicalDatastoreType.CONFIGURATION, path); + + // verify that read transactions use config snapshot + verify(configSnapshot).read(path); + } + + @Test(expected = UnsupportedOperationException.class) + public void testRegisterDataChangeListener() { + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + final DOMDataChangeListener listener = mock(DOMDataChangeListener.class); + broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, path, listener, + AsyncDataBroker.DataChangeScope.BASE); + } + + @Test(expected = UnsupportedOperationException.class) + public void testCreateTransactionChain() { + final TransactionChainListener listener = mock(TransactionChainListener.class); + broker.createTransactionChain(listener); + } + + @Test + public void testGetSupportedExtensions() { + final Map, DOMDataBrokerExtension> supportedExtensions = + broker.getSupportedExtensions(); + assertTrue(supportedExtensions.isEmpty()); + } + + +} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTreeTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTreeTest.java new file mode 100644 index 000000000..f4c2f1e5b --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/OperationalDataTreeTest.java @@ -0,0 +1,171 @@ +/* + * 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.data.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +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.collect.Iterables; +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.v3po.translate.read.ReadContext; +import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; +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.ReadFailedException; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +public class OperationalDataTreeTest { + + @Mock + private BindingNormalizedNodeSerializer serializer; + @Mock + private ReaderRegistry reader; + + private OperationalDataTree operationalData; + + @Mock + private InstanceIdentifier id; + @Mock + private Map.Entry> entry; + @Mock + private SchemaContext globalContext; + @Mock + private DataSchemaNode schemaNode; + @Mock + private ReadContext readCtx; + + @Before + public void setUp() { + initMocks(this); + operationalData = new OperationalDataTree(serializer, globalContext, reader); + doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class)); + } + + @Test + public void testReadNode() throws Exception { + final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); + final YangInstanceIdentifier.PathArgument pArg = mock(YangInstanceIdentifier.PathArgument.class); + doReturn(pArg).when(yangId).getLastPathArgument(); + + doReturn(QName.create("namespace", "2012-12-12", "local")).when(pArg).getNodeType(); + doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); + + final DataObject dataObject = mock(DataObject.class); + doReturn(Optional.of(dataObject)).when(reader).read(same(id), any(ReadContext.class)); + + when(serializer.toNormalizedNode(id, dataObject)).thenReturn(entry); + final DataContainerChild expectedValue = mock(DataContainerChild.class); + doReturn(expectedValue).when(entry).getValue(); + + final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); + + verify(serializer).fromYangInstanceIdentifier(yangId); + verify(reader).read(same(id), any(ReadContext.class)); + final Optional> result = future.get(); + assertTrue(result.isPresent()); + assertEquals(expectedValue, result.get()); + } + + @Test + public void testReadNonExistingNode() throws Exception { + final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); + doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); + doReturn(Optional.absent()).when(reader).read(same(id), any(ReadContext.class)); + + final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); + + verify(serializer).fromYangInstanceIdentifier(yangId); + verify(reader).read(same(id), any(ReadContext.class)); + final Optional> result = future.get(); + assertFalse(result.isPresent()); + } + + @Test + public void testReadFailed() throws Exception{ + doThrow(io.fd.honeycomb.v3po.translate.read.ReadFailedException.class).when(reader).readAll(any(ReadContext.class)); + + final CheckedFuture>, ReadFailedException> future = + operationalData.read( YangInstanceIdentifier.EMPTY); + + try { + future.checkedGet(); + } catch (ReadFailedException e) { + assertTrue(e.getCause() instanceof io.fd.honeycomb.v3po.translate.read.ReadFailedException); + return; + } + fail("ReadFailedException was expected"); + } + + @Test + public void testReadRootWithOneNonListElement() throws Exception { + // Prepare data + final InstanceIdentifier vppStateII = InstanceIdentifier.create(VppState.class); + final VppState vppState = mock(VppState.class); + Multimap, DataObject> dataObjects = LinkedListMultimap.create(); + dataObjects.put(vppStateII, vppState); + doReturn(dataObjects).when(reader).readAll(any(ReadContext.class)); + + // Init serializer + final YangInstanceIdentifier vppYangId = YangInstanceIdentifier.builder().node(VppState.QNAME).build(); + when(serializer.toYangInstanceIdentifier(vppStateII)).thenReturn(vppYangId); + when(serializer.toNormalizedNode(vppStateII, vppState)).thenReturn(entry); + final DataContainerChild vppStateContainer = mock(DataContainerChild.class); + doReturn(vppStateContainer).when(entry).getValue(); + doReturn(vppYangId.getLastPathArgument()).when(vppStateContainer).getIdentifier(); + + // Read root + final CheckedFuture>, ReadFailedException> future = + operationalData.read(YangInstanceIdentifier.EMPTY); + + verify(reader).readAll(any(ReadContext.class)); + verify(serializer).toYangInstanceIdentifier(vppStateII); + verify(serializer).toNormalizedNode(vppStateII, vppState); + + // Check the result is an ContainerNode with only one child + final Optional> result = future.get(); + assertTrue(result.isPresent()); + + final ContainerNode rootNode = (ContainerNode) result.get(); + assertEquals(SchemaContext.NAME, rootNode.getIdentifier().getNodeType()); + assertEquals(vppStateContainer, Iterables.getOnlyElement(rootNode.getValue())); + } +} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java new file mode 100644 index 000000000..30fdd1392 --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ReadOnlyTransactionTest.java @@ -0,0 +1,68 @@ +/* + * 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.data.impl; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +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.data.ReadableDataTree; +import io.fd.honeycomb.v3po.data.DataTreeSnapshot; +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.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class ReadOnlyTransactionTest { + + @Mock + private ReadableDataTree operationalData; + @Mock + private DataTreeSnapshot configSnapshot; + + private ReadOnlyTransaction readOnlyTx; + + @Before + public void setUp() { + initMocks(this); + readOnlyTx = new ReadOnlyTransaction(operationalData, configSnapshot); + } + + @Test + public void testExists() { + final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); + final CheckedFuture>, ReadFailedException> + future = mock(CheckedFuture.class); + when(operationalData.read(path)).thenReturn(future); + + readOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path); + + verify(operationalData).read(path); + } + + @Test + public void testGetIdentifier() { + assertNotNull(readOnlyTx.getIdentifier()); + } +} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VPPConfigDataTreeTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VPPConfigDataTreeTest.java deleted file mode 100644 index ecb9ac4ab..000000000 --- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VPPConfigDataTreeTest.java +++ /dev/null @@ -1,270 +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.data.impl; - -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.anyMap; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -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.data.VppDataTreeSnapshot; -import io.fd.honeycomb.v3po.translate.TranslationException; -import io.fd.honeycomb.v3po.translate.write.WriteContext; -import io.fd.honeycomb.v3po.translate.write.WriterRegistry; -import java.util.ArrayList; -import java.util.Collections; -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.ReadFailedException; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; - -public class VPPConfigDataTreeTest { - - @Mock - private WriterRegistry vppWriter; - @Mock - private BindingNormalizedNodeSerializer serializer; - @Mock - private DataTree dataTree; - @Mock - private DataTreeModification modification; - - private VppConfigDataTree proxy; - - @Before - public void setUp() { - initMocks(this); - proxy = new VppConfigDataTree(serializer, dataTree, vppWriter); - } - - @Test - public void testRead() throws Exception { - final DataTreeSnapshot snapshot = mock(DataTreeSnapshot.class); - when(dataTree.takeSnapshot()).thenReturn(snapshot); - - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - final Optional node = mock(Optional.class); - doReturn(node).when(snapshot).readNode(path); - - final VppDataTreeSnapshot vppDataTreeSnapshot = proxy.takeSnapshot(); - final CheckedFuture>, ReadFailedException> future = - vppDataTreeSnapshot.read(path); - - verify(dataTree).takeSnapshot(); - verify(snapshot).readNode(path); - - assertTrue(future.isDone()); - assertEquals(node, future.get()); - } - - @Test - public void testNewModification() throws Exception { - final DataTreeSnapshot snapshot = mock(DataTreeSnapshot.class); - when(dataTree.takeSnapshot()).thenReturn(snapshot); - - when(snapshot.newModification()).thenReturn(modification); - - final VppDataTreeSnapshot vppDataTreeSnapshot = proxy.takeSnapshot(); - final DataTreeModification newModification = vppDataTreeSnapshot.newModification(); - verify(dataTree).takeSnapshot(); - verify(snapshot).newModification(); - - assertEquals(modification, newModification); - } - - @Test - public void testCommitSuccessful() throws Exception { - final DataObject dataBefore = mockDataObject("before", Ethernet.class); - final DataObject dataAfter = mockDataObject("after", Ethernet.class); - - // Prepare modification: - final DataTreeCandidateNode rootNode = mockRootNode(); - // data before: - final ContainerNode nodeBefore = mockContainerNode(dataBefore); - when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); - // data after: - final ContainerNode nodeAfter = mockContainerNode(dataAfter); - when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); - - // Run the test - proxy.commit(modification); - - // Verify all changes were processed: - verify(vppWriter).update( - mapOf(dataBefore, Ethernet.class), - mapOf(dataAfter, Ethernet.class), - any(WriteContext.class)); - - // Verify modification was validated - verify(dataTree).validate(modification); - } - - private Map, DataObject> mapOf(final DataObject dataBefore, final Class type) { - return eq( - Collections., DataObject>singletonMap(InstanceIdentifier.create(type), - dataBefore)); - } - - private DataObject mockDataObject(final String name, final Class classToMock) { - final DataObject dataBefore = mock(classToMock, name); - doReturn(classToMock).when(dataBefore).getImplementedInterface(); - return dataBefore; - } - - @Test - public void testCommitUndoSuccessful() throws Exception { - // Prepare data changes: - final DataObject dataBefore = mockDataObject("before", Ethernet.class); - final DataObject dataAfter = mockDataObject("after", Ethernet.class); - - final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock( - io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class); - - // Fail on update: - final TranslationException failedOnUpdateException = new TranslationException("update failed"); - doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter, - failedOnUpdateException)).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); - - // Prepare modification: - final DataTreeCandidateNode rootNode = mockRootNode(); - // data before: - final ContainerNode nodeBefore = mockContainerNode(dataBefore); - when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); - // data after: - final ContainerNode nodeAfter = mockContainerNode(dataAfter); - when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); - - // Run the test - try { - proxy.commit(modification); - } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) { - verify(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); - verify(reverter).revert(); - assertEquals(failedOnUpdateException, e.getCause()); - return; - } - - fail("WriterRegistry.BulkUpdateException was expected"); - } - - @Test - public void testCommitUndoFailed() throws Exception { - // Prepare data changes: - final DataObject dataBefore = mockDataObject("before", Ethernet.class); - final DataObject dataAfter = mockDataObject("after", Ethernet.class); - - final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock( - io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class); - - // Fail on update: - doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter, - new TranslationException("update failed"))).when(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); - - // Fail on revert: - final TranslationException failedOnRevertException = new TranslationException("update failed"); - final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException = - new io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException(Collections.>emptyList(), - failedOnRevertException); - doThrow(revertFailedException).when(reverter).revert(); - - // Prepare modification: - final DataTreeCandidateNode rootNode = mockRootNode(); - // data before: - final ContainerNode nodeBefore = mockContainerNode(dataBefore); - when(rootNode.getDataBefore()).thenReturn(Optional.>fromNullable(nodeBefore)); - // data after: - final ContainerNode nodeAfter = mockContainerNode(dataAfter); - when(rootNode.getDataAfter()).thenReturn(Optional.>fromNullable(nodeAfter)); - - // Run the test - try { - proxy.commit(modification); - } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException e) { - verify(vppWriter).update(anyMap(), anyMap(), any(WriteContext.class)); - verify(reverter).revert(); - assertEquals(failedOnRevertException, e.getCause()); - return; - } - - fail("RevertFailedException was expected"); - } - - private DataTreeCandidateNode mockRootNode() { - final DataTreeCandidate candidate = mock(DataTreeCandidate.class); - when(dataTree.prepare(modification)).thenReturn(candidate); - - final DataTreeCandidateNode rootNode = mock(DataTreeCandidateNode.class); - when(candidate.getRootNode()).thenReturn(rootNode); - - return rootNode; - } - - private ContainerNode mockContainerNode(DataObject... modifications) { - final int numberOfChildren = modifications.length; - - final YangInstanceIdentifier.NodeIdentifier identifier = - YangInstanceIdentifier.NodeIdentifier.create(QName.create("/")); - - final ContainerNode node = mock(ContainerNode.class); - when(node.getIdentifier()).thenReturn(identifier); - - final List list = new ArrayList<>(numberOfChildren); - doReturn(list).when(node).getValue(); - - for (DataObject modification : modifications) { - final DataContainerChild child = mock(DataContainerChild.class); - when(child.getIdentifier()).thenReturn(mock(YangInstanceIdentifier.PathArgument.class)); - list.add(child); - - final Map.Entry entry = mock(Map.Entry.class); - final Class implementedInterface = - (Class) modification.getImplementedInterface(); - final InstanceIdentifier id = InstanceIdentifier.create(implementedInterface); - - doReturn(id).when(entry).getKey(); - doReturn(modification).when(entry).getValue(); - doReturn(entry).when(serializer).fromNormalizedNode(any(YangInstanceIdentifier.class), eq(child)); - } - return node; - } -} diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppDataBrokerTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppDataBrokerTest.java deleted file mode 100644 index 0a7cd80ae..000000000 --- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppDataBrokerTest.java +++ /dev/null @@ -1,111 +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.data.impl; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.honeycomb.v3po.data.ReadableVppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; -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.AsyncDataBroker; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; - -public class VppDataBrokerTest { - - @Mock - private ReadableVppDataTree operationalData; - @Mock - private VppDataTree confiDataTree; - @Mock - private VppDataTreeSnapshot configSnapshot; - private VppDataBroker broker; - - @Before - public void setUp() { - initMocks(this); - when(confiDataTree.takeSnapshot()).thenReturn(configSnapshot); - broker = new VppDataBroker(operationalData, confiDataTree); - } - - @Test - public void testNewReadWriteTransaction() { - final DOMDataReadWriteTransaction readWriteTx = broker.newReadWriteTransaction(); - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - readWriteTx.read(LogicalDatastoreType.CONFIGURATION, path); - - // verify that read and write transactions use the same config snapshot - verify(configSnapshot).read(path); - verify(configSnapshot).newModification(); - } - - @Test - public void testNewWriteOnlyTransaction() { - final DOMDataWriteTransaction writeTx = broker.newWriteOnlyTransaction(); - - // verify that write transactions use config snapshot - verify(configSnapshot).newModification(); - } - - @Test - public void testNewReadOnlyTransaction() { - final DOMDataReadOnlyTransaction readTx = broker.newReadOnlyTransaction(); - - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - readTx.read(LogicalDatastoreType.CONFIGURATION, path); - - // verify that read transactions use config snapshot - verify(configSnapshot).read(path); - } - - @Test(expected = UnsupportedOperationException.class) - public void testRegisterDataChangeListener() { - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - final DOMDataChangeListener listener = mock(DOMDataChangeListener.class); - broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, path, listener, - AsyncDataBroker.DataChangeScope.BASE); - } - - @Test(expected = UnsupportedOperationException.class) - public void testCreateTransactionChain() { - final TransactionChainListener listener = mock(TransactionChainListener.class); - broker.createTransactionChain(listener); - } - - @Test - public void testGetSupportedExtensions() { - final Map, DOMDataBrokerExtension> supportedExtensions = - broker.getSupportedExtensions(); - assertTrue(supportedExtensions.isEmpty()); - } - - -} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTreeTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTreeTest.java deleted file mode 100644 index d0b45fa65..000000000 --- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppOperationalDataTreeTest.java +++ /dev/null @@ -1,171 +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.data.impl; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -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.collect.Iterables; -import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.Multimap; -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.translate.read.ReadContext; -import io.fd.honeycomb.v3po.translate.read.ReaderRegistry; -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.ReadFailedException; -import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; - -public class VppOperationalDataTreeTest { - - @Mock - private BindingNormalizedNodeSerializer serializer; - @Mock - private ReaderRegistry reader; - - private VppOperationalDataTree operationalData; - - @Mock - private InstanceIdentifier id; - @Mock - private Map.Entry> entry; - @Mock - private SchemaContext globalContext; - @Mock - private DataSchemaNode schemaNode; - @Mock - private ReadContext readCtx; - - @Before - public void setUp() { - initMocks(this); - operationalData = new VppOperationalDataTree(serializer, globalContext, reader); - doReturn(schemaNode).when(globalContext).getDataChildByName(any(QName.class)); - } - - @Test - public void testReadNode() throws Exception { - final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); - final YangInstanceIdentifier.PathArgument pArg = mock(YangInstanceIdentifier.PathArgument.class); - doReturn(pArg).when(yangId).getLastPathArgument(); - - doReturn(QName.create("namespace", "2012-12-12", "local")).when(pArg).getNodeType(); - doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); - - final DataObject dataObject = mock(DataObject.class); - doReturn(Optional.of(dataObject)).when(reader).read(same(id), any(ReadContext.class)); - - when(serializer.toNormalizedNode(id, dataObject)).thenReturn(entry); - final DataContainerChild expectedValue = mock(DataContainerChild.class); - doReturn(expectedValue).when(entry).getValue(); - - final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); - - verify(serializer).fromYangInstanceIdentifier(yangId); - verify(reader).read(same(id), any(ReadContext.class)); - final Optional> result = future.get(); - assertTrue(result.isPresent()); - assertEquals(expectedValue, result.get()); - } - - @Test - public void testReadNonExistingNode() throws Exception { - final YangInstanceIdentifier yangId = mock(YangInstanceIdentifier.class); - doReturn(id).when(serializer).fromYangInstanceIdentifier(yangId); - doReturn(Optional.absent()).when(reader).read(same(id), any(ReadContext.class)); - - final CheckedFuture>, ReadFailedException> future = operationalData.read(yangId); - - verify(serializer).fromYangInstanceIdentifier(yangId); - verify(reader).read(same(id), any(ReadContext.class)); - final Optional> result = future.get(); - assertFalse(result.isPresent()); - } - - @Test - public void testReadFailed() throws Exception{ - doThrow(io.fd.honeycomb.v3po.translate.read.ReadFailedException.class).when(reader).readAll(any(ReadContext.class)); - - final CheckedFuture>, ReadFailedException> future = - operationalData.read( YangInstanceIdentifier.EMPTY); - - try { - future.checkedGet(); - } catch (ReadFailedException e) { - assertTrue(e.getCause() instanceof io.fd.honeycomb.v3po.translate.read.ReadFailedException); - return; - } - fail("ReadFailedException was expected"); - } - - @Test - public void testReadRootWithOneNonListElement() throws Exception { - // Prepare data - final InstanceIdentifier vppStateII = InstanceIdentifier.create(VppState.class); - final VppState vppState = mock(VppState.class); - Multimap, DataObject> dataObjects = LinkedListMultimap.create(); - dataObjects.put(vppStateII, vppState); - doReturn(dataObjects).when(reader).readAll(any(ReadContext.class)); - - // Init serializer - final YangInstanceIdentifier vppYangId = YangInstanceIdentifier.builder().node(VppState.QNAME).build(); - when(serializer.toYangInstanceIdentifier(vppStateII)).thenReturn(vppYangId); - when(serializer.toNormalizedNode(vppStateII, vppState)).thenReturn(entry); - final DataContainerChild vppStateContainer = mock(DataContainerChild.class); - doReturn(vppStateContainer).when(entry).getValue(); - doReturn(vppYangId.getLastPathArgument()).when(vppStateContainer).getIdentifier(); - - // Read root - final CheckedFuture>, ReadFailedException> future = - operationalData.read(YangInstanceIdentifier.EMPTY); - - verify(reader).readAll(any(ReadContext.class)); - verify(serializer).toYangInstanceIdentifier(vppStateII); - verify(serializer).toNormalizedNode(vppStateII, vppState); - - // Check the result is an ContainerNode with only one child - final Optional> result = future.get(); - assertTrue(result.isPresent()); - - final ContainerNode rootNode = (ContainerNode) result.get(); - assertEquals(SchemaContext.NAME, rootNode.getIdentifier().getNodeType()); - assertEquals(vppStateContainer, Iterables.getOnlyElement(rootNode.getValue())); - } -} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransactionTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransactionTest.java deleted file mode 100644 index b0c64bbdf..000000000 --- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppReadOnlyTransactionTest.java +++ /dev/null @@ -1,68 +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.data.impl; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.mock; -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.data.ReadableVppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; -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.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; - -public class VppReadOnlyTransactionTest { - - @Mock - private ReadableVppDataTree operationalData; - @Mock - private VppDataTreeSnapshot configSnapshot; - - private VppReadOnlyTransaction readOnlyTx; - - @Before - public void setUp() { - initMocks(this); - readOnlyTx = new VppReadOnlyTransaction(operationalData, configSnapshot); - } - - @Test - public void testExists() { - final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class); - final CheckedFuture>, ReadFailedException> - future = mock(CheckedFuture.class); - when(operationalData.read(path)).thenReturn(future); - - readOnlyTx.exists(LogicalDatastoreType.OPERATIONAL, path); - - verify(operationalData).read(path); - } - - @Test - public void testGetIdentifier() { - assertNotNull(readOnlyTx.getIdentifier()); - } -} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransactionTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransactionTest.java deleted file mode 100644 index ad93b148a..000000000 --- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/VppWriteTransactionTest.java +++ /dev/null @@ -1,136 +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.data.impl; - -import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - -import com.google.common.util.concurrent.CheckedFuture; -import io.fd.honeycomb.v3po.data.VppDataTree; -import io.fd.honeycomb.v3po.data.VppDataTreeSnapshot; -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.TransactionCommitFailedException; -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.DataValidationFailedException; - -public class VppWriteTransactionTest { - - @Mock - private VppDataTree configDataTree; - @Mock - private VppDataTreeSnapshot configSnapshot; - @Mock - private YangInstanceIdentifier path; - @Mock - private NormalizedNode data; - @Mock - private DataTreeModification dataTreeModification; - - private VppWriteTransaction writeTx; - - @Before - public void setUp() { - initMocks(this); - when(configSnapshot.newModification()).thenReturn(dataTreeModification); - writeTx = new VppWriteTransaction(configDataTree, configSnapshot); - } - - @Test - public void testPut() { - writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); - verify(dataTreeModification).write(path, data); - } - - @Test(expected = IllegalArgumentException.class) - public void testPutOperational() { - writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data); - verify(dataTreeModification).write(path, data); - } - - @Test(expected = IllegalStateException.class) - public void testOnFinishedTx() { - writeTx.submit(); - writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); - verify(dataTreeModification).write(path, data); - } - - @Test - public void testMerge() { - writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, data); - verify(dataTreeModification).merge(path, data); - } - - @Test - public void testCancel() { - assertTrue(writeTx.cancel()); - } - - @Test - public void testCancelFinished() { - writeTx.submit(); - assertFalse(writeTx.cancel()); - } - - @Test - public void testDelete() { - writeTx.delete(LogicalDatastoreType.CONFIGURATION, path); - verify(dataTreeModification).delete(path); - } - - @Test - public void testSubmit() throws Exception { - writeTx.submit(); - verify(dataTreeModification).ready(); - verify(configDataTree).commit(dataTreeModification); - } - - @Test - public void testSubmitFailed() throws Exception { - doThrow(mock(DataValidationFailedException.class)).when(configDataTree).commit(dataTreeModification); - final CheckedFuture future = writeTx.submit(); - try { - future.get(); - } catch (Exception e) { - assertTrue(e.getCause() instanceof TransactionCommitFailedException); - return; - } - fail("Expected exception to be thrown"); - - } - - @Test(expected = UnsupportedOperationException.class) - public void testCommit() { - writeTx.commit(); - } - - @Test - public void testGetIdentifier() { - assertNotNull(writeTx.getIdentifier()); - } -} \ No newline at end of file diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java new file mode 100644 index 000000000..d0360dbd8 --- /dev/null +++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/WriteTransactionTest.java @@ -0,0 +1,136 @@ +/* + * 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.data.impl; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.common.util.concurrent.CheckedFuture; +import io.fd.honeycomb.v3po.data.ModifiableDataTree; +import io.fd.honeycomb.v3po.data.DataTreeSnapshot; +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.TransactionCommitFailedException; +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.DataValidationFailedException; + +public class WriteTransactionTest { + + @Mock + private ModifiableDataTree configDataTree; + @Mock + private DataTreeSnapshot configSnapshot; + @Mock + private YangInstanceIdentifier path; + @Mock + private NormalizedNode data; + @Mock + private DataTreeModification dataTreeModification; + + private WriteTransaction writeTx; + + @Before + public void setUp() { + initMocks(this); + when(configSnapshot.newModification()).thenReturn(dataTreeModification); + writeTx = new WriteTransaction(configDataTree, configSnapshot); + } + + @Test + public void testPut() { + writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); + verify(dataTreeModification).write(path, data); + } + + @Test(expected = IllegalArgumentException.class) + public void testPutOperational() { + writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data); + verify(dataTreeModification).write(path, data); + } + + @Test(expected = IllegalStateException.class) + public void testOnFinishedTx() { + writeTx.submit(); + writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); + verify(dataTreeModification).write(path, data); + } + + @Test + public void testMerge() { + writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, data); + verify(dataTreeModification).merge(path, data); + } + + @Test + public void testCancel() { + assertTrue(writeTx.cancel()); + } + + @Test + public void testCancelFinished() { + writeTx.submit(); + assertFalse(writeTx.cancel()); + } + + @Test + public void testDelete() { + writeTx.delete(LogicalDatastoreType.CONFIGURATION, path); + verify(dataTreeModification).delete(path); + } + + @Test + public void testSubmit() throws Exception { + writeTx.submit(); + verify(dataTreeModification).ready(); + verify(configDataTree).modify(dataTreeModification); + } + + @Test + public void testSubmitFailed() throws Exception { + doThrow(mock(DataValidationFailedException.class)).when(configDataTree).modify(dataTreeModification); + final CheckedFuture future = writeTx.submit(); + try { + future.get(); + } catch (Exception e) { + assertTrue(e.getCause() instanceof TransactionCommitFailedException); + return; + } + fail("Expected exception to be thrown"); + + } + + @Test(expected = UnsupportedOperationException.class) + public void testCommit() { + writeTx.commit(); + } + + @Test + public void testGetIdentifier() { + assertNotNull(writeTx.getIdentifier()); + } +} \ No newline at end of file -- cgit 1.2.3-korg