1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.compatibility.common.tradefed.testtype; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertTrue; 20 import static org.junit.Assert.fail; 21 22 import com.android.tradefed.build.DeviceBuildInfo; 23 import com.android.tradefed.config.OptionSetter; 24 import com.android.tradefed.invoker.ExecutionFiles.FilesKey; 25 import com.android.tradefed.invoker.TestInformation; 26 import com.android.tradefed.log.LogUtil.CLog; 27 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 28 import com.android.tradefed.result.ITestInvocationListener; 29 import com.android.tradefed.result.TestDescription; 30 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics; 31 import com.android.tradefed.testtype.HostTest; 32 import com.android.tradefed.testtype.IRemoteTest; 33 import com.android.tradefed.util.FileUtil; 34 import com.android.tradefed.util.proto.TfMetricProtoUtil; 35 36 import org.easymock.EasyMock; 37 import org.junit.After; 38 import org.junit.Before; 39 import org.junit.Rule; 40 import org.junit.Test; 41 import org.junit.runner.RunWith; 42 import org.junit.runners.JUnit4; 43 44 import java.io.File; 45 import java.io.IOException; 46 import java.io.InputStream; 47 import java.net.MalformedURLException; 48 import java.net.URL; 49 import java.net.URLClassLoader; 50 import java.util.Arrays; 51 import java.util.HashMap; 52 import java.util.List; 53 import java.util.Map; 54 55 /** 56 * Unit tests for {@link JarHostTest}. 57 */ 58 @RunWith(JUnit4.class) 59 public class JarHostTestTest { 60 61 private static final String TEST_JAR1 = "/testtype/testJar1.jar"; 62 private JarHostTest mTest; 63 private DeviceBuildInfo mStubBuildInfo; 64 private TestInformation mTestInfo; 65 private File mTestDir = null; 66 private ITestInvocationListener mListener; 67 68 /** 69 * More testable version of {@link JarHostTest} 70 */ 71 public static class JarHostTestable extends JarHostTest { 72 73 public static File mTestDir; JarHostTestable()74 public JarHostTestable() {} 75 JarHostTestable(File testDir)76 public JarHostTestable(File testDir) { 77 mTestDir = testDir; 78 } 79 } 80 81 @Before setUp()82 public void setUp() throws Exception { 83 mTest = new JarHostTest(); 84 mTestDir = FileUtil.createTempDir("jarhostest"); 85 mListener = EasyMock.createMock(ITestInvocationListener.class); 86 OptionSetter setter = new OptionSetter(mTest); 87 setter.setOptionValue("enable-pretty-logs", "false"); 88 mStubBuildInfo = new DeviceBuildInfo(); 89 mStubBuildInfo.setTestsDir(mTestDir, "v1"); 90 mTestInfo = TestInformation.newBuilder().build(); 91 mTestInfo.executionFiles().put(FilesKey.TESTS_DIRECTORY, mTestDir); 92 } 93 94 @After tearDown()95 public void tearDown() throws Exception { 96 FileUtil.recursiveDelete(mTestDir); 97 } 98 99 /** 100 * Helper to read a file from the res/testtype directory and return it. 101 * 102 * @param filename the name of the file in the res/testtype directory 103 * @param parentDir dir where to put the jar. Null if in default tmp directory. 104 * @return the extracted jar file. 105 */ getJarResource(String filename, File parentDir)106 protected File getJarResource(String filename, File parentDir) throws IOException { 107 InputStream jarFileStream = getClass().getResourceAsStream(filename); 108 File jarFile = FileUtil.createTempFile("test", ".jar", parentDir); 109 FileUtil.writeToFile(jarFileStream, jarFile); 110 return jarFile; 111 } 112 113 /** 114 * Test class, we have to annotate with full org.junit.Test to avoid name collision in import. 115 */ 116 @RunWith(JUnit4.class) 117 public static class Junit4TestClass { Junit4TestClass()118 public Junit4TestClass() {} 119 @org.junit.Test testPass1()120 public void testPass1() {} 121 } 122 123 /** 124 * Test class, we have to annotate with full org.junit.Test to avoid name collision in import. 125 */ 126 @RunWith(JUnit4.class) 127 public static class Junit4TestClass2 { Junit4TestClass2()128 public Junit4TestClass2() {} 129 @Rule public TestMetrics metrics = new TestMetrics(); 130 131 @org.junit.Test testPass2()132 public void testPass2() { 133 metrics.addTestMetric("key", "value"); 134 } 135 } 136 137 /** 138 * Test that {@link JarHostTest#split()} inherited from {@link HostTest} is still good. 139 */ 140 @Test testSplit_withoutJar()141 public void testSplit_withoutJar() throws Exception { 142 OptionSetter setter = new OptionSetter(mTest); 143 setter.setOptionValue("class", "com.android.compatibility.common.tradefed.testtype." 144 + "JarHostTestTest$Junit4TestClass"); 145 setter.setOptionValue("class", "com.android.compatibility.common.tradefed.testtype." 146 + "JarHostTestTest$Junit4TestClass2"); 147 // sharCount is ignored; will split by number of classes 148 List<IRemoteTest> res = (List<IRemoteTest>) mTest.split(1, mTestInfo); 149 assertEquals(2, res.size()); 150 assertTrue(res.get(0) instanceof JarHostTest); 151 assertTrue(res.get(1) instanceof JarHostTest); 152 } 153 154 /** 155 * Test that {@link JarHostTest#split()} can split classes coming from a jar. 156 */ 157 @Test testSplit_withJar()158 public void testSplit_withJar() throws Exception { 159 File testJar = getJarResource(TEST_JAR1, mTestDir); 160 mTest = new JarHostTestable(mTestDir); 161 mTest.setBuild(mStubBuildInfo); 162 OptionSetter setter = new OptionSetter(mTest); 163 setter.setOptionValue("enable-pretty-logs", "false"); 164 setter.setOptionValue("jar", testJar.getName()); 165 // sharCount is ignored; will split by number of classes 166 List<IRemoteTest> res = (List<IRemoteTest>) mTest.split(1, mTestInfo); 167 assertEquals(2, res.size()); 168 assertTrue(res.get(0) instanceof JarHostTest); 169 assertEquals("[android.ui.cts.TaskSwitchingTest]", 170 ((JarHostTest)res.get(0)).getClassNames().toString()); 171 assertTrue(res.get(1) instanceof JarHostTest); 172 assertEquals("[android.ui.cts.InstallTimeTest]", 173 ((JarHostTest)res.get(1)).getClassNames().toString()); 174 } 175 176 /** 177 * Testable version of {@link JarHostTest} that allows adding jar to classpath for testing 178 * purpose. 179 */ 180 public static class JarHostTestLoader extends JarHostTestable { 181 182 private static File mTestJar; 183 JarHostTestLoader()184 public JarHostTestLoader() {} 185 JarHostTestLoader(File testDir, File jar)186 public JarHostTestLoader(File testDir, File jar) { 187 super(testDir); 188 mTestJar = jar; 189 } 190 191 @Override getClassLoader()192 protected ClassLoader getClassLoader() { 193 ClassLoader child = super.getClassLoader(); 194 try { 195 child = new URLClassLoader(Arrays.asList(mTestJar.toURI().toURL()) 196 .toArray(new URL[]{}), super.getClassLoader()); 197 } catch (MalformedURLException e) { 198 CLog.e(e); 199 } 200 return child; 201 } 202 } 203 204 /** 205 * If a jar file is not found, the countTest will fail but we still want to report a 206 * testRunStart and End pair for results. 207 */ 208 @Test testCountTestFails()209 public void testCountTestFails() throws Exception { 210 OptionSetter setter = new OptionSetter(mTest); 211 setter.setOptionValue("jar", "thisjardoesnotexistatall.jar"); 212 mListener.testRunStarted(EasyMock.anyObject(), EasyMock.eq(0)); 213 mListener.testRunEnded(EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject()); 214 EasyMock.replay(mListener); 215 try { 216 mTest.run(mTestInfo, mListener); 217 fail("Should have thrown an exception."); 218 } catch(RuntimeException expected) { 219 // expected 220 } 221 EasyMock.verify(mListener); 222 } 223 224 /** 225 * Test that metrics from tests in JarHost are reported and accounted for. 226 */ 227 @Test testJarHostMetrics()228 public void testJarHostMetrics() throws Exception { 229 OptionSetter setter = new OptionSetter(mTest); 230 setter.setOptionValue("class", "com.android.compatibility.common.tradefed.testtype." 231 + "JarHostTestTest$Junit4TestClass2"); 232 mListener.testRunStarted(EasyMock.anyObject(), EasyMock.eq(1)); 233 TestDescription tid = new TestDescription("com.android.compatibility.common.tradefed." 234 + "testtype.JarHostTestTest$Junit4TestClass2", "testPass2"); 235 mListener.testStarted(EasyMock.eq(tid), EasyMock.anyLong()); 236 Map<String, String> metrics = new HashMap<>(); 237 metrics.put("key", "value"); 238 mListener.testEnded(EasyMock.eq(tid), EasyMock.anyLong(), 239 EasyMock.eq(TfMetricProtoUtil.upgradeConvert(metrics))); 240 mListener.testRunEnded(EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject()); 241 EasyMock.replay(mListener); 242 mTest.run(mTestInfo, mListener); 243 EasyMock.verify(mListener); 244 } 245 } 246