RestconfServer requires ApiPath identifiers
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / jaxrs / RestconfDataPutTest.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.restconf.nb.jaxrs;
9
10 import static org.junit.jupiter.api.Assertions.assertNull;
11 import static org.mockito.ArgumentMatchers.any;
12 import static org.mockito.ArgumentMatchers.eq;
13 import static org.mockito.Mockito.doNothing;
14 import static org.mockito.Mockito.doReturn;
15 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
16 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
17 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
18
19 import java.util.List;
20 import java.util.Optional;
21 import javax.ws.rs.core.MultivaluedHashMap;
22 import javax.ws.rs.core.MultivaluedMap;
23 import org.junit.jupiter.api.BeforeEach;
24 import org.junit.jupiter.api.Test;
25 import org.junit.jupiter.api.extension.ExtendWith;
26 import org.mockito.Mock;
27 import org.mockito.junit.jupiter.MockitoExtension;
28 import org.opendaylight.mdsal.common.api.CommitInfo;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
33 import org.opendaylight.mdsal.dom.api.DOMRpcService;
34 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
35 import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
36 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
38
39 @ExtendWith(MockitoExtension.class)
40 class RestconfDataPutTest extends AbstractRestconfTest {
41     private final MultivaluedMap<String, String> queryParamenters = new MultivaluedHashMap<>();
42
43     @Mock
44     private DOMDataTreeReadTransaction readTx;
45     @Mock
46     private DOMDataTreeReadWriteTransaction rwTx;
47
48     @BeforeEach
49     void beforeEach() {
50         doReturn(readTx).when(dataBroker).newReadOnlyTransaction();
51         doReturn(rwTx).when(dataBroker).newReadWriteTransaction();
52         doReturn(CommitInfo.emptyFluentFuture()).when(rwTx).commit();
53     }
54
55     @Test
56     void testPutData() {
57         doReturn(queryParamenters).when(uriInfo).getQueryParameters();
58         doReturn(immediateTrueFluentFuture()).when(readTx).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
59         doNothing().when(rwTx).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
60
61         assertNull(assertEntity(204, ar -> restconf.dataJsonPUT(JUKEBOX_API_PATH, uriInfo, stringInputStream("""
62             {
63               "example-jukebox:jukebox" : {
64                 "player": {
65                   "gap": "0.2"
66                 }
67               }
68             }"""), ar)));
69     }
70
71     @Test
72     void testPutDataWithMountPoint() {
73         doReturn(queryParamenters).when(uriInfo).getQueryParameters();
74         doReturn(immediateTrueFluentFuture()).when(readTx).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
75         doNothing().when(rwTx).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
76         doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(any());
77         doReturn(Optional.of(FixedDOMSchemaService.of(JUKEBOX_SCHEMA))).when(mountPoint)
78         .getService(DOMSchemaService.class);
79         doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class);
80         doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class);
81         doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class);
82
83         assertNull(assertEntity(204, ar -> restconf.dataXmlPUT(
84             new JaxRsApiPath("example-jukebox:jukebox/yang-ext:mount/example-jukebox:jukebox"), uriInfo,
85             stringInputStream("""
86                 <jukebox xmlns="http://example.com/ns/example-jukebox">
87                   <player>
88                     <gap>0.2</gap>
89                   </player>
90                 </jukebox>"""), ar)));
91     }
92
93     @Test
94     public void testPutDataWithInsertLast() {
95         // Mocking the query parameters to include 'insert=last'
96         final var queryParams = new MultivaluedHashMap<String, String>();
97         queryParams.put("insert", List.of("last"));
98         doReturn(queryParams).when(uriInfo).getQueryParameters();
99
100         doReturn(immediateFalseFluentFuture()).when(readTx)
101             .exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
102
103         assertNull(assertEntity(201, ar -> restconf.dataJsonPUT(
104             new JaxRsApiPath("example-jukebox:jukebox/playlist=0/song=3"), uriInfo, stringInputStream("""
105             {
106               "example-jukebox:song" : [
107                 {
108                    "index": "3"
109                 }
110               ]
111             }"""), ar)));
112     }
113
114     @Test
115     public void testPutDataWithInsertFirst() {
116         // Mocking the query parameters to include 'insert=first'
117         final var queryParams = new MultivaluedHashMap<String, String>();
118         queryParams.put("insert", List.of("first"));
119         doReturn(queryParams).when(uriInfo).getQueryParameters();
120
121         doReturn(immediateFalseFluentFuture()).when(readTx)
122             .exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
123         // Mocking existed playlist with two songs in DS
124         doReturn(immediateFluentFuture(Optional.of(PLAYLIST_WITH_SONGS))).when(rwTx)
125             .read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
126
127         assertNull(assertEntity(201, ar -> restconf.dataJsonPUT(
128             new JaxRsApiPath("example-jukebox:jukebox/playlist=0/song=3"), uriInfo, stringInputStream("""
129             {
130               "example-jukebox:song" : [
131                 {
132                    "index": "3"
133                 }
134               ]
135             }"""), ar)));
136     }
137
138     @Test
139     public void testPutDataWithInsertBefore() {
140         // Mocking the query parameters to include 'insert=before' and 'point=example-jukebox:jukebox/playlist=0/song=2'
141         final var queryParams = new MultivaluedHashMap<String, String>();
142         queryParams.put("insert", List.of("before"));
143         queryParams.put("point", List.of("example-jukebox:jukebox/playlist=0/song=2"));
144         doReturn(queryParams).when(uriInfo).getQueryParameters();
145
146         doReturn(immediateFalseFluentFuture()).when(readTx)
147             .exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
148         // Mocking existed playlist with two songs in DS
149         doReturn(immediateFluentFuture(Optional.of(PLAYLIST_WITH_SONGS))).when(rwTx)
150             .read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
151
152         assertNull(assertEntity(201, ar -> restconf.dataJsonPUT(
153             new JaxRsApiPath("example-jukebox:jukebox/playlist=0/song=3"), uriInfo, stringInputStream("""
154             {
155               "example-jukebox:song" : [
156                 {
157                    "index": "3",
158                    "id" = "C"
159                 }
160               ]
161             }"""), ar)));
162     }
163
164     @Test
165     public void testPutDataWithInsertAfter() {
166         // Mocking the query parameters to include 'insert=after' and 'point=example-jukebox:jukebox/playlist=0/song=1'
167         final var queryParams = new MultivaluedHashMap<String, String>();
168         queryParams.put("insert", List.of("after"));
169         queryParams.put("point", List.of("example-jukebox:jukebox/playlist=0/song=1"));
170         doReturn(queryParams).when(uriInfo).getQueryParameters();
171
172         doReturn(immediateFalseFluentFuture()).when(readTx)
173             .exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
174         doReturn(immediateFluentFuture(Optional.of(PLAYLIST_WITH_SONGS))).when(rwTx)
175             .read(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class));
176
177         assertNull(assertEntity(201, ar -> restconf.dataJsonPUT(
178             new JaxRsApiPath("example-jukebox:jukebox/playlist=0/song=3"), uriInfo, stringInputStream("""
179             {
180               "example-jukebox:song" : [
181                 {
182                    "index": "3",
183                    "id" = "C"
184                 }
185               ]
186             }"""), ar)));
187     }
188 }