1 /*
2  * Copyright (C) 2022 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.data.measurement.migration;
18 
19 import static com.android.adservices.common.DbTestUtil.getDbHelperForTest;
20 import static com.android.adservices.data.measurement.migration.MigrationTestHelper.createReferenceDbAtVersion;
21 
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.verify;
25 
26 import android.content.Context;
27 import android.database.sqlite.SQLiteDatabase;
28 
29 import androidx.test.core.app.ApplicationProvider;
30 
31 import com.android.adservices.common.DbTestUtil;
32 import com.android.adservices.data.measurement.MeasurementDbHelper;
33 
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.mockito.Mock;
37 
38 import java.io.File;
39 import java.util.stream.Stream;
40 
41 /**
42  * Base class for {@link IMeasurementDbMigrator}s migrating to v7+ versions. Extending this class
43  * brings in schema validation for creating the DB at a version as well as migrating from previous
44  * version to the target version. Verification is done against a database built at the target
45  * version using the scripts defined in {@link
46  * com.android.adservices.data.measurement.MeasurementDbSchemaTrail}. To introduce test class for
47  * migration to a new version x, i.e. MeasurementDbMigratorVxTest, the following steps need to be
48  * followed -
49  *
50  * <ol>
51  *   <li>Create new entries for create table statements and create index statements for the new
52  *       version in {@link com.android.adservices.data.measurement.MeasurementDbSchemaTrail}
53  *   <li>Extend {@link MeasurementDbMigratorTestBase}
54  *   <li>Override {@link MeasurementDbMigratorTestBase#getTargetVersion()} and return the integer x.
55  *   <li>Override {@link MeasurementDbMigratorTestBase#getTestSubject()} and return the object to
56  *       test, i.e. an instance of MeasurementDbMigratorVx.
57  *   <li>Add a test for data migration to MeasurementDbMigratorVxTest class.
58  * </ol>
59  */
60 public abstract class MeasurementDbMigratorTestBase {
61     protected static final Context sContext = ApplicationProvider.getApplicationContext();
62     protected static final String MEASUREMENT_DATABASE_NAME_FOR_MIGRATION =
63             "adservices_msmt_migration.db";
64     protected static final String MEASUREMENT_DATABASE_REFERENCE_DB_NAME =
65             "adservices_msmt_migration_reference.db";
66 
67     @Mock private SQLiteDatabase mDb;
68 
69     @Before
setup()70     public void setup() {
71         Stream.of(MEASUREMENT_DATABASE_NAME_FOR_MIGRATION, MEASUREMENT_DATABASE_REFERENCE_DB_NAME)
72                 .map(sContext::getDatabasePath)
73                 .filter(File::exists)
74                 .forEach(File::delete);
75     }
76 
77     @Test
performMigration_alreadyOnHigherVersion_skipMigration()78     public void performMigration_alreadyOnHigherVersion_skipMigration() {
79         // Execution
80         getTestSubject().performMigration(mDb, (getTargetVersion() + 1), (getTargetVersion() + 2));
81 
82         // Verify
83         verify(mDb, never()).execSQL(any());
84     }
85 
86     @Test
performMigration_lowerRequestedVersion_skipMigration()87     public void performMigration_lowerRequestedVersion_skipMigration() {
88         // Execution
89         getTestSubject().performMigration(mDb, (getTargetVersion() - 2), (getTargetVersion() - 1));
90 
91         // Verify
92         verify(mDb, never()).execSQL(any());
93     }
94 
95     @Test
performMigration_createAtTargetVersion_dbIsAsExpected()96     public void performMigration_createAtTargetVersion_dbIsAsExpected() {
97         // Setup
98         MeasurementDbHelper dbHelper =
99                 new MeasurementDbHelper(
100                         sContext,
101                         MEASUREMENT_DATABASE_NAME_FOR_MIGRATION,
102                         getTargetVersion(),
103                         getDbHelperForTest());
104         SQLiteDatabase goldenDb =
105                 createReferenceDbAtVersion(
106                         sContext, MEASUREMENT_DATABASE_REFERENCE_DB_NAME, getTargetVersion());
107 
108         // Execution - invokes onCreate implicitly
109         SQLiteDatabase actualDb = dbHelper.getWritableDatabase();
110 
111         // Assertion
112         DbTestUtil.assertDatabasesEqual(goldenDb, actualDb);
113     }
114 
115     @Test
performMigration_migrateFromPrevToTargetVersion_dbIsAsExpected()116     public void performMigration_migrateFromPrevToTargetVersion_dbIsAsExpected() {
117         // Setup
118         int prevVersion = getTargetVersion() - 1;
119         MeasurementDbHelper dbHelper =
120                 new MeasurementDbHelper(
121                         sContext,
122                         MEASUREMENT_DATABASE_NAME_FOR_MIGRATION,
123                         prevVersion,
124                         getDbHelperForTest());
125         SQLiteDatabase goldenDb =
126                 createReferenceDbAtVersion(
127                         sContext, MEASUREMENT_DATABASE_REFERENCE_DB_NAME, getTargetVersion());
128 
129         // Execution
130         SQLiteDatabase actualDb = dbHelper.getWritableDatabase();
131         getTestSubject().performMigration(actualDb, prevVersion, getTargetVersion());
132 
133         // Assertion
134         DbTestUtil.assertDatabasesEqual(goldenDb, actualDb);
135     }
136 
getTargetVersion()137     abstract int getTargetVersion();
138 
getTestSubject()139     abstract AbstractMeasurementDbMigrator getTestSubject();
140 }
141