diff options
author | Julien Desprez <jdesprez@google.com> | 2017-06-19 19:05:26 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-06-19 19:05:27 +0000 |
commit | d96fa8d2f5676a2576e5152317e8837a93942dd1 (patch) | |
tree | 34eee5ac924cb82d49b517e9ea9eb8f070c44910 | |
parent | 3ebf8320cf4513d07bd67f51f11b5d409500dea2 (diff) | |
parent | 265766c7ac8bf5ede81dde1e1f833267cfa4cd25 (diff) | |
download | tradefederation-d96fa8d2f5676a2576e5152317e8837a93942dd1.tar.gz |
Merge "Make IBuildInfo serializable" into oc-dev
8 files changed, 261 insertions, 14 deletions
diff --git a/src/com/android/tradefed/build/IBuildInfo.java b/src/com/android/tradefed/build/IBuildInfo.java index 385e1bf75..f88e443e4 100644 --- a/src/com/android/tradefed/build/IBuildInfo.java +++ b/src/com/android/tradefed/build/IBuildInfo.java @@ -18,13 +18,12 @@ package com.android.tradefed.build; import com.android.tradefed.device.ITestDevice; import java.io.File; +import java.io.Serializable; import java.util.Collection; import java.util.Map; -/** - * Holds information about the build under test. - */ -public interface IBuildInfo { +/** Holds information about the build under test. */ +public interface IBuildInfo extends Serializable { /** * Default value when build ID is unknown. diff --git a/src/com/android/tradefed/build/VersionedFile.java b/src/com/android/tradefed/build/VersionedFile.java index 24bd031ad..2c71b07d4 100644 --- a/src/com/android/tradefed/build/VersionedFile.java +++ b/src/com/android/tradefed/build/VersionedFile.java @@ -16,11 +16,10 @@ package com.android.tradefed.build; import java.io.File; +import java.io.Serializable; -/** - * Data structure representing a file that has an associated version. - */ -public class VersionedFile { +/** Data structure representing a file that has an associated version. */ +public class VersionedFile implements Serializable { private final File mFile; private final String mVersion; diff --git a/src/com/android/tradefed/util/MultiMap.java b/src/com/android/tradefed/util/MultiMap.java index 16517bb48..1123e6d64 100644 --- a/src/com/android/tradefed/util/MultiMap.java +++ b/src/com/android/tradefed/util/MultiMap.java @@ -17,16 +17,15 @@ package com.android.tradefed.util; import com.google.common.base.Objects; +import java.io.Serializable; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; -/** - * A {@link Map} that supports multiple values per key. - */ -public class MultiMap<K, V> { +/** A {@link Map} that supports multiple values per key. */ +public class MultiMap<K, V> implements Serializable { private final Map<K, List<V>> mInternalMap; diff --git a/src/com/android/tradefed/util/SerializationUtil.java b/src/com/android/tradefed/util/SerializationUtil.java new file mode 100644 index 000000000..0c991fffd --- /dev/null +++ b/src/com/android/tradefed/util/SerializationUtil.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ +package com.android.tradefed.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** Utility to serialize/deserialize an object that implements {@link Serializable}. */ +public class SerializationUtil { + + /** + * Serialize a object that implements {@link Serializable}. + * + * @param o the object to serialize. + * @return the {@link File} where the object was serialized. + * @throws IOException if serialization fails. + */ + public static File serialize(Serializable o) throws IOException { + File tmpSerialized = FileUtil.createTempFile("serial-util", ".ser"); + FileOutputStream fileOut = null; + ObjectOutputStream out = null; + try { + fileOut = new FileOutputStream(tmpSerialized); + out = new ObjectOutputStream(fileOut); + out.writeObject(o); + } catch (IOException e) { + // catch in order to clean up the tmp file. + FileUtil.deleteFile(tmpSerialized); + throw e; + } finally { + StreamUtil.close(out); + StreamUtil.close(fileOut); + } + return tmpSerialized; + } + + /** + * Deserialize an object that was serialized using {@link #serialize(Serializable)}. + * + * @param serializedFile the file where the object was serialized. + * @param deleteFile true if the serialized file should be deleted once deserialized. + * @return the Object deserialized. + * @throws IOException if the deserialization fails. + */ + public static Object deserialize(File serializedFile, boolean deleteFile) throws IOException { + FileInputStream fileIn = null; + ObjectInputStream in = null; + try { + fileIn = new FileInputStream(serializedFile); + in = new ObjectInputStream(fileIn); + return in.readObject(); + } catch (ClassNotFoundException cnfe) { + throw new RuntimeException(cnfe); + } finally { + StreamUtil.close(in); + StreamUtil.close(fileIn); + if (deleteFile) { + FileUtil.deleteFile(serializedFile); + } + } + } +} diff --git a/tests/src/com/android/tradefed/UnitTests.java b/tests/src/com/android/tradefed/UnitTests.java index 8f064a311..a30198576 100644 --- a/tests/src/com/android/tradefed/UnitTests.java +++ b/tests/src/com/android/tradefed/UnitTests.java @@ -186,6 +186,7 @@ import com.android.tradefed.util.PsParserTest; import com.android.tradefed.util.QuotationAwareTokenizerTest; import com.android.tradefed.util.RegexTrieTest; import com.android.tradefed.util.RunUtilTest; +import com.android.tradefed.util.SerializationUtilTest; import com.android.tradefed.util.SimplePerfStatResultParserTest; import com.android.tradefed.util.SimplePerfUtilTest; import com.android.tradefed.util.SimpleStatsTest; @@ -430,6 +431,7 @@ import org.junit.runners.Suite.SuiteClasses; QuotationAwareTokenizerTest.class, RegexTrieTest.class, RunUtilTest.class, + SerializationUtilTest.class, SimplePerfStatResultParserTest.class, SimplePerfUtilTest.class, SimpleStatsTest.class, diff --git a/tests/src/com/android/tradefed/build/BuildInfoTest.java b/tests/src/com/android/tradefed/build/BuildInfoTest.java index ad5b4e817..3a23d3c5a 100644 --- a/tests/src/com/android/tradefed/build/BuildInfoTest.java +++ b/tests/src/com/android/tradefed/build/BuildInfoTest.java @@ -15,9 +15,13 @@ */ package com.android.tradefed.build; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import com.android.tradefed.util.FileUtil; +import com.android.tradefed.util.SerializationUtil; import org.junit.After; import org.junit.Before; @@ -98,4 +102,18 @@ public class BuildInfoTest { + "build_flavor=testFlavor, branch=testBranch, serial=fakeSerial}"; assertEquals(expected, mBuildInfo.toString()); } + + /** + * Test that all the components of {@link BuildInfo} can be serialized via the default java + * object serialization. + */ + @Test + public void testSerialization() throws Exception { + File tmpSerialized = SerializationUtil.serialize(mBuildInfo); + Object o = SerializationUtil.deserialize(tmpSerialized, true); + assertTrue(o instanceof BuildInfo); + BuildInfo test = (BuildInfo) o; + // use the custom build info equals to check similar properties + assertTrue(mBuildInfo.equals(test)); + } } diff --git a/tests/src/com/android/tradefed/build/DeviceFolderBuildInfoTest.java b/tests/src/com/android/tradefed/build/DeviceFolderBuildInfoTest.java index b21d261ad..fb8c7dfa8 100644 --- a/tests/src/com/android/tradefed/build/DeviceFolderBuildInfoTest.java +++ b/tests/src/com/android/tradefed/build/DeviceFolderBuildInfoTest.java @@ -15,9 +15,11 @@ */ package com.android.tradefed.build; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import com.android.tradefed.util.FileUtil; +import com.android.tradefed.util.SerializationUtil; import org.junit.After; import org.junit.Before; @@ -90,4 +92,24 @@ public class DeviceFolderBuildInfoTest { assertEquals(1, files.size()); assertTrue(hasFile(files, "img-version")); } + + /** + * Test that all the components of {@link DeviceFolderBuildInfo} can be serialized via the + * default java object serialization. + */ + @Test + public void testSerialization() throws Exception { + DeviceBuildInfo deviceBuildInfo = new DeviceBuildInfo(); + deviceBuildInfo.setDeviceImageFile(new File("fake"), "version 32"); + mDeviceFolderBuildInfo.setDeviceBuild(deviceBuildInfo); + File tmpSerialized = SerializationUtil.serialize(mDeviceFolderBuildInfo); + Object o = SerializationUtil.deserialize(tmpSerialized, true); + assertTrue(o instanceof DeviceFolderBuildInfo); + DeviceFolderBuildInfo test = (DeviceFolderBuildInfo) o; + // use the custom build info equals to check similar properties + assertTrue(mDeviceFolderBuildInfo.equals(test)); + // Both sub-build properties have been copied. + assertEquals("version 32", mDeviceFolderBuildInfo.getDeviceBuildId()); + assertEquals("version 32", test.getDeviceBuildId()); + } } diff --git a/tests/src/com/android/tradefed/util/SerializationUtilTest.java b/tests/src/com/android/tradefed/util/SerializationUtilTest.java new file mode 100644 index 000000000..f992069aa --- /dev/null +++ b/tests/src/com/android/tradefed/util/SerializationUtilTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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. + */ +package com.android.tradefed.util; + +import static org.junit.Assert.*; + +import com.android.tradefed.build.BuildInfo; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.NotSerializableException; +import java.io.Serializable; +import java.io.StreamCorruptedException; + +/** Unit tests for {@link SerializationUtil}. */ +@RunWith(JUnit4.class) +public class SerializationUtilTest { + + /** + * Test class that implements {@link Serializable} but has an attribute that is not serializable + */ + public static class SerialTestClass implements Serializable { + public InputStream mStream; + + public SerialTestClass() { + mStream = new ByteArrayInputStream("test".getBytes()); + } + } + + /** Tests that serialization and deserialization creates a similar object from the original. */ + @Test + public void testSerialize_Deserialize() throws Exception { + BuildInfo b = new BuildInfo(); + File tmpSerialized = SerializationUtil.serialize(b); + Object o = SerializationUtil.deserialize(tmpSerialized, true); + assertTrue(o instanceof BuildInfo); + BuildInfo test = (BuildInfo) o; + // use the custom build info equals to check similar properties + assertTrue(b.equals(test)); + assertTrue(!tmpSerialized.exists()); + } + + /** + * Tests that serialization and deserialization creates a similar object from the original but + * does not delete the temporary serial file. + */ + @Test + public void testSerialize_Deserialize_noDelete() throws Exception { + BuildInfo b = new BuildInfo(); + File tmpSerialized = SerializationUtil.serialize(b); + try { + Object o = SerializationUtil.deserialize(tmpSerialized, false); + assertTrue(o instanceof BuildInfo); + BuildInfo test = (BuildInfo) o; + // use the custom build info equals to check similar properties + assertTrue(b.equals(test)); + assertTrue(tmpSerialized.exists()); + } finally { + FileUtil.deleteFile(tmpSerialized); + } + } + + /** Test {@link SerializationUtil#deserialize(File, boolean)} for a non existing file. */ + @Test + public void testDeserialize_noFile() { + try { + SerializationUtil.deserialize(new File("doesnotexists"), true); + fail("Should have thrown an exception."); + } catch (IOException expected) { + // expected + } + } + + /** + * Test {@link SerializationUtil#deserialize(File, boolean)} for a corrupted stream, it should + * throw an exception. + */ + @Test + public void testSerialize_Deserialize_corrupted() throws Exception { + BuildInfo b = new BuildInfo(); + File tmpSerialized = SerializationUtil.serialize(b); + // add some extra data + FileUtil.writeToFile("oh I am corrupted", tmpSerialized, false); + try { + SerializationUtil.deserialize(tmpSerialized, true); + fail("Should have thrown an exception."); + } catch (StreamCorruptedException expected) { + // expected + } + // the file was still deleted as expected. + assertTrue(!tmpSerialized.exists()); + } + + /** + * Test {@link SerializationUtil#serialize(Serializable)} on an object that is not serializable + * because of one of its attribute. Method should throw an exception. + */ + @Test + public void testSerialized_notSerializable() throws Exception { + SerialTestClass test = new SerialTestClass(); + try { + SerializationUtil.serialize(test); + fail("Should have thrown an exception."); + } catch (NotSerializableException expected) { + // the ByteArrayInputStream attribute is not serializable. + assertEquals("java.io.ByteArrayInputStream", expected.getMessage()); + } + } +} |