2 * Copyright (c) 2020 Lumina Networks, Inc. and others. All rights reserved.
3 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
11 import static org.mockito.ArgumentMatchers.any;
12 import static org.mockito.Mockito.doReturn;
13 import static org.mockito.Mockito.verify;
15 import com.google.common.util.concurrent.Futures;
16 import java.util.Optional;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.junit.runner.RunWith;
20 import org.mockito.Mock;
21 import org.mockito.junit.MockitoJUnitRunner;
22 import org.opendaylight.mdsal.common.api.CommitInfo;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
25 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
28 import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
29 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
30 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
31 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
32 import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
33 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
34 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
35 import org.opendaylight.yangtools.yang.common.QName;
36 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
39 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
43 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
44 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
45 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
46 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
47 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
49 @RunWith(MockitoJUnitRunner.StrictStubs.class)
50 public class PlainPatchDataTransactionUtilTest {
51 private static final String PATH_FOR_NEW_SCHEMA_CONTEXT = "/jukebox";
53 private DOMDataTreeReadWriteTransaction readWrite;
55 private DOMDataTreeReadTransaction read;
57 private DOMDataTreeWriteTransaction write;
59 private DOMDataBroker mockDataBroker;
61 private NetconfDataTreeService netconfService;
63 private LeafNode<?> leafGap;
64 private ContainerNode jukeboxContainerWithPlayer;
65 private ContainerNode jukeboxContainerWithPlaylist;
66 private EffectiveModelContext schema;
67 private DataSchemaNode schemaNodeForGap;
68 private YangInstanceIdentifier iidGap;
69 private DataSchemaNode schemaNodeForJukebox;
70 private YangInstanceIdentifier iidJukebox;
73 public void setUp() throws Exception {
74 schema = YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles(PATH_FOR_NEW_SCHEMA_CONTEXT));
76 final QName qnJukebox = QName.create("http://example.com/ns/example-jukebox", "2015-04-04", "jukebox");
77 final QName qnPlayer = QName.create(qnJukebox, "player");
78 final QName qnGap = QName.create(qnJukebox, "gap");
79 final QName qnPlaylist = QName.create(qnJukebox, "playlist");
80 final QName qnPlaylistKey = QName.create(qnJukebox, "name");
82 final NodeIdentifierWithPredicates nidBandA =
83 NodeIdentifierWithPredicates.of(qnPlaylist, qnPlaylistKey, "MyFavoriteBand-A");
84 final NodeIdentifierWithPredicates nidBandB =
85 NodeIdentifierWithPredicates.of(qnPlaylist, qnPlaylistKey, "MyFavoriteBand-B");
87 iidGap = YangInstanceIdentifier.builder()
92 schemaNodeForGap = DataSchemaContextTree.from(schema).findChild(iidGap).orElseThrow()
95 iidJukebox = YangInstanceIdentifier.builder()
98 schemaNodeForJukebox = DataSchemaContextTree.from(schema)
99 .findChild(iidJukebox).orElseThrow().getDataSchemaNode();
101 leafGap = Builders.leafBuilder()
102 .withNodeIdentifier(new NodeIdentifier(qnGap))
105 final ContainerNode playerContainer = Builders.containerBuilder()
106 .withNodeIdentifier(new NodeIdentifier(qnPlayer))
109 jukeboxContainerWithPlayer = Builders.containerBuilder()
110 .withNodeIdentifier(new NodeIdentifier(qnJukebox))
111 .withChild(playerContainer)
116 final LeafNode<Object> leafBandA = Builders.leafBuilder()
117 .withNodeIdentifier(new NodeIdentifier(QName.create(qnJukebox, "name")))
118 .withValue("MyFavoriteBand-A")
120 final LeafNode<Object> leafDescriptionA = Builders.leafBuilder()
121 .withNodeIdentifier(new NodeIdentifier(QName.create(qnJukebox, "description")))
122 .withValue("band description A")
124 final MapEntryNode entryBandA = Builders.mapEntryBuilder()
125 .withNodeIdentifier(nidBandA)
126 .withChild(leafBandA)
127 .withChild(leafDescriptionA)
130 final LeafNode<Object> leafBandB = Builders.leafBuilder()
131 .withNodeIdentifier(new NodeIdentifier(QName.create(qnJukebox, "name")))
132 .withValue("MyFavoriteBand-B")
134 final LeafNode<Object> leafDescriptionB = Builders.leafBuilder()
135 .withNodeIdentifier(new NodeIdentifier(QName.create(qnJukebox, "description")))
136 .withValue("band description B")
138 final MapEntryNode entryBandB = Builders.mapEntryBuilder()
139 .withNodeIdentifier(nidBandB)
140 .withChild(leafBandB)
141 .withChild(leafDescriptionB)
144 final MapNode listBands = Builders.mapBuilder()
145 .withNodeIdentifier(new NodeIdentifier(qnPlaylist))
146 .withChild(entryBandA)
147 .withChild(entryBandB)
149 jukeboxContainerWithPlaylist = Builders.containerBuilder()
150 .withNodeIdentifier(new NodeIdentifier(qnJukebox))
151 .withChild(listBands)
154 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).lock();
155 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).unlock();
159 public void testPatchContainerData() {
160 final InstanceIdentifierContext<DataSchemaNode> iidContext =
161 new InstanceIdentifierContext<>(iidJukebox, schemaNodeForJukebox, null, schema);
162 final NormalizedNodePayload payload = NormalizedNodePayload.of(iidContext, jukeboxContainerWithPlayer);
164 doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
165 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
166 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
167 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).merge(any(), any(),any(),
170 PlainPatchDataTransactionUtil.patchData(payload, new MdsalRestconfStrategy(mockDataBroker), schema);
171 verify(readWrite).merge(LogicalDatastoreType.CONFIGURATION,
172 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
174 PlainPatchDataTransactionUtil.patchData(payload, new NetconfRestconfStrategy(netconfService),
176 verify(netconfService).merge(LogicalDatastoreType.CONFIGURATION,
177 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
181 public void testPatchLeafData() {
182 final InstanceIdentifierContext<DataSchemaNode> iidContext =
183 new InstanceIdentifierContext<>(iidGap, schemaNodeForGap, null, schema);
184 final NormalizedNodePayload payload = NormalizedNodePayload.of(iidContext, leafGap);
186 doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
187 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
188 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
189 .merge(any(), any(), any(), any());
190 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
192 PlainPatchDataTransactionUtil.patchData(payload, new MdsalRestconfStrategy(mockDataBroker), schema);
193 verify(readWrite).merge(LogicalDatastoreType.CONFIGURATION,
194 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData());
196 PlainPatchDataTransactionUtil.patchData(payload, new NetconfRestconfStrategy(netconfService),
198 verify(netconfService).lock();
199 verify(netconfService).merge(LogicalDatastoreType.CONFIGURATION,
200 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), Optional.empty());
204 public void testPatchListData() {
205 final InstanceIdentifierContext<DataSchemaNode> iidContext =
206 new InstanceIdentifierContext<>(iidJukebox, schemaNodeForJukebox, null, schema);
207 final NormalizedNodePayload payload = NormalizedNodePayload.of(iidContext, jukeboxContainerWithPlaylist);
209 doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction();
210 doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
211 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit();
212 doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
213 .merge(any(), any(),any(),any());
215 PlainPatchDataTransactionUtil.patchData(payload, new MdsalRestconfStrategy(mockDataBroker), schema);
216 verify(readWrite).merge(LogicalDatastoreType.CONFIGURATION, iidJukebox, payload.getData());
218 PlainPatchDataTransactionUtil.patchData(payload, new NetconfRestconfStrategy(netconfService),
220 verify(netconfService).merge(LogicalDatastoreType.CONFIGURATION, iidJukebox, payload.getData(),