1 /* 2 * Copyright (C) 2020 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 17 package com.android.csuite.core; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.testng.Assert.assertThrows; 22 23 import com.android.tradefed.build.BuildInfo; 24 import com.android.tradefed.config.Configuration; 25 import com.android.tradefed.config.IConfiguration; 26 import com.android.tradefed.config.OptionSetter; 27 import com.android.tradefed.device.ITestDevice; 28 import com.android.tradefed.invoker.IInvocationContext; 29 import com.android.tradefed.invoker.InvocationContext; 30 import com.android.tradefed.invoker.TestInformation; 31 32 import com.google.common.collect.ImmutableList; 33 import com.google.common.jimfs.Jimfs; 34 import com.google.common.truth.IterableSubject; 35 import com.google.common.truth.StringSubject; 36 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 import org.junit.runners.JUnit4; 40 import org.mockito.Mockito; 41 42 import java.io.IOException; 43 import java.io.UncheckedIOException; 44 import java.nio.file.FileSystem; 45 import java.nio.file.Files; 46 import java.nio.file.Path; 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.List; 50 import java.util.concurrent.atomic.AtomicBoolean; 51 import java.util.stream.Stream; 52 53 @RunWith(JUnit4.class) 54 public final class ModuleGeneratorTest { 55 private static final String TEST_PACKAGE_NAME1 = "test.package.name1"; 56 private static final String TEST_PACKAGE_NAME2 = "test.package.name2"; 57 private static final String TEST_PACKAGE_NAME3 = "test.package.name3"; 58 private static final Exception NO_EXCEPTION = null; 59 60 private final FileSystem mFileSystem = 61 Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix()); 62 63 @Test tearDown_nonModuleFilesExist_doesNotDelete()64 public void tearDown_nonModuleFilesExist_doesNotDelete() throws Exception { 65 Path testsDir = createTestsDir(); 66 Path nonModule = Files.createFile(testsDir.resolve("a")); 67 ModuleGenerator generator = new GeneratorBuilder().setTestsDir(testsDir).build(); 68 69 generator.tearDown(createTestInfo(), NO_EXCEPTION); 70 71 assertThatListDirectory(testsDir).containsExactly(nonModule); 72 } 73 74 @Test tearDown_preserveNonGeneratedModules_doesNotDelete()75 public void tearDown_preserveNonGeneratedModules_doesNotDelete() throws Exception { 76 Path testsDir = createTestsDir(); 77 Path nonGeneratedModule = 78 Files.createFile( 79 testsDir.resolve("b" + ModuleGenerator.MODULE_FILE_NAME_EXTENSION)); 80 ModuleGenerator sut = new GeneratorBuilder().setTestsDir(testsDir).build(); 81 OptionSetter option = new OptionSetter(sut); 82 option.setOptionValue(ModuleGenerator.OPTION_PRESERVE_EXISTING_MODULES, "true"); 83 84 sut.tearDown(createTestInfo(), NO_EXCEPTION); 85 86 assertThatListDirectory(testsDir).containsExactly(nonGeneratedModule); 87 } 88 89 @Test tearDown_doesNotPreserveNonGeneratedModules_delete()90 public void tearDown_doesNotPreserveNonGeneratedModules_delete() throws Exception { 91 Path testsDir = createTestsDir(); 92 Path nonGeneratedModule = 93 Files.createFile( 94 testsDir.resolve("b" + ModuleGenerator.MODULE_FILE_NAME_EXTENSION)); 95 ModuleGenerator sut = new GeneratorBuilder().setTestsDir(testsDir).build(); 96 OptionSetter option = new OptionSetter(sut); 97 option.setOptionValue(ModuleGenerator.OPTION_PRESERVE_EXISTING_MODULES, "false"); 98 99 sut.tearDown(createTestInfo(), NO_EXCEPTION); 100 101 assertThatListDirectory(testsDir).doesNotContain(nonGeneratedModule); 102 } 103 104 @Test tearDown_packageNamesProvided_deletesGeneratedModules()105 public void tearDown_packageNamesProvided_deletesGeneratedModules() throws Exception { 106 Path testsDir = createTestsDir(); 107 ModuleGenerator generator1 = 108 new GeneratorBuilder() 109 .setTestsDir(testsDir) 110 .addModuleInfoProvider( 111 config -> 112 Stream.of( 113 new ModuleInfoProvider.ModuleInfo( 114 TEST_PACKAGE_NAME1, ""))) 115 .addModuleInfoProvider( 116 config -> 117 Stream.of( 118 new ModuleInfoProvider.ModuleInfo( 119 TEST_PACKAGE_NAME2, ""))) 120 .build(); 121 generator1.split(); 122 ModuleGenerator generator2 = new GeneratorBuilder().setTestsDir(testsDir).build(); 123 124 generator2.tearDown(createTestInfo(), NO_EXCEPTION); 125 126 assertThatListDirectory(testsDir).isEmpty(); 127 } 128 129 @Test tearDown_moduleInfoNotProvided_doesNotThrowError()130 public void tearDown_moduleInfoNotProvided_doesNotThrowError() throws Exception { 131 ModuleGenerator generator = new GeneratorBuilder().setTestsDir(createTestsDir()).build(); 132 generator.split(); 133 134 generator.tearDown(createTestInfo(), NO_EXCEPTION); 135 } 136 137 @Test split_moduleInfoStreamProvided_streamIsClosed()138 public void split_moduleInfoStreamProvided_streamIsClosed() throws Exception { 139 AtomicBoolean wasClosed = new AtomicBoolean(false); 140 ModuleGenerator generator = 141 new GeneratorBuilder() 142 .setTestsDir(createTestsDir()) 143 .addModuleInfoProvider( 144 config -> 145 Stream.of( 146 new ModuleInfoProvider.ModuleInfo( 147 TEST_PACKAGE_NAME1, "")) 148 .onClose(() -> wasClosed.set(true))) 149 .build(); 150 151 generator.split(); 152 153 assertThat(wasClosed.get()).isTrue(); 154 } 155 156 @Test split_moduleInfoProvidersSpecified_contentIsWritten()157 public void split_moduleInfoProvidersSpecified_contentIsWritten() throws Exception { 158 Path testsDir = createTestsDir(); 159 String content1 = "a"; 160 String content2 = "b"; 161 ModuleGenerator generator = 162 new GeneratorBuilder() 163 .setTestsDir(testsDir) 164 .addModuleInfoProvider( 165 config -> 166 Stream.of( 167 new ModuleInfoProvider.ModuleInfo( 168 TEST_PACKAGE_NAME1, content1))) 169 .addModuleInfoProvider( 170 config -> 171 Stream.of( 172 new ModuleInfoProvider.ModuleInfo( 173 TEST_PACKAGE_NAME2, content2))) 174 .build(); 175 176 generator.split(); 177 178 assertThatModuleConfigFileContent(testsDir, TEST_PACKAGE_NAME1).contains(content1); 179 assertThatModuleConfigFileContent(testsDir, TEST_PACKAGE_NAME2).contains(content2); 180 } 181 182 @Test split_emptyModuleNameProvided_throwsException()183 public void split_emptyModuleNameProvided_throwsException() throws Exception { 184 Path testsDir = createTestsDir(); 185 ModuleGenerator generator = 186 new GeneratorBuilder() 187 .setTestsDir(testsDir) 188 .addModuleInfoProvider( 189 config -> Stream.of(new ModuleInfoProvider.ModuleInfo(" ", "a"))) 190 .build(); 191 192 assertThrows(IllegalArgumentException.class, () -> generator.split()); 193 } 194 195 @Test split_duplicatedModuleNamesProvided_throwsException()196 public void split_duplicatedModuleNamesProvided_throwsException() throws Exception { 197 Path testsDir = createTestsDir(); 198 ModuleGenerator generator = 199 new GeneratorBuilder() 200 .setTestsDir(testsDir) 201 .addModuleInfoProvider( 202 config -> 203 Stream.of( 204 new ModuleInfoProvider.ModuleInfo( 205 TEST_PACKAGE_NAME1, "a"))) 206 .addModuleInfoProvider( 207 config -> 208 Stream.of( 209 new ModuleInfoProvider.ModuleInfo( 210 TEST_PACKAGE_NAME1, "b"))) 211 .build(); 212 213 assertThrows(IllegalArgumentException.class, () -> generator.split()); 214 } 215 216 @Test split_moduleInfoProvidersSpecified_generateModulesForAll()217 public void split_moduleInfoProvidersSpecified_generateModulesForAll() throws Exception { 218 Path testsDir = createTestsDir(); 219 ModuleGenerator generator = 220 new GeneratorBuilder() 221 .setTestsDir(testsDir) 222 .addModuleInfoProvider( 223 config -> 224 Arrays.asList( 225 new ModuleInfoProvider.ModuleInfo( 226 TEST_PACKAGE_NAME1, ""), 227 new ModuleInfoProvider.ModuleInfo( 228 TEST_PACKAGE_NAME2, "")) 229 .stream()) 230 .addModuleInfoProvider( 231 config -> 232 Stream.of( 233 new ModuleInfoProvider.ModuleInfo( 234 TEST_PACKAGE_NAME3, ""))) 235 .build(); 236 237 generator.split(); 238 239 assertThatListDirectory(testsDir) 240 .containsExactly( 241 getModuleConfigFile(testsDir, TEST_PACKAGE_NAME1), 242 getModuleConfigFile(testsDir, TEST_PACKAGE_NAME2), 243 getModuleConfigFile(testsDir, TEST_PACKAGE_NAME3)); 244 } 245 246 @Test split_streamThrowsException_throwsException()247 public void split_streamThrowsException_throwsException() throws Exception { 248 ModuleGenerator generator = 249 new GeneratorBuilder() 250 .setTestsDir(createTestsDir()) 251 .addModuleInfoProvider( 252 config -> 253 Arrays.stream(new String[] {"a"}) 254 .map( 255 i -> { 256 throw new UncheckedIOException( 257 new IOException()); 258 })) 259 .build(); 260 261 assertThrows(UncheckedIOException.class, () -> generator.split()); 262 } 263 264 @Test split_providerThrowsException_throwsException()265 public void split_providerThrowsException_throwsException() throws Exception { 266 ModuleGenerator generator = 267 new GeneratorBuilder() 268 .setTestsDir(createTestsDir()) 269 .addModuleInfoProvider( 270 config -> { 271 throw new UncheckedIOException(new IOException()); 272 }) 273 .build(); 274 275 assertThrows(UncheckedIOException.class, () -> generator.split()); 276 } 277 278 @Test split_noProviders_doesNotGenerate()279 public void split_noProviders_doesNotGenerate() throws Exception { 280 Path testsDir = createTestsDir(); 281 ModuleGenerator generator = new GeneratorBuilder().setTestsDir(testsDir).build(); 282 283 generator.split(); 284 285 assertThatListDirectory(testsDir).isEmpty(); 286 } 287 assertThatModuleConfigFileContent( Path testsDir, String packageName)288 private static StringSubject assertThatModuleConfigFileContent( 289 Path testsDir, String packageName) throws IOException { 290 return assertThat( 291 new String(Files.readAllBytes(getModuleConfigFile(testsDir, packageName)))); 292 } 293 assertThatListDirectory(Path dir)294 private static IterableSubject assertThatListDirectory(Path dir) throws IOException { 295 // Convert stream to list because com.google.common.truth.Truth8 is not available. 296 return assertThat( 297 Files.walk(dir) 298 .filter(p -> !p.equals(dir)) 299 .collect(ImmutableList.toImmutableList())); 300 } 301 getModuleConfigFile(Path baseDir, String packageName)302 private static Path getModuleConfigFile(Path baseDir, String packageName) { 303 return baseDir.resolve(packageName + ".config"); 304 } 305 createTestsDir()306 private Path createTestsDir() throws IOException { 307 Path rootPath = mFileSystem.getPath("csuite"); 308 Files.createDirectories(rootPath); 309 return Files.createTempDirectory(rootPath, "testDir"); 310 } 311 312 private static final class GeneratorBuilder { 313 private final List<ModuleInfoProvider> mModuleInfoProviders = new ArrayList<>(); 314 private Path mTestsDir; 315 addModuleInfoProvider(ModuleInfoProvider moduleInfoProviders)316 GeneratorBuilder addModuleInfoProvider(ModuleInfoProvider moduleInfoProviders) { 317 mModuleInfoProviders.add(moduleInfoProviders); 318 return this; 319 } 320 setTestsDir(Path testsDir)321 GeneratorBuilder setTestsDir(Path testsDir) { 322 mTestsDir = testsDir; 323 return this; 324 } 325 build()326 ModuleGenerator build() throws Exception { 327 ModuleGenerator generator = new ModuleGenerator(buildInfo -> mTestsDir); 328 329 IConfiguration configuration = new Configuration("name", "description"); 330 configuration.setConfigurationObjectList( 331 ModuleInfoProvider.MODULE_INFO_PROVIDER_OBJECT_TYPE, mModuleInfoProviders); 332 generator.setConfiguration(configuration); 333 334 return generator; 335 } 336 } 337 createTestInfo()338 private static TestInformation createTestInfo() { 339 IInvocationContext context = new InvocationContext(); 340 context.addAllocatedDevice("device1", Mockito.mock(ITestDevice.class)); 341 context.addDeviceBuildInfo("device1", new BuildInfo()); 342 return TestInformation.newBuilder().setInvocationContext(context).build(); 343 } 344 } 345