import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.MockitoAnnotations.initMocks;
import static org.opendaylight.restconf.common.patch.PatchEditOperation.CREATE;
import static org.opendaylight.restconf.common.patch.PatchEditOperation.DELETE;
import static org.opendaylight.restconf.common.patch.PatchEditOperation.MERGE;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.SettableFuture;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
-import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.api.NetconfDocumentedException;
+import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
-import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.common.patch.PatchContext;
import org.opendaylight.restconf.common.patch.PatchEntity;
import org.opendaylight.restconf.common.patch.PatchStatusContext;
import org.opendaylight.restconf.common.patch.PatchStatusEntity;
import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
-import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
-import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.yangtools.yang.common.ErrorSeverity;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class PatchDataTransactionUtilTest {
-
private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
-
- @Mock
- private DOMTransactionChain transactionChain;
-
@Mock
private DOMDataTreeReadWriteTransaction rwTransaction;
-
@Mock
private DOMDataBroker mockDataBroker;
+ @Mock
+ private NetconfDataTreeService netconfService;
- private TransactionChainHandler transactionChainHandler;
- private SchemaContextRef refSchemaCtx;
+ private EffectiveModelContext refSchemaCtx;
private YangInstanceIdentifier instanceIdContainer;
private YangInstanceIdentifier instanceIdCreateAndDelete;
private YangInstanceIdentifier instanceIdMerge;
@Before
public void setUp() throws Exception {
- initMocks(this);
-
- doReturn(transactionChain).when(mockDataBroker).createTransactionChain(any());
- transactionChainHandler = new TransactionChainHandler(mockDataBroker);
-
- this.refSchemaCtx = new SchemaContextRef(
- YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles(PATH_FOR_NEW_SCHEMA_CONTEXT)));
+ this.refSchemaCtx = YangParserTestUtils.parseYangFiles(
+ TestRestconfUtils.loadFiles(PATH_FOR_NEW_SCHEMA_CONTEXT));
final QName baseQName = QName.create("http://example.com/ns/example-jukebox", "2015-04-04", "jukebox");
final QName containerPlayerQName = QName.create(baseQName, "player");
final QName leafGapQName = QName.create(baseQName, "gap");
.build();
/* Mocks */
- doReturn(this.rwTransaction).when(this.transactionChain).newReadWriteTransaction();
+ doReturn(this.rwTransaction).when(this.mockDataBroker).newReadWriteTransaction();
doReturn(CommitInfo.emptyFluentFuture()).when(this.rwTransaction).commit();
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService).commit();
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService).discardChanges();
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService).unlock();
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService).lock();
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService).merge(any(), any(),
+ any(), any());
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService).replace(any(), any(),
+ any(), any());
}
@Test
public void testPatchDataReplaceMergeAndRemove() {
- doReturn(immediateFalseFluentFuture()).doReturn(immediateTrueFluentFuture())
- .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeMerge);
-
final PatchEntity entityReplace =
new PatchEntity("edit1", REPLACE, this.targetNodeMerge, this.buildArtistList);
final PatchEntity entityMerge = new PatchEntity("edit2", MERGE, this.targetNodeMerge, this.buildArtistList);
entities.add(entityRemove);
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
- new InstanceIdentifierContext<>(this.instanceIdMerge, null, null, this.refSchemaCtx.get());
+ new InstanceIdentifierContext<>(this.instanceIdMerge, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchRMRm");
- final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
- final PatchStatusContext patchStatusContext =
- PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
- for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
- assertTrue(entity.isOk());
- }
- assertTrue(patchStatusContext.isOk());
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService)
+ .remove(LogicalDatastoreType.CONFIGURATION, targetNodeMerge);
+
+ patch(patchContext, new MdsalRestconfStrategy(mockDataBroker), false);
+ patch(patchContext, new NetconfRestconfStrategy(netconfService), false);
}
@Test
- public void testPatchDataCreateAndDelete() throws Exception {
+ public void testPatchDataCreateAndDelete() {
doReturn(immediateFalseFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION,
this.instanceIdContainer);
doReturn(immediateTrueFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION,
this.targetNodeForCreateAndDelete);
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService)
+ .create(LogicalDatastoreType.CONFIGURATION, this.instanceIdContainer, this.buildBaseContainerForTests,
+ Optional.empty());
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService)
+ .delete(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
final PatchEntity entityCreate =
new PatchEntity("edit1", CREATE, this.instanceIdContainer, this.buildBaseContainerForTests);
entities.add(entityDelete);
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
- new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx.get());
+ new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchCD");
- final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
- final PatchStatusContext patchStatusContext =
- PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
-
- for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
- assertTrue("Edit " + entity.getEditId() + " failed", entity.isOk());
- }
- assertTrue(patchStatusContext.isOk());
+ patch(patchContext, new MdsalRestconfStrategy(mockDataBroker), true);
+ patch(patchContext, new NetconfRestconfStrategy(netconfService), true);
}
@Test
public void deleteNonexistentDataTest() {
doReturn(immediateFalseFluentFuture()).when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION,
this.targetNodeForCreateAndDelete);
+ final NetconfDocumentedException exception = new NetconfDocumentedException("id",
+ ErrorType.RPC, ErrorTag.DATA_MISSING, ErrorSeverity.ERROR);
+ final SettableFuture<? extends DOMRpcResult> ret = SettableFuture.create();
+ ret.setException(new TransactionCommitFailedException(
+ String.format("Commit of transaction %s failed", this), exception));
+
+ doReturn(ret).when(this.netconfService).commit();
+ doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(this.netconfService)
+ .delete(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
final PatchEntity entityDelete = new PatchEntity("edit", DELETE, this.targetNodeForCreateAndDelete);
final List<PatchEntity> entities = new ArrayList<>();
entities.add(entityDelete);
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
- new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx.get());
+ new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchD");
- final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
- final PatchStatusContext patchStatusContext =
- PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
-
- assertFalse(patchStatusContext.isOk());
- assertEquals(RestconfError.ErrorType.PROTOCOL,
- patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorType());
- assertEquals(RestconfError.ErrorTag.DATA_MISSING,
- patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorTag());
+ deleteMdsal(patchContext, new MdsalRestconfStrategy(mockDataBroker));
+ deleteNetconf(patchContext, new NetconfRestconfStrategy(netconfService));
}
@Test
- public void testPatchMergePutContainer() throws Exception {
- doReturn(immediateFalseFluentFuture()).doReturn(immediateTrueFluentFuture())
- .when(this.rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, this.targetNodeForCreateAndDelete);
-
+ public void testPatchMergePutContainer() {
final PatchEntity entityMerge =
new PatchEntity("edit1", MERGE, this.instanceIdContainer, this.buildBaseContainerForTests);
final List<PatchEntity> entities = new ArrayList<>();
entities.add(entityMerge);
final InstanceIdentifierContext<? extends SchemaNode> iidContext =
- new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx.get());
+ new InstanceIdentifierContext<>(this.instanceIdCreateAndDelete, null, null, this.refSchemaCtx);
final PatchContext patchContext = new PatchContext(iidContext, entities, "patchM");
- final TransactionVarsWrapper wrapper = new TransactionVarsWrapper(iidContext, null, transactionChainHandler);
- final PatchStatusContext patchStatusContext =
- PatchDataTransactionUtil.patchData(patchContext, wrapper, this.refSchemaCtx);
+ patch(patchContext, new MdsalRestconfStrategy(mockDataBroker), false);
+ patch(patchContext, new NetconfRestconfStrategy(netconfService), false);
+ }
+ private void patch(final PatchContext patchContext, final RestconfStrategy strategy,
+ final boolean failed) {
+ final PatchStatusContext patchStatusContext =
+ PatchDataTransactionUtil.patchData(patchContext, strategy, this.refSchemaCtx);
for (final PatchStatusEntity entity : patchStatusContext.getEditCollection()) {
- assertTrue(entity.isOk());
+ if (failed) {
+ assertTrue("Edit " + entity.getEditId() + " failed", entity.isOk());
+ } else {
+ assertTrue(entity.isOk());
+ }
}
assertTrue(patchStatusContext.isOk());
}
+
+ private void deleteMdsal(final PatchContext patchContext, final RestconfStrategy strategy) {
+ final PatchStatusContext patchStatusContext =
+ PatchDataTransactionUtil.patchData(patchContext, strategy, this.refSchemaCtx);
+
+ assertFalse(patchStatusContext.isOk());
+ assertEquals(ErrorType.PROTOCOL,
+ patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorType());
+ assertEquals(ErrorTag.DATA_MISSING,
+ patchStatusContext.getEditCollection().get(0).getEditErrors().get(0).getErrorTag());
+ }
+
+ private void deleteNetconf(final PatchContext patchContext, final RestconfStrategy strategy) {
+ final PatchStatusContext patchStatusContext =
+ PatchDataTransactionUtil.patchData(patchContext, strategy, this.refSchemaCtx);
+
+ assertFalse(patchStatusContext.isOk());
+ assertEquals(ErrorType.PROTOCOL,
+ patchStatusContext.getGlobalErrors().get(0).getErrorType());
+ assertEquals(ErrorTag.DATA_MISSING,
+ patchStatusContext.getGlobalErrors().get(0).getErrorTag());
+ }
}