From 573cccc17981fa8d003e76fd57ad36c8dc0a29a5 Mon Sep 17 00:00:00 2001 From: Jakub Toth Date: Mon, 13 Jun 2016 14:49:47 +0200 Subject: [PATCH] Bug 2594 - PUT method returns wrong status for create resource *remove get() and checkedGet() on future objects, add callback *fix tests Change-Id: I48f8f825da2427357c3f8948cbea52d2f9c235ce Signed-off-by: Jakub Toth --- .../sal/restconf/impl/BrokerFacade.java | 159 +++++++++----- .../netconf/sal/restconf/impl/PutResult.java | 52 +++++ .../sal/restconf/impl/RestconfImpl.java | 198 ++++++++++++++---- .../restful/utils/FutureCallbackTx.java | 2 +- .../to/cnsn/test/RestPutListDataTest.java | 10 +- .../restconf/impl/test/BrokerFacadeTest.java | 130 ++++++------ .../test/JSONRestconfServiceImplTest.java | 69 +++--- .../impl/test/RestDeleteOperationTest.java | 5 +- .../restconf/impl/test/RestPutConfigTest.java | 34 +-- .../impl/test/RestPutOperationTest.java | 47 +++-- 10 files changed, 469 insertions(+), 237 deletions(-) create mode 100644 restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/PutResult.java diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java index b0e4c48541..45ce551691 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java @@ -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 commitConfigurationDataPut( + /** + * PUT configuration data + * + * 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 commitConfigurationDataPut( + final DOMDataReadWriteTransaction newReadWriteTransaction = this.domDataBroker.newReadWriteTransaction(); + final Status status = readDataViaTransaction(newReadWriteTransaction, CONFIGURATION, path) != null ? Status.OK + : Status.CREATED; + final CheckedFuture future = putDataViaTransaction( + newReadWriteTransaction, CONFIGURATION, path, payload, globalSchema); + return new PutResult(status, future); + } + + /** + * PUT configuration data (Mount point) + * + * 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 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 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>> listenableFuture = transaction.read(datastore, path); - if (listenableFuture != null) { - Optional> 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>>() { + + @Override + public void onSuccess(final Optional> 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> 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 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 normalizedPathWithoutChildArgs = new ArrayList<>(); - YangInstanceIdentifier rootNormalizedPath = null; - - final Iterator 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 index 0000000000..befd2cefd9 --- /dev/null +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/PutResult.java @@ -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 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 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 getFutureOfPutData() { + return this.future; + } +} diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java index 4389224583..9540fbe48f 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/netconf/sal/restconf/impl/RestconfImpl.java @@ -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() { + + @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 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() { + + @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 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() { + + @Override + public void onSuccess(final Void result) { + handlerLoggerDelete(null); + waiter.countDown(); } - } catch (final Exception e) { - final Optional 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 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; + } + } } diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureCallbackTx.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureCallbackTx.java index 8094087ac2..0a83ab1a1e 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureCallbackTx.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureCallbackTx.java @@ -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 diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java index 7078b38ecd..1b450d482e 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java @@ -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); } /** diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java index 9fbf9007e3..4308c7ab73 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java @@ -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>,ReadFailedException> dummyNodeInFuture = wrapDummyNode(dummyNode); + CheckedFuture>,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>,ReadFailedException> wrapDummyNode(final NormalizedNode dummyNode) { + private CheckedFuture>,ReadFailedException> wrapDummyNode( + final NormalizedNode dummyNode) { return Futures.immediateCheckedFuture(Optional.> 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 future = Futures.immediateCheckedFuture(expResult); - when(mockRpcService.invokeRpc(type, dummyNode)).thenReturn(future); + when(this.mockRpcService.invokeRpc(this.type, this.dummyNode)).thenReturn(future); - final CheckedFuture actualFuture = brokerFacade.invokeRpc(type, dummyNode); + final CheckedFuture 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 expFuture = mock(CheckedFuture.class); + when(this.rwTransaction.submit()).thenReturn(expFuture); - when(wTransaction.submit()).thenReturn(expFuture); + final Optional> optionalMock = mock(Optional.class); + when(optionalMock.get()).thenReturn(null); + final CheckedFuture>, ReadFailedException> readFuture = Futures + .immediateCheckedFuture(optionalMock); + when(this.rwTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))) + .thenReturn(readFuture); - final Future actualFuture = brokerFacade.commitConfigurationDataPut((SchemaContext)null, instanceID, dummyNode); + final PutResult result = this.brokerFacade.commitConfigurationDataPut(mock(SchemaContext.class), + this.instanceID, this.dummyNode); + final Future 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 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 actualFuture = brokerFacade.commitConfigurationDataPost( - (SchemaContext)null, instanceID, dummyNode); + final CheckedFuture 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 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 expFuture = mock(CheckedFuture.class); - when(wTransaction.submit()).thenReturn(expFuture); + when(this.wTransaction.submit()).thenReturn(expFuture); - final CheckedFuture actualFuture = brokerFacade - .commitConfigurationDataDelete(instanceID); + final CheckedFuture 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 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); } /** diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java index 26a8632e72..b472f1781f 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java @@ -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 capturedPath = ArgumentCaptor.forClass(YangInstanceIdentifier.class); final ArgumentCaptor 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 optionalResp = this.service.get(uriPath, LogicalDatastoreType.CONFIGURATION); - - assertEquals("Response present", false, optionalResp.isPresent()); + this.service.get(uriPath, LogicalDatastoreType.CONFIGURATION); } @Test(expected=OperationFailedException.class) diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java index 53b37fb29c..b5435e149a 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java @@ -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()); diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java index bb879722cb..972ab2d428 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java @@ -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 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); } } diff --git a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java index 80cf7a34e7..160df40e5d 100644 --- a/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java +++ b/restconf/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java @@ -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 dummyFuture = mock(CheckedFuture.class); - + final CheckedFuture 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 dummyFuture = mock(CheckedFuture.class); - when( - brokerFacade.commitConfigurationDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class), - any(NormalizedNode.class))).thenReturn(dummyFuture); + final CheckedFuture 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( -- 2.36.6