2 * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.restconf.nb.rfc8040.rests.transactions;
10 import static org.hamcrest.CoreMatchers.containsString;
11 import static org.hamcrest.CoreMatchers.instanceOf;
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertFalse;
15 import static org.junit.Assert.assertNotNull;
16 import static org.junit.Assert.assertNull;
17 import static org.junit.Assert.assertThrows;
18 import static org.junit.Assert.assertTrue;
20 import com.google.common.collect.ImmutableList;
21 import com.google.common.util.concurrent.Futures;
22 import java.util.List;
23 import java.util.concurrent.ExecutionException;
24 import javax.ws.rs.core.UriInfo;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.mockito.Mock;
30 import org.opendaylight.restconf.api.ApiPath;
31 import org.opendaylight.restconf.api.QueryParameters;
32 import org.opendaylight.restconf.api.query.ContentParam;
33 import org.opendaylight.restconf.api.query.PrettyPrintParam;
34 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
35 import org.opendaylight.restconf.common.patch.PatchContext;
36 import org.opendaylight.restconf.common.patch.PatchEntity;
37 import org.opendaylight.restconf.nb.rfc8040.AbstractJukeboxTest;
38 import org.opendaylight.restconf.server.api.DatabindContext;
39 import org.opendaylight.restconf.server.api.PatchStatusContext;
40 import org.opendaylight.restconf.server.api.PatchStatusEntity;
41 import org.opendaylight.restconf.server.api.ServerRequest;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.patch.rev170222.yang.patch.yang.patch.Edit.Operation;
43 import org.opendaylight.yangtools.yang.common.ErrorTag;
44 import org.opendaylight.yangtools.yang.common.ErrorType;
45 import org.opendaylight.yangtools.yang.common.QName;
46 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
47 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
48 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
49 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
50 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
51 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
52 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
53 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
54 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
55 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
56 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
57 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
58 import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode;
59 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
60 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
61 import org.w3c.dom.DOMException;
63 abstract class AbstractRestconfStrategyTest extends AbstractJukeboxTest {
64 static final ContainerNode JUKEBOX_WITH_BANDS = ImmutableNodes.newContainerBuilder()
65 .withNodeIdentifier(new NodeIdentifier(JUKEBOX_QNAME))
66 .withChild(ImmutableNodes.newSystemMapBuilder()
67 .withNodeIdentifier(new NodeIdentifier(PLAYLIST_QNAME))
68 .withChild(BAND_ENTRY)
69 .withChild(ImmutableNodes.newMapEntryBuilder()
70 .withNodeIdentifier(NodeIdentifierWithPredicates.of(PLAYLIST_QNAME, NAME_QNAME, "name of band 2"))
71 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "name of band 2"))
72 .withChild(ImmutableNodes.leafNode(DESCRIPTION_QNAME, "band description 2"))
76 static final ContainerNode JUKEBOX_WITH_PLAYLIST = ImmutableNodes.newContainerBuilder()
77 .withNodeIdentifier(new NodeIdentifier(JUKEBOX_QNAME))
78 .withChild(ImmutableNodes.newSystemMapBuilder()
79 .withNodeIdentifier(new NodeIdentifier(PLAYLIST_QNAME))
80 .withChild(ImmutableNodes.newMapEntryBuilder()
81 .withNodeIdentifier(NodeIdentifierWithPredicates.of(PLAYLIST_QNAME, NAME_QNAME, "MyFavoriteBand-A"))
82 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "MyFavoriteBand-A"))
83 .withChild(ImmutableNodes.leafNode(DESCRIPTION_QNAME, "band description A"))
85 .withChild(ImmutableNodes.newMapEntryBuilder()
86 .withNodeIdentifier(NodeIdentifierWithPredicates.of(PLAYLIST_QNAME, NAME_QNAME, "MyFavoriteBand-B"))
87 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "MyFavoriteBand-B"))
88 .withChild(ImmutableNodes.leafNode(DESCRIPTION_QNAME, "band description B"))
92 static final MapNode PLAYLIST = ImmutableNodes.newSystemMapBuilder()
93 .withNodeIdentifier(new NodeIdentifier(PLAYLIST_QNAME))
94 .withChild(BAND_ENTRY)
96 // instance identifier for accessing container node "player"
97 static final YangInstanceIdentifier PLAYER_IID = YangInstanceIdentifier.of(JUKEBOX_QNAME, PLAYER_QNAME);
98 static final YangInstanceIdentifier ARTIST_IID = YangInstanceIdentifier.builder()
102 .nodeWithKey(ARTIST_QNAME, NAME_QNAME, "name of artist")
104 // FIXME: this looks weird
105 static final YangInstanceIdentifier CREATE_AND_DELETE_TARGET = GAP_IID.node(PLAYER_QNAME).node(GAP_QNAME);
108 static final QName BASE = QName.create("ns", "2016-02-28", "base");
109 private static final QName LIST_KEY_QNAME = QName.create(BASE, "list-key");
110 private static final QName LEAF_LIST_QNAME = QName.create(BASE, "leaf-list");
111 private static final QName LIST_QNAME = QName.create(BASE, "list");
112 static final QName CONT_QNAME = QName.create(BASE, "cont");
114 private static final NodeIdentifierWithPredicates NODE_WITH_KEY =
115 NodeIdentifierWithPredicates.of(LIST_QNAME, LIST_KEY_QNAME, "keyValue");
116 private static final NodeIdentifierWithPredicates NODE_WITH_KEY_2 =
117 NodeIdentifierWithPredicates.of(LIST_QNAME, LIST_KEY_QNAME, "keyValue2");
119 private static final LeafNode<?> CONTENT = ImmutableNodes.leafNode(QName.create(BASE, "leaf-content"), "content");
120 private static final LeafNode<?> CONTENT_2 =
121 ImmutableNodes.leafNode(QName.create(BASE, "leaf-content-different"), "content-different");
122 static final YangInstanceIdentifier PATH = YangInstanceIdentifier.builder()
127 static final YangInstanceIdentifier PATH_2 = YangInstanceIdentifier.builder()
130 .node(NODE_WITH_KEY_2)
132 static final YangInstanceIdentifier PATH_3 = YangInstanceIdentifier.of(CONT_QNAME, LIST_QNAME);
133 private static final MapEntryNode DATA = ImmutableNodes.newMapEntryBuilder()
134 .withNodeIdentifier(NODE_WITH_KEY)
137 static final MapEntryNode DATA_2 = ImmutableNodes.newMapEntryBuilder()
138 .withNodeIdentifier(NODE_WITH_KEY)
139 .withChild(CONTENT_2)
141 private static final LeafNode<?> CONTENT_LEAF = ImmutableNodes.leafNode(QName.create(BASE, "content"), "test");
142 private static final LeafNode<?> CONTENT_LEAF_2 = ImmutableNodes.leafNode(QName.create(BASE, "content2"), "test2");
143 static final ContainerNode DATA_3 = ImmutableNodes.newContainerBuilder()
144 .withNodeIdentifier(new NodeIdentifier(QName.create(BASE, "container")))
145 .withChild(CONTENT_LEAF)
147 static final ContainerNode DATA_4 = ImmutableNodes.newContainerBuilder()
148 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create(BASE, "container2")))
149 .withChild(CONTENT_LEAF_2)
151 static final MapNode LIST_DATA = ImmutableNodes.newSystemMapBuilder()
152 .withNodeIdentifier(new NodeIdentifier(QName.create(LIST_QNAME, "list")))
155 static final MapNode LIST_DATA_2 = ImmutableNodes.newSystemMapBuilder()
156 .withNodeIdentifier(new NodeIdentifier(QName.create(LIST_QNAME, "list")))
160 static final UserMapNode ORDERED_MAP_NODE_1 = ImmutableNodes.newUserMapBuilder()
161 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
164 static final UserMapNode ORDERED_MAP_NODE_2 = ImmutableNodes.newUserMapBuilder()
165 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
169 private static final MapEntryNode CHECK_DATA = ImmutableNodes.newMapEntryBuilder()
170 .withNodeIdentifier(NODE_WITH_KEY)
171 .withChild(CONTENT_2)
174 static final LeafSetNode<String> LEAF_SET_NODE_1 = ImmutableNodes.<String>newSystemLeafSetBuilder()
175 .withNodeIdentifier(new NodeIdentifier(LEAF_LIST_QNAME))
176 .withChildValue("one")
177 .withChildValue("two")
179 static final LeafSetNode<String> LEAF_SET_NODE_2 = ImmutableNodes.<String>newSystemLeafSetBuilder()
180 .withNodeIdentifier(new NodeIdentifier(LEAF_LIST_QNAME))
181 .withChildValue("three")
183 static final LeafSetNode<String> ORDERED_LEAF_SET_NODE_1 = ImmutableNodes.<String>newUserLeafSetBuilder()
184 .withNodeIdentifier(new NodeIdentifier(LEAF_LIST_QNAME))
185 .withChildValue("one")
186 .withChildValue("two")
188 static final LeafSetNode<String> ORDERED_LEAF_SET_NODE_2 = ImmutableNodes.<String>newUserLeafSetBuilder()
189 .withNodeIdentifier(new NodeIdentifier(LEAF_LIST_QNAME))
190 .withChildValue("three")
191 .withChildValue("four")
193 static final YangInstanceIdentifier LEAF_SET_NODE_PATH = YangInstanceIdentifier.builder()
195 .node(LEAF_LIST_QNAME)
197 private static final UnkeyedListEntryNode UNKEYED_LIST_ENTRY_NODE_1 = ImmutableNodes.newUnkeyedListEntryBuilder()
198 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
201 private static final UnkeyedListEntryNode UNKEYED_LIST_ENTRY_NODE_2 = ImmutableNodes.newUnkeyedListEntryBuilder()
202 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
203 .withChild(CONTENT_2)
205 static final UnkeyedListNode UNKEYED_LIST_NODE_1 = ImmutableNodes.newUnkeyedListBuilder()
206 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
207 .withChild(UNKEYED_LIST_ENTRY_NODE_1)
209 static final UnkeyedListNode UNKEYED_LIST_NODE_2 = ImmutableNodes.newUnkeyedListBuilder()
210 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(LIST_QNAME))
211 .withChild(UNKEYED_LIST_ENTRY_NODE_2)
213 private static final NodeIdentifier NODE_IDENTIFIER =
214 new NodeIdentifier(QName.create("ns", "2016-02-28", "container"));
215 private static final ServerRequest REQUEST = ServerRequest.of(QueryParameters.of(), PrettyPrintParam.TRUE);
218 private EffectiveModelContext mockSchemaContext;
220 private UriInfo uriInfo;
222 private DatabindContext mockDatabind;
225 public void initMockDatabind() {
226 mockDatabind = DatabindContext.ofModel(mockSchemaContext);
229 abstract @NonNull RestconfStrategy newStrategy(DatabindContext databind);
231 final @NonNull RestconfStrategy jukeboxStrategy() {
232 return newStrategy(JUKEBOX_DATABIND);
235 final @NonNull RestconfStrategy mockStrategy() {
236 return newStrategy(mockDatabind);
240 * Test of successful DELETE operation.
243 public final void testDeleteData() throws Exception {
244 final var future = testDeleteDataStrategy().dataDELETE(REQUEST, ApiPath.empty());
245 assertNotNull(Futures.getDone(future));
248 abstract @NonNull RestconfStrategy testDeleteDataStrategy();
251 * Negative test for DELETE operation when data to delete does not exist. Error DATA_MISSING is expected.
254 public final void testNegativeDeleteData() {
255 final var future = testNegativeDeleteDataStrategy().dataDELETE(REQUEST, ApiPath.empty());
256 final var ex = assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
257 assertThat(ex, instanceOf(RestconfDocumentedException.class));
258 final var errors = ((RestconfDocumentedException) ex).getErrors();
259 assertEquals(1, errors.size());
260 final var error = errors.get(0);
261 assertEquals(ErrorType.PROTOCOL, error.getErrorType());
262 assertEquals(ErrorTag.DATA_MISSING, error.getErrorTag());
265 abstract @NonNull RestconfStrategy testNegativeDeleteDataStrategy();
268 public final void testPostContainerData() {
269 testPostContainerDataStrategy().postData(JUKEBOX_IID, EMPTY_JUKEBOX, null);
272 abstract @NonNull RestconfStrategy testPostContainerDataStrategy();
275 public final void testPostListData() {
276 testPostListDataStrategy(BAND_ENTRY, PLAYLIST_IID.node(BAND_ENTRY.name())).postData(PLAYLIST_IID, PLAYLIST,
280 abstract @NonNull RestconfStrategy testPostListDataStrategy(MapEntryNode entryNode, YangInstanceIdentifier node);
283 public final void testPostDataFail() {
284 final var domException = new DOMException((short) 414, "Post request failed");
285 final var future = testPostDataFailStrategy(domException).postData(JUKEBOX_IID, EMPTY_JUKEBOX, null);
286 final var cause = assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
287 assertThat(cause, instanceOf(RestconfDocumentedException.class));
288 final var errors = ((RestconfDocumentedException) cause).getErrors();
289 assertEquals(1, errors.size());
290 assertThat(errors.get(0).getErrorInfo(), containsString(domException.getMessage()));
293 abstract @NonNull RestconfStrategy testPostDataFailStrategy(DOMException domException);
296 public final void testPatchContainerData() {
297 testPatchContainerDataStrategy().merge(JUKEBOX_IID, EMPTY_JUKEBOX).getOrThrow();
300 abstract @NonNull RestconfStrategy testPatchContainerDataStrategy();
303 public final void testPatchLeafData() {
304 testPatchLeafDataStrategy().merge(GAP_IID, GAP_LEAF).getOrThrow();
307 abstract @NonNull RestconfStrategy testPatchLeafDataStrategy();
310 public final void testPatchListData() {
311 testPatchListDataStrategy().merge(JUKEBOX_IID, JUKEBOX_WITH_PLAYLIST).getOrThrow();
314 abstract @NonNull RestconfStrategy testPatchListDataStrategy();
317 public final void testPatchDataReplaceMergeAndRemove() {
318 final var buildArtistList = ImmutableNodes.newSystemMapBuilder()
319 .withNodeIdentifier(new NodeIdentifier(ARTIST_QNAME))
320 .withChild(ImmutableNodes.newMapEntryBuilder()
321 .withNodeIdentifier(NodeIdentifierWithPredicates.of(ARTIST_QNAME, NAME_QNAME, "name of artist"))
322 .withChild(ImmutableNodes.leafNode(NAME_QNAME, "name of artist"))
323 .withChild(ImmutableNodes.leafNode(DESCRIPTION_QNAME, "description of artist"))
327 patch(new PatchContext("patchRMRm",
328 List.of(new PatchEntity("edit1", Operation.Replace, ARTIST_IID, buildArtistList),
329 new PatchEntity("edit2", Operation.Merge, ARTIST_IID, buildArtistList),
330 new PatchEntity("edit3", Operation.Remove, ARTIST_IID))),
331 testPatchDataReplaceMergeAndRemoveStrategy(), false);
334 abstract @NonNull RestconfStrategy testPatchDataReplaceMergeAndRemoveStrategy();
337 public final void testPatchDataCreateAndDelete() {
338 patch(new PatchContext("patchCD", List.of(
339 new PatchEntity("edit1", Operation.Create, PLAYER_IID, EMPTY_JUKEBOX),
340 new PatchEntity("edit2", Operation.Delete, CREATE_AND_DELETE_TARGET))),
341 testPatchDataCreateAndDeleteStrategy(), true);
344 abstract @NonNull RestconfStrategy testPatchDataCreateAndDeleteStrategy();
347 public final void testPatchMergePutContainer() {
348 patch(new PatchContext("patchM", List.of(new PatchEntity("edit1", Operation.Merge, PLAYER_IID, EMPTY_JUKEBOX))),
349 testPatchMergePutContainerStrategy(), false);
352 abstract @NonNull RestconfStrategy testPatchMergePutContainerStrategy();
355 public final void testDeleteNonexistentData() {
356 final var status = deleteNonexistentDataTestStrategy().patchData(
357 new PatchContext("patchD", List.of(new PatchEntity("edit", Operation.Delete, CREATE_AND_DELETE_TARGET))))
358 .getOrThrow().status();
359 assertEquals("patchD", status.patchId());
360 assertFalse(status.ok());
361 final var edits = status.editCollection();
362 assertEquals(1, edits.size());
363 final var edit = edits.get(0);
364 assertEquals("edit", edit.getEditId());
365 assertTestDeleteNonexistentData(status, edit);
368 abstract @NonNull RestconfStrategy deleteNonexistentDataTestStrategy();
370 abstract void assertTestDeleteNonexistentData(@NonNull PatchStatusContext status, @NonNull PatchStatusEntity edit);
373 public final void readDataConfigTest() {
374 assertEquals(DATA_3, readData(ContentParam.CONFIG, PATH, readDataConfigTestStrategy()));
377 abstract @NonNull RestconfStrategy readDataConfigTestStrategy();
380 public final void readAllHavingOnlyConfigTest() {
381 assertEquals(DATA_3, readData(ContentParam.ALL, PATH, readAllHavingOnlyConfigTestStrategy()));
384 abstract @NonNull RestconfStrategy readAllHavingOnlyConfigTestStrategy();
387 public final void readAllHavingOnlyNonConfigTest() {
388 assertEquals(DATA_2, readData(ContentParam.ALL, PATH_2, readAllHavingOnlyNonConfigTestStrategy()));
391 abstract @NonNull RestconfStrategy readAllHavingOnlyNonConfigTestStrategy();
394 public final void readDataNonConfigTest() {
395 assertEquals(DATA_2, readData(ContentParam.NONCONFIG, PATH_2, readDataNonConfigTestStrategy()));
398 abstract @NonNull RestconfStrategy readDataNonConfigTestStrategy();
401 public final void readContainerDataAllTest() {
402 assertEquals(ImmutableNodes.newContainerBuilder()
403 .withNodeIdentifier(NODE_IDENTIFIER)
404 .withChild(CONTENT_LEAF)
405 .withChild(CONTENT_LEAF_2)
406 .build(), readData(ContentParam.ALL, PATH, readContainerDataAllTestStrategy()));
409 abstract @NonNull RestconfStrategy readContainerDataAllTestStrategy();
412 public final void readContainerDataConfigNoValueOfContentTest() {
413 assertEquals(ImmutableNodes.newContainerBuilder()
414 .withNodeIdentifier(NODE_IDENTIFIER)
415 .withChild(CONTENT_LEAF)
416 .withChild(CONTENT_LEAF_2)
417 .build(), readData(ContentParam.ALL, PATH, readContainerDataConfigNoValueOfContentTestStrategy()));
420 abstract @NonNull RestconfStrategy readContainerDataConfigNoValueOfContentTestStrategy();
423 public final void readListDataAllTest() {
424 assertEquals(ImmutableNodes.newSystemMapBuilder()
425 .withNodeIdentifier(new NodeIdentifier(QName.create("ns", "2016-02-28", "list")))
426 .withChild(CHECK_DATA)
427 .build(), readData(ContentParam.ALL, PATH_3, readListDataAllTestStrategy()));
430 abstract @NonNull RestconfStrategy readListDataAllTestStrategy();
433 public final void readOrderedListDataAllTest() {
434 assertEquals(ImmutableNodes.newUserMapBuilder()
435 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
436 .withChild(CHECK_DATA)
437 .build(), readData(ContentParam.ALL, PATH_3, readOrderedListDataAllTestStrategy()));
440 abstract @NonNull RestconfStrategy readOrderedListDataAllTestStrategy();
443 public void readUnkeyedListDataAllTest() {
444 assertEquals(ImmutableNodes.newUnkeyedListBuilder()
445 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
446 .withChild(ImmutableNodes.newUnkeyedListEntryBuilder()
447 .withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
448 .withChild(UNKEYED_LIST_ENTRY_NODE_1.body().iterator().next())
449 .withChild(UNKEYED_LIST_ENTRY_NODE_2.body().iterator().next())
451 .build(), readData(ContentParam.ALL, PATH_3, readUnkeyedListDataAllTestStrategy()));
454 abstract @NonNull RestconfStrategy readUnkeyedListDataAllTestStrategy();
457 public final void readLeafListDataAllTest() {
458 assertEquals(ImmutableNodes.<String>newSystemLeafSetBuilder()
459 .withNodeIdentifier(new NodeIdentifier(LEAF_LIST_QNAME))
460 .withValue(ImmutableList.<LeafSetEntryNode<String>>builder()
461 .addAll(LEAF_SET_NODE_1.body())
462 .addAll(LEAF_SET_NODE_2.body())
464 .build(), readData(ContentParam.ALL, LEAF_SET_NODE_PATH, readLeafListDataAllTestStrategy()));
467 abstract @NonNull RestconfStrategy readLeafListDataAllTestStrategy();
470 public final void readOrderedLeafListDataAllTest() {
471 assertEquals(ImmutableNodes.<String>newUserLeafSetBuilder()
472 .withNodeIdentifier(new NodeIdentifier(LEAF_LIST_QNAME))
473 .withValue(ImmutableList.<LeafSetEntryNode<String>>builder()
474 .addAll(ORDERED_LEAF_SET_NODE_1.body())
475 .addAll(ORDERED_LEAF_SET_NODE_2.body())
477 .build(), readData(ContentParam.ALL, LEAF_SET_NODE_PATH, readOrderedLeafListDataAllTestStrategy()));
480 abstract @NonNull RestconfStrategy readOrderedLeafListDataAllTestStrategy();
483 public void readDataWrongPathOrNoContentTest() {
484 assertNull(readData(ContentParam.CONFIG, PATH_2, readDataWrongPathOrNoContentTestStrategy()));
487 abstract @NonNull RestconfStrategy readDataWrongPathOrNoContentTestStrategy();
490 * Read specific type of data from data store via transaction.
492 * @param content type of data to read (config, state, all)
493 * @param strategy {@link RestconfStrategy} - wrapper for variables
494 * @return {@link NormalizedNode}
496 private static @Nullable NormalizedNode readData(final @NonNull ContentParam content,
497 final YangInstanceIdentifier path, final @NonNull RestconfStrategy strategy) {
498 return strategy.readData(content, path, null);
501 private static void patch(final PatchContext patchContext, final RestconfStrategy strategy, final boolean failed) {
502 final var patchStatusContext = strategy.patchData(patchContext).getOrThrow().status();
503 for (var entity : patchStatusContext.editCollection()) {
505 assertTrue("Edit " + entity.getEditId() + " failed", entity.isOk());
507 assertTrue(entity.isOk());
510 assertTrue(patchStatusContext.ok());