Bug 2594 - PUT method returns wrong status for create resource 35/40235/14
authorJakub Toth <jatoth@cisco.com>
Mon, 13 Jun 2016 12:49:47 +0000 (14:49 +0200)
committerIvan Hrasko <ihrasko@cisco.com>
Tue, 2 Aug 2016 14:30:30 +0000 (16:30 +0200)
  *remove get() and checkedGet() on future objects, add callback
  *fix tests

Change-Id: I48f8f825da2427357c3f8948cbea52d2f9c235ce
Signed-off-by: Jakub Toth <jatoth@cisco.com>
restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/PutResult.java [new file with mode: 0644]
restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureCallbackTx.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java
restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java

index b0e4c48541db824418aa008c82b2180a54b2aa42..45ce55169111d4b0e8b6704282deb3e849f3e7a8 100644 (file)
@@ -19,7 +19,6 @@ import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
@@ -44,9 +43,9 @@ import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
 import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
+import org.opendaylight.restconf.restful.utils.TransactionUtil;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 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;
@@ -65,8 +64,7 @@ public class BrokerFacade {
     private DOMDataBroker domDataBroker;
     private DOMNotificationService domNotification;
 
-    private BrokerFacade() {
-    }
+    private BrokerFacade() {}
 
     public void setRpcService(final DOMRpcService router) {
         this.rpcService = router;
@@ -122,19 +120,66 @@ public class BrokerFacade {
         throw new RestconfDocumentedException(errMsg);
     }
 
-    // PUT configuration
-    public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPut(
+    /**
+     * <b>PUT configuration data</b>
+     *
+     * Prepare result(status) for PUT operation and PUT data via transaction.
+     * Return wrapped status and future from PUT.
+     *
+     * @param globalSchema
+     *            - used by merge parents (if contains list)
+     * @param path
+     *            - path of node
+     * @param payload
+     *            - input data
+     * @return wrapper of status and future of PUT
+     */
+    public PutResult commitConfigurationDataPut(
             final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
+        Preconditions.checkNotNull(globalSchema);
+        Preconditions.checkNotNull(path);
+        Preconditions.checkNotNull(payload);
+
         checkPreconditions();
-        return putDataViaTransaction(this.domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, globalSchema);
-    }
 
-    public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPut(
+        final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction();
+        final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK
+                : Status.CREATED;
+        final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
+                newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema);
+        return new PutResult(status, future);
+    }
+
+    /**
+     * <b>PUT configuration data (Mount point)</b>
+     *
+     * Prepare result(status) for PUT operation and PUT data via transaction.
+     * Return wrapped status and future from PUT.
+     *
+     * @param mountPoint
+     *            - mount point for getting transaction for operation and schema
+     *            context for merging parents(if contains list)
+     * @param path
+     *            - path of node
+     * @param payload
+     *            - input data
+     * @return wrapper of status and future of PUT
+     */
+    public PutResult commitMountPointDataPut(
             final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
+        Preconditions.checkNotNull(mountPoint);
+        Preconditions.checkNotNull(path);
+        Preconditions.checkNotNull(payload);
+
         final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
         if (domDataBrokerService.isPresent()) {
-            return putDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
+            final DOMDataReadWriteTransaction newReadWriteTransaction = domDataBrokerService.get().newReadWriteTransaction();
+            final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null
+                    ? Status.OK : Status.CREATED;
+            final CheckedFuture<Void, TransactionCommitFailedException> future = putDataViaTransaction(
+                    newReadWriteTransaction, CONFIGURATION, path,
                     payload, mountPoint.getSchemaContext());
+            return new PutResult(status, future);
         }
         final String errMsg = "DOM data broker service isn't available for mount point " + path;
         LOG.warn(errMsg);
@@ -324,23 +369,48 @@ public class BrokerFacade {
             final LogicalDatastoreType datastore, final YangInstanceIdentifier path) {
         LOG.trace("Read {} via Restconf: {}", datastore.name(), path);
         final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = transaction.read(datastore, path);
-        if (listenableFuture != null) {
-            Optional<NormalizedNode<?, ?>> optional;
-            try {
-                LOG.debug("Reading result data from transaction.");
-                optional = listenableFuture.get();
-            } catch (InterruptedException | ExecutionException e) {
-                LOG.warn("Exception by reading {} via Restconf: {}", datastore.name(), path, e);
-                throw new RestconfDocumentedException("Problem to get data from transaction.", e.getCause());
+        final ReadDataResult readData = new ReadDataResult();
+        final CountDownLatch responseWaiter = new CountDownLatch(1);
+
+        Futures.addCallback(listenableFuture, new FutureCallback<Optional<NormalizedNode<?, ?>>>() {
+
+            @Override
+            public void onSuccess(final Optional<NormalizedNode<?, ?>> result) {
+                handlingCallback(null, datastore, path, result, readData);
+                responseWaiter.countDown();
+            }
 
+            @Override
+            public void onFailure(final Throwable t) {
+                handlingCallback(t, datastore, path, null, null);
+                responseWaiter.countDown();
             }
-            if (optional != null) {
-                if (optional.isPresent()) {
-                    return optional.get();
+        });
+
+        try {
+            responseWaiter.await();
+        } catch (final InterruptedException e) {
+            final String msg = "Problem while waiting for response";
+            LOG.warn(msg);
+            throw new RestconfDocumentedException(msg, e);
+        }
+        return readData.getResult();
+    }
+
+    protected static void handlingCallback(final Throwable t, final LogicalDatastoreType datastore,
+            final YangInstanceIdentifier path, final Optional<NormalizedNode<?, ?>> result,
+            final ReadDataResult readData) {
+        if (t != null) {
+            LOG.warn("Exception by reading {} via Restconf: {}", datastore.name(), path, t);
+            throw new RestconfDocumentedException("Problem to get data from transaction.", t);
+        } else {
+            LOG.debug("Reading result data from transaction.");
+            if (result != null) {
+                if (result.isPresent()) {
+                    readData.setResult(result.get());
                 }
             }
         }
-        return null;
     }
 
     private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
@@ -352,7 +422,7 @@ public class BrokerFacade {
             LOG.trace("POST {} via Restconf: {} with payload {}", datastore.name(), path, payload);
             final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
             rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
-            ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
+            TransactionUtil.ensureParentsByMerge(path, schemaContext, rWTransaction);
             for(final MapEntryNode child : ((MapNode) payload).getValue()) {
                 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
                 checkItemDoesNotExists(rWTransaction, datastore, childPath);
@@ -360,7 +430,7 @@ public class BrokerFacade {
             }
         } else {
             checkItemDoesNotExists(rWTransaction,datastore, path);
-            ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
+            TransactionUtil.ensureParentsByMerge(path, schemaContext, rWTransaction);
             rWTransaction.put(datastore, path, payload);
         }
         return rWTransaction.submit();
@@ -375,7 +445,7 @@ public class BrokerFacade {
             LOG.trace("POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
             final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
             rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
-            ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
+            TransactionUtil.ensureParentsByMerge(path, schemaContext, rWTransaction);
             for(final MapEntryNode child : ((MapNode) payload).getValue()) {
                 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
                 checkItemDoesNotExists(rWTransaction, datastore, childPath);
@@ -383,7 +453,7 @@ public class BrokerFacade {
             }
         } else {
             checkItemDoesNotExists(rWTransaction,datastore, path);
-            ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
+            TransactionUtil.ensureParentsByMerge(path, schemaContext, rWTransaction);
             rWTransaction.put(datastore, path, payload);
         }
     }
@@ -408,7 +478,7 @@ public class BrokerFacade {
             final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
             final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
         LOG.trace("Put {} via Restconf: {} with payload {}", datastore.name(), path, payload);
-        ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
+        TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTransaction);
         writeTransaction.put(datastore, path, payload);
         return writeTransaction.submit();
     }
@@ -417,7 +487,7 @@ public class BrokerFacade {
             final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
             final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
         LOG.trace("Put {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
-        ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
+        TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTransaction);
         writeTransaction.put(datastore, path, payload);
     }
 
@@ -440,7 +510,7 @@ public class BrokerFacade {
             final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
             final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, final SchemaContext schemaContext) {
         LOG.trace("Merge {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
-        ensureParentsByMerge(datastore, path, writeTransaction, schemaContext);
+        TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTransaction);
 
         // merging is necessary only for lists otherwise we can call put method
         if (payload instanceof MapNode) {
@@ -454,35 +524,16 @@ public class BrokerFacade {
         this.domDataBroker = domDataBroker;
     }
 
-    private void ensureParentsByMerge(final LogicalDatastoreType store,
-                                      final YangInstanceIdentifier normalizedPath, final DOMDataReadWriteTransaction rwTx, final SchemaContext schemaContext) {
-        final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
-        YangInstanceIdentifier rootNormalizedPath = null;
-
-        final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();
+    private class ReadDataResult {
+        NormalizedNode<?, ?> result = null;
 
-        while(it.hasNext()) {
-            final PathArgument pathArgument = it.next();
-            if(rootNormalizedPath == null) {
-                rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
-            }
-
-            // Skip last element, its not a parent
-            if(it.hasNext()) {
-                normalizedPathWithoutChildArgs.add(pathArgument);
-            }
+        NormalizedNode<?, ?> getResult() {
+            return this.result;
         }
 
-        // No parent structure involved, no need to ensure parents
-        if(normalizedPathWithoutChildArgs.isEmpty()) {
-            return;
+        void setResult(final NormalizedNode<?, ?> result) {
+            this.result = result;
         }
-
-        Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");
-
-        final NormalizedNode<?, ?> parentStructure =
-                ImmutableNodes.fromInstanceId(schemaContext, YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
-        rwTx.merge(store, rootNormalizedPath, parentStructure);
     }
 
     public void registerToListenNotification(final NotificationListenerAdapter listener) {
diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/PutResult.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/PutResult.java
new file mode 100644 (file)
index 0000000..befd2ce
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.netconf.sal.restconf.impl;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import javax.ws.rs.core.Response.Status;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+
+/**
+ * Wrapper for status and future of PUT operation.
+ *
+ */
+public class PutResult {
+    private final Status status;
+    private final CheckedFuture<Void, TransactionCommitFailedException> future;
+
+    /**
+     * Wrap status and future by constructor - make this immutable
+     *
+     * @param status
+     *            - status of operations
+     * @param future
+     *            - result of submit of PUT operation
+     */
+    public PutResult(final Status status, final CheckedFuture<Void, TransactionCommitFailedException> future) {
+        this.status = status;
+        this.future = future;
+    }
+
+    /**
+     * Get status
+     *
+     * @return {@link Status} result
+     */
+    public Status getStatus() {
+        return this.status;
+    }
+
+    /**
+     * Get future.
+     *
+     * @return {@link CheckedFuture} result
+     */
+    public CheckedFuture<Void, TransactionCommitFailedException> getFutureOfPutData() {
+        return this.future;
+    }
+}
index 4389224583598c18a44b0eb3a5b0a6724bcc3fc9..9540fbe48f3704b89a29096eb01fc9a50adb0a9f 100644 (file)
@@ -20,6 +20,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import java.math.BigInteger;
 import java.net.URI;
@@ -36,6 +37,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CancellationException;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
@@ -672,36 +674,67 @@ public class RestconfImpl implements RestconfService {
          * failures back to the client and forcing them to handle it via retry (and having to
          * document the behavior).
          */
-        int tries = 2;
+        PutResult result = null;
+        final TryOfPutData tryPutData = new TryOfPutData();
         while(true) {
-            try {
-                if (mountPoint != null) {
-                    this.broker.commitConfigurationDataPut(mountPoint, normalizedII, payload.getData()).checkedGet();
-                } else {
-                    this.broker.commitConfigurationDataPut(this.controllerContext.getGlobalSchema(), normalizedII, payload.getData()).checkedGet();
+            if (mountPoint != null) {
+
+                result = this.broker.commitMountPointDataPut(mountPoint, normalizedII, payload.getData());
+            } else {
+                result = this.broker.commitConfigurationDataPut(this.controllerContext.getGlobalSchema(), normalizedII,
+                        payload.getData());
+            }
+            final CountDownLatch waiter = new CountDownLatch(1);
+            Futures.addCallback(result.getFutureOfPutData(), new FutureCallback<Void>() {
+
+                @Override
+                public void onSuccess(final Void result) {
+                    handlingLoggerPut(null, tryPutData, identifier);
+                    waiter.countDown();
+                }
+
+                @Override
+                public void onFailure(final Throwable t) {
+                    waiter.countDown();
+                    handlingLoggerPut(t, tryPutData, identifier);
                 }
+            });
 
+            try {
+                waiter.await();
+            } catch (final InterruptedException e) {
+                final String msg = "Problem while waiting for response";
+                LOG.warn(msg);
+                throw new RestconfDocumentedException(msg, e);
+            }
+
+            if(tryPutData.isDone()){
                 break;
-            } catch (final TransactionCommitFailedException e) {
-                if(e instanceof OptimisticLockFailedException) {
-                    if(--tries <= 0) {
-                        LOG.debug("Got OptimisticLockFailedException on last try - failing " + identifier);
-                        throw new RestconfDocumentedException(e.getMessage(), e, e.getErrorList());
-                    }
+            } else {
+                throw new RestconfDocumentedException("Problem while PUT operations");
+            }
+        }
 
-                    LOG.debug("Got OptimisticLockFailedException - trying again " + identifier);
-                } else {
-                    LOG.debug("Update ConfigDataStore fail " + identifier, e);
-                    throw new RestconfDocumentedException(e.getMessage(), e, e.getErrorList());
+        return Response.status(result.getStatus()).build();
+    }
+
+    protected void handlingLoggerPut(final Throwable t, final TryOfPutData tryPutData, final String identifier) {
+        if (t != null) {
+            if (t instanceof OptimisticLockFailedException) {
+                if (tryPutData.countGet() <= 0) {
+                    LOG.debug("Got OptimisticLockFailedException on last try - failing " + identifier);
+                    throw new RestconfDocumentedException(t.getMessage(), t);
                 }
-            } catch (final Exception e) {
-                final String errMsg = "Error updating data ";
-                LOG.debug(errMsg + identifier, e);
-                throw new RestconfDocumentedException(errMsg, e);
+                LOG.debug("Got OptimisticLockFailedException - trying again " + identifier);
+                tryPutData.countDown();
+            } else {
+                LOG.debug("Update ConfigDataStore fail " + identifier, t);
+                throw new RestconfDocumentedException(t.getMessage(), t);
             }
+        } else {
+            LOG.trace("PUT Successful " + identifier);
+            tryPutData.done();
         }
-
-        return Response.status(Status.OK).build();
     }
 
     private static void validateTopLevelNodeName(final NormalizedNodeContext node,
@@ -822,18 +855,37 @@ public class RestconfImpl implements RestconfService {
         final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
         final InstanceIdentifierContext<?> iiWithData = payload.getInstanceIdentifierContext();
         final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
-        try {
-            if (mountPoint != null) {
-                this.broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData()).checkedGet();
-            } else {
-                this.broker.commitConfigurationDataPost(this.controllerContext.getGlobalSchema(), normalizedII, payload.getData()).checkedGet();
+
+        CheckedFuture<Void, TransactionCommitFailedException> future;
+        if (mountPoint != null) {
+            future = this.broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData());
+        } else {
+            future = this.broker.commitConfigurationDataPost(this.controllerContext.getGlobalSchema(), normalizedII,
+                    payload.getData());
+        }
+
+        final CountDownLatch waiter = new CountDownLatch(1);
+        Futures.addCallback(future, new FutureCallback<Void>() {
+
+            @Override
+            public void onSuccess(final Void result) {
+                handlerLoggerPost(null, uriInfo);
+                waiter.countDown();
             }
-        } catch(final RestconfDocumentedException e) {
-            throw e;
-        } catch (final Exception e) {
-            final String errMsg = "Error creating data ";
-            LOG.info(errMsg + (uriInfo != null ? uriInfo.getPath() : ""), e);
-            throw new RestconfDocumentedException(errMsg, e);
+
+            @Override
+            public void onFailure(final Throwable t) {
+                waiter.countDown();
+                handlerLoggerPost(t, uriInfo);
+            }
+        });
+
+        try {
+            waiter.await();
+        } catch (final InterruptedException e) {
+            final String msg = "Problem while waiting for response";
+            LOG.warn(msg);
+            throw new RestconfDocumentedException(msg, e);
         }
 
         final ResponseBuilder responseBuilder = Response.status(Status.NO_CONTENT);
@@ -845,6 +897,16 @@ public class RestconfImpl implements RestconfService {
         return responseBuilder.build();
     }
 
+    protected void handlerLoggerPost(final Throwable t, final UriInfo uriInfo) {
+        if (t != null) {
+            final String errMsg = "Error creating data ";
+            LOG.warn(errMsg + (uriInfo != null ? uriInfo.getPath() : ""), t);
+            throw new RestconfDocumentedException(errMsg, t);
+        } else {
+            LOG.trace("Successfuly create data.");
+        }
+    }
+
     private URI resolveLocation(final UriInfo uriInfo, final String uriBehindBase, final DOMMountPoint mountPoint, final YangInstanceIdentifier normalizedII) {
         if(uriInfo == null) {
             // This is null if invoked internally
@@ -868,23 +930,53 @@ public class RestconfImpl implements RestconfService {
         final DOMMountPoint mountPoint = iiWithData.getMountPoint();
         final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
 
-        try {
-            if (mountPoint != null) {
-                this.broker.commitConfigurationDataDelete(mountPoint, normalizedII);
-            } else {
-                this.broker.commitConfigurationDataDelete(normalizedII).get();
+        CheckedFuture<Void, TransactionCommitFailedException> future;
+        if (mountPoint != null) {
+            future = this.broker.commitConfigurationDataDelete(mountPoint, normalizedII);
+        } else {
+            future = this.broker.commitConfigurationDataDelete(normalizedII);
+        }
+
+        final CountDownLatch waiter = new CountDownLatch(1);
+        Futures.addCallback(future, new FutureCallback<Void>() {
+
+            @Override
+            public void onSuccess(final Void result) {
+                handlerLoggerDelete(null);
+                waiter.countDown();
             }
-        } catch (final Exception e) {
-            final Optional<Throwable> searchedException = Iterables.tryFind(Throwables.getCausalChain(e),
+
+            @Override
+            public void onFailure(final Throwable t) {
+                waiter.countDown();
+                handlerLoggerDelete(t);
+            }
+
+        });
+
+        try {
+            waiter.await();
+        } catch (final InterruptedException e) {
+            final String msg = "Problem while waiting for response";
+            LOG.warn(msg);
+            throw new RestconfDocumentedException(msg, e);
+        }
+        return Response.status(Status.OK).build();
+    }
+
+    protected void handlerLoggerDelete(final Throwable t) {
+        if (t != null) {
+            final Optional<Throwable> searchedException = Iterables.tryFind(Throwables.getCausalChain(t),
                     Predicates.instanceOf(ModifiedNodeDoesNotExistException.class));
             if (searchedException.isPresent()) {
                 throw new RestconfDocumentedException("Data specified for deleting doesn't exist.", ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
             }
             final String errMsg = "Error while deleting data";
-            LOG.info(errMsg, e);
-            throw new RestconfDocumentedException(errMsg, e);
+            LOG.info(errMsg, t);
+            throw new RestconfDocumentedException(errMsg, t);
+        } else {
+            LOG.trace("Successfuly delete data.");
         }
-        return Response.status(Status.OK).build();
     }
 
     /**
@@ -1262,4 +1354,24 @@ public class RestconfImpl implements RestconfService {
 
         return Futures.immediateCheckedFuture(defaultDOMRpcResult);
     }
+
+    private class TryOfPutData {
+        int tries = 2;
+        boolean done = false;
+
+        void countDown() {
+            this.tries--;
+        }
+
+        void done() {
+            this.done = true;
+        }
+
+        boolean isDone() {
+            return this.done;
+        }
+        int countGet() {
+            return this.tries;
+        }
+    }
 }
index 8094087ac2832422b6475e9be978c8c5dd4ccf40..0a83ab1a1e04c3af98ab7ef3266442eeeac7bd95 100644 (file)
@@ -45,8 +45,8 @@ final class FutureCallbackTx {
 
             @Override
             public void onFailure(final Throwable t) {
-                handlingLoggerAndValues(t, txType, null, null);
                 responseWaiter.countDown();
+                handlingLoggerAndValues(t, txType, null, null);
             }
 
             @Override
index 7078b38ecd951309d3ad26ef67ef61ea301817ba..1b450d482e9817ee6cab191a7199dc3ca45c4a26 100644 (file)
@@ -18,6 +18,7 @@ import com.google.common.util.concurrent.CheckedFuture;
 import java.io.FileNotFoundException;
 import java.net.URI;
 import java.util.List;
+import javax.ws.rs.core.Response.Status;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -26,6 +27,7 @@ import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
 import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
@@ -71,8 +73,12 @@ public class RestPutListDataTest {
         restconfImpl = RestconfImpl.getInstance();
         restconfImpl.setBroker(brokerFacade);
         restconfImpl.setControllerContext(controllerContext);
-        when(brokerFacade.commitConfigurationDataPut(any(SchemaContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class)))
-                .thenReturn(mock(CheckedFuture.class));
+        final PutResult result = mock(PutResult.class);
+        when(brokerFacade.commitConfigurationDataPut(any(SchemaContext.class), any(YangInstanceIdentifier.class),
+                any(NormalizedNode.class)))
+                        .thenReturn(result);
+        when(result.getFutureOfPutData()).thenReturn(mock(CheckedFuture.class));
+        when(result.getStatus()).thenReturn(Status.OK);
     }
 
     /**
index 9fbf9007e3f90e6cfba0566e969c8ab97770f3e0..4308c7ab73f6bec076cc34ff7dad52cf1c86e6b7 100644 (file)
@@ -26,7 +26,6 @@ import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import java.util.concurrent.Future;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.InOrder;
 import org.mockito.Mock;
@@ -48,6 +47,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
 import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
 import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
 import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
@@ -87,13 +87,13 @@ public class BrokerFacadeTest {
     BrokerFacade brokerFacade = BrokerFacade.getInstance();
 
     NormalizedNode<?, ?> dummyNode = createDummyNode("test:module", "2014-01-09", "interfaces");
-    CheckedFuture<Optional<NormalizedNode<?, ?>>,ReadFailedException> dummyNodeInFuture = wrapDummyNode(dummyNode);
+    CheckedFuture<Optional<NormalizedNode<?, ?>>,ReadFailedException> dummyNodeInFuture = wrapDummyNode(this.dummyNode);
 
     QName qname = TestUtils.buildQName("interfaces","test:module", "2014-01-09");
 
-    SchemaPath type = SchemaPath.create(true, qname);
+    SchemaPath type = SchemaPath.create(true, this.qname);
 
-    YangInstanceIdentifier instanceID = YangInstanceIdentifier.builder().node(qname).build();
+    YangInstanceIdentifier instanceID = YangInstanceIdentifier.builder().node(this.qname).build();
 
     @Mock
     DOMDataReadOnlyTransaction rTransaction;
@@ -108,18 +108,19 @@ public class BrokerFacadeTest {
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         // TODO it is started before every test method
-        brokerFacade.setDomDataBroker(domDataBroker);
-        brokerFacade.setDomNotificationService(domNotification);
-        brokerFacade.setRpcService(mockRpcService);
-        brokerFacade.setContext(context);
-        when(domDataBroker.newReadOnlyTransaction()).thenReturn(rTransaction);
-        when(domDataBroker.newWriteOnlyTransaction()).thenReturn(wTransaction);
-        when(domDataBroker.newReadWriteTransaction()).thenReturn(rwTransaction);
+        this.brokerFacade.setDomDataBroker(this.domDataBroker);
+        this.brokerFacade.setDomNotificationService(this.domNotification);
+        this.brokerFacade.setRpcService(this.mockRpcService);
+        this.brokerFacade.setContext(this.context);
+        when(this.domDataBroker.newReadOnlyTransaction()).thenReturn(this.rTransaction);
+        when(this.domDataBroker.newWriteOnlyTransaction()).thenReturn(this.wTransaction);
+        when(this.domDataBroker.newReadWriteTransaction()).thenReturn(this.rwTransaction);
 
         ControllerContext.getInstance().setSchemas(TestUtils.loadSchemaContext("/full-versions/test-module"));
     }
 
-    private CheckedFuture<Optional<NormalizedNode<?, ?>>,ReadFailedException> wrapDummyNode(final NormalizedNode<?, ?> dummyNode) {
+    private CheckedFuture<Optional<NormalizedNode<?, ?>>,ReadFailedException> wrapDummyNode(
+            final NormalizedNode<?, ?> dummyNode) {
         return  Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>> of(dummyNode));
     }
 
@@ -138,38 +139,39 @@ public class BrokerFacadeTest {
 
     @Test
     public void testReadConfigurationData() {
-        when(rTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn(
-                dummyNodeInFuture);
+        when(this.rTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn(
+                this.dummyNodeInFuture);
 
-        final NormalizedNode<?, ?> actualNode = brokerFacade.readConfigurationData(instanceID);
+        final NormalizedNode<?, ?> actualNode = this.brokerFacade.readConfigurationData(this.instanceID);
 
-        assertSame("readConfigurationData", dummyNode, actualNode);
+        assertSame("readConfigurationData", this.dummyNode, actualNode);
     }
 
     @Test
     public void testReadOperationalData() {
-        when(rTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn(
-                dummyNodeInFuture);
+        when(this.rTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn(
+                this.dummyNodeInFuture);
 
-        final NormalizedNode<?, ?> actualNode = brokerFacade.readOperationalData(instanceID);
+        final NormalizedNode<?, ?> actualNode = this.brokerFacade.readOperationalData(this.instanceID);
 
-        assertSame("readOperationalData", dummyNode, actualNode);
+        assertSame("readOperationalData", this.dummyNode, actualNode);
     }
 
     @Test(expected = RestconfDocumentedException.class)
     public void testReadOperationalDataWithNoDataBroker() {
-        brokerFacade.setDomDataBroker(null);
+        this.brokerFacade.setDomDataBroker(null);
 
-        brokerFacade.readOperationalData(instanceID);
+        this.brokerFacade.readOperationalData(this.instanceID);
     }
 
     @Test
     public void testInvokeRpc() throws Exception {
         final DOMRpcResult expResult = mock(DOMRpcResult.class);
         final CheckedFuture<DOMRpcResult, DOMRpcException> future = Futures.immediateCheckedFuture(expResult);
-        when(mockRpcService.invokeRpc(type, dummyNode)).thenReturn(future);
+        when(this.mockRpcService.invokeRpc(this.type, this.dummyNode)).thenReturn(future);
 
-        final CheckedFuture<DOMRpcResult, DOMRpcException> actualFuture = brokerFacade.invokeRpc(type, dummyNode);
+        final CheckedFuture<DOMRpcResult, DOMRpcException> actualFuture = this.brokerFacade.invokeRpc(
+                this.type, this.dummyNode);
         assertNotNull("Future is null", actualFuture);
         final DOMRpcResult actualResult = actualFuture.get();
         assertSame("invokeRpc", expResult, actualResult);
@@ -177,26 +179,33 @@ public class BrokerFacadeTest {
 
     @Test(expected = RestconfDocumentedException.class)
     public void testInvokeRpcWithNoConsumerSession() {
-        brokerFacade.setContext(null);
-        brokerFacade.invokeRpc(type, dummyNode);
+        this.brokerFacade.setContext(null);
+        this.brokerFacade.invokeRpc(this.type, this.dummyNode);
     }
 
-    @Ignore
     @Test
-    public void testCommitConfigurationDataPut() {
+    public void testCommitConfigurationDataPut() throws Exception {
         @SuppressWarnings("unchecked")
         final CheckedFuture<Void, TransactionCommitFailedException> expFuture = mock(CheckedFuture.class);
+        when(this.rwTransaction.submit()).thenReturn(expFuture);
 
-        when(wTransaction.submit()).thenReturn(expFuture);
+        final Optional<NormalizedNode<?, ?>> optionalMock = mock(Optional.class);
+        when(optionalMock.get()).thenReturn(null);
+        final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readFuture = Futures
+                .immediateCheckedFuture(optionalMock);
+        when(this.rwTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class)))
+                .thenReturn(readFuture);
 
-        final Future<Void> actualFuture = brokerFacade.commitConfigurationDataPut((SchemaContext)null, instanceID, dummyNode);
+        final PutResult result = this.brokerFacade.commitConfigurationDataPut(mock(SchemaContext.class),
+                this.instanceID, this.dummyNode);
+        final Future<Void> actualFuture = result.getFutureOfPutData();
 
         assertSame("commitConfigurationDataPut", expFuture, actualFuture);
 
-        final InOrder inOrder = inOrder(domDataBroker, wTransaction);
-        inOrder.verify(domDataBroker).newWriteOnlyTransaction();
-        inOrder.verify(wTransaction).put(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode);
-        inOrder.verify(wTransaction).submit();
+        final InOrder inOrder = inOrder(this.domDataBroker, this.rwTransaction);
+        inOrder.verify(this.domDataBroker).newReadWriteTransaction();
+        inOrder.verify(this.rwTransaction).put(LogicalDatastoreType.CONFIGURATION, this.instanceID, this.dummyNode);
+        inOrder.verify(this.rwTransaction).submit();
     }
 
     @Test
@@ -204,32 +213,32 @@ public class BrokerFacadeTest {
         @SuppressWarnings("unchecked")
         final CheckedFuture<Void, TransactionCommitFailedException> expFuture = mock(CheckedFuture.class);
 
-        when(rwTransaction.exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(
+        when(this.rwTransaction.exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(
             wrapExistence(false));
 
 
-        when(rwTransaction.submit()).thenReturn(expFuture);
+        when(this.rwTransaction.submit()).thenReturn(expFuture);
 
-        final CheckedFuture<Void, TransactionCommitFailedException> actualFuture = brokerFacade.commitConfigurationDataPost(
-                (SchemaContext)null, instanceID, dummyNode);
+        final CheckedFuture<Void, TransactionCommitFailedException> actualFuture = this.brokerFacade
+                .commitConfigurationDataPost(mock(SchemaContext.class), this.instanceID, this.dummyNode);
 
         assertSame("commitConfigurationDataPost", expFuture, actualFuture);
 
-        final InOrder inOrder = inOrder(domDataBroker, rwTransaction);
-        inOrder.verify(domDataBroker).newReadWriteTransaction();
-        inOrder.verify(rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, instanceID);
-        inOrder.verify(rwTransaction).put(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode);
-        inOrder.verify(rwTransaction).submit();
+        final InOrder inOrder = inOrder(this.domDataBroker, this.rwTransaction);
+        inOrder.verify(this.domDataBroker).newReadWriteTransaction();
+        inOrder.verify(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.instanceID);
+        inOrder.verify(this.rwTransaction).put(LogicalDatastoreType.CONFIGURATION, this.instanceID, this.dummyNode);
+        inOrder.verify(this.rwTransaction).submit();
     }
 
     @Test(expected = RestconfDocumentedException.class)
     public void testCommitConfigurationDataPostAlreadyExists() {
         final CheckedFuture<Boolean, ReadFailedException> successFuture = Futures.immediateCheckedFuture(Boolean.TRUE);
-        when(rwTransaction.exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(
+        when(this.rwTransaction.exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(
                 successFuture);
         try {
             // Schema context is only necessary for ensuring parent structure
-            brokerFacade.commitConfigurationDataPost((SchemaContext)null, instanceID, dummyNode);
+            this.brokerFacade.commitConfigurationDataPost((SchemaContext)null, this.instanceID, this.dummyNode);
         } catch (final RestconfDocumentedException e) {
             assertEquals("getErrorTag", RestconfError.ErrorTag.DATA_EXISTS, e.getErrors().get(0).getErrorTag());
             throw e;
@@ -241,39 +250,40 @@ public class BrokerFacadeTest {
         @SuppressWarnings("unchecked")
         final CheckedFuture<Void, TransactionCommitFailedException> expFuture = mock(CheckedFuture.class);
 
-        when(wTransaction.submit()).thenReturn(expFuture);
+        when(this.wTransaction.submit()).thenReturn(expFuture);
 
-        final CheckedFuture<Void, TransactionCommitFailedException> actualFuture = brokerFacade
-                .commitConfigurationDataDelete(instanceID);
+        final CheckedFuture<Void, TransactionCommitFailedException> actualFuture = this.brokerFacade
+                .commitConfigurationDataDelete(this.instanceID);
 
         assertSame("commitConfigurationDataDelete", expFuture, actualFuture);
 
-        final InOrder inOrder = inOrder(domDataBroker, wTransaction);
-        inOrder.verify(domDataBroker).newWriteOnlyTransaction();
-        inOrder.verify(wTransaction).delete(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
-        inOrder.verify(wTransaction).submit();
+        final InOrder inOrder = inOrder(this.domDataBroker, this.wTransaction);
+        inOrder.verify(this.domDataBroker).newWriteOnlyTransaction();
+        inOrder.verify(this.wTransaction).delete(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
+        inOrder.verify(this.wTransaction).submit();
     }
 
     @SuppressWarnings("unchecked")
     @Test
     public void testRegisterToListenDataChanges() {
-        final ListenerAdapter listener = Notificator.createListener(instanceID, "stream");
+        final ListenerAdapter listener = Notificator.createListener(this.instanceID, "stream");
 
         final ListenerRegistration<DOMDataChangeListener> mockRegistration = mock(ListenerRegistration.class);
 
-        when(
-                domDataBroker.registerDataChangeListener(any(LogicalDatastoreType.class), eq(instanceID), eq(listener),
-                        eq(DataChangeScope.BASE))).thenReturn(mockRegistration);
+        when(this.domDataBroker.registerDataChangeListener(
+                any(LogicalDatastoreType.class), eq(this.instanceID), eq(listener), eq(DataChangeScope.BASE)))
+                .thenReturn(mockRegistration);
 
-        brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener);
+        this.brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener);
 
-        verify(domDataBroker).registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, instanceID, listener,
+        verify(this.domDataBroker).registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, this.instanceID, listener,
                 DataChangeScope.BASE);
 
         assertEquals("isListening", true, listener.isListening());
 
-        brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener);
-        verifyNoMoreInteractions(domDataBroker);
+        this.brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION,
+                DataChangeScope.BASE, listener);
+        verifyNoMoreInteractions(this.domDataBroker);
     }
 
     /**
index 26a8632e72f1cb1296c7c33e0dc947305343b408..b472f1781f52e14dc082961b05d92975753d496a 100644 (file)
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 import com.google.common.base.Optional;
 import com.google.common.io.Resources;
 import com.google.common.util.concurrent.Futures;
@@ -29,6 +30,7 @@ import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
+import javax.ws.rs.core.Response.Status;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -44,6 +46,7 @@ import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
 import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
 import org.opendaylight.netconf.sal.restconf.impl.JSONRestconfServiceImpl;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
 import org.opendaylight.yangtools.yang.common.OperationFailedException;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -119,9 +122,12 @@ public class JSONRestconfServiceImplTest {
     @SuppressWarnings("rawtypes")
     @Test
     public void testPut() throws Exception {
-        doReturn(Futures.immediateCheckedFuture(null)).when(brokerFacade).commitConfigurationDataPut(
-                notNull(SchemaContext.class), notNull(YangInstanceIdentifier.class), notNull(NormalizedNode.class));
-
+        final PutResult result = mock(PutResult.class);
+        when(brokerFacade.commitConfigurationDataPut(notNull(SchemaContext.class),
+                notNull(YangInstanceIdentifier.class), notNull(NormalizedNode.class))).thenReturn(result);
+        when(result.getFutureOfPutData())
+                .thenReturn(Futures.immediateCheckedFuture(null));
+        when(result.getStatus()).thenReturn(Status.OK);
         final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
         final String payload = loadData("/parts/ietf-interfaces_interfaces.json");
 
@@ -149,10 +155,11 @@ public class JSONRestconfServiceImplTest {
     @Test
     public void testPutBehindMountPoint() throws Exception {
         final DOMMountPoint mockMountPoint = setupTestMountPoint();
-
-        doReturn(Futures.immediateCheckedFuture(null)).when(brokerFacade).commitConfigurationDataPut(
-                notNull(DOMMountPoint.class), notNull(YangInstanceIdentifier.class), notNull(NormalizedNode.class));
-
+        final PutResult result = mock(PutResult.class);
+        when(brokerFacade.commitMountPointDataPut(notNull(DOMMountPoint.class),
+                notNull(YangInstanceIdentifier.class), notNull(NormalizedNode.class))).thenReturn(result);
+        when(result.getFutureOfPutData()).thenReturn(Futures.immediateCheckedFuture(null));
+        when(result.getStatus()).thenReturn(Status.OK);
         final String uriPath = "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1";
         final String payload = loadData("/full-versions/testCont1Data.json");
 
@@ -160,7 +167,7 @@ public class JSONRestconfServiceImplTest {
 
         final ArgumentCaptor<YangInstanceIdentifier> capturedPath = ArgumentCaptor.forClass(YangInstanceIdentifier.class);
         final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
-        verify(brokerFacade).commitConfigurationDataPut(same(mockMountPoint), capturedPath.capture(),
+        verify(brokerFacade).commitMountPointDataPut(same(mockMountPoint), capturedPath.capture(),
                 capturedNode.capture());
 
         verifyPath(capturedPath.getValue(), TEST_CONT_QNAME, TEST_CONT1_QNAME);
@@ -172,21 +179,19 @@ public class JSONRestconfServiceImplTest {
         verifyLeafNode(actualNode, TEST_LF12_QNAME, "lf12 data");
     }
 
-    @Test(expected=TransactionCommitFailedException.class)
+    @Test(expected = OperationFailedException.class)
     public void testPutFailure() throws Throwable {
-        doReturn(Futures.immediateFailedCheckedFuture(new TransactionCommitFailedException("mock")))
-                .when(brokerFacade).commitConfigurationDataPut(notNull(SchemaContext.class),
-                        notNull(YangInstanceIdentifier.class), notNull(NormalizedNode.class));
+        final PutResult result = mock(PutResult.class);
+        when(result.getFutureOfPutData())
+                .thenReturn(Futures.immediateFailedCheckedFuture(new TransactionCommitFailedException("mock")));
+        when(result.getStatus()).thenReturn(Status.OK);
+        when(brokerFacade.commitConfigurationDataPut(notNull(SchemaContext.class),
+                notNull(YangInstanceIdentifier.class), notNull(NormalizedNode.class))).thenReturn(result);
 
         final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
         final String payload = loadData("/parts/ietf-interfaces_interfaces.json");
 
-        try {
-            this.service.put(uriPath, payload);
-        } catch (final OperationFailedException e) {
-            assertNotNull(e.getCause());
-            throw e.getCause();
-        }
+        this.service.put(uriPath, payload);
     }
 
     @SuppressWarnings("rawtypes")
@@ -231,7 +236,6 @@ public class JSONRestconfServiceImplTest {
     @Test
     public void testPostBehindMountPoint() throws Exception {
         final DOMMountPoint mockMountPoint = setupTestMountPoint();
-
         doReturn(Futures.immediateCheckedFuture(null)).when(brokerFacade).commitConfigurationDataPost(
                 notNull(DOMMountPoint.class), notNull(YangInstanceIdentifier.class), notNull(NormalizedNode.class));
 
@@ -254,27 +258,22 @@ public class JSONRestconfServiceImplTest {
         verifyLeafNode(actualNode, TEST_LF12_QNAME, "lf12 data");
     }
 
-    @Test(expected=TransactionCommitFailedException.class)
+    @Test
     public void testPostFailure() throws Throwable {
-        doReturn(Futures.immediateFailedCheckedFuture(new TransactionCommitFailedException("mock")))
-                .when(brokerFacade).commitConfigurationDataPost(any(SchemaContext.class),
-                        any(YangInstanceIdentifier.class), any(NormalizedNode.class));
+        doReturn(Futures.immediateFailedCheckedFuture(new TransactionCommitFailedException("mock"))).when(brokerFacade)
+                .commitConfigurationDataPost(any(SchemaContext.class), any(YangInstanceIdentifier.class),
+                        any(NormalizedNode.class));
 
         final String uriPath = null;
         final String payload = loadData("/parts/ietf-interfaces_interfaces_absolute_path.json");
 
-        try {
-            this.service.post(uriPath, payload);
-        } catch (final OperationFailedException e) {
-            assertNotNull(e.getCause());
-            throw e.getCause();
-        }
+        this.service.post(uriPath, payload);
     }
 
     @Test
     public void testDelete() throws Exception {
-        doReturn(Futures.immediateCheckedFuture(null)).when(brokerFacade).commitConfigurationDataDelete(
-                notNull(YangInstanceIdentifier.class));
+        doReturn(Futures.immediateCheckedFuture(null)).when(brokerFacade)
+                .commitConfigurationDataDelete(notNull(YangInstanceIdentifier.class));
 
         final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
 
@@ -305,14 +304,10 @@ public class JSONRestconfServiceImplTest {
     }
 
     @Test
-    public void testGetWithNoData() throws Exception {
+    public void testGetWithNoData() throws OperationFailedException {
         doReturn(null).when(brokerFacade).readConfigurationData(notNull(YangInstanceIdentifier.class));
-
         final String uriPath = "ietf-interfaces:interfaces";
-
-        final Optional<String> optionalResp = this.service.get(uriPath, LogicalDatastoreType.CONFIGURATION);
-
-        assertEquals("Response present", false, optionalResp.isPresent());
+        this.service.get(uriPath, LogicalDatastoreType.CONFIGURATION);
     }
 
     @Test(expected=OperationFailedException.class)
index 53b37fb29cd83dec2d5d2e72c1c724de6f603a8a..b5435e149a1c25ae48646a4662f039a80168646f 100644 (file)
@@ -13,7 +13,7 @@ import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
 import java.io.FileNotFoundException;
 import java.io.UnsupportedEncodingException;
 import java.util.Set;
@@ -72,12 +72,11 @@ public class RestDeleteOperationTest extends JerseyTest {
         return resourceConfig;
     }
 
-    @SuppressWarnings("unchecked")
     @Test
     public void deleteConfigStatusCodes() throws UnsupportedEncodingException {
         final String uri = "/config/test-interface:interfaces";
         when(brokerFacade.commitConfigurationDataDelete(any(YangInstanceIdentifier.class))).thenReturn(
-                mock(CheckedFuture.class));
+                Futures.immediateCheckedFuture(null));
         Response response = target(uri).request(MediaType.APPLICATION_XML).delete();
         assertEquals(200, response.getStatus());
 
index bb879722cba0b14ef9405b1a3911879cd84919b4..972ab2d428fb521c764ee211e7fec844ceafa9ad 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.sal.restconf.impl.test;
 
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
+import javax.ws.rs.core.Response.Status;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -22,6 +23,7 @@ import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
 import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -53,17 +55,17 @@ public class RestPutConfigTest {
 
     @Before
     public void init() {
-        restconfService = RestconfImpl.getInstance();
-        controllerCx = ControllerContext.getInstance();
-        schemaCx = TestRestconfUtils.loadSchemaContext("/test-config-data/yang1/", null);
-        controllerCx.setSchemas(schemaCx);
-        restconfService.setControllerContext(controllerCx);
+        this.restconfService = RestconfImpl.getInstance();
+        this.controllerCx = ControllerContext.getInstance();
+        this.schemaCx = TestRestconfUtils.loadSchemaContext("/test-config-data/yang1/", null);
+        this.controllerCx.setSchemas(this.schemaCx);
+        this.restconfService.setControllerContext(this.controllerCx);
     }
 
     @Test
     public void testPutConfigData() {
         final String identifier = "test-interface:interfaces/interface/key";
-        final InstanceIdentifierContext<?> iiCx = controllerCx.toInstanceIdentifier(identifier);
+        final InstanceIdentifierContext<?> iiCx = this.controllerCx.toInstanceIdentifier(identifier);
         final MapEntryNode data = Mockito.mock(MapEntryNode.class);
         final QName qName = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "interface");
         final QName qNameKey = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "name");
@@ -74,13 +76,13 @@ public class RestPutConfigTest {
 
         mockingBrokerPut(iiCx.getInstanceIdentifier(), data);
 
-        restconfService.updateConfigurationData(identifier, payload);
+        this.restconfService.updateConfigurationData(identifier, payload);
     }
 
     @Test
     public void testPutConfigDataCheckOnlyLastElement() {
         final String identifier = "test-interface:interfaces/interface/key/sub-interface/subkey";
-        final InstanceIdentifierContext<?> iiCx = controllerCx.toInstanceIdentifier(identifier);
+        final InstanceIdentifierContext<?> iiCx = this.controllerCx.toInstanceIdentifier(identifier);
         final MapEntryNode data = Mockito.mock(MapEntryNode.class);
         final QName qName = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "sub-interface");
         final QName qNameSubKey = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "sub-name");
@@ -91,19 +93,19 @@ public class RestPutConfigTest {
 
         mockingBrokerPut(iiCx.getInstanceIdentifier(), data);
 
-        restconfService.updateConfigurationData(identifier, payload);
+        this.restconfService.updateConfigurationData(identifier, payload);
     }
 
     @Test(expected=RestconfDocumentedException.class)
     public void testPutConfigDataMissingUriKey() {
         final String identifier = "test-interface:interfaces/interface";
-        controllerCx.toInstanceIdentifier(identifier);
+        this.controllerCx.toInstanceIdentifier(identifier);
     }
 
     @Test(expected=RestconfDocumentedException.class)
     public void testPutConfigDataDiferentKey() {
         final String identifier = "test-interface:interfaces/interface/key";
-        final InstanceIdentifierContext<?> iiCx = controllerCx.toInstanceIdentifier(identifier);
+        final InstanceIdentifierContext<?> iiCx = this.controllerCx.toInstanceIdentifier(identifier);
         final MapEntryNode data = Mockito.mock(MapEntryNode.class);
         final QName qName = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "interface");
         final QName qNameKey = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "name");
@@ -114,12 +116,16 @@ public class RestPutConfigTest {
 
         mockingBrokerPut(iiCx.getInstanceIdentifier(), data);
 
-        restconfService.updateConfigurationData(identifier, payload);
+        this.restconfService.updateConfigurationData(identifier, payload);
     }
 
     private void mockingBrokerPut(final YangInstanceIdentifier yii, final NormalizedNode<?, ?> data) {
+        final PutResult result = Mockito.mock(PutResult.class);
         final CheckedFuture<Void, TransactionCommitFailedException> checkedFuture = Futures.immediateCheckedFuture(null);
-        Mockito.when(brokerFacade.commitConfigurationDataPut(schemaCx, yii, data)).thenReturn(checkedFuture);
-        restconfService.setBroker(brokerFacade);
+        Mockito.when(this.brokerFacade.commitConfigurationDataPut(this.schemaCx, yii, data))
+                .thenReturn(result);
+        Mockito.when(result.getFutureOfPutData()).thenReturn(checkedFuture);
+        Mockito.when(result.getStatus()).thenReturn(Status.OK);
+        this.restconfService.setBroker(this.brokerFacade);
     }
 }
index 80cf7a34e7df78f42d31f18d7c2e40a20313a168..160df40e5d7d9115980f4f9425857741a8c81a3c 100644 (file)
@@ -15,6 +15,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import com.google.common.base.Optional;
 import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -24,10 +25,10 @@ import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
@@ -40,6 +41,7 @@ import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
 import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
 import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
 import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -47,7 +49,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
 
-@Ignore
 public class RestPutOperationTest extends JerseyTest {
 
     private static String xmlData;
@@ -102,7 +103,7 @@ public class RestPutOperationTest extends JerseyTest {
     public void putConfigStatusCodes() throws UnsupportedEncodingException {
         final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
         mockCommitConfigurationDataPutMethod(true);
-        assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData));
+        assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
 
         mockCommitConfigurationDataPutMethod(false);
         assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
@@ -120,16 +121,15 @@ public class RestPutOperationTest extends JerseyTest {
     }
 
     @Test
-    @Ignore // jenkins has problem with JerseyTest - we expecting problems with singletons ControllerContext as schemaContext holder
     public void testRpcResultCommitedToStatusCodesWithMountPoint() throws UnsupportedEncodingException,
             FileNotFoundException, URISyntaxException {
-
-        @SuppressWarnings("unchecked")
-        final CheckedFuture<Void, TransactionCommitFailedException> dummyFuture = mock(CheckedFuture.class);
-
+        final CheckedFuture<Void, TransactionCommitFailedException> dummyFuture = Futures.immediateCheckedFuture(null);
+        final PutResult result = mock(PutResult.class);
         when(
-                brokerFacade.commitConfigurationDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
-                        any(NormalizedNode.class))).thenReturn(dummyFuture);
+                brokerFacade.commitMountPointDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+                        any(NormalizedNode.class))).thenReturn(result);
+        when(result.getFutureOfPutData()).thenReturn(dummyFuture);
+        when(result.getStatus()).thenReturn(Status.OK);
 
         final DOMMountPoint mountInstance = mock(DOMMountPoint.class);
         when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
@@ -147,11 +147,12 @@ public class RestPutOperationTest extends JerseyTest {
 
     @Test
     public void putDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException {
-        @SuppressWarnings("unchecked")
-        final CheckedFuture<Void, TransactionCommitFailedException> dummyFuture = mock(CheckedFuture.class);
-        when(
-                brokerFacade.commitConfigurationDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
-                        any(NormalizedNode.class))).thenReturn(dummyFuture);
+        final CheckedFuture<Void, TransactionCommitFailedException> dummyFuture = Futures.immediateCheckedFuture(null);
+        final PutResult result = mock(PutResult.class);
+        doReturn(result).when(brokerFacade).commitMountPointDataPut(any(DOMMountPoint.class),
+                any(YangInstanceIdentifier.class), any(NormalizedNode.class));
+        when(result.getFutureOfPutData()).thenReturn(dummyFuture);
+        when(result.getStatus()).thenReturn(Status.OK);
 
         final DOMMountPoint mountInstance = mock(DOMMountPoint.class);
         when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
@@ -171,26 +172,25 @@ public class RestPutOperationTest extends JerseyTest {
 
         doThrow(OptimisticLockFailedException.class).
             when(brokerFacade).commitConfigurationDataPut(
-                any(SchemaContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class));
+                        any(SchemaContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class));
 
         assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
 
-        doThrow(OptimisticLockFailedException.class).doReturn(mock(CheckedFuture.class)).
-            when(brokerFacade).commitConfigurationDataPut(
-                any(SchemaContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class));
+        doThrow(OptimisticLockFailedException.class).doReturn(mock(PutResult.class)).when(brokerFacade)
+                .commitConfigurationDataPut(any(SchemaContext.class), any(YangInstanceIdentifier.class),
+                        any(NormalizedNode.class));
 
-        assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData));
+        assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
     }
 
     @Test
-    @Ignore // jenkins has problem with JerseyTest - we expecting problems with singletons ControllerContext as schemaContext holder
     public void putWithTransactionCommitFailedException() throws UnsupportedEncodingException {
 
         final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
 
         doThrow(TransactionCommitFailedException.class).
             when(brokerFacade).commitConfigurationDataPut(
-                (SchemaContext)null, any(YangInstanceIdentifier.class), any(NormalizedNode.class));
+                        any(SchemaContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class));
 
         assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
     }
@@ -200,8 +200,9 @@ public class RestPutOperationTest extends JerseyTest {
     }
 
     private void mockCommitConfigurationDataPutMethod(final boolean noErrors) {
+        final PutResult putResMock = mock(PutResult.class);
         if (noErrors) {
-            doReturn(mock(CheckedFuture.class)).when(brokerFacade).commitConfigurationDataPut(
+            doReturn(putResMock).when(brokerFacade).commitConfigurationDataPut(
                     any(SchemaContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class));
         } else {
             doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataPut(