public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
final YangInstanceIdentifier path) {
checkPreconditions();
- return deleteDataViaTransaction(domDataBroker.newWriteOnlyTransaction(), CONFIGURATION, path);
+ return deleteDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path);
}
public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataDelete(
final DOMMountPoint mountPoint, final YangInstanceIdentifier path) {
final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
if (domDataBrokerService.isPresent()) {
- return deleteDataViaTransaction(domDataBrokerService.get().newWriteOnlyTransaction(), CONFIGURATION, path);
+ return deleteDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path);
}
final String errMsg = "DOM data broker service isn't available for mount point " + path;
LOG.warn(errMsg);
}
}
- private void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ private void checkItemExists(final DOMDataReadWriteTransaction rWTransaction,
+ final LogicalDatastoreType store, final YangInstanceIdentifier path) {
+ final ListenableFuture<Boolean> futureDatastoreData = rWTransaction.exists(store, path);
+ try {
+ if (!futureDatastoreData.get()) {
+ final String errMsg = "Operation via Restconf was not executed because data does not exist";
+ LOG.trace("{}:{}", errMsg, path);
+ rWTransaction.cancel();
+ throw new RestconfDocumentedException("Data does not exist for path: " + path, ErrorType.PROTOCOL,
+ ErrorTag.DATA_MISSING);
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("It wasn't possible to get data loaded from datastore at path {}", path, e);
+ }
+ }
+
+ private void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,
+ final LogicalDatastoreType store, final YangInstanceIdentifier path) {
final ListenableFuture<Boolean> futureDatastoreData = rWTransaction.exists(store, path);
try {
if (futureDatastoreData.get()) {
- final String errMsg = "Post Configuration via Restconf was not executed because data already exists";
+ final String errMsg = "Operation via Restconf was not executed because data already exists";
LOG.trace("{}:{}", errMsg, path);
rWTransaction.cancel();
throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
} catch (InterruptedException | ExecutionException e) {
LOG.warn("It wasn't possible to get data loaded from datastore at path {}", path, e);
}
-
}
private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
}
private CheckedFuture<Void, TransactionCommitFailedException> deleteDataViaTransaction(
- final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
+ final DOMDataReadWriteTransaction readWriteTransaction, final LogicalDatastoreType datastore,
final YangInstanceIdentifier path) {
LOG.trace("Delete {} via Restconf: {}", datastore.name(), path);
- writeTransaction.delete(datastore, path);
- return writeTransaction.submit();
+ checkItemExists(readWriteTransaction, datastore, path);
+ readWriteTransaction.delete(datastore, path);
+ return readWriteTransaction.submit();
}
private void deleteDataWithinTransaction(
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
-import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.ModifiedNodeDoesNotExistException;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
try {
if (mountPoint != null) {
- broker.commitConfigurationDataDelete(mountPoint, normalizedII);
+ broker.commitConfigurationDataDelete(mountPoint, normalizedII).checkedGet();
} else {
- broker.commitConfigurationDataDelete(normalizedII).get();
- }
- } catch (final Exception e) {
- final Optional<Throwable> searchedException = Iterables.tryFind(Throwables.getCausalChain(e),
- Predicates.instanceOf(ModifiedNodeDoesNotExistException.class));
- if (searchedException.isPresent()) {
- throw new RestconfDocumentedException("Data specified for deleting doesn't exist.", ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
+ broker.commitConfigurationDataDelete(normalizedII).checkedGet();
}
+ } catch (final TransactionCommitFailedException e) {
final String errMsg = "Error while deleting data";
LOG.info(errMsg, e);
throw new RestconfDocumentedException(errMsg, e);
}
+
return Response.status(Status.OK).build();
}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
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;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
import org.opendaylight.netconf.sal.streams.listeners.Notificator;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
* @author Thomas Pantelis
*/
public class BrokerFacadeTest {
-
- @Mock
- DOMDataBroker domDataBroker;
-
- @Mock
- ConsumerSession context;
-
- @Mock
- DOMRpcService mockRpcService;
-
- @Mock
- DOMMountPoint mockMountInstance;
-
- BrokerFacade brokerFacade = BrokerFacade.getInstance();
-
- NormalizedNode<?, ?> dummyNode = createDummyNode("test:module", "2014-01-09", "interfaces");
- CheckedFuture<Optional<NormalizedNode<?, ?>>,ReadFailedException> dummyNodeInFuture = wrapDummyNode(dummyNode);
-
- QName qname = TestUtils.buildQName("interfaces","test:module", "2014-01-09");
-
- SchemaPath type = SchemaPath.create(true, qname);
-
- YangInstanceIdentifier instanceID = YangInstanceIdentifier.builder().node(qname).build();
-
- @Mock
- DOMDataReadOnlyTransaction rTransaction;
-
- @Mock
- DOMDataWriteTransaction wTransaction;
-
- @Mock
- DOMDataReadWriteTransaction rwTransaction;
+ @Mock private DOMDataBroker domDataBroker;
+ @Mock private ConsumerSession context;
+ @Mock private DOMRpcService mockRpcService;
+ @Mock private DOMMountPoint mockMountInstance;
+
+ private final BrokerFacade brokerFacade = BrokerFacade.getInstance();
+ private final NormalizedNode<?, ?> dummyNode = createDummyNode("test:module", "2014-01-09", "interfaces");
+ private final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> dummyNodeInFuture =
+ wrapDummyNode(dummyNode);
+ private final QName qname = TestUtils.buildQName("interfaces","test:module", "2014-01-09");
+ private final SchemaPath type = SchemaPath.create(true, qname);
+ private final YangInstanceIdentifier instanceID = YangInstanceIdentifier.builder().node(qname).build();
+
+ @Mock private DOMDataReadOnlyTransaction rTransaction;
+ @Mock private DOMDataWriteTransaction wTransaction;
+ @Mock private DOMDataReadWriteTransaction rwTransaction;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- // TODO it is started before every test method
brokerFacade.setDomDataBroker(domDataBroker);
brokerFacade.setRpcService(mockRpcService);
brokerFacade.setContext(context);
when(domDataBroker.newReadWriteTransaction()).thenReturn(rwTransaction);
ControllerContext.getInstance().setSchemas(TestUtils.loadSchemaContext("/full-versions/test-module"));
-
}
- private CheckedFuture<Optional<NormalizedNode<?, ?>>,ReadFailedException> wrapDummyNode(final NormalizedNode<?, ?> dummyNode) {
- return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>> of(dummyNode));
+ private CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> wrapDummyNode(
+ final NormalizedNode<?, ?> dummyNode) {
+ return Futures.immediateCheckedFuture(Optional.<NormalizedNode<?, ?>> of(dummyNode));
}
- private CheckedFuture<Boolean,ReadFailedException> wrapExistence(final Boolean exists) {
- return Futures.immediateCheckedFuture(exists);
+ private CheckedFuture<Boolean, ReadFailedException> wrapExistence(final Boolean exists) {
+ return Futures.immediateCheckedFuture(exists);
}
-
/**
* Value of this node shouldn't be important for testing purposes
*/
when(rwTransaction.exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class))).thenReturn(
wrapExistence(false));
-
when(rwTransaction.submit()).thenReturn(expFuture);
final CheckedFuture<Void, TransactionCommitFailedException> actualFuture = brokerFacade.commitConfigurationDataPost(
}
}
+ /**
+ * Positive test of delete operation when data to delete exits. Returned value and order of steps are validated.
+ */
@Test
- public void testCommitConfigurationDataDelete() {
- @SuppressWarnings("unchecked")
- final CheckedFuture<Void, TransactionCommitFailedException> expFuture = mock(CheckedFuture.class);
+ public void testCommitConfigurationDataDelete() throws Exception {
+ // assume that data to delete exists
+ prepareDataForDelete(true);
- when(wTransaction.submit()).thenReturn(expFuture);
+ // expected result
+ final CheckedFuture<Void, TransactionCommitFailedException> expFuture = mock(CheckedFuture.class);
+ when(rwTransaction.submit()).thenReturn(expFuture);
+ // test
final CheckedFuture<Void, TransactionCommitFailedException> actualFuture = brokerFacade
.commitConfigurationDataDelete(instanceID);
+ // verify result and interactions
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();
+ // check exists, delete, submit
+ final InOrder inOrder = inOrder(domDataBroker, rwTransaction);
+ inOrder.verify(rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, instanceID);
+ inOrder.verify(rwTransaction).delete(LogicalDatastoreType.CONFIGURATION, instanceID);
+ inOrder.verify(rwTransaction).submit();
+ }
+
+ /**
+ * Negative test of delete operation when data to delete does not exist. Error 404 should be returned.
+ */
+ @Test
+ public void testCommitConfigurationDataDeleteNoData() throws Exception {
+ // assume that data to delete does not exist
+ prepareDataForDelete(false);
+
+ // try to delete and expect 404 error
+ try {
+ brokerFacade.commitConfigurationDataDelete(instanceID);
+ fail("Delete operation should fail due to missing data");
+ } catch (final RestconfDocumentedException e) {
+ assertEquals(ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
+ assertEquals(ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
+ assertEquals(404, e.getErrors().get(0).getErrorTag().getStatusCode());
+ }
+ }
+
+ /**
+ * Prepare conditions to test delete operation. Data to delete exists or does not exist according to value of
+ * {@code assumeDataExists} parameter.
+ * @param assumeDataExists
+ * @throws Exception
+ */
+ private void prepareDataForDelete(final boolean assumeDataExists) throws Exception {
+ final CheckedFuture<Boolean, ReadFailedException> checkDataExistFuture = mock(CheckedFuture.class);
+ when(checkDataExistFuture.get()).thenReturn(assumeDataExists);
+ when(rwTransaction.exists(LogicalDatastoreType.CONFIGURATION, instanceID)).thenReturn(checkDataExistFuture);
}
@SuppressWarnings("unchecked")
brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener);
verifyNoMoreInteractions(domDataBroker);
-
}
}