aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Hahn <jrh3@att.com>2018-09-13 12:40:37 -0400
committerJim Hahn <jrh3@att.com>2018-09-14 15:14:44 -0400
commit29dd6526f2a86a312578a9ee5d743e8150eacd97 (patch)
tree27ad9156366876c716572d5cef694caa17f9d0f8
parent6d8ab316a635f15816d202b3cc7bdccca67c867e (diff)
add more junit coverage to new Serializer class
Removed calls to superclass methods so that appropriate exceptions are thrown. Better comments for new tests. Removed @Ignore from tests. Removed tabs from pom. Change-Id: I97fa63951eed4c2ac5ce0a267d8da5134a2a1c71 Issue-ID: POLICY-1106 Signed-off-by: Jim Hahn <jrh3@att.com>
-rw-r--r--utils-test/pom.xml144
-rw-r--r--utils-test/src/main/java/org/onap/policy/common/utils/io/Serializer.java64
-rw-r--r--utils-test/src/test/java/org/onap/policy/common/utils/io/SerializerTest.java280
3 files changed, 410 insertions, 78 deletions
diff --git a/utils-test/pom.xml b/utils-test/pom.xml
index 933104b0..c87da916 100644
--- a/utils-test/pom.xml
+++ b/utils-test/pom.xml
@@ -7,9 +7,9 @@
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.
@@ -19,70 +19,80 @@
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.onap.policy.common</groupId>
- <artifactId>common-modules</artifactId>
- <version>1.3.0-SNAPSHOT</version>
- </parent>
-
- <artifactId>utils-test</artifactId>
- <description>Common Utilities to facilitate testing via JUnit</description>
- <packaging>jar</packaging>
-
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- </dependency>
- <dependency>
- <groupId>org.onap.policy.common</groupId>
- <artifactId>utils</artifactId>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onap.policy.common</groupId>
+ <artifactId>common-modules</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>utils-test</artifactId>
+ <description>Common Utilities to facilitate testing via JUnit</description>
+ <packaging>jar</packaging>
+
+ <properties>
+ <powermock.version>1.6.6</powermock.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.common</groupId>
+ <artifactId>utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.powermock</groupId>
+ <artifactId>powermock-api-mockito</artifactId>
+ <version>${powermock.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
- <build>
- <pluginManagement>
- <plugins>
- <!--This plugin's configuration is used to store Eclipse m2e settings
- only. It has no influence on the Maven build itself. -->
- <plugin>
- <groupId>org.eclipse.m2e</groupId>
- <artifactId>lifecycle-mapping</artifactId>
- <version>1.0.0</version>
- <configuration>
- <lifecycleMappingMetadata>
- <pluginExecutions>
- <pluginExecution>
- <pluginExecutionFilter>
- <groupId>org.jacoco</groupId>
- <artifactId>
- jacoco-maven-plugin
- </artifactId>
- <versionRange>
- [0.7.1.201405082137,)
- </versionRange>
- <goals>
- <goal>prepare-agent</goal>
- </goals>
- </pluginExecutionFilter>
- <action>
- <ignore></ignore>
- </action>
- </pluginExecution>
- </pluginExecutions>
- </lifecycleMappingMetadata>
- </configuration>
- </plugin>
- </plugins>
- </pluginManagement>
- </build>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven
+ build itself. -->
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.jacoco</groupId>
+ <artifactId>
+ jacoco-maven-plugin
+ </artifactId>
+ <versionRange>
+ [0.7.1.201405082137,)
+ </versionRange>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore></ignore>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
</project>
diff --git a/utils-test/src/main/java/org/onap/policy/common/utils/io/Serializer.java b/utils-test/src/main/java/org/onap/policy/common/utils/io/Serializer.java
index 740aad47..227b810a 100644
--- a/utils-test/src/main/java/org/onap/policy/common/utils/io/Serializer.java
+++ b/utils-test/src/main/java/org/onap/policy/common/utils/io/Serializer.java
@@ -32,6 +32,11 @@ import java.io.ObjectOutputStream;
public class Serializer {
/**
+ * Factory to access various objects. May be overridden for junit tests.
+ */
+ private static Factory factory = new Factory();
+
+ /**
* The constructor.
*/
private Serializer() {
@@ -40,15 +45,20 @@ public class Serializer {
/**
* Serializes an object into a byte array.
- *
+ *
* @param object the object to be serialized
* @return the byte array containing the serialized object
* @throws IOException if an error occurs
*/
public static <T> byte[] serialize(T object) throws IOException {
- try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
- try (ObjectOutputStream oos = new ObjectOutputStream(out)) {
- oos.writeObject(object);
+ try (ByteArrayOutputStream out = factory.makeByteArrayOutputStream()) {
+ try (ObjectOutputStream oos = factory.makeObjectOutputStream(out)) {
+ /*
+ * writeObject() is final and mockito can't mock final methods. In
+ * addition, powermock seemed to be having difficulty with the junit test
+ * class as well, so we'll just do it with a factory method.
+ */
+ factory.writeObject(object, oos);
}
return out.toByteArray();
@@ -57,7 +67,7 @@ public class Serializer {
/**
* De-serializes an object from a byte array.
- *
+ *
* @param clazz class of object that is expected to be de-serialized
* @param data the byte array containing the serialized object
* @return the object that was de-serialized from the byte array
@@ -65,9 +75,14 @@ public class Serializer {
*/
public static <T> T deserialize(Class<T> clazz, byte[] data) throws IOException {
- try (ByteArrayInputStream in = new ByteArrayInputStream(data);
- ObjectInputStream ois = new ObjectInputStream(in)) {
- return clazz.cast(ois.readObject());
+ try (ByteArrayInputStream in = factory.makeByteArrayInputStream(data);
+ ObjectInputStream ois = factory.makeObjectInputStream(in)) {
+ /*
+ * readObject() is final and mockito can't mock final methods. In addition,
+ * powermock seemed to be having difficulty with the junit test class as well,
+ * so we'll just do it with a factory method.
+ */
+ return clazz.cast(factory.readObject(ois));
} catch (ClassNotFoundException e) {
throw new IOException(e);
@@ -77,7 +92,7 @@ public class Serializer {
/**
* Runs an object through a complete round trip, serializing and then de-serializing
* it.
- *
+ *
* @param object object to be serialized
* @return the object that was de-serialized
* @throws IOException if an error occurs
@@ -86,4 +101,35 @@ public class Serializer {
public static <T> T roundTrip(T object) throws IOException {
return (T) deserialize(object.getClass(), serialize(object));
}
+
+ /**
+ * Factory to access various objects.
+ */
+ public static class Factory {
+
+ public ByteArrayOutputStream makeByteArrayOutputStream() {
+ return new ByteArrayOutputStream();
+ }
+
+ public ByteArrayInputStream makeByteArrayInputStream(byte[] data) {
+ return new ByteArrayInputStream(data);
+ }
+
+ public ObjectOutputStream makeObjectOutputStream(ByteArrayOutputStream out) throws IOException {
+ return new ObjectOutputStream(out);
+ }
+
+ public ObjectInputStream makeObjectInputStream(ByteArrayInputStream in) throws IOException {
+ return new ObjectInputStream(in);
+ }
+
+ public void writeObject(Object object, ObjectOutputStream oos) throws IOException {
+ oos.writeObject(object);
+ }
+
+ public Object readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ return ois.readObject();
+ }
+
+ }
}
diff --git a/utils-test/src/test/java/org/onap/policy/common/utils/io/SerializerTest.java b/utils-test/src/test/java/org/onap/policy/common/utils/io/SerializerTest.java
index 4d4385fc..bdf0dba9 100644
--- a/utils-test/src/test/java/org/onap/policy/common/utils/io/SerializerTest.java
+++ b/utils-test/src/test/java/org/onap/policy/common/utils/io/SerializerTest.java
@@ -7,9 +7,9 @@
* 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.
@@ -21,14 +21,52 @@
package org.onap.policy.common.utils.io;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
+import org.onap.policy.common.utils.io.Serializer.Factory;
+import org.powermock.reflect.Whitebox;
public class SerializerTest {
+ /**
+ * Saved and restored when tests complete. Also restored at the start of each test.
+ */
+ private static Factory saveFactory;
+
+ @BeforeClass
+ public static void setUpBeforeClass() {
+ saveFactory = Whitebox.getInternalState(Serializer.class, "factory");
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() {
+ Whitebox.setInternalState(Serializer.class, "factory", saveFactory);
+ }
+
+ @Before
+ public void setUp() {
+ setFactory(saveFactory);
+ }
+
+ @Test
+ public void testFactory() {
+ assertNotNull(saveFactory);
+ }
+
@Test
public void testSerialize() throws Exception {
MyObject obj1 = new MyObject(3);
@@ -48,6 +86,83 @@ public class SerializerTest {
}
@Test
+ public void testSerialize_ArrayCloseEx() throws Exception {
+ IOException ex = new IOException("testSerialize_ArrayCloseEx");
+
+ /*
+ * This stream will throw an exception when close() is invoked. However, close()
+ * is called twice, once by the ObjectOutputStream and once by the code we want to
+ * test. As a result, we'll have the first close() succeed and the second one
+ * fail.
+ */
+ ByteArrayOutputStream out = new ByteArrayOutputStream() {
+ private int nclose = 0;
+
+ @Override
+ public void close() throws IOException {
+ if (++nclose > 1) {
+ throw ex;
+ }
+ }
+ };
+
+ /*
+ * Use a factory that returns our special stream.
+ */
+ setFactory(new Factory() {
+ @Override
+ public ByteArrayOutputStream makeByteArrayOutputStream() {
+ return out;
+ }
+ });
+
+ assertEquals(ex, expectException(() -> Serializer.serialize(new MyObject(100))));
+ }
+
+ @Test
+ public void testSerialize_ObjectWriteEx() throws Exception {
+ IOException ex = new IOException("testSerialize_ObjectWriteEx");
+
+ /*
+ * Use a factory that throws an exception when writeObject() is invoked.
+ */
+ setFactory(new Factory() {
+ @Override
+ public void writeObject(Object object, ObjectOutputStream oos) throws IOException {
+ throw ex;
+ }
+ });
+
+ assertEquals(ex, expectException(() -> Serializer.serialize(new MyObject(110))));
+ }
+
+ @Test
+ public void testSerialize_ObjectCloseEx() throws Exception {
+ IOException ex = new IOException("testSerialize_ObjectCloseEx");
+ ObjectOutputStream oos = mock(ObjectOutputStream.class);
+ doThrow(ex).when(oos).close();
+
+ /*
+ * Use a factory that returns the mocked object which throws an exception when
+ * close() is invoked. However, we also have to override writeObject() so that it
+ * succeeds even through we're using a mock.
+ */
+ setFactory(new Factory() {
+ @Override
+ public ObjectOutputStream makeObjectOutputStream(ByteArrayOutputStream out) throws IOException {
+ return oos;
+ }
+
+ @Override
+ public void writeObject(Object object, ObjectOutputStream oos) throws IOException {
+ return;
+ }
+ });
+
+ assertEquals(ex, expectException(() -> Serializer.serialize(new MyObject(120))));
+ }
+
+ @Test
public void testDeserialize() throws Exception {
MyObject obj1 = new MyObject(3);
byte[] data = Serializer.serialize(obj1);
@@ -57,6 +172,136 @@ public class SerializerTest {
}
@Test
+ public void testDeserialize_ArrayCloseEx() throws Exception {
+ IOException ex = new IOException("testSerialize_ObjectWriteEx");
+
+ /*
+ * Use a factory that returns a stream that will throw an exception when close()
+ * is invoked. However, close() is called twice, once by the ObjectInputStream and
+ * once by the code we want to test. As a result, we'll have the first close()
+ * succeed and the second one fail.
+ */
+ setFactory(new Factory() {
+ @Override
+ public ByteArrayInputStream makeByteArrayInputStream(byte[] data) {
+ return new ByteArrayInputStream(data) {
+ private int nclose = 0;
+
+ @Override
+ public void close() throws IOException {
+ if (++nclose > 1) {
+ throw ex;
+ }
+ }
+ };
+ }
+ });
+
+ byte[] data = Serializer.serialize(new MyObject(300));
+ assertEquals(ex, expectException(() -> Serializer.deserialize(MyObject.class, data)));
+ }
+
+ @Test
+ public void testDeserialize_ObjectReadClassEx() throws Exception {
+ ClassNotFoundException ex = new ClassNotFoundException("testDeserialize_ObjectReadClassEx");
+
+ /*
+ * Use a factory that throws a ClassNotFoundException when readObject() is
+ * invoked.
+ */
+ setFactory(new Factory() {
+ @Override
+ public Object readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ throw ex;
+ }
+ });
+
+ byte[] data = Serializer.serialize(new MyObject(305));
+
+ Exception exwrap = expectException(() -> Serializer.deserialize(MyObject.class, data));
+ assertTrue(exwrap instanceof IOException);
+ assertNotNull(exwrap.getCause());
+ assertEquals(ex, exwrap.getCause());
+ }
+
+ @Test
+ public void testDeserialize_ObjectReadEx() throws Exception {
+ IOException ex = new IOException("testDeserialize_ObjectReadEx");
+
+ /*
+ * Use a factory that throws an IOException when readObject() is invoked.
+ */
+ setFactory(new Factory() {
+ @Override
+ public Object readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ throw ex;
+ }
+ });
+
+ byte[] data = Serializer.serialize(new MyObject(310));
+ assertEquals(ex, expectException(() -> Serializer.deserialize(MyObject.class, data)));
+ }
+
+ @Test
+ public void testDeserialize_ObjectCloseEx() throws Exception {
+ IOException ex = new IOException("testDeserialize_ObjectCloseEx");
+
+ /*
+ * Use a factory that returns an ObjectInputStream that throws an exception when
+ * close() is invoked.
+ */
+ setFactory(new Factory() {
+ @Override
+ public ObjectInputStream makeObjectInputStream(ByteArrayInputStream in) throws IOException {
+ return new ObjectInputStream(in) {
+ @Override
+ public void close() throws IOException {
+ throw ex;
+ }
+ };
+ }
+ });
+
+ byte[] data = Serializer.serialize(new MyObject(320));
+ assertEquals(ex, expectException(() -> Serializer.deserialize(MyObject.class, data)));
+ }
+
+ @Test
+ public void testDeserialize_BothCloseEx() throws Exception {
+ IOException ex = new IOException("testDeserialize_BothCloseEx");
+ IOException ex2 = new IOException("testDeserialize_BothCloseEx_2");
+
+ /*
+ * Use a factory that returns input streams, both of which throw exceptions when
+ * close() is invoked.
+ */
+ setFactory(new Factory() {
+ @Override
+ public ByteArrayInputStream makeByteArrayInputStream(byte[] data) {
+ return new ByteArrayInputStream(data) {
+ @Override
+ public void close() throws IOException {
+ throw ex;
+ }
+ };
+ }
+
+ @Override
+ public ObjectInputStream makeObjectInputStream(ByteArrayInputStream in) throws IOException {
+ return new ObjectInputStream(in) {
+ @Override
+ public void close() throws IOException {
+ throw ex2;
+ }
+ };
+ }
+ });
+
+ byte[] data = Serializer.serialize(new MyObject(330));
+ assertEquals(ex2, expectException(() -> Serializer.deserialize(MyObject.class, data)));
+ }
+
+ @Test
public void testRoundTrip() throws Exception {
MyObject obj1 = new MyObject(3);
@@ -70,6 +315,37 @@ public class SerializerTest {
}
/**
+ * Sets a new factory in the Serializer.
+ *
+ * @param factory new factory to be set
+ */
+ private void setFactory(Factory factory) {
+ Whitebox.setInternalState(Serializer.class, "factory", factory);
+ }
+
+ /**
+ * Applies a function, which is expected to throw an exception.
+ *
+ * @param func the function to apply
+ * @return the exception thrown by the function, or {@code null} if it did not throw
+ * an exception
+ */
+ private Exception expectException(RunnerWithEx func) {
+ try {
+ func.apply();
+ return null;
+
+ } catch (Exception ex) {
+ return ex;
+ }
+ }
+
+ @FunctionalInterface
+ private static interface RunnerWithEx {
+ public void apply() throws Exception;
+ }
+
+ /**
* Simple, serializable object.
*/
public static class MyObject implements Serializable {