summaryrefslogtreecommitdiffstats
path: root/mod/runtimeapi/runtime-web/src/test/java/org/onap/dcae/runtime/web/ClientMocking.java
diff options
context:
space:
mode:
Diffstat (limited to 'mod/runtimeapi/runtime-web/src/test/java/org/onap/dcae/runtime/web/ClientMocking.java')
-rw-r--r--mod/runtimeapi/runtime-web/src/test/java/org/onap/dcae/runtime/web/ClientMocking.java346
1 files changed, 346 insertions, 0 deletions
diff --git a/mod/runtimeapi/runtime-web/src/test/java/org/onap/dcae/runtime/web/ClientMocking.java b/mod/runtimeapi/runtime-web/src/test/java/org/onap/dcae/runtime/web/ClientMocking.java
new file mode 100644
index 0000000..14acf90
--- /dev/null
+++ b/mod/runtimeapi/runtime-web/src/test/java/org/onap/dcae/runtime/web/ClientMocking.java
@@ -0,0 +1,346 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcae.runtime.web;
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.util.Base64;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.ArrayList;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.http.HttpResponse;
+import org.apache.http.message.BasicHttpResponse;
+import org.apache.http.message.BasicStatusLine;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.StatusLine;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Simulate responses from RestTemplate based clients.
+ */
+
+public class ClientMocking implements Answer<HttpResponse> {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ /**
+ * Replace single quotes with double quotes.
+ * Makes it easy to write JSON strings.
+ *
+ * @param s String with single quotes.
+ * @return String replacing single quotes with double quotes.
+ */
+ public static String xq(String s) {
+ return s.replaceAll("'", "\"");
+ }
+
+ private static class BasicCloseableHttpResponse extends BasicHttpResponse implements CloseableHttpResponse {
+ public BasicCloseableHttpResponse(StatusLine line) {
+ super(line);
+ }
+
+ @Override
+ public void close() throws IOException {
+ // no op
+ }
+ }
+
+ /**
+ * Information on request being processed
+ */
+ public static class RequestInfo {
+ private HttpUriRequest req;
+ private String line;
+
+ /**
+ * Collect information on a request.
+ * @param req The request to examine.
+ */
+ public RequestInfo(HttpUriRequest req) {
+ this.req = req;
+ line = getMethod() + " " + getPath() + (req.getURI().getQuery() == null ? "": ("?" + req.getURI().getQuery()));
+ }
+
+ /**
+ * Get the method.
+ *
+ * @return The HTTP method of the request.
+ */
+ public String getMethod() {
+ return req.getMethod();
+ }
+
+ /**
+ * Get the method and URI
+ *
+ * @return The method and URI of the request, including any query string.
+ */
+ public String getLine() {
+ return line;
+ }
+
+ /**
+ * Get the path component of the URI
+ *
+ * @return The URI excluding the query string.
+ */
+ public String getPath() {
+ return req.getURI().getPath();
+ }
+
+ /**
+ * Check whether the named header is missing.
+ *
+ * @return true if the header is absent.
+ */
+ public boolean lacksHeader(String name) {
+ return req.getFirstHeader(name) == null;
+ }
+
+ /**
+ * Check whether the header has the specified header value.
+ *
+ * @return true if the header is missing or has the wrong value.
+ */
+ public boolean lacksHeaderValue(String name, String value) {
+ return req.getFirstHeader(name) == null || !value.equals(req.getFirstHeader(name).getValue());
+ }
+ }
+
+ private static class Response {
+ private Predicate<RequestInfo> matcher;
+ private byte[] body;
+ private Consumer<RequestInfo> action;
+ private int code = 200;
+ private String message = "OK";
+ private ContentType contentType = ContentType.APPLICATION_JSON;
+ }
+
+ private static Predicate<RequestInfo> s2p(String line) {
+ return r -> r.getLine().equals(line);
+ }
+
+ private ArrayList<Response> responses;
+ private HttpClient client;
+
+ /**
+ * Create a responder to handle requests.
+ */
+ public ClientMocking() throws IOException {
+ responses = new ArrayList<>();
+ client = mock(HttpClient.class);
+ when(client.execute(any(HttpUriRequest.class), any(HttpContext.class))).thenAnswer(this);
+ }
+
+ /**
+ * Redirect the template to this responder.
+ *
+ * @param template The RestTemplate to redirect.
+ * @return This responder.
+ */
+ public ClientMocking applyTo(RestTemplate template) {
+ template.setRequestFactory(new HttpComponentsClientHttpRequestFactory(client));
+ return this;
+ }
+
+ /**
+ * Set the identified RestTemplate field to use this responder.
+ *
+ * @param object The object containing the RestTemplate.
+ * @param fieldName The name of the RestTemplate field in the object.
+ * @return This responder.
+ */
+ public ClientMocking applyTo(Object object, String fieldName) {
+ return applyTo((RestTemplate)ReflectionTestUtils.getField(object, fieldName));
+ }
+
+ /**
+ * Set the restTemplate field of an object to use this responder.
+ *
+ * Typically, the object will be a FederationClient or a GatewayClient.
+ * @param object The object with the restTemplate field.
+ * @return This responder.
+ */
+ public ClientMocking applyTo(Object object) {
+ return applyTo(object, "restTemplate");
+ }
+
+ @Override
+ public HttpResponse answer(InvocationOnMock invocation) throws Throwable {
+ RequestInfo info = new RequestInfo((HttpUriRequest)invocation.getArguments()[0]);
+ for (Response r: responses) {
+ if (r.matcher.test(info)) {
+ if (r.action != null) {
+ r.action.accept(info);
+ }
+ BasicCloseableHttpResponse ret = new BasicCloseableHttpResponse(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), r.code, r.message));
+ if (r.body != null) {
+ ret.setEntity(new ByteArrayEntity(r.body, r.contentType));
+ ret.addHeader("Content-Length", String.valueOf(r.body.length));
+ if (r.body.length != 0) {
+ ret.addHeader("Content-Type", r.contentType.toString());
+ }
+ }
+ if (log.isInfoEnabled()) {
+ log.info("Mock client response to {} is {}", info.getLine(), (r.body == null? "null": new String(r.body)));
+ }
+ return ret;
+ }
+ }
+ throw new IOException("Mock unhandled " + info.getLine());
+ }
+
+ /**
+ * Handle the specified requests.
+ *
+ * @param matcher A predicate for matching requests.
+ * @param body The response body to return.
+ * @param type The content type of the body.
+ * @param action An action to perform, whenever the request is handled.
+ * @return This responder.
+ */
+ public ClientMocking on(Predicate<RequestInfo> matcher, byte[] body, ContentType type, Consumer<RequestInfo> action) {
+ Response r = new Response();
+ r.matcher = matcher;
+ r.body = body;
+ r.contentType = type;
+ r.action = action;
+ responses.add(r);
+ return this;
+ }
+
+ /**
+ * Handle the specified request.
+ *
+ * @param line The HTTP method and URI to handle.
+ * @param body The response body to return.
+ * @param type The content type of the body.
+ * @param action An action to perform, whenever the request is handled.
+ * @return This responder.
+ */
+ public ClientMocking on(String line, String body, ContentType type, Consumer<RequestInfo> action) {
+ return on(s2p(line), body.getBytes(), type, action);
+ }
+
+ /**
+ * Handle the specified request.
+ *
+ * @param line The HTTP method and URI to handle.
+ * @param body The response body to return, as a JSON string.
+ * @param action An action to perform, whenever the request is handled.
+ * @return This responder.
+ */
+ public ClientMocking on(String line, String body, Consumer<RequestInfo> action) {
+ return on(line, body, ContentType.APPLICATION_JSON, action);
+ }
+
+ /**
+ * Handle the specified request.
+ *
+ * @param line The HTTP method and URI to handle.
+ * @param body The response body to return, as a JSON string.
+ * @return This responder.
+ */
+ public ClientMocking on(String line, String body) {
+ return on(line, body, ContentType.APPLICATION_JSON);
+ }
+
+ /**
+ * Handle the specified request.
+ *
+ * @param line The HTTP method and URI to handle.
+ * @param body The response body to return, as a JSON string.
+ * @param type The content type of the body.
+ * @return This responder.
+ */
+ public ClientMocking on(String line, String body, ContentType type) {
+ return on(line, body, type, null);
+ }
+
+ /**
+ * Fail the specified requests.
+ *
+ * @param matcher A predicate for matching requests.
+ * @param code The HTTP error code to return.
+ * @param message The HTTP error status message to return.
+ * @return This responder.
+ */
+ public ClientMocking errorOn(Predicate<RequestInfo> matcher, int code, String message) {
+ Response r = new Response();
+ r.matcher = matcher;
+ r.code = code;
+ r.message = message;
+ responses.add(r);
+ return this;
+ }
+
+ /**
+ * Fail the specified request.
+ *
+ * @param line The HTTP method and URI to handle.
+ * @param code The HTTP error code to return.
+ * @param message The HTTP error status message to return.
+ * @return This responder.
+ */
+ public ClientMocking errorOn(String line, int code, String message) {
+ return errorOn(s2p(line), code, message);
+ }
+
+ /**
+ * Fail the request if no auth header
+ *
+ * @param code The HTTP error code to return.
+ * @param message The HTTP error status message to return.
+ * @return This responder.
+ */
+ public ClientMocking errorOnNoAuth(int code, String message) {
+ return errorOn(ri -> ri.lacksHeader("Authorization"), code, message);
+ }
+
+ /**
+ * Fail the request if wrong auth header
+ *
+ * @param username The expected user name.
+ * @param password The expected password.
+ * @param code The HTTP error code to return.
+ * @param message The HTTP error status message to return.
+ * @return This responder.
+ */
+ public ClientMocking errorOnBadAuth(String username, String password, int code, String message) {
+ String authhdr = "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
+ return errorOn(ri -> ri.lacksHeaderValue("Authorization", authhdr), code, message);
+ }
+}