package org.opendaylight.controller.sal.restconf.impl.test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
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.InstanceIdentifierContext;
+import org.opendaylight.netconf.sal.restconf.impl.PATCHContext;
+import org.opendaylight.netconf.sal.restconf.impl.PATCHStatusContext;
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;
import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.restconf.handlers.SchemaContextHandler;
+import org.opendaylight.restconf.handlers.TransactionChainHandler;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
* @author Thomas Pantelis
*/
public class BrokerFacadeTest {
- @Mock private DOMDataBroker domDataBroker;
- @Mock private DOMNotificationService domNotification;
- @Mock private ConsumerSession context;
- @Mock private DOMRpcService mockRpcService;
- @Mock private DOMMountPoint mockMountInstance;
+
+ @Mock
+ private DOMDataBroker domDataBroker;
+ @Mock
+ private DOMNotificationService domNotification;
+ @Mock
+ private ConsumerSession context;
+ @Mock
+ private DOMRpcService mockRpcService;
+ @Mock
+ private DOMMountPoint mockMountInstance;
+ @Mock
+ private DOMDataReadOnlyTransaction rTransaction;
+ @Mock
+ private DOMDataWriteTransaction wTransaction;
+ @Mock
+ private DOMDataReadWriteTransaction rwTransaction;
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);
+ wrapDummyNode(this.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;
+ private final SchemaPath type = SchemaPath.create(true, this.qname);
+ private final YangInstanceIdentifier instanceID = YangInstanceIdentifier.builder().node(this.qname).build();
@Before
public void setUp() throws Exception {
when(this.rwTransaction.read(LogicalDatastoreType.CONFIGURATION, this.instanceID)).thenReturn(readFuture);
final PutResult result = this.brokerFacade.commitConfigurationDataPut(mock(SchemaContext.class),
- this.instanceID, this.dummyNode);
+ this.instanceID, this.dummyNode, null, null);
final Future<Void> actualFuture = result.getFutureOfPutData();
when(this.rwTransaction.submit()).thenReturn(expFuture);
final CheckedFuture<Void, TransactionCommitFailedException> actualFuture = this.brokerFacade
- .commitConfigurationDataPost(mock(SchemaContext.class), this.instanceID, this.dummyNode);
+ .commitConfigurationDataPost(mock(SchemaContext.class), this.instanceID, this.dummyNode, null, null);
assertSame("commitConfigurationDataPost", expFuture, actualFuture);
.thenReturn(successFuture);
try {
// Schema context is only necessary for ensuring parent structure
- this.brokerFacade.commitConfigurationDataPost((SchemaContext) null, this.instanceID, this.dummyNode);
+ this.brokerFacade.commitConfigurationDataPost((SchemaContext) null, this.instanceID, this.dummyNode, null,
+ null);
} catch (final RestconfDocumentedException e) {
assertEquals("getErrorTag", RestconfError.ErrorTag.DATA_EXISTS, e.getErrors().get(0).getErrorTag());
throw e;
@Test
public void testRegisterToListenDataChanges() {
- final ListenerAdapter listener = Notificator.createListener(this.instanceID, "stream");
+ final ListenerAdapter listener = Notificator.createListener(this.instanceID, "stream",
+ NotificationOutputType.XML);
@SuppressWarnings("unchecked")
final ListenerRegistration<DOMDataChangeListener> mockRegistration = mock(ListenerRegistration.class);
* Create, register, close and remove notification listener.
*/
@Test
- public void testRegisterToListenNotificationChanges() {
+ public void testRegisterToListenNotificationChanges() throws Exception {
// create test notification listener
final String identifier = "create-notification-stream/toaster:toastDone";
final SchemaPath path = SchemaPath.create(true,
// registrations should be invoked only once
verify(this.domNotification, times(1)).registerNotificationListener(listener, listener.getSchemaPath());
+ final DOMTransactionChain transactionChain = mock(DOMTransactionChain.class);
+ final DOMDataWriteTransaction wTx = mock(DOMDataWriteTransaction.class);
+ final CheckedFuture checked = Futures.immediateCheckedFuture("");
+ when(wTx.submit()).thenReturn(checked);
+ when(transactionChain.newWriteOnlyTransaction()).thenReturn(wTx);
+ final TransactionChainHandler transactionChainHandler = new TransactionChainHandler(transactionChain);
+ final SchemaContextHandler schemaHandler = Mockito.mock(SchemaContextHandler.class);
+ final SchemaContext schCtx = TestUtils.loadSchemaContext("/modules");
+ when(schemaHandler.get()).thenReturn(schCtx);
+ listener.setCloseVars(transactionChainHandler, schemaHandler);
// close and remove test notification listener
listener.close();
- Notificator.removeNotificationListenerIfNoSubscriberExists(listener);
+ Notificator.removeListenerIfNoSubscriberExists(listener);
+ }
+
+ /**
+ * Test PATCH method on the server with no data
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testPatchConfigurationDataWithinTransactionServer() throws Exception {
+ final PATCHContext patchContext = mock(PATCHContext.class);
+ final InstanceIdentifierContext identifierContext = mock(InstanceIdentifierContext.class);
+ final CheckedFuture<Void, TransactionCommitFailedException> expFuture = Futures.immediateCheckedFuture(null);
+
+ when(patchContext.getData()).thenReturn(Lists.newArrayList());
+ when(patchContext.getInstanceIdentifierContext()).thenReturn(identifierContext);
+
+ // no mount point
+ when(identifierContext.getMountPoint()).thenReturn(null);
+
+ when(this.rwTransaction.submit()).thenReturn(expFuture);
+
+ final PATCHStatusContext status = this.brokerFacade.patchConfigurationDataWithinTransaction(patchContext);
+
+ // assert success
+ assertTrue("PATCH operation should be successful on server", status.isOk());
+ }
+
+ /**
+ * Test PATCH method on mounted device with no data
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testPatchConfigurationDataWithinTransactionMount() throws Exception {
+ final PATCHContext patchContext = mock(PATCHContext.class);
+ final InstanceIdentifierContext identifierContext = mock(InstanceIdentifierContext.class);
+ final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
+ final DOMDataBroker mountDataBroker = mock(DOMDataBroker.class);
+ final DOMDataReadWriteTransaction transaction = mock(DOMDataReadWriteTransaction.class);
+ final CheckedFuture<Void, TransactionCommitFailedException> expFuture = Futures.immediateCheckedFuture(null);
+
+ when(patchContext.getData()).thenReturn(Lists.newArrayList());
+ when(patchContext.getInstanceIdentifierContext()).thenReturn(identifierContext);
+
+ // return mount point with broker
+ when(identifierContext.getMountPoint()).thenReturn(mountPoint);
+ when(mountPoint.getService(DOMDataBroker.class)).thenReturn(Optional.of(mountDataBroker));
+ when(mountDataBroker.newReadWriteTransaction()).thenReturn(transaction);
+ when(transaction.submit()).thenReturn(expFuture);
+
+ final PATCHStatusContext status = this.brokerFacade.patchConfigurationDataWithinTransaction(patchContext);
+
+ // assert success
+ assertTrue("PATCH operation should be successful on mounted device", status.isOk());
+ }
+
+ /**
+ * Negative test for PATCH operation when mounted device does not support {@link DOMDataBroker service.
+ * PATCH operation should fail with global error.
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testPatchConfigurationDataWithinTransactionMountFail() throws Exception {
+ final PATCHContext patchContext = mock(PATCHContext.class);
+ final InstanceIdentifierContext identifierContext = mock(InstanceIdentifierContext.class);
+ final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
+ final DOMDataBroker mountDataBroker = mock(DOMDataBroker.class);
+ final DOMDataReadWriteTransaction transaction = mock(DOMDataReadWriteTransaction.class);
+ final CheckedFuture<Void, TransactionCommitFailedException> expFuture = Futures.immediateCheckedFuture(null);
+
+ when(patchContext.getData()).thenReturn(Lists.newArrayList());
+ when(patchContext.getInstanceIdentifierContext()).thenReturn(identifierContext);
+ when(identifierContext.getMountPoint()).thenReturn(mountPoint);
+
+ // missing broker on mounted device
+ when(mountPoint.getService(DOMDataBroker.class)).thenReturn(Optional.absent());
+
+ when(mountDataBroker.newReadWriteTransaction()).thenReturn(transaction);
+ when(transaction.submit()).thenReturn(expFuture);
+
+ final PATCHStatusContext status = this.brokerFacade.patchConfigurationDataWithinTransaction(patchContext);
+
+ // assert not successful operation with error
+ assertNotNull(status.getGlobalErrors());
+ assertEquals(1, status.getGlobalErrors().size());
+ assertEquals(ErrorType.APPLICATION, status.getGlobalErrors().get(0).getErrorType());
+ assertEquals(ErrorTag.OPERATION_FAILED, status.getGlobalErrors().get(0).getErrorTag());
+
+ assertFalse("PATCH operation should fail on mounted device without Broker", status.isOk());
}
}