From 173c4dbea9a1175a6f18031a221bb701deeecaa7 Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Mon, 9 Sep 2019 16:51:32 -0400 Subject: Create StandardYamlCoder Created StandardYamlCoder which is like a StandardCoder, except that the original converts to/from JSON, while the new class converts to/from YAML. Also added YamlMessageBodyHandler and incorporated it into the http server so that it supports a media type of */yaml. Change-Id: Ibd83a9f6d355a330f63e435f2bb41affcf1947c2 Issue-ID: POLICY-2065 Signed-off-by: Jim Hahn --- .../endpoints/http/server/test/HttpServerTest.java | 111 ++++++++-- .../endpoints/http/server/test/MyYamlProvider.java | 82 ++++++++ .../http/server/test/RestEchoService.java | 2 +- .../endpoints/http/server/test/RestServerTest.java | 4 +- .../server/test/YamlMessageBodyHandlerTest.java | 230 +++++++++++++++++++++ 5 files changed, 410 insertions(+), 19 deletions(-) create mode 100644 policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyYamlProvider.java create mode 100644 policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/YamlMessageBodyHandlerTest.java (limited to 'policy-endpoints/src/test/java/org/onap/policy/common') diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpServerTest.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpServerTest.java index f2b53648..84f82f1a 100644 --- a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpServerTest.java +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpServerTest.java @@ -26,9 +26,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import com.google.gson.Gson; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; +import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; @@ -40,6 +39,7 @@ import org.junit.Before; import org.junit.Test; import org.onap.policy.common.endpoints.http.server.HttpServletServer; import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance; +import org.onap.policy.common.utils.coder.StandardYamlCoder; import org.onap.policy.common.utils.gson.GsonTestUtils; import org.onap.policy.common.utils.network.NetworkUtil; import org.slf4j.Logger; @@ -50,6 +50,8 @@ import org.slf4j.LoggerFactory; */ public class HttpServerTest { private static final String LOCALHOST = "localhost"; + private static final String JSON_MEDIA = "application/json"; + private static final String YAML_MEDIA = "application/yaml"; private static final String SWAGGER_JSON = "/swagger.json"; private static final String JUNIT_ECHO_HELLO = "/junit/echo/hello"; private static final String JUNIT_ECHO_FULL_REQUEST = "/junit/echo/full/request"; @@ -84,6 +86,7 @@ public class HttpServerTest { MyJacksonProvider.resetSome(); MyGsonProvider.resetSome(); + MyYamlProvider.resetSome(); } private static void incrementPort() { @@ -112,7 +115,7 @@ public class HttpServerTest { request.setText(SOME_TEXT); String reqText = gson.toJson(request); - String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, reqText); + String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText); assertEquals(reqText, response); } @@ -135,7 +138,7 @@ public class HttpServerTest { request.setText(SOME_TEXT); String reqText = gson.toJson(request); - String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, reqText); + String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText); assertEquals(reqText, response); assertTrue(MyJacksonProvider.hasReadSome()); @@ -143,6 +146,9 @@ public class HttpServerTest { assertFalse(MyGsonProvider.hasReadSome()); assertFalse(MyGsonProvider.hasWrittenSome()); + + assertFalse(MyYamlProvider.hasReadSome()); + assertFalse(MyYamlProvider.hasWrittenSome()); } @Test @@ -164,7 +170,7 @@ public class HttpServerTest { request.setText(SOME_TEXT); String reqText = gson.toJson(request); - String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, reqText); + String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText); assertEquals(reqText, response); assertTrue(MyGsonProvider.hasReadSome()); @@ -172,6 +178,43 @@ public class HttpServerTest { assertFalse(MyJacksonProvider.hasReadSome()); assertFalse(MyJacksonProvider.hasWrittenSome()); + + assertFalse(MyYamlProvider.hasReadSome()); + assertFalse(MyYamlProvider.hasWrittenSome()); + } + + @Test + public void testYamlPackageServer() throws Exception { + logger.info("-- testYamlPackageServer() --"); + + HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory() + .build("echo", LOCALHOST, port, "/", false, true); + + server.setSerializationProvider(MyYamlProvider.class.getName()); + server.addServletPackage("/*", this.getClass().getPackage().getName()); + server.addFilterClass("/*", TestFilter.class.getName()); + server.waitedStart(5000); + + assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive()); + + RestEchoReqResp request = new RestEchoReqResp(); + request.setRequestId(100); + request.setText(SOME_TEXT); + String reqText = new StandardYamlCoder().encode(request); + + String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, YAML_MEDIA, reqText); + + // response reader strips newlines, so we should, too, before comparing + assertEquals(reqText.replace("\n", ""), response); + + assertTrue(MyYamlProvider.hasReadSome()); + assertTrue(MyYamlProvider.hasWrittenSome()); + + assertFalse(MyGsonProvider.hasReadSome()); + assertFalse(MyGsonProvider.hasWrittenSome()); + + assertFalse(MyJacksonProvider.hasReadSome()); + assertFalse(MyJacksonProvider.hasWrittenSome()); } @Test @@ -191,7 +234,7 @@ public class HttpServerTest { request.setText(SOME_TEXT); String reqText = gson.toJson(request); - String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, reqText); + String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText); assertEquals(reqText, response); } @@ -213,7 +256,7 @@ public class HttpServerTest { request.setText(SOME_TEXT); String reqText = gson.toJson(request); - String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, reqText); + String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText); assertEquals(reqText, response); assertTrue(MyJacksonProvider.hasReadSome()); @@ -221,6 +264,9 @@ public class HttpServerTest { assertFalse(MyGsonProvider.hasReadSome()); assertFalse(MyGsonProvider.hasWrittenSome()); + + assertFalse(MyYamlProvider.hasReadSome()); + assertFalse(MyYamlProvider.hasWrittenSome()); } @Test @@ -241,7 +287,7 @@ public class HttpServerTest { request.setText(SOME_TEXT); String reqText = gson.toJson(request); - String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, reqText); + String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, JSON_MEDIA, reqText); assertEquals(reqText, response); assertTrue(MyGsonProvider.hasReadSome()); @@ -249,6 +295,42 @@ public class HttpServerTest { assertFalse(MyJacksonProvider.hasReadSome()); assertFalse(MyJacksonProvider.hasWrittenSome()); + + assertFalse(MyYamlProvider.hasReadSome()); + assertFalse(MyYamlProvider.hasWrittenSome()); + } + + @Test + public void testYamlClassServer() throws Exception { + logger.info("-- testYamlClassServer() --"); + + HttpServletServer server = HttpServletServerFactoryInstance.getServerFactory() + .build("echo", LOCALHOST, port, "/", false, true); + server.setSerializationProvider(MyYamlProvider.class.getName()); + server.addServletClass("/*", RestEchoService.class.getName()); + server.addFilterClass("/*", TestFilter.class.getName()); + server.waitedStart(5000); + + assertTrue(HttpServletServerFactoryInstance.getServerFactory().get(port).isAlive()); + + RestEchoReqResp request = new RestEchoReqResp(); + request.setRequestId(100); + request.setText(SOME_TEXT); + String reqText = new StandardYamlCoder().encode(request); + + String response = http(portUrl + JUNIT_ECHO_FULL_REQUEST, YAML_MEDIA, reqText); + + // response reader strips newlines, so we should, too, before comparing + assertEquals(reqText.replace("\n", ""), response); + + assertTrue(MyYamlProvider.hasReadSome()); + assertTrue(MyYamlProvider.hasWrittenSome()); + + assertFalse(MyGsonProvider.hasReadSome()); + assertFalse(MyGsonProvider.hasWrittenSome()); + + assertFalse(MyJacksonProvider.hasReadSome()); + assertFalse(MyJacksonProvider.hasWrittenSome()); } @Test @@ -416,7 +498,7 @@ public class HttpServerTest { * @throws IOException thrown is IO exception occurs * @throws InterruptedException thrown if thread interrupted occurs */ - private String http(String urlString, String post) + private String http(String urlString, String mediaType, String post) throws IOException, InterruptedException { URL url = new URL(urlString); if (!NetworkUtil.isTcpPortOpen(url.getHost(), url.getPort(), 25, 2)) { @@ -425,7 +507,7 @@ public class HttpServerTest { HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "application/json"); + conn.setRequestProperty("Content-Type", mediaType); IOUtils.write(post, conn.getOutputStream()); return response(conn); } @@ -438,14 +520,9 @@ public class HttpServerTest { * @throws IOException if an I/O error occurs */ private String response(URLConnection conn) throws IOException { - StringBuilder response = new StringBuilder(); - try (BufferedReader ioReader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { - String line; - while ((line = ioReader.readLine()) != null) { - response.append(line); - } + try (InputStream inpstr = conn.getInputStream()) { + return String.join("", IOUtils.readLines(inpstr)); } - return response.toString(); } } diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyYamlProvider.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyYamlProvider.java new file mode 100644 index 00000000..098ecb44 --- /dev/null +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/MyYamlProvider.java @@ -0,0 +1,82 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 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.policy.common.endpoints.http.server.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import lombok.AccessLevel; +import lombok.Setter; +import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler; + +/** + * YamlMessageBodyHandler that tracks activities. + */ +public class MyYamlProvider extends YamlMessageBodyHandler { + + @Setter(AccessLevel.PRIVATE) + private static boolean readSome = false; + + @Setter(AccessLevel.PRIVATE) + private static boolean wroteSome = false; + + /** + * Constructs the object and resets the variables to indicate that no activity has + * occurred yet. + */ + public MyYamlProvider() { + super(); + } + + @Override + public Object readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, InputStream entityStream) throws IOException { + + setReadSome(true); + return super.readFrom(type, genericType, annotations, mediaType, httpHeaders, entityStream); + } + + @Override + public void writeTo(Object object, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, + MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException { + + setWroteSome(true); + super.writeTo(object, type, genericType, annotations, mediaType, httpHeaders, entityStream); + } + + public static boolean hasReadSome() { + return readSome; + } + + public static boolean hasWrittenSome() { + return wroteSome; + } + + public static void resetSome() { + MyYamlProvider.readSome = false; + MyYamlProvider.wroteSome = false; + } + +} diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoService.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoService.java index 9db1053f..27ce300c 100644 --- a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoService.java +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestEchoService.java @@ -56,7 +56,7 @@ public class RestEchoService { @POST @Path("/full/request") - @Produces(MediaType.APPLICATION_JSON) + @Produces({MediaType.APPLICATION_JSON, "application/yaml"}) @ApiOperation(value = "echoes back the request structure", response = RestEchoReqResp.class) public Response echoFullyPost(RestEchoReqResp reqResp) { return Response.status(Status.OK).entity(reqResp).build(); diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestServerTest.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestServerTest.java index fd9b59f7..ee28b96d 100644 --- a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestServerTest.java +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/RestServerTest.java @@ -56,6 +56,7 @@ import org.onap.policy.common.endpoints.http.server.HttpServletServerFactory; import org.onap.policy.common.endpoints.http.server.JsonExceptionMapper; import org.onap.policy.common.endpoints.http.server.RestServer; import org.onap.policy.common.endpoints.http.server.RestServer.Factory; +import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler; import org.onap.policy.common.endpoints.http.server.aaf.AafAuthFilter; import org.onap.policy.common.endpoints.parameters.RestServerParameters; import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties; @@ -211,7 +212,8 @@ public class RestServerTest { assertEquals(PASS, props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_AUTH_PASSWORD_SUFFIX)); assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_HTTPS_SUFFIX)); assertEquals("true", props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_AAF_SUFFIX)); - assertEquals(String.join(",", GsonMessageBodyHandler.class.getName(), JsonExceptionMapper.class.getName()), + assertEquals(String.join(",", GsonMessageBodyHandler.class.getName(), YamlMessageBodyHandler.class.getName(), + JsonExceptionMapper.class.getName()), props.getProperty(svcpfx + PolicyEndPointProperties.PROPERTY_HTTP_SERIALIZATION_PROVIDER)); } diff --git a/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/YamlMessageBodyHandlerTest.java b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/YamlMessageBodyHandlerTest.java new file mode 100644 index 00000000..b8963e9b --- /dev/null +++ b/policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/YamlMessageBodyHandlerTest.java @@ -0,0 +1,230 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 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.policy.common.endpoints.http.server.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import javax.ws.rs.core.MediaType; +import org.junit.Before; +import org.junit.Test; +import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler; + +public class YamlMessageBodyHandlerTest { + private static final String EXPECTED_EXCEPTION = "expected exception"; + + private static final String GEN_TYPE = "some-type"; + private static final String[] subtypes = {"yaml"}; + + @SuppressWarnings("rawtypes") + private static final Class GEN_CLASS = MyObject.class; + + @SuppressWarnings("unchecked") + private static final Class CLASS_OBJ = GEN_CLASS; + + private YamlMessageBodyHandler hdlr; + + @Before + public void setUp() { + hdlr = new YamlMessageBodyHandler(); + } + + @Test + public void testIsWriteable() { + for (String subtype : subtypes) { + assertTrue("writeable " + subtype, hdlr.isWriteable(null, null, null, new MediaType(GEN_TYPE, subtype))); + + } + + // the remaining should be FALSE + + // null media type + assertFalse(hdlr.isWriteable(null, null, null, null)); + + // null subtype + assertFalse(hdlr.isWriteable(null, null, null, new MediaType(GEN_TYPE, null))); + + // text subtype + assertFalse(hdlr.isWriteable(null, null, null, MediaType.TEXT_HTML_TYPE)); + } + + @Test + public void testGetSize() { + assertEquals(-1, hdlr.getSize(null, null, null, null, null)); + } + + @Test + public void testWriteTo_testReadFrom() throws Exception { + ByteArrayOutputStream outstr = new ByteArrayOutputStream(); + MyObject obj1 = new MyObject(10); + hdlr.writeTo(obj1, obj1.getClass(), CLASS_OBJ, null, null, null, outstr); + + Object obj2 = hdlr.readFrom(CLASS_OBJ, CLASS_OBJ, null, null, null, + new ByteArrayInputStream(outstr.toByteArray())); + assertEquals(obj1.toString(), obj2.toString()); + } + + @Test + public void testWriteTo_DifferentTypes() throws Exception { + ByteArrayOutputStream outstr = new ByteArrayOutputStream(); + + // use a derived type, but specify the base type when writing + MyObject obj1 = new DerivedObject(10); + hdlr.writeTo(obj1, obj1.getClass(), CLASS_OBJ, null, null, null, outstr); + + Object obj2 = hdlr.readFrom(CLASS_OBJ, CLASS_OBJ, null, null, null, + new ByteArrayInputStream(outstr.toByteArray())); + assertEquals(obj1.toString(), obj2.toString()); + } + + @Test + public void testWriteTo_Ex() throws Exception { + OutputStream outstr = new OutputStream() { + @Override + public void write(int value) throws IOException { + throw new IOException(EXPECTED_EXCEPTION); + } + }; + + MyObject obj1 = new MyObject(10); + + assertThatThrownBy(() -> hdlr.writeTo(obj1, obj1.getClass(), CLASS_OBJ, null, null, null, outstr)) + .isInstanceOf(IOException.class); + + outstr.close(); + } + + @Test + public void testIsReadable() { + for (String subtype : subtypes) { + assertTrue("readable " + subtype, hdlr.isReadable(null, null, null, new MediaType(GEN_TYPE, subtype))); + + } + + // the remaining should be FALSE + + // null media type + assertFalse(hdlr.isReadable(null, null, null, null)); + + // null subtype + assertFalse(hdlr.isReadable(null, null, null, new MediaType(GEN_TYPE, null))); + + // text subtype + assertFalse(hdlr.isReadable(null, null, null, MediaType.TEXT_HTML_TYPE)); + } + + @Test + public void testReadFrom_DifferentTypes() throws Exception { + ByteArrayOutputStream outstr = new ByteArrayOutputStream(); + MyObject obj1 = new MyObject(10); + hdlr.writeTo(obj1, obj1.getClass(), CLASS_OBJ, null, null, null, outstr); + + // use a derived type, but specify the base type when reading + @SuppressWarnings("rawtypes") + Class clazz = DerivedObject.class; + + @SuppressWarnings("unchecked") + Class objclazz = clazz; + + Object obj2 = hdlr.readFrom(objclazz, CLASS_OBJ, null, null, null, + new ByteArrayInputStream(outstr.toByteArray())); + assertEquals(obj1.toString(), obj2.toString()); + } + + @Test + public void testReadFrom_Ex() throws Exception { + InputStream inpstr = new InputStream() { + @Override + public int read() throws IOException { + throw new IOException(EXPECTED_EXCEPTION); + } + }; + + assertThatThrownBy(() -> hdlr.readFrom(CLASS_OBJ, CLASS_OBJ, null, null, null, inpstr)) + .isInstanceOf(IOException.class); + + inpstr.close(); + } + + @Test + public void testMapDouble() throws Exception { + MyMap map = new MyMap(); + map.props = new HashMap<>(); + map.props.put("plainString", "def"); + map.props.put("negInt", -10); + map.props.put("doubleVal", 12.5); + map.props.put("posLong", 100000000000L); + + ByteArrayOutputStream outstr = new ByteArrayOutputStream(); + hdlr.writeTo(map, map.getClass(), map.getClass(), null, null, null, outstr); + + Object obj2 = hdlr.readFrom(Object.class, map.getClass(), null, null, null, + new ByteArrayInputStream(outstr.toByteArray())); + assertEquals(map.toString(), obj2.toString()); + + map = (MyMap) obj2; + + assertEquals(-10, map.props.get("negInt")); + assertEquals(100000000000L, map.props.get("posLong")); + assertEquals(12.5, map.props.get("doubleVal")); + } + + public static class DerivedObject extends MyObject { + public DerivedObject(int id) { + super(id); + } + } + + public static class MyObject { + private int id; + + public MyObject() { + super(); + } + + public MyObject(int id) { + this.id = id; + } + + @Override + public String toString() { + return "MyObject [id=" + id + "]"; + } + } + + private static class MyMap { + private Map props; + + @Override + public String toString() { + return props.toString(); + } + } +} -- cgit 1.2.3-korg