• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.launcher3.model;
17 
18 import static androidx.test.InstrumentationRegistry.getContext;
19 
20 import static junit.framework.Assert.assertEquals;
21 import static junit.framework.Assert.assertFalse;
22 import static junit.framework.Assert.assertNotSame;
23 import static junit.framework.Assert.assertTrue;
24 
25 import static org.mockito.Mockito.doAnswer;
26 import static org.mockito.Mockito.spy;
27 import static org.mockito.Mockito.when;
28 
29 import android.content.ContentValues;
30 import android.content.Context;
31 import android.content.res.Resources;
32 import android.database.Cursor;
33 import android.database.sqlite.SQLiteDatabase;
34 import android.database.sqlite.SQLiteOpenHelper;
35 
36 import androidx.test.ext.junit.runners.AndroidJUnit4;
37 import androidx.test.filters.SmallTest;
38 import androidx.test.platform.app.InstrumentationRegistry;
39 
40 import com.android.launcher3.LauncherSettings.Favorites;
41 import com.android.launcher3.R;
42 import com.android.launcher3.pm.UserCache;
43 
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 
48 import java.io.File;
49 
50 /**
51  * Tests for {@link DbDowngradeHelper}
52  */
53 @SmallTest
54 @RunWith(AndroidJUnit4.class)
55 public class DbDowngradeHelperTest {
56 
57     private static final String SCHEMA_FILE = "test_schema.json";
58     private static final String DB_FILE = "test.db";
59 
60     private Context mContext;
61     private File mSchemaFile;
62     private File mDbFile;
63 
64     @Before
setup()65     public void setup() {
66         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
67         mSchemaFile = mContext.getFileStreamPath(SCHEMA_FILE);
68         mDbFile = mContext.getDatabasePath(DB_FILE);
69     }
70 
71     @Test
testDowngradeSchemaMatchesVersion()72     public void testDowngradeSchemaMatchesVersion() throws Exception {
73         mSchemaFile.delete();
74         assertFalse(mSchemaFile.exists());
75         DbDowngradeHelper.updateSchemaFile(mSchemaFile, 0, mContext);
76         assertEquals(DatabaseHelper.SCHEMA_VERSION, DbDowngradeHelper.parse(mSchemaFile).version);
77     }
78 
79     @Test
testUpdateSchemaFile()80     public void testUpdateSchemaFile() throws Exception {
81         // Setup mock resources
82         Resources res = spy(mContext.getResources());
83         Resources myRes = getContext().getResources();
84         doAnswer(i -> myRes.openRawResource(
85                 myRes.getIdentifier("db_schema_v10", "raw", getContext().getPackageName())))
86                 .when(res).openRawResource(R.raw.downgrade_schema);
87         Context context = spy(mContext);
88         when(context.getResources()).thenReturn(res);
89 
90         mSchemaFile.delete();
91         assertFalse(mSchemaFile.exists());
92 
93         DbDowngradeHelper.updateSchemaFile(mSchemaFile, 10, context);
94         assertTrue(mSchemaFile.exists());
95         assertEquals(10, DbDowngradeHelper.parse(mSchemaFile).version);
96 
97         // Schema is updated on version upgrade
98         assertTrue(mSchemaFile.setLastModified(0));
99         DbDowngradeHelper.updateSchemaFile(mSchemaFile, 11, context);
100         assertNotSame(0, mSchemaFile.lastModified());
101 
102         // Schema is not updated when version is same
103         assertTrue(mSchemaFile.setLastModified(0));
104         DbDowngradeHelper.updateSchemaFile(mSchemaFile, 10, context);
105         assertEquals(0, mSchemaFile.lastModified());
106 
107         // Schema is not updated on version downgrade
108         DbDowngradeHelper.updateSchemaFile(mSchemaFile, 3, context);
109         assertEquals(0, mSchemaFile.lastModified());
110     }
111 
112     @Test
testDowngrade_success_v31()113     public void testDowngrade_success_v31() throws Exception {
114         setupTestDb();
115 
116         try (SQLiteOpenHelper helper = new MyDatabaseHelper()) {
117             assertFalse(hasFavoritesColumn(helper.getWritableDatabase(), "iconPackage"));
118             assertFalse(hasFavoritesColumn(helper.getWritableDatabase(), "iconResource"));
119         }
120 
121         try (TestOpenHelper helper = new TestOpenHelper(24)) {
122             assertTrue(hasFavoritesColumn(helper.getWritableDatabase(), "iconPackage"));
123             assertTrue(hasFavoritesColumn(helper.getWritableDatabase(), "iconResource"));
124         }
125     }
126 
127     @Test
testDowngrade_success_v24()128     public void testDowngrade_success_v24() throws Exception {
129         setupTestDb();
130 
131         TestOpenHelper helper = new TestOpenHelper(24);
132         assertEquals(24, helper.getReadableDatabase().getVersion());
133         helper.close();
134     }
135 
136     @Test
testDowngrade_success_v22()137     public void testDowngrade_success_v22() throws Exception {
138         setupTestDb();
139 
140         try (SQLiteOpenHelper helper = new TestOpenHelper(22)) {
141             assertEquals(22, helper.getWritableDatabase().getVersion());
142             assertFalse(hasFavoritesColumn(helper.getWritableDatabase(), Favorites.OPTIONS));
143             assertEquals(10, getFavoriteDataCount(helper.getWritableDatabase()));
144         }
145 
146         try (SQLiteOpenHelper helper = new MyDatabaseHelper()) {
147             assertEquals(DatabaseHelper.SCHEMA_VERSION,
148                     helper.getWritableDatabase().getVersion());
149             assertTrue(hasFavoritesColumn(helper.getWritableDatabase(), Favorites.OPTIONS));
150             assertEquals(10, getFavoriteDataCount(helper.getWritableDatabase()));
151         }
152     }
153 
154     @Test(expected = DowngradeFailException.class)
testDowngrade_fail_v20()155     public void testDowngrade_fail_v20() throws Exception {
156         setupTestDb();
157 
158         TestOpenHelper helper = new TestOpenHelper(20);
159         helper.getReadableDatabase().getVersion();
160     }
161 
setupTestDb()162     private void setupTestDb() throws Exception {
163         mSchemaFile.delete();
164         mDbFile.delete();
165 
166         DbDowngradeHelper.updateSchemaFile(mSchemaFile, DatabaseHelper.SCHEMA_VERSION, mContext);
167 
168         DatabaseHelper dbHelper = new MyDatabaseHelper();
169         // Insert mock data
170         for (int i = 0; i < 10; i++) {
171             ContentValues values = new ContentValues();
172             values.put(Favorites._ID, i);
173             values.put(Favorites.TITLE, "title " + i);
174             dbHelper.getWritableDatabase().insert(Favorites.TABLE_NAME, null, values);
175         }
176         dbHelper.close();
177     }
178 
179     private class TestOpenHelper extends SQLiteOpenHelper {
180 
TestOpenHelper(int version)181         public TestOpenHelper(int version) {
182             super(mContext, DB_FILE, null, version);
183         }
184 
185         @Override
onCreate(SQLiteDatabase sqLiteDatabase)186         public void onCreate(SQLiteDatabase sqLiteDatabase) {
187             throw new RuntimeException("DB should already be created");
188         }
189 
190         @Override
onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)191         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
192             throw new RuntimeException("Only downgrade supported");
193         }
194 
195         @Override
onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion)196         public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
197             try {
198                 DbDowngradeHelper.parse(mSchemaFile).onDowngrade(db, oldVersion, newVersion);
199             } catch (Exception e) {
200                 throw new DowngradeFailException(e);
201             }
202         }
203     }
204 
205     private static class DowngradeFailException extends RuntimeException {
DowngradeFailException(Exception e)206         public DowngradeFailException(Exception e) {
207             super(e);
208         }
209     }
210 
hasFavoritesColumn(SQLiteDatabase db, String columnName)211     private static boolean hasFavoritesColumn(SQLiteDatabase db, String columnName) {
212         try (Cursor c = db.query(Favorites.TABLE_NAME, null, null, null, null, null, null)) {
213             return c.getColumnIndex(columnName) >= 0;
214         }
215     }
216 
getFavoriteDataCount(SQLiteDatabase db)217     public static int getFavoriteDataCount(SQLiteDatabase db) {
218         try (Cursor c = db.query(Favorites.TABLE_NAME, null, null, null, null, null, null)) {
219             return c.getCount();
220         }
221     }
222 
223     private class MyDatabaseHelper extends DatabaseHelper {
224 
MyDatabaseHelper()225         MyDatabaseHelper() {
226             super(mContext, DB_FILE,
227                     UserCache.INSTANCE.get(mContext)::getSerialNumberForUser,
228                     () -> { });
229         }
230 
231         @Override
onOpen(SQLiteDatabase db)232         public void onOpen(SQLiteDatabase db) { }
233     }
234 }
235