1 /* 2 * Copyright (C) 2023 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.adservices.room.test; 18 19 import android.cts.install.lib.host.InstallUtilsHost; 20 21 import com.android.tradefed.config.Option; 22 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 23 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 24 import com.android.tradefed.util.FileUtil; 25 26 27 import org.junit.Test; 28 import org.junit.runner.RunWith; 29 30 import java.io.File; 31 import java.io.IOException; 32 import java.util.Arrays; 33 import java.util.Map; 34 import java.util.regex.Pattern; 35 import java.util.stream.Collectors; 36 import java.util.zip.ZipEntry; 37 import java.util.zip.ZipFile; 38 39 /** 40 * Asserts Room database version get bumped up between M-trains. 41 * 42 * <p>Since the Room json schema file only live in the UnitTest package, we need to download and 43 * read the json from the zip. 44 * 45 * <p>The test will compare the highest version between mainline branch and M-train release build. 46 * 47 * <p>If M-train build contains a certain DB, then: 48 * 49 * <ol> 50 * <li>The DB must present in the new version; 51 * <li>If highest version in the new version is the same, the schema file should stay same; and 52 * <li>Database version should never go down. 53 * </ol> 54 */ 55 @RunWith(DeviceJUnit4ClassRunner.class) 56 public class RoomDatabaseVersionBumpGuardrailTest extends BaseHostJUnit4Test { 57 58 // This is not a perfect matcher as it could be fragile of file with other naming strategy. 59 private static final Pattern SCHEMA_FILE_PATTERN = 60 Pattern.compile("^assets/com\\.android\\..*/\\d*\\.json$"); 61 public static final String AD_SERVICES_SERVICE_CORE_UNIT_TESTS_APK_FILE_NAME = 62 "AdServicesServiceCoreUnitTests.apk"; 63 protected final InstallUtilsHost mHostUtils = new InstallUtilsHost(this); 64 65 // The schema lib should be configured in gcl to point to the right package. 66 @Option(name = "base-schema-lib") 67 protected String mBaseSchemaLib; 68 69 @Option(name = "new-schema-lib") 70 protected String mNewSchemaLib; 71 72 @Option(name = "schema-apk-name") 73 protected String mSchemaApkName = AD_SERVICES_SERVICE_CORE_UNIT_TESTS_APK_FILE_NAME; 74 75 @Test roomDatabaseVersionBumpGuardrailTest()76 public void roomDatabaseVersionBumpGuardrailTest() throws Exception { 77 ZipFile baseSchemas = getTestPackageFromFile(mBaseSchemaLib); 78 ZipFile newSchemas = getTestPackageFromFile(mNewSchemaLib); 79 80 StringBuilder errors = new StringBuilder(); 81 Map<String, ZipEntry> newSchemasByFileName = 82 newSchemas.stream() 83 .filter(f -> SCHEMA_FILE_PATTERN.matcher(f.getName()).matches()) 84 .collect(Collectors.toMap(ZipEntry::getName, e -> e)); 85 86 for (ZipEntry baseFile : 87 baseSchemas.stream() 88 .filter(f -> SCHEMA_FILE_PATTERN.matcher(f.getName()).matches()) 89 .collect(Collectors.toList())) { 90 ZipEntry newFile = newSchemasByFileName.get(baseFile.getName()); 91 if (newFile == null) { 92 errors.append( 93 String.format( 94 "Database json file %s is removed in the new version. Please add" 95 + " back.\n", 96 baseFile.getName())); 97 continue; 98 } 99 if (!Arrays.equals( 100 baseSchemas.getInputStream(baseFile).readAllBytes(), 101 newSchemas.getInputStream(newFile).readAllBytes())) { 102 errors.append( 103 String.format( 104 "Database json file '%s' changed between major build. Please revert" 105 + " change and/or bump up DB version.\n", 106 baseFile.getName())); 107 } 108 } 109 110 if (errors.length() != 0) { 111 throw new IllegalStateException(errors.toString()); 112 } 113 } 114 getTestPackageFromFile(String lib)115 private ZipFile getTestPackageFromFile(String lib) throws IOException { 116 File testPackage = mHostUtils.getTestFile(lib); 117 return new ZipFile(FileUtil.findFile(testPackage, mSchemaApkName)); 118 } 119 } 120