b69d3d4aa87f0f1cfa6faa0d8002d1b0690fc03d
[netconf.git] /
1 /*
2  * Copyright (c) 2024 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.server;
9
10 import static org.mockito.ArgumentMatchers.any;
11 import static org.mockito.ArgumentMatchers.eq;
12 import static org.mockito.ArgumentMatchers.isNull;
13 import static org.mockito.Mockito.doAnswer;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.doThrow;
16 import static org.opendaylight.restconf.server.PathParameters.MODULES;
17 import static org.opendaylight.restconf.server.PathParameters.YANG_LIBRARY_VERSION;
18 import static org.opendaylight.restconf.server.RestconfRequestDispatcher.MISSING_FILENAME_ERROR;
19 import static org.opendaylight.restconf.server.RestconfRequestDispatcher.REVISION;
20 import static org.opendaylight.restconf.server.RestconfRequestDispatcher.SOURCE_READ_FAILURE_ERROR;
21 import static org.opendaylight.restconf.server.TestUtils.answerCompleteWith;
22 import static org.opendaylight.restconf.server.TestUtils.assertErrorResponse;
23 import static org.opendaylight.restconf.server.TestUtils.assertOptionsResponse;
24 import static org.opendaylight.restconf.server.TestUtils.assertResponse;
25 import static org.opendaylight.restconf.server.TestUtils.buildRequest;
26 import static org.opendaylight.restconf.server.TestUtils.charSource;
27 import static org.opendaylight.restconf.server.TestUtils.formattableBody;
28
29 import com.google.common.io.ByteSource;
30 import com.google.common.io.CharSource;
31 import io.netty.handler.codec.http.DefaultFullHttpRequest;
32 import io.netty.handler.codec.http.HttpMethod;
33 import io.netty.handler.codec.http.HttpResponseStatus;
34 import io.netty.handler.codec.http.HttpVersion;
35 import java.io.IOException;
36 import java.util.stream.Stream;
37 import org.junit.jupiter.params.ParameterizedTest;
38 import org.junit.jupiter.params.provider.Arguments;
39 import org.junit.jupiter.params.provider.MethodSource;
40 import org.junit.jupiter.params.provider.ValueSource;
41 import org.mockito.Mock;
42 import org.opendaylight.restconf.server.TestUtils.TestEncoding;
43 import org.opendaylight.restconf.server.api.ModulesGetResult;
44 import org.opendaylight.yangtools.yang.common.ErrorTag;
45
46 class ModulesRequestProcessorTest extends AbstractRequestProcessorTest {
47     private static final String YANG_LIBRARY_VERSION_URI = BASE_PATH + YANG_LIBRARY_VERSION;
48     private static final String MODULES_PATH = BASE_PATH + MODULES + "/";
49     private static final String MODULE_FILENAME = "module-filename";
50     private static final String MODULE_URI = MODULES_PATH + MODULE_FILENAME;
51     private static final String MODULE_URI_WITH_MOUNT = MODULES_PATH + MOUNT_PATH + "/" + MODULE_FILENAME;
52     private static final String REVISION_VALUE = "revision-value";
53     private static final String REVISION_PARAM = "?" + REVISION + "=" + REVISION_VALUE;
54     private static final String YANG_CONTENT = "yang-content";
55     private static final String YIN_CONTENT = "yin-content";
56
57     @Mock
58     private CharSource source;
59     @Mock
60     private ByteSource byteSource;
61
62     @ParameterizedTest
63     @ValueSource(strings = {YANG_LIBRARY_VERSION_URI, MODULES_PATH, MODULE_URI, MODULE_URI_WITH_MOUNT})
64     void options(final String uri) {
65         final var request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.OPTIONS, uri);
66         assertOptionsResponse(dispatch(request), "GET, HEAD, OPTIONS");
67     }
68
69     @ParameterizedTest
70     @MethodSource("encodings")
71     void getYangLibraryVersion(final TestEncoding encoding, final String content) {
72         final var result = formattableBody(encoding, content);
73         doAnswer(answerCompleteWith(result)).when(server).yangLibraryVersionGET(any());
74
75         final var request = buildRequest(HttpMethod.GET, YANG_LIBRARY_VERSION_URI, encoding, null);
76         final var response = dispatch(request);
77         assertResponse(response, HttpResponseStatus.OK, encoding.responseType, content);
78     }
79
80     @ParameterizedTest
81     @MethodSource("modules")
82     void getModule(final TestEncoding encoding, final String content, final boolean hasRevision) {
83         final var result = new ModulesGetResult(charSource(content));
84         final var revision = hasRevision ? REVISION_VALUE : null;
85         if (encoding.isYin()) {
86             doAnswer(answerCompleteWith(result)).when(server).modulesYinGET(any(), eq(MODULE_FILENAME), eq(revision));
87         } else {
88             doAnswer(answerCompleteWith(result)).when(server).modulesYangGET(any(), eq(MODULE_FILENAME), eq(revision));
89         }
90
91         final var uri = MODULE_URI + (hasRevision ? REVISION_PARAM : "");
92         final var request = buildRequest(HttpMethod.GET, uri, encoding, null);
93         final var response = dispatch(request);
94         assertResponse(response, HttpResponseStatus.OK, encoding.responseType, content);
95     }
96
97     @ParameterizedTest
98     @MethodSource("modules")
99     void getModuleWithMountPath(final TestEncoding encoding, final String content, final boolean hasRevision) {
100         final var result = new ModulesGetResult(charSource(content));
101         final var revision = hasRevision ? REVISION_VALUE : null;
102         if (encoding.isYin()) {
103             doAnswer(answerCompleteWith(result)).when(server)
104                 .modulesYinGET(any(), eq(MOUNT_API_PATH), eq(MODULE_FILENAME), eq(revision));
105         } else {
106             doAnswer(answerCompleteWith(result)).when(server)
107                 .modulesYangGET(any(), eq(MOUNT_API_PATH), eq(MODULE_FILENAME), eq(revision));
108         }
109         final var uri = MODULE_URI_WITH_MOUNT + (hasRevision ? REVISION_PARAM : "");
110         final var request = buildRequest(HttpMethod.GET, uri, encoding, null);
111         final var response = dispatch(request);
112         assertResponse(response, HttpResponseStatus.OK, encoding.responseType, content);
113     }
114
115     private static Stream<Arguments> modules() {
116         return Stream.of(
117             // encoding, content, hasRevision
118             Arguments.of(TestEncoding.YANG, YANG_CONTENT, true),
119             Arguments.of(TestEncoding.YANG, YANG_CONTENT, false),
120             Arguments.of(TestEncoding.YIN, YIN_CONTENT, true),
121             Arguments.of(TestEncoding.YIN, YIN_CONTENT, false)
122         );
123     }
124
125     @ParameterizedTest
126     @MethodSource("moduleErrorEncodings")
127     void noFilenameError(final TestEncoding encoding, final TestEncoding errorEncoding) {
128         final var request = buildRequest(HttpMethod.GET, MODULES_PATH, encoding, null);
129         final var response = dispatch(request);
130         assertErrorResponse(response, errorEncoding, ErrorTag.MISSING_ELEMENT, MISSING_FILENAME_ERROR);
131     }
132
133     @ParameterizedTest
134     @MethodSource("moduleErrorEncodings")
135     void sourceReadFailure(final TestEncoding encoding, final TestEncoding errorEncoding) throws IOException {
136         final var errorMessage = "source-read-failure";
137         doReturn(byteSource).when(source).asByteSource(any());
138         doThrow(new IOException(errorMessage)).when(byteSource).read();
139
140         final var result = new ModulesGetResult(source);
141         if (encoding.isYin()) {
142             doAnswer(answerCompleteWith(result)).when(server).modulesYinGET(any(), eq(MODULE_FILENAME), isNull());
143         } else {
144             doAnswer(answerCompleteWith(result)).when(server).modulesYangGET(any(), eq(MODULE_FILENAME), isNull());
145         }
146
147         final var request = buildRequest(HttpMethod.GET, MODULE_URI, encoding, null);
148         final var response = dispatch(request);
149         assertErrorResponse(response, errorEncoding, ErrorTag.OPERATION_FAILED,
150             SOURCE_READ_FAILURE_ERROR + errorMessage);
151     }
152
153     private static Stream<Arguments> moduleErrorEncodings() {
154         return Stream.of(
155             // request accept encoding, error response encoding
156             Arguments.of(TestEncoding.YANG, DEFAULT_ENCODING),
157             Arguments.of(TestEncoding.YIN, TestEncoding.XML)
158         );
159     }
160 }