2 * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.restconf.server;
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;
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;
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";
55 private CharSource source;
57 private ByteSource byteSource;
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");
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());
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);
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));
85 doAnswer(answerCompleteWith(result)).when(server).modulesYangGET(any(), eq(MODULE_FILENAME), eq(revision));
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);
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));
103 doAnswer(answerCompleteWith(result)).when(server)
104 .modulesYangGET(any(), eq(MOUNT_API_PATH), eq(MODULE_FILENAME), eq(revision));
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);
112 private static Stream<Arguments> modules() {
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)
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());
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));
137 final var result = new ModulesGetResult(source);
138 if (encoding.isYin()) {
139 doAnswer(answerCompleteWith(result)).when(server).modulesYinGET(any(), eq(MODULE_FILENAME), isNull());
141 doAnswer(answerCompleteWith(result)).when(server).modulesYangGET(any(), eq(MODULE_FILENAME), isNull());
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));
150 private static Stream<Arguments> moduleErrorEncodings() {
152 // request accept encoding, error response encoding
153 Arguments.of(TestEncoding.YANG, DEFAULT_ENCODING),
154 Arguments.of(TestEncoding.YIN, TestEncoding.XML)