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.tradefed.testtype.suite; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertNull; 20 import static org.junit.Assert.assertTrue; 21 import static org.junit.Assert.fail; 22 import static org.mockito.Mockito.mock; 23 24 import com.android.tradefed.build.IBuildInfo; 25 import com.android.tradefed.build.IDeviceBuildInfo; 26 import com.android.tradefed.config.ConfigurationException; 27 import com.android.tradefed.config.IConfiguration; 28 import com.android.tradefed.config.OptionSetter; 29 import com.android.tradefed.device.ITestDevice; 30 import com.android.tradefed.invoker.InvocationContext; 31 import com.android.tradefed.result.ITestInvocationListener; 32 import com.android.tradefed.testtype.IRemoteTest; 33 import com.android.tradefed.testtype.StubTest; 34 import com.android.tradefed.util.FileUtil; 35 import com.android.tradefed.util.ZipUtil; 36 37 import org.easymock.EasyMock; 38 import org.junit.Before; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 import org.junit.runners.JUnit4; 42 43 import java.io.File; 44 import java.util.ArrayList; 45 import java.util.Collection; 46 import java.util.LinkedHashMap; 47 import java.util.List; 48 49 /** 50 * Unit tests for {@link TfSuiteRunner}. 51 */ 52 @RunWith(JUnit4.class) 53 public class TfSuiteRunnerTest { 54 55 private static final String TEST_CONFIG = 56 "<configuration description=\"Runs a stub tests part of some suite\">\n" 57 + " <option name=\"test-suite-tag\" value=\"example-suite\" />\n" 58 + " <test class=\"com.android.tradefed.testtype.StubTest\" />\n" 59 + "</configuration>"; 60 61 private TfSuiteRunner mRunner; 62 63 @Before 64 public void setUp() { 65 mRunner = new TfSuiteRunner(); 66 } 67 68 /** 69 * Test for {@link TfSuiteRunner#loadTests()} implementation, for basic example configurations. 70 */ 71 @Test 72 public void testLoadTests() throws Exception { 73 OptionSetter setter = new OptionSetter(mRunner); 74 setter.setOptionValue("suite-config-prefix", "suite"); 75 setter.setOptionValue("run-suite-tag", "example-suite"); 76 LinkedHashMap <String, IConfiguration> configMap = mRunner.loadTests(); 77 assertEquals(2, configMap.size()); 78 assertTrue(configMap.containsKey("suite/stub1")); 79 assertTrue(configMap.containsKey("suite/stub2")); 80 } 81 82 /** 83 * Test for {@link TfSuiteRunner#loadTests()} implementation, only stub1.xml is part of this 84 * suite. 85 */ 86 @Test 87 public void testLoadTests_suite2() throws Exception { 88 OptionSetter setter = new OptionSetter(mRunner); 89 setter.setOptionValue("suite-config-prefix", "suite"); 90 setter.setOptionValue("run-suite-tag", "example-suite2"); 91 LinkedHashMap <String, IConfiguration> configMap = mRunner.loadTests(); 92 assertEquals(1, configMap.size()); 93 assertTrue(configMap.containsKey("suite/stub1")); 94 } 95 96 /** Test that when splitting, the instance of the implementation is used. */ 97 @Test 98 public void testSplit() throws Exception { 99 OptionSetter setter = new OptionSetter(mRunner); 100 setter.setOptionValue("suite-config-prefix", "suite"); 101 setter.setOptionValue("run-suite-tag", "example-suite"); 102 Collection<IRemoteTest> tests = mRunner.split(2); 103 assertEquals(2, tests.size()); 104 for (IRemoteTest test : tests) { 105 assertTrue(test instanceof TfSuiteRunner); 106 } 107 } 108 109 /** 110 * Test that when {@link TfSuiteRunner} run-suite-tag is not set we cannot shard since there is 111 * no configuration. 112 */ 113 @Test 114 public void testSplit_nothingToLoad() throws Exception { 115 OptionSetter setter = new OptionSetter(mRunner); 116 setter.setOptionValue("suite-config-prefix", "doesnotexists"); 117 setter.setOptionValue("run-suite-tag", "doesnotexists"); 118 assertNull(mRunner.split(2)); 119 } 120 121 /** 122 * Attempt to load a suite from a suite, but the sub-suite does not have a default run-suite-tag 123 * so it cannot run anything. 124 */ 125 @Test 126 public void testLoadSuite_noSubConfigs() throws ConfigurationException { 127 OptionSetter setter = new OptionSetter(mRunner); 128 setter.setOptionValue("suite-config-prefix", "suite"); 129 setter.setOptionValue("run-suite-tag", "test-empty"); 130 LinkedHashMap<String, IConfiguration> configMap = mRunner.loadTests(); 131 assertEquals(0, configMap.size()); 132 } 133 134 /** 135 * Attempt to load a suite from a suite, the sub-suite has a default run-suite-tag that will be 136 * loaded. 137 */ 138 @Test 139 public void testLoadSuite() throws ConfigurationException { 140 OptionSetter setter = new OptionSetter(mRunner); 141 setter.setOptionValue("suite-config-prefix", "suite"); 142 setter.setOptionValue("run-suite-tag", "test-sub-suite"); 143 LinkedHashMap<String, IConfiguration> configMap = mRunner.loadTests(); 144 assertEquals(3, configMap.size()); 145 // 2 test configs loaded from the sub-suite 146 assertTrue(configMap.containsKey("suite/stub1")); 147 assertTrue(configMap.containsKey("suite/stub2")); 148 // 1 config from the left over <test> that was not a suite. 149 assertTrue(configMap.containsKey("suite/sub-suite")); 150 IConfiguration config = configMap.get("suite/sub-suite"); 151 // assert that the TfSuiteRunner was removed from the config, only the stubTest remains 152 assertTrue(config.getTests().size() == 1); 153 assertTrue(config.getTests().get(0) instanceof StubTest); 154 } 155 156 /** 157 * In case of cycle include of sub-suite configuration. We throw an exception to prevent any 158 * weird runs. 159 */ 160 @Test 161 public void testLoadSuite_cycle() throws ConfigurationException { 162 OptionSetter setter = new OptionSetter(mRunner); 163 setter.setOptionValue("suite-config-prefix", "suite"); 164 setter.setOptionValue("run-suite-tag", "test-cycle-a"); 165 try { 166 mRunner.loadTests(); 167 fail("Should have thrown an exception."); 168 } catch (RuntimeException expected) { 169 // expected 170 } 171 } 172 173 /** Test for {@link TfSuiteRunner#run(ITestInvocationListener)} when loading another suite. */ 174 @Test 175 public void testLoadTests_suite() throws Exception { 176 OptionSetter setter = new OptionSetter(mRunner); 177 setter.setOptionValue("suite-config-prefix", "suite"); 178 setter.setOptionValue("run-suite-tag", "example-suite3"); 179 ITestInvocationListener listener = EasyMock.createMock(ITestInvocationListener.class); 180 mRunner.setDevice(mock(ITestDevice.class)); 181 mRunner.setBuild(mock(IBuildInfo.class)); 182 mRunner.setSystemStatusChecker(new ArrayList<>()); 183 mRunner.setInvocationContext(new InvocationContext()); 184 // runs the expanded suite 185 listener.testModuleStarted(EasyMock.anyObject()); 186 listener.testRunStarted("suite/stub1", 0); 187 listener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject()); 188 listener.testModuleEnded(); 189 EasyMock.replay(listener); 190 mRunner.run(listener); 191 EasyMock.verify(listener); 192 } 193 194 /** 195 * Test for {@link TfSuiteRunner#run(ITestInvocationListener)} when loading test configs from 196 * additional-tests-zip. 197 */ 198 @Test 199 public void testLoadTests_additionalTestsZip() throws Exception { 200 File tmpDir = null; 201 File deviceTestDir = null; 202 File additionalTestsZipFile = null; 203 try { 204 tmpDir = FileUtil.createTempDir("test"); 205 // tests directory for the build. 206 deviceTestDir = FileUtil.createTempDir("build-info-test-dir"); 207 208 File zipDir = FileUtil.getFileForPath(tmpDir, "suite"); 209 FileUtil.mkdirsRWX(zipDir); 210 211 // Create 2 test configs inside a zip. 212 File testConfig = new File(zipDir, "test1.config"); 213 FileUtil.writeToFile(TEST_CONFIG, testConfig); 214 File testConfig2 = new File(zipDir, "test2.config"); 215 FileUtil.writeToFile(TEST_CONFIG, testConfig2); 216 additionalTestsZipFile = ZipUtil.createZip(zipDir); 217 218 OptionSetter setter = new OptionSetter(mRunner); 219 setter.setOptionValue("suite-config-prefix", "suite"); 220 setter.setOptionValue("run-suite-tag", "example-suite"); 221 setter.setOptionValue("additional-tests-zip", additionalTestsZipFile.getAbsolutePath()); 222 223 IDeviceBuildInfo deviceBuildInfo = EasyMock.createMock(IDeviceBuildInfo.class); 224 EasyMock.expect(deviceBuildInfo.getTestsDir()).andReturn(deviceTestDir); 225 mRunner.setBuild(deviceBuildInfo); 226 227 EasyMock.replay(deviceBuildInfo); 228 LinkedHashMap<String, IConfiguration> configMap = mRunner.loadTests(); 229 assertEquals(4, configMap.size()); 230 // The keySet should be stable and always ensure the same order of files. 231 List<String> keyList = new ArrayList<>(configMap.keySet()); 232 // test1 and test2 name was sanitized to look like the included configs. 233 assertEquals("suite/test1", keyList.get(0)); 234 assertEquals("suite/test2", keyList.get(1)); 235 assertEquals("suite/stub1", keyList.get(2)); 236 assertEquals("suite/stub2", keyList.get(3)); 237 EasyMock.verify(deviceBuildInfo); 238 } finally { 239 FileUtil.recursiveDelete(deviceTestDir); 240 FileUtil.recursiveDelete(tmpDir); 241 FileUtil.recursiveDelete(additionalTestsZipFile); 242 } 243 } 244 } 245