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