diff options
author | Jim Hahn <jrh3@att.com> | 2018-09-13 12:40:37 -0400 |
---|---|---|
committer | Jim Hahn <jrh3@att.com> | 2018-09-14 15:14:44 -0400 |
commit | 29dd6526f2a86a312578a9ee5d743e8150eacd97 (patch) | |
tree | 27ad9156366876c716572d5cef694caa17f9d0f8 /utils-test/src | |
parent | 6d8ab316a635f15816d202b3cc7bdccca67c867e (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>
Diffstat (limited to 'utils-test/src')
-rw-r--r-- | utils-test/src/main/java/org/onap/policy/common/utils/io/Serializer.java | 64 | ||||
-rw-r--r-- | utils-test/src/test/java/org/onap/policy/common/utils/io/SerializerTest.java | 280 |
2 files changed, 333 insertions, 11 deletions
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 { |