Introduce YangPatchStatusBody
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / jaxrs / RestconfDataPatchTest.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.mockito.Mockito.doNothing;
11 import static org.mockito.Mockito.doReturn;
12 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFalseFluentFuture;
13 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
14
15 import org.junit.jupiter.api.BeforeEach;
16 import org.junit.jupiter.api.Test;
17 import org.junit.jupiter.api.extension.ExtendWith;
18 import org.mockito.Mock;
19 import org.mockito.junit.jupiter.MockitoExtension;
20 import org.opendaylight.mdsal.common.api.CommitInfo;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
23 import org.opendaylight.restconf.server.spi.YangPatchStatusBody;
24
25 @ExtendWith(MockitoExtension.class)
26 class RestconfDataPatchTest extends AbstractRestconfTest {
27     @Mock
28     private DOMDataTreeReadWriteTransaction tx;
29
30     @BeforeEach
31     void beforeEach() {
32         doReturn(tx).when(dataBroker).newReadWriteTransaction();
33     }
34
35     @Test
36     void testPatchData() {
37         doNothing().when(tx).delete(LogicalDatastoreType.CONFIGURATION, GAP_IID);
38         doReturn(immediateFalseFluentFuture()).when(tx).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
39         doReturn(immediateTrueFluentFuture()).when(tx).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
40         doReturn(CommitInfo.emptyFluentFuture()).when(tx).commit();
41
42         final var body = assertEntity(YangPatchStatusBody.class, 200,
43             ar -> restconf.dataYangJsonPATCH(stringInputStream("""
44                 {
45                   "ietf-yang-patch:yang-patch" : {
46                     "patch-id" : "test patch id",
47                     "edit" : [
48                       {
49                         "edit-id" : "create data",
50                         "operation" : "create",
51                         "target" : "/example-jukebox:jukebox",
52                         "value" : {
53                           "jukebox" : {
54                             "player" : {
55                               "gap" : "0.2"
56                             }
57                           }
58                         }
59                       },
60                       {
61                         "edit-id" : "replace data",
62                         "operation" : "replace",
63                         "target" : "/example-jukebox:jukebox",
64                         "value" : {
65                           "jukebox" : {
66                             "player" : {
67                               "gap" : "0.3"
68                             }
69                           }
70                         }
71                       },
72                       {
73                         "edit-id" : "delete data",
74                         "operation" : "delete",
75                         "target" : "/example-jukebox:jukebox/player/gap"
76                       }
77                     ]
78                   }
79                 }"""), ar));
80
81         assertFormat("""
82             {"ietf-yang-patch:yang-patch-status":{"patch-id":"test patch id","ok":[null]}}""", body::formatToJSON);
83     }
84
85     @Test
86     void testPatchDataDeleteNotExist() {
87         doNothing().when(tx).delete(LogicalDatastoreType.CONFIGURATION, GAP_IID);
88         doReturn(immediateFalseFluentFuture()).when(tx).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
89         doReturn(immediateFalseFluentFuture()).when(tx).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
90         doReturn(true).when(tx).cancel();
91
92         final var body = assertEntity(YangPatchStatusBody.class, 409, ar -> restconf.dataYangJsonPATCH(
93             stringInputStream("""
94                 {
95                   "ietf-yang-patch:yang-patch" : {
96                     "patch-id" : "test patch id",
97                     "edit" : [
98                       {
99                         "edit-id" : "create data",
100                         "operation" : "create",
101                         "target" : "/example-jukebox:jukebox",
102                         "value" : {
103                           "jukebox" : {
104                             "player" : {
105                               "gap" : "0.2"
106                             }
107                           }
108                         }
109                       },
110                       {
111                         "edit-id" : "remove data",
112                         "operation" : "remove",
113                         "target" : "/example-jukebox:jukebox/player/gap"
114                       },
115                       {
116                         "edit-id" : "delete data",
117                         "operation" : "delete",
118                         "target" : "/example-jukebox:jukebox/player/gap"
119                       }
120                     ]
121                   }
122                 }"""), ar));
123
124         assertFormat("""
125             {"ietf-yang-patch:yang-patch-status":{"patch-id":"test patch id","edit-status":{"edit":[\
126             {"edit-id":"create data","ok":[null]},\
127             {"edit-id":"remove data","ok":[null]},\
128             {"edit-id":"delete data","errors":{"error":[{"error-type":"protocol","error-tag":"data-missing",\
129             "error-path":"/example-jukebox:jukebox/player/gap","error-message":"Data does not exist"}]}}]}}}""",
130             body::formatToJSON);
131     }
132
133     @Test
134     void testPatchDataMountPoint() throws Exception {
135         doNothing().when(tx).delete(LogicalDatastoreType.CONFIGURATION, GAP_IID);
136         doReturn(immediateFalseFluentFuture()).when(tx).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
137         doReturn(immediateTrueFluentFuture()).when(tx).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
138         doReturn(CommitInfo.emptyFluentFuture()).when(tx).commit();
139
140         final var body = assertEntity(YangPatchStatusBody.class, 200,
141             ar -> restconf.dataYangXmlPATCH(stringInputStream("""
142                 <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
143                   <patch-id>test patch id</patch-id>
144                   <edit>
145                     <edit-id>create data</edit-id>
146                     <operation>create</operation>
147                     <target>/example-jukebox:jukebox</target>
148                     <value>
149                       <jukebox xmlns="http://example.com/ns/example-jukebox">
150                         <player>
151                           <gap>0.2</gap>
152                         </player>
153                       </jukebox>
154                     </value>
155                   </edit>
156                   <edit>
157                     <edit-id>replace data</edit-id>
158                     <operation>replace</operation>
159                     <target>/example-jukebox:jukebox</target>
160                     <value>
161                       <jukebox xmlns="http://example.com/ns/example-jukebox">
162                         <player>
163                           <gap>0.3</gap>
164                         </player>
165                       </jukebox>
166                     </value>
167                   </edit>
168                   <edit>
169                     <edit-id>delete data</edit-id>
170                     <operation>delete</operation>
171                     <target>/example-jukebox:jukebox/player/gap</target>
172                   </edit>
173                 </yang-patch>"""), ar));
174
175         assertFormat("""
176             <yang-patch-status xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">\
177             <patch-id>test patch id</patch-id><ok/>\
178             </yang-patch-status>""", body::formatToXML);
179     }
180 }