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