1 /* 2 * Copyright (C) 2015 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.tradefed.testtype; 17 18 import com.android.ddmlib.IDevice; 19 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; 20 import com.android.ddmlib.testrunner.TestIdentifier; 21 import com.android.tradefed.config.OptionSetter; 22 import com.android.tradefed.device.DeviceNotAvailableException; 23 import com.android.tradefed.device.ITestDevice; 24 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 25 import com.android.tradefed.result.ITestInvocationListener; 26 import com.android.tradefed.result.ITestLifeCycleReceiver; 27 import com.android.tradefed.util.FileUtil; 28 29 import junit.framework.TestCase; 30 31 import org.easymock.EasyMock; 32 33 import java.io.File; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.concurrent.TimeUnit; 37 38 /** 39 * Unit tests for {@link AndroidJUnitTest} 40 */ 41 public class AndroidJUnitTestTest extends TestCase { 42 43 private static final int TEST_TIMEOUT = 0; 44 private static final long SHELL_TIMEOUT = 0; 45 private static final String TEST_PACKAGE_VALUE = "com.foo"; 46 private static final TestIdentifier TEST1 = new TestIdentifier("Test", "test1"); 47 private static final TestIdentifier TEST2 = new TestIdentifier("Test", "test2"); 48 49 /** The {@link AndroidJUnitTest} under test, with all dependencies mocked out */ 50 private AndroidJUnitTest mAndroidJUnitTest; 51 52 // The mock objects. 53 private IDevice mMockIDevice; 54 private ITestDevice mMockTestDevice; 55 private IRemoteAndroidTestRunner mMockRemoteRunner; 56 private ITestInvocationListener mMockListener; 57 58 @Override 59 protected void setUp() throws Exception { 60 super.setUp(); 61 62 mMockIDevice = EasyMock.createMock(IDevice.class); 63 mMockTestDevice = EasyMock.createMock(ITestDevice.class); 64 EasyMock.expect(mMockTestDevice.getIDevice()).andStubReturn(mMockIDevice); 65 EasyMock.expect(mMockTestDevice.getSerialNumber()).andStubReturn("serial"); 66 mMockRemoteRunner = EasyMock.createMock(IRemoteAndroidTestRunner.class); 67 mMockListener = EasyMock.createMock(ITestInvocationListener.class); 68 69 mAndroidJUnitTest = new AndroidJUnitTest() { 70 @Override 71 IRemoteAndroidTestRunner createRemoteAndroidTestRunner(String packageName, 72 String runnerName, IDevice device) { 73 return mMockRemoteRunner; 74 } 75 }; 76 mAndroidJUnitTest.setPackageName(TEST_PACKAGE_VALUE); 77 mAndroidJUnitTest.setDevice(mMockTestDevice); 78 // default to no rerun, for simplicity 79 mAndroidJUnitTest.setRerunMode(false); 80 // default to no timeout for simplicity 81 mAndroidJUnitTest.setTestTimeout(TEST_TIMEOUT); 82 mAndroidJUnitTest.setShellTimeout(SHELL_TIMEOUT); 83 mMockRemoteRunner.setMaxTimeToOutputResponse(SHELL_TIMEOUT, TimeUnit.MILLISECONDS); 84 mMockRemoteRunner.setMaxTimeout(0L, TimeUnit.MILLISECONDS); 85 mMockRemoteRunner.addInstrumentationArg(InstrumentationTest.TEST_TIMEOUT_INST_ARGS_KEY, 86 Long.toString(SHELL_TIMEOUT)); 87 mMockRemoteRunner.addInstrumentationArg( 88 AndroidJUnitTest.NEW_RUN_LISTENER_ORDER_KEY, "true"); 89 } 90 91 /** 92 * Test list of tests to run is filtered by include filters. 93 */ 94 public void testRun_includeFilterClass() throws Exception { 95 // expect this call 96 mMockRemoteRunner.addInstrumentationArg("class", TEST1.toString()); 97 setRunTestExpectations(); 98 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 99 mAndroidJUnitTest.addIncludeFilter(TEST1.toString()); 100 mAndroidJUnitTest.run(mMockListener); 101 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 102 } 103 104 /** 105 * Test list of tests to run is filtered by exclude filters. 106 */ 107 public void testRun_excludeFilterClass() throws Exception { 108 // expect this call 109 mMockRemoteRunner.addInstrumentationArg("notClass", TEST1.toString()); 110 setRunTestExpectations(); 111 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 112 mAndroidJUnitTest.addExcludeFilter(TEST1.toString()); 113 mAndroidJUnitTest.run(mMockListener); 114 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 115 } 116 117 /** 118 * Test list of tests to run is filtered by include and exclude filters. 119 */ 120 public void testRun_includeAndExcludeFilterClass() throws Exception { 121 // expect this call 122 mMockRemoteRunner.addInstrumentationArg("class", TEST1.getClassName()); 123 mMockRemoteRunner.addInstrumentationArg("notClass", TEST2.toString()); 124 setRunTestExpectations(); 125 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 126 mAndroidJUnitTest.addIncludeFilter(TEST1.getClassName()); 127 mAndroidJUnitTest.addExcludeFilter(TEST2.toString()); 128 mAndroidJUnitTest.run(mMockListener); 129 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 130 } 131 132 /** 133 * Test list of tests to run is filtered by include filters. 134 */ 135 public void testRun_includeFilterPackage() throws Exception { 136 // expect this call 137 mMockRemoteRunner.addInstrumentationArg("package", "com.android.test"); 138 setRunTestExpectations(); 139 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 140 mAndroidJUnitTest.addIncludeFilter("com.android.test"); 141 mAndroidJUnitTest.run(mMockListener); 142 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 143 } 144 145 /** 146 * Test list of tests to run is filtered by exclude filters. 147 */ 148 public void testRun_excludeFilterPackage() throws Exception { 149 // expect this call 150 mMockRemoteRunner.addInstrumentationArg("notPackage", "com.android.not"); 151 setRunTestExpectations(); 152 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 153 mAndroidJUnitTest.addExcludeFilter("com.android.not"); 154 mAndroidJUnitTest.run(mMockListener); 155 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 156 } 157 158 /** 159 * Test list of tests to run is filtered by include and exclude filters. 160 */ 161 public void testRun_includeAndExcludeFilterPackage() throws Exception { 162 // expect this call 163 mMockRemoteRunner.addInstrumentationArg("package", "com.android.test"); 164 mMockRemoteRunner.addInstrumentationArg("notPackage", "com.android.not"); 165 setRunTestExpectations(); 166 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 167 mAndroidJUnitTest.addIncludeFilter("com.android.test"); 168 mAndroidJUnitTest.addExcludeFilter("com.android.not"); 169 mAndroidJUnitTest.run(mMockListener); 170 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 171 } 172 173 /** 174 * Test list of tests to run is filtered by include and exclude filters. 175 */ 176 public void testRun_includeAndExcludeFilters() throws Exception { 177 // expect this call 178 mMockRemoteRunner.addInstrumentationArg("class", TEST1.getClassName()); 179 mMockRemoteRunner.addInstrumentationArg("notClass", TEST2.toString()); 180 mMockRemoteRunner.addInstrumentationArg("package", "com.android.test"); 181 mMockRemoteRunner.addInstrumentationArg("notPackage", "com.android.not"); 182 setRunTestExpectations(); 183 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 184 mAndroidJUnitTest.addIncludeFilter(TEST1.getClassName()); 185 mAndroidJUnitTest.addExcludeFilter(TEST2.toString()); 186 mAndroidJUnitTest.addIncludeFilter("com.android.test"); 187 mAndroidJUnitTest.addExcludeFilter("com.android.not"); 188 mAndroidJUnitTest.run(mMockListener); 189 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 190 } 191 192 /** 193 * Test list of tests to run is filtered by include file. 194 */ 195 public void testRun_includeFile() throws Exception { 196 mMockRemoteRunner.addInstrumentationArg( 197 EasyMock.eq("testFile"), EasyMock.<String>anyObject()); 198 setRunTestExpectations(); 199 EasyMock.expect(mMockTestDevice.pushFile( 200 EasyMock.<File>anyObject(), EasyMock.<String>anyObject())).andReturn(Boolean.TRUE); 201 EasyMock.expect(mMockTestDevice.executeShellCommand(EasyMock.<String>anyObject())) 202 .andReturn("") 203 .times(2); 204 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 205 206 File tmpFile = FileUtil.createTempFile("testFile", ".txt"); 207 try { 208 mAndroidJUnitTest.setIncludeTestFile(tmpFile); 209 mAndroidJUnitTest.run(mMockListener); 210 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 211 } finally { 212 FileUtil.deleteFile(tmpFile); 213 } 214 215 } 216 217 /** 218 * Test list of tests to run is filtered by exclude file. 219 */ 220 public void testRun_excludeFile() throws Exception { 221 mMockRemoteRunner.addInstrumentationArg( 222 EasyMock.eq("notTestFile"), EasyMock.<String>anyObject()); 223 setRunTestExpectations(); 224 EasyMock.expect(mMockTestDevice.pushFile( 225 EasyMock.<File>anyObject(), EasyMock.<String>anyObject())).andReturn(Boolean.TRUE); 226 EasyMock.expect(mMockTestDevice.executeShellCommand(EasyMock.<String>anyObject())) 227 .andReturn("") 228 .times(2); 229 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 230 231 File tmpFile = FileUtil.createTempFile("notTestFile", ".txt"); 232 try { 233 mAndroidJUnitTest.setExcludeTestFile(tmpFile); 234 mAndroidJUnitTest.run(mMockListener); 235 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 236 } finally { 237 FileUtil.deleteFile(tmpFile); 238 } 239 240 } 241 242 /** 243 * Test list of tests to run is filtered by include file, does not override existing filters. 244 */ 245 public void testRun_testFileAndFilters() throws Exception { 246 mMockRemoteRunner.addInstrumentationArg( 247 EasyMock.eq("testFile"), EasyMock.<String>anyObject()); 248 mMockRemoteRunner.addInstrumentationArg( 249 EasyMock.eq("notTestFile"), EasyMock.<String>anyObject()); 250 mMockRemoteRunner.addInstrumentationArg("class", TEST1.getClassName()); 251 mMockRemoteRunner.addInstrumentationArg("notClass", TEST2.toString()); 252 setRunTestExpectations(); 253 EasyMock.expect(mMockTestDevice.pushFile(EasyMock.<File>anyObject(), 254 EasyMock.<String>anyObject())).andReturn(Boolean.TRUE).times(2); 255 EasyMock.expect(mMockTestDevice.executeShellCommand(EasyMock.<String>anyObject())) 256 .andReturn("") 257 .times(4); 258 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 259 260 File tmpFileInclude = FileUtil.createTempFile("includeFile", ".txt"); 261 File tmpFileExclude = FileUtil.createTempFile("excludeFile", ".txt"); 262 try { 263 mAndroidJUnitTest.addIncludeFilter(TEST1.getClassName()); 264 mAndroidJUnitTest.addExcludeFilter(TEST2.toString()); 265 mAndroidJUnitTest.setIncludeTestFile(tmpFileInclude); 266 mAndroidJUnitTest.setExcludeTestFile(tmpFileExclude); 267 mAndroidJUnitTest.run(mMockListener); 268 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 269 } finally { 270 FileUtil.deleteFile(tmpFileInclude); 271 FileUtil.deleteFile(tmpFileExclude); 272 } 273 } 274 275 /** 276 * Test that when pushing the filters fails, we have a test run failure since we were not able 277 * to run anything. 278 */ 279 public void testRun_testFileAndFilters_fails() throws Exception { 280 mMockRemoteRunner = EasyMock.createMock(IRemoteAndroidTestRunner.class); 281 EasyMock.expect( 282 mMockTestDevice.pushFile( 283 EasyMock.<File>anyObject(), EasyMock.<String>anyObject())) 284 .andThrow(new DeviceNotAvailableException("failed to push", "device1")); 285 286 mMockListener.testRunStarted(EasyMock.anyObject(), EasyMock.eq(0)); 287 mMockListener.testRunFailed("failed to push"); 288 mMockListener.testRunEnded(0, new HashMap<String, Metric>()); 289 290 EasyMock.replay(mMockRemoteRunner, mMockTestDevice, mMockListener); 291 File tmpFileInclude = FileUtil.createTempFile("includeFile", ".txt"); 292 File tmpFileExclude = FileUtil.createTempFile("excludeFile", ".txt"); 293 try { 294 mAndroidJUnitTest.addIncludeFilter(TEST1.getClassName()); 295 mAndroidJUnitTest.addExcludeFilter(TEST2.toString()); 296 mAndroidJUnitTest.setIncludeTestFile(tmpFileInclude); 297 mAndroidJUnitTest.setExcludeTestFile(tmpFileExclude); 298 mAndroidJUnitTest.run(mMockListener); 299 fail("Should have thrown an exception."); 300 } catch (DeviceNotAvailableException expected) { 301 //expected 302 } finally { 303 FileUtil.deleteFile(tmpFileInclude); 304 FileUtil.deleteFile(tmpFileExclude); 305 } 306 EasyMock.verify(mMockRemoteRunner, mMockTestDevice, mMockListener); 307 } 308 309 /** 310 * Test that setting option for "test-file-filter" works as intended 311 */ 312 public void testRun_setTestFileOptions() throws Exception { 313 mMockRemoteRunner.addInstrumentationArg( 314 EasyMock.eq("testFile"), EasyMock.<String>anyObject()); 315 mMockRemoteRunner.addInstrumentationArg( 316 EasyMock.eq("notTestFile"), EasyMock.<String>anyObject()); 317 setRunTestExpectations(); 318 EasyMock.expect( 319 mMockTestDevice.pushFile( 320 EasyMock.<File>anyObject(), EasyMock.<String>anyObject())) 321 .andReturn(Boolean.TRUE) 322 .times(2); 323 EasyMock.expect(mMockTestDevice.executeShellCommand(EasyMock.<String>anyObject())) 324 .andReturn("") 325 .times(4); 326 EasyMock.replay(mMockRemoteRunner, mMockTestDevice); 327 328 File tmpFileInclude = FileUtil.createTempFile("includeFile", ".txt"); 329 File tmpFileExclude = FileUtil.createTempFile("excludeFile", ".txt"); 330 try { 331 OptionSetter setter = new OptionSetter(mAndroidJUnitTest); 332 setter.setOptionValue("test-file-include-filter", tmpFileInclude.getAbsolutePath()); 333 setter.setOptionValue("test-file-exclude-filter", tmpFileExclude.getAbsolutePath()); 334 mAndroidJUnitTest.run(mMockListener); 335 EasyMock.verify(mMockRemoteRunner, mMockTestDevice); 336 } finally { 337 FileUtil.deleteFile(tmpFileInclude); 338 FileUtil.deleteFile(tmpFileExclude); 339 } 340 341 } 342 343 private void setRunTestExpectations() throws DeviceNotAvailableException { 344 EasyMock.expect( 345 mMockTestDevice.runInstrumentationTests( 346 EasyMock.eq(mMockRemoteRunner), 347 (ITestLifeCycleReceiver) EasyMock.anyObject())) 348 .andReturn(Boolean.TRUE); 349 } 350 351 /** 352 * Test isClassOrMethod returns true for <package>.<class> and <package>.<class>#<method> but 353 * not for <package>. 354 */ 355 public void testIsClassOrMethod() throws Exception { 356 assertFalse("String was just package", mAndroidJUnitTest.isClassOrMethod("android.test")); 357 assertTrue("String was class", mAndroidJUnitTest.isClassOrMethod("android.test.Foo")); 358 assertTrue("String was method", mAndroidJUnitTest.isClassOrMethod("android.test.Foo#bar")); 359 } 360 361 /** 362 * Test that {@link AndroidJUnitTest#split()} returns null if the runner is not shardable. 363 */ 364 public void testSplit_notShardable() { 365 mAndroidJUnitTest.setRunnerName("fake.runner.not.shardable"); 366 assertNull(mAndroidJUnitTest.split()); 367 } 368 369 /** 370 * Test that {@link AndroidJUnitTest#split()} returns null if no shards have been requested. 371 */ 372 public void testSplit_noShardRequested() { 373 assertEquals(AndroidJUnitTest.AJUR, mAndroidJUnitTest.getRunnerName()); 374 assertNull(mAndroidJUnitTest.split()); 375 } 376 377 /** Test that {@link AndroidJUnitTest#split(int)} returns 3 shards when requested to do so. */ 378 public void testSplit_threeShards() throws Exception { 379 mAndroidJUnitTest = new AndroidJUnitTest(); 380 assertEquals(AndroidJUnitTest.AJUR, mAndroidJUnitTest.getRunnerName()); 381 OptionSetter setter = new OptionSetter(mAndroidJUnitTest); 382 setter.setOptionValue("runtime-hint", "60s"); 383 List<IRemoteTest> res = (List<IRemoteTest>) mAndroidJUnitTest.split(3); 384 assertNotNull(res); 385 assertEquals(3, res.size()); 386 // Third of the execution time on each shard. 387 assertEquals(20000L, ((AndroidJUnitTest)res.get(0)).getRuntimeHint()); 388 assertEquals(20000L, ((AndroidJUnitTest)res.get(1)).getRuntimeHint()); 389 assertEquals(20000L, ((AndroidJUnitTest)res.get(2)).getRuntimeHint()); 390 // Make sure shards cannot be re-sharded 391 assertNull(((AndroidJUnitTest) res.get(0)).split(2)); 392 assertNull(((AndroidJUnitTest) res.get(0)).split()); 393 } 394 395 /** 396 * Test that {@link AndroidJUnitTest#split(int)} can only split up to the ajur-max-shard option. 397 */ 398 public void testSplit_maxShard() throws Exception { 399 mAndroidJUnitTest = new AndroidJUnitTest(); 400 assertEquals(AndroidJUnitTest.AJUR, mAndroidJUnitTest.getRunnerName()); 401 OptionSetter setter = new OptionSetter(mAndroidJUnitTest); 402 setter.setOptionValue("runtime-hint", "60s"); 403 setter.setOptionValue("ajur-max-shard", "2"); 404 List<IRemoteTest> res = (List<IRemoteTest>) mAndroidJUnitTest.split(3); 405 assertNotNull(res); 406 assertEquals(2, res.size()); 407 // Third of the execution time on each shard. 408 assertEquals(30000L, ((AndroidJUnitTest) res.get(0)).getRuntimeHint()); 409 assertEquals(30000L, ((AndroidJUnitTest) res.get(1)).getRuntimeHint()); 410 // Make sure shards cannot be re-sharded 411 assertNull(((AndroidJUnitTest) res.get(0)).split(2)); 412 assertNull(((AndroidJUnitTest) res.get(0)).split()); 413 } 414 } 415