Use first child in POST payloads
[netconf.git] / restconf / sal-rest-docgen / src / test / java / org / opendaylight / netconf / sal / rest / doc / impl / ApiDocGeneratorRFC8040Test.java
1 /*
2  * Copyright (c) 2021 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.netconf.sal.rest.doc.impl;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15
16 import com.fasterxml.jackson.databind.JsonNode;
17 import com.fasterxml.jackson.databind.node.ObjectNode;
18 import com.google.common.collect.ImmutableList;
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Set;
22 import java.util.stream.Collectors;
23 import java.util.stream.StreamSupport;
24 import org.junit.Test;
25 import org.opendaylight.netconf.sal.rest.doc.swagger.OpenApiObject;
26 import org.opendaylight.netconf.sal.rest.doc.swagger.SwaggerObject;
27
28 public final class ApiDocGeneratorRFC8040Test extends AbstractApiDocTest {
29     private static final String NAME = "toaster2";
30     private static final String MY_YANG = "my-yang";
31     private static final String MY_YANG_REVISION = "2022-10-06";
32     private static final String REVISION_DATE = "2009-11-20";
33     private static final String NAME_2 = "toaster";
34     private static final String REVISION_DATE_2 = "2009-11-20";
35     private static final String PATH_PARAMS_TEST_MODULE = "path-params-test";
36     private static final String MANDATORY_TEST = "mandatory-test";
37     private static final String CONFIG_ROOT_CONTAINER = "mandatory-test_config_root-container";
38     private static final String CONFIG_ROOT_CONTAINER_POST = "mandatory-test_config_root-container_post";
39     private static final String ROOT_CONTAINER = "mandatory-test_root-container";
40     private static final String CONFIG_MANDATORY_CONTAINER = "mandatory-test_root-container_config_mandatory-container";
41     private static final String CONFIG_MANDATORY_CONTAINER_POST
42         = "mandatory-test_root-container_config_mandatory-container_post";
43     private static final String MANDATORY_CONTAINER = "mandatory-test_root-container_mandatory-container";
44     private static final String CONFIG_MANDATORY_LIST = "mandatory-test_root-container_config_mandatory-list";
45     private static final String CONFIG_MANDATORY_LIST_POST = "mandatory-test_root-container_config_mandatory-list_post";
46     private static final String MANDATORY_LIST = "mandatory-test_root-container_mandatory-list";
47     private static final String MANDATORY_TEST_MODULE = "mandatory-test_module";
48     private static final String CHOICE_TEST_MODULE = "choice-test";
49     private static final String PROPERTIES = "properties";
50     private static final String CONTAINER = "container";
51     private static final String LIST = "list";
52
53     private final ApiDocGeneratorRFC8040 generator = new ApiDocGeneratorRFC8040(SCHEMA_SERVICE);
54
55     /**
56      * Test that paths are generated according to the model.
57      */
58     @Test
59     public void testPaths() {
60         final SwaggerObject doc = (SwaggerObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
61             ApiDocServiceImpl.OAversion.V2_0);
62
63         assertEquals(List.of("/rests/data",
64             "/rests/data/toaster2:toaster",
65             "/rests/data/toaster2:toaster/toasterSlot={slotId}",
66             "/rests/data/toaster2:toaster/toasterSlot={slotId}/toaster-augmented:slotInfo",
67             "/rests/data/toaster2:lst",
68             "/rests/data/toaster2:lst/cont1",
69             "/rests/data/toaster2:lst/cont1/cont11",
70             "/rests/data/toaster2:lst/cont1/lst11",
71             "/rests/data/toaster2:lst/lst1={key1},{key2}",
72             "/rests/operations/toaster2:make-toast",
73             "/rests/operations/toaster2:cancel-toast",
74             "/rests/operations/toaster2:restock-toaster"),
75             ImmutableList.copyOf(doc.getPaths().fieldNames()));
76     }
77
78     /**
79      * Test that generated configuration paths allow to use operations: get, put, delete and post.
80      */
81     @Test
82     public void testConfigPaths() {
83         final List<String> configPaths = List.of("/rests/data/toaster2:lst",
84                 "/rests/data/toaster2:lst/cont1",
85                 "/rests/data/toaster2:lst/cont1/cont11",
86                 "/rests/data/toaster2:lst/cont1/lst11",
87                 "/rests/data/toaster2:lst/lst1={key1},{key2}");
88
89         final SwaggerObject doc = (SwaggerObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
90             ApiDocServiceImpl.OAversion.V2_0);
91
92         for (final String path : configPaths) {
93             final JsonNode node = doc.getPaths().get(path);
94             assertFalse(node.path("get").isMissingNode());
95             assertFalse(node.path("put").isMissingNode());
96             assertFalse(node.path("delete").isMissingNode());
97             assertFalse(node.path("post").isMissingNode());
98         }
99     }
100
101     /**
102      * Test that generated document contains the following definitions.
103      */
104     @Test
105     public void testDefinitions() {
106         final SwaggerObject doc = (SwaggerObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
107             ApiDocServiceImpl.OAversion.V2_0);
108
109         final ObjectNode definitions = doc.getDefinitions();
110         assertNotNull(definitions);
111
112         final JsonNode configLstTop = definitions.get("toaster2_config_lst_TOP");
113         assertNotNull(configLstTop);
114         DocGenTestHelper.containsReferences(configLstTop, "toaster2:lst", "#/definitions/toaster2_config_lst");
115
116         final JsonNode configLst = definitions.get("toaster2_config_lst");
117         assertNotNull(configLst);
118         DocGenTestHelper.containsReferences(configLst, "lst1", "#/definitions/toaster2_lst_config_lst1");
119         DocGenTestHelper.containsReferences(configLst, "cont1", "#/definitions/toaster2_lst_config_cont1");
120
121         final JsonNode configLst1Top = definitions.get("toaster2_lst_config_lst1_TOP");
122         assertNotNull(configLst1Top);
123         DocGenTestHelper.containsReferences(configLst1Top, "toaster2:lst1", "#/definitions/toaster2_lst_config_lst1");
124
125         final JsonNode configLst1 = definitions.get("toaster2_lst_config_lst1");
126         assertNotNull(configLst1);
127
128         final JsonNode configCont1Top = definitions.get("toaster2_lst_config_cont1_TOP");
129         assertNotNull(configCont1Top);
130         DocGenTestHelper.containsReferences(configCont1Top, "toaster2:cont1",
131             "#/definitions/toaster2_lst_config_cont1");
132
133         final JsonNode configCont1 = definitions.get("toaster2_lst_config_cont1");
134         assertNotNull(configCont1);
135         DocGenTestHelper.containsReferences(configCont1, "cont11", "#/definitions/toaster2_lst_cont1_config_cont11");
136         DocGenTestHelper.containsReferences(configCont1, "lst11", "#/definitions/toaster2_lst_cont1_config_lst11");
137
138         final JsonNode configCont11Top = definitions.get("toaster2_lst_cont1_config_cont11_TOP");
139         assertNotNull(configCont11Top);
140         DocGenTestHelper.containsReferences(configCont11Top, "toaster2:cont11",
141             "#/definitions/toaster2_lst_cont1_config_cont11");
142
143         final JsonNode configCont11 = definitions.get("toaster2_lst_cont1_config_cont11");
144         assertNotNull(configCont11);
145
146         final JsonNode configLst11Top = definitions.get("toaster2_lst_cont1_config_lst11_TOP");
147         assertNotNull(configLst11Top);
148         DocGenTestHelper.containsReferences(configLst11Top, "toaster2:lst11",
149             "#/definitions/toaster2_lst_cont1_config_lst11");
150
151         final JsonNode configLst11 = definitions.get("toaster2_lst_cont1_config_lst11");
152         assertNotNull(configLst11);
153     }
154
155     /**
156      * Test that generated document contains RPC definition for "make-toast" with correct input.
157      */
158     @Test
159     public void testRPC() {
160         final SwaggerObject doc = (SwaggerObject) generator.getApiDeclaration(NAME_2, REVISION_DATE_2, URI_INFO,
161             ApiDocServiceImpl.OAversion.V2_0);
162         assertNotNull(doc);
163
164         final ObjectNode definitions = doc.getDefinitions();
165         final JsonNode inputTop = definitions.get("toaster_make-toast_input_TOP");
166         assertNotNull(inputTop);
167         final String testString = "{\"toaster:input\":{\"$ref\":\"#/definitions/toaster_make-toast_input\"}}";
168         assertEquals(testString, inputTop.get("properties").toString());
169         final JsonNode input = definitions.get("toaster_make-toast_input");
170         final JsonNode properties = input.get("properties");
171         assertTrue(properties.has("toasterDoneness"));
172         assertTrue(properties.has("toasterToastType"));
173     }
174
175     @Test
176     public void testMandatory() {
177         final var doc = (OpenApiObject) generator.getApiDeclaration(MANDATORY_TEST, null, URI_INFO,
178             ApiDocServiceImpl.OAversion.V3_0);
179         assertNotNull(doc);
180         final var definitions = doc.getComponents().getSchemas();
181         final var containersWithRequired = new ArrayList<String>();
182
183         final var reqRootContainerElements = Set.of("mandatory-root-leaf", "mandatory-container",
184             "mandatory-first-choice", "mandatory-list");
185         verifyRequiredField(definitions.get(CONFIG_ROOT_CONTAINER), reqRootContainerElements);
186         containersWithRequired.add(CONFIG_ROOT_CONTAINER);
187         verifyRequiredField(definitions.get(ROOT_CONTAINER), reqRootContainerElements);
188         containersWithRequired.add(ROOT_CONTAINER);
189         verifyRequiredField(definitions.get(CONFIG_ROOT_CONTAINER_POST), reqRootContainerElements);
190         containersWithRequired.add(CONFIG_ROOT_CONTAINER_POST);
191
192         final var reqMandatoryContainerElements = Set.of("mandatory-leaf", "leaf-list-with-min-elements");
193         verifyRequiredField(definitions.get(CONFIG_MANDATORY_CONTAINER), reqMandatoryContainerElements);
194         containersWithRequired.add(CONFIG_MANDATORY_CONTAINER);
195         verifyRequiredField(definitions.get(MANDATORY_CONTAINER), reqMandatoryContainerElements);
196         containersWithRequired.add(MANDATORY_CONTAINER);
197         verifyRequiredField(definitions.get(CONFIG_MANDATORY_CONTAINER_POST), reqMandatoryContainerElements);
198         containersWithRequired.add(CONFIG_MANDATORY_CONTAINER_POST);
199
200         final var reqMandatoryListElements = Set.of("mandatory-list-field");
201         verifyRequiredField(definitions.get(CONFIG_MANDATORY_LIST), reqMandatoryListElements);
202         containersWithRequired.add(CONFIG_MANDATORY_LIST);
203         verifyRequiredField(definitions.get(MANDATORY_LIST), reqMandatoryListElements);
204         containersWithRequired.add(MANDATORY_LIST);
205         verifyRequiredField(definitions.get(CONFIG_MANDATORY_LIST_POST), reqMandatoryListElements);
206         containersWithRequired.add(CONFIG_MANDATORY_LIST_POST);
207
208         final var testModuleMandatoryArray = Set.of("root-container", "root-mandatory-list");
209         verifyRequiredField(definitions.get(MANDATORY_TEST_MODULE), testModuleMandatoryArray);
210         containersWithRequired.add(MANDATORY_TEST_MODULE);
211
212         verifyThatPropertyDoesNotHaveRequired(containersWithRequired, definitions);
213     }
214
215     /**
216      * Test that request parameters are correctly numbered.
217      *
218      * <p>
219      * It means we should have name and name1, etc. when we have the same parameter in path multiple times.
220      */
221     @Test
222     public void testParametersNumbering() {
223         final var doc = (OpenApiObject) generator.getApiDeclaration(PATH_PARAMS_TEST_MODULE, null, URI_INFO,
224             ApiDocServiceImpl.OAversion.V3_0);
225
226         var pathToList1 = "/rests/data/path-params-test:cont/list1={name}";
227         assertTrue(doc.getPaths().has(pathToList1));
228         assertEquals(List.of("name"), getPathParameters(doc.getPaths(), pathToList1));
229
230         var pathToList2 = "/rests/data/path-params-test:cont/list1={name}/list2={name1}";
231         assertTrue(doc.getPaths().has(pathToList2));
232         assertEquals(List.of("name", "name1"), getPathParameters(doc.getPaths(), pathToList2));
233
234         var pathToList3 = "/rests/data/path-params-test:cont/list3={name}";
235         assertTrue(doc.getPaths().has(pathToList3));
236         assertEquals(List.of("name"), getPathParameters(doc.getPaths(), pathToList3));
237
238         var pathToList4 = "/rests/data/path-params-test:cont/list1={name}/list4={name1}";
239         assertTrue(doc.getPaths().has(pathToList4));
240         assertEquals(List.of("name", "name1"), getPathParameters(doc.getPaths(), pathToList4));
241
242         var pathToList5 = "/rests/data/path-params-test:cont/list1={name}/cont2";
243         assertTrue(doc.getPaths().has(pathToList4));
244         assertEquals(List.of("name"), getPathParameters(doc.getPaths(), pathToList5));
245     }
246
247     private static void verifyThatPropertyDoesNotHaveRequired(final List<String> expected,
248         final ObjectNode definitions) {
249         final var fields = definitions.fields();
250         while (fields.hasNext()) {
251             final var next = fields.next();
252             final var nodeName = next.getKey();
253             final var jsonNode = next.getValue();
254             if (expected.contains(nodeName)) {
255                 continue;
256             }
257             assertNull("Json node " + nodeName + " should not have 'required' field in body",
258                 jsonNode.get("required"));
259         }
260     }
261
262     private static void verifyRequiredField(final JsonNode rootContainer, final Set<String> expected) {
263         assertNotNull(rootContainer);
264         final var required = rootContainer.get("required");
265         assertNotNull(required);
266         assertTrue(required.isArray());
267         final var actualContainerArray = StreamSupport.stream(required.spliterator(), false)
268             .map(JsonNode::textValue)
269             .collect(Collectors.toSet());
270         assertEquals(expected, actualContainerArray);
271     }
272
273     /**
274      * Test that request for actions is correct and has parameters.
275      */
276     @Test
277     public void testActionPathsParams() {
278         final var doc = (OpenApiObject) generator.getApiDeclaration("action-types", null, URI_INFO,
279             ApiDocServiceImpl.OAversion.V3_0);
280
281         final var pathWithParameters = "/rests/operations/action-types:list={name}/list-action";
282         assertTrue(doc.getPaths().has(pathWithParameters));
283         assertEquals(List.of("name"), getPathParameters(doc.getPaths(), pathWithParameters));
284
285         final var pathWithoutParameters = "/rests/operations/action-types:multi-container/inner-container/action";
286         assertTrue(doc.getPaths().has(pathWithoutParameters));
287         assertEquals(List.of(), getPathParameters(doc.getPaths(), pathWithoutParameters));
288     }
289
290     @Test
291     public void testChoice() {
292         final var doc = (SwaggerObject) generator.getApiDeclaration(CHOICE_TEST_MODULE, null, URI_INFO,
293             ApiDocServiceImpl.OAversion.V2_0);
294         assertNotNull(doc);
295
296         final var definitions = doc.getDefinitions();
297         JsonNode firstContainer = definitions.get("choice-test_first-container");
298         assertEquals("default-value",
299                 firstContainer.get(PROPERTIES).get("leaf-default").get("default").asText());
300         assertFalse(firstContainer.get(PROPERTIES).has("leaf-non-default"));
301
302         JsonNode secondContainer = definitions.get("choice-test_second-container");
303         assertTrue(secondContainer.get(PROPERTIES).has("leaf-first-case"));
304         assertFalse(secondContainer.get(PROPERTIES).has("leaf-second-case"));
305     }
306
307     @Test
308     public void testSimpleOpenApiObjects() {
309         final var doc = (OpenApiObject) generator.getApiDeclaration(MY_YANG, MY_YANG_REVISION, URI_INFO,
310             ApiDocServiceImpl.OAversion.V3_0);
311         assertEquals(List.of("/rests/data", "/rests/data/my-yang:data"),
312                 ImmutableList.copyOf(doc.getPaths().fieldNames()));
313
314         final var JsonNodeMyYangData = doc.getPaths().get("/rests/data/my-yang:data");
315         verifyRequestRef(JsonNodeMyYangData.path("post"),
316                 "#/components/schemas/my-yang_config_data_post",
317                 "#/components/schemas/my-yang_config_data_post_xml");
318         verifyRequestRef(JsonNodeMyYangData.path("put"), "#/components/schemas/my-yang_config_data_TOP",
319                 "#/components/schemas/my-yang_config_data");
320         verifyRequestRef(JsonNodeMyYangData.path("get"), "#/components/schemas/my-yang_data_TOP",
321                 "#/components/schemas/my-yang_data");
322
323         // Test `components/schemas` objects
324         final var definitions = doc.getComponents().getSchemas();
325         assertEquals(7, definitions.size());
326         assertTrue(definitions.has("my-yang_config_data"));
327         assertTrue(definitions.has("my-yang_config_data_post"));
328         assertTrue(definitions.has("my-yang_config_data_post_xml"));
329         assertTrue(definitions.has("my-yang_config_data_TOP"));
330         assertTrue(definitions.has("my-yang_data"));
331         assertTrue(definitions.has("my-yang_data_TOP"));
332         assertTrue(definitions.has("my-yang_module"));
333     }
334
335     @Test
336     public void testToaster2OpenApiObjects() {
337         final var doc = (OpenApiObject) generator.getApiDeclaration(NAME, REVISION_DATE, URI_INFO,
338             ApiDocServiceImpl.OAversion.V3_0);
339         final var jsonNodeToaster = doc.getPaths().get("/rests/data/toaster2:toaster");
340         verifyPostRequestRef(jsonNodeToaster.path("post"),
341             "#/components/schemas/toaster2_toaster_config_toasterSlot_post",
342             "#/components/schemas/toaster2_toaster_config_toasterSlot_post_xml", LIST);
343         verifyRequestRef(jsonNodeToaster.path("put"), "#/components/schemas/toaster2_config_toaster_TOP",
344                 "#/components/schemas/toaster2_config_toaster");
345         verifyRequestRef(jsonNodeToaster.path("get"), "#/components/schemas/toaster2_toaster_TOP",
346                 "#/components/schemas/toaster2_toaster");
347
348         final var jsonNodeToasterSlot = doc.getPaths().get("/rests/data/toaster2:toaster/toasterSlot={slotId}");
349         verifyPostRequestRef(jsonNodeToasterSlot.path("post"),
350                 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo_post",
351                 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo_post_xml", CONTAINER);
352         verifyRequestRef(jsonNodeToasterSlot.path("put"),
353                 "#/components/schemas/toaster2_toaster_config_toasterSlot_TOP",
354                 "#/components/schemas/toaster2_toaster_config_toasterSlot");
355         verifyRequestRef(jsonNodeToasterSlot.path("get"), "#/components/schemas/toaster2_toaster_toasterSlot_TOP",
356                 "#/components/schemas/toaster2_toaster_toasterSlot");
357
358         final var jsonNodeSlotInfo = doc.getPaths().get(
359                 "/rests/data/toaster2:toaster/toasterSlot={slotId}/toaster-augmented:slotInfo");
360         verifyRequestRef(jsonNodeSlotInfo.path("post"),
361                 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo_post",
362                 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo_post_xml");
363         verifyRequestRef(jsonNodeSlotInfo.path("put"),
364                 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo_TOP",
365                 "#/components/schemas/toaster2_toaster_toasterSlot_config_slotInfo");
366         verifyRequestRef(jsonNodeSlotInfo.path("get"), "#/components/schemas/toaster2_toaster_toasterSlot_slotInfo_TOP",
367                 "#/components/schemas/toaster2_toaster_toasterSlot_slotInfo");
368
369         final var jsonNodeLst = doc.getPaths().get("/rests/data/toaster2:lst");
370         verifyPostRequestRef(jsonNodeLst.path("post"), "#/components/schemas/toaster2_lst_config_cont1_post",
371                 "#/components/schemas/toaster2_lst_config_cont1_post_xml", CONTAINER);
372         verifyRequestRef(jsonNodeLst.path("put"), "#/components/schemas/toaster2_config_lst_TOP",
373                 "#/components/schemas/toaster2_config_lst");
374         verifyRequestRef(jsonNodeLst.path("get"), "#/components/schemas/toaster2_lst_TOP",
375                 "#/components/schemas/toaster2_lst");
376
377         final var jsonNodeLst1 = doc.getPaths().get("/rests/data/toaster2:lst/lst1={key1},{key2}");
378         verifyRequestRef(jsonNodeLst1.path("post"), "#/components/schemas/toaster2_lst_config_lst1_post",
379                 "#/components/schemas/toaster2_lst_config_lst1_post_xml");
380         verifyRequestRef(jsonNodeLst1.path("put"), "#/components/schemas/toaster2_lst_config_lst1_TOP",
381                 "#/components/schemas/toaster2_lst_config_lst1");
382         verifyRequestRef(jsonNodeLst1.path("get"), "#/components/schemas/toaster2_lst_lst1_TOP",
383                 "#/components/schemas/toaster2_lst_lst1");
384
385         final var jsonNodeMakeToast = doc.getPaths().get("/rests/operations/toaster2:make-toast");
386         assertTrue(jsonNodeMakeToast.path("get").isMissingNode());
387         verifyRequestRef(jsonNodeMakeToast.path("post"), "#/components/schemas/toaster2_make-toast_input_TOP",
388                 "#/components/schemas/toaster2_make-toast_input");
389
390         final var jsonNodeCancelToast = doc.getPaths().get("/rests/operations/toaster2:cancel-toast");
391         assertTrue(jsonNodeCancelToast.path("get").isMissingNode());
392         // Test RPC with empty input
393         final var postContent = jsonNodeCancelToast.path("post").get("requestBody").get("content");
394         final var jsonSchema = postContent.get("application/json").get("schema");
395         assertNull(jsonSchema.get("$ref"));
396         assertEquals(2, jsonSchema.size());
397         final var xmlSchema = postContent.get("application/xml").get("schema");
398         assertNull(xmlSchema.get("$ref"));
399         assertEquals(2, xmlSchema.size());
400         // Test `components/schemas` objects
401         final var definitions = doc.getComponents().getSchemas();
402         assertEquals(60, definitions.size());
403     }
404
405     /**
406      *  Test JSON and XML references for request operation.
407      */
408     private static void verifyRequestRef(final JsonNode path, final String expectedJsonRef,
409             final String expectedXmlRef) {
410         final JsonNode postContent;
411         if (path.get("requestBody") != null) {
412             postContent = path.get("requestBody").get("content");
413         } else {
414             postContent = path.get("responses").get("200").get("content");
415         }
416         assertNotNull(postContent);
417         final var postJsonRef = postContent.get("application/json").get("schema").get("$ref");
418         assertNotNull(postJsonRef);
419         assertEquals(expectedJsonRef, postJsonRef.textValue());
420         final var postXmlRef = postContent.get("application/xml").get("schema").get("$ref");
421         assertNotNull(postXmlRef);
422         assertEquals(expectedXmlRef, postXmlRef.textValue());
423     }
424
425     private static void verifyPostRequestRef(final JsonNode path, final String expectedJsonRef,
426         final String expectedXmlRef, String nodeType) {
427         final JsonNode postContent;
428         if (path.get("requestBody") != null) {
429             postContent = path.get("requestBody").get("content");
430         } else {
431             postContent = path.get("responses").get("200").get("content");
432         }
433         assertNotNull(postContent);
434         final String postJsonRef;
435         if (nodeType.equals(CONTAINER)) {
436             postJsonRef = postContent.path("application/json").path("schema").path("properties").elements().next()
437                 .path("$ref").textValue();
438         } else {
439             postJsonRef = postContent.path("application/json").path("schema").path("properties").elements().next()
440                 .path("items").path("$ref").textValue();
441         }
442         assertEquals(expectedJsonRef, postJsonRef);
443         final var postXmlRef = postContent.get("application/xml").get("schema").get("$ref");
444         assertNotNull(postXmlRef);
445         assertEquals(expectedXmlRef, postXmlRef.textValue());
446     }
447 }