From 29dd6526f2a86a312578a9ee5d743e8150eacd97 Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Thu, 13 Sep 2018 12:40:37 -0400 Subject: 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 --- .../policy/common/utils/io/SerializerTest.java | 280 ++++++++++++++++++++- 1 file changed, 278 insertions(+), 2 deletions(-) (limited to 'utils-test/src/test/java') 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); @@ -47,6 +85,83 @@ public class SerializerTest { Serializer.serialize(new NotSerializable()); } + @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); @@ -56,6 +171,136 @@ public class SerializerTest { assertEquals(obj1.value, obj2.value); } + @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); @@ -69,6 +314,37 @@ public class SerializerTest { Serializer.roundTrip(new NotSerializable()); } + /** + * 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. */ -- cgit 1.2.3-korg