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
17package android.database;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertNotNull;
21import static org.junit.Assert.assertTrue;
22import static org.junit.Assert.fail;
23
24import android.content.Context;
25import android.database.sqlite.SQLiteDatabase;
26import android.database.sqlite.SQLiteDatabaseConfiguration;
27import android.database.sqlite.SQLiteDebug;
28import android.database.sqlite.SQLiteOpenHelper;
29import android.support.test.InstrumentationRegistry;
30import android.support.test.filters.SmallTest;
31import android.support.test.runner.AndroidJUnit4;
32import android.util.Log;
33
34import org.junit.After;
35import org.junit.Before;
36import org.junit.Test;
37import org.junit.runner.RunWith;
38
39import java.util.ArrayList;
40import java.util.List;
41
42/**
43 * Tests for {@link SQLiteOpenHelper}
44 *
45 * <p>Run with:  bit FrameworksCoreTests:android.database.SQLiteOpenHelperTest
46 */
47@RunWith(AndroidJUnit4.class)
48@SmallTest
49public class SQLiteOpenHelperTest {
50    private static final String TAG = "SQLiteOpenHelperTest";
51
52    private TestHelper mTestHelper;
53    private Context mContext;
54    private List<SQLiteOpenHelper> mHelpersToClose;
55
56    private static class TestHelper extends SQLiteOpenHelper {
57        TestHelper(Context context) { // In-memory
58            super(context, null, null, 1);
59        }
60
61        TestHelper(Context context, String name) {
62            super(context, name, null, 1);
63        }
64
65        TestHelper(Context context, String name, int version, SQLiteDatabase.OpenParams params) {
66            super(context, name, version, params);
67        }
68
69        @Override
70        public void onCreate(SQLiteDatabase db) {
71        }
72
73        @Override
74        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
75        }
76    }
77
78    @Before
79    public void setup() {
80        mContext = InstrumentationRegistry.getContext();
81        mTestHelper = new TestHelper(mContext, "openhelper_test");
82        mHelpersToClose = new ArrayList<>();
83        mHelpersToClose.add(mTestHelper);
84    }
85
86    @After
87    public void teardown() {
88        for (SQLiteOpenHelper helper : mHelpersToClose) {
89            try {
90                helper.close();
91                if (mTestHelper.getDatabaseName() != null) {
92                    SQLiteDatabase.deleteDatabase(
93                            mContext.getDatabasePath(mTestHelper.getDatabaseName()));
94                }
95            } catch (RuntimeException ex) {
96                Log.w(TAG, "Error occured when closing db helper " + helper, ex);
97            }
98        }
99    }
100
101    @Test
102    public void testLookasideDefault() throws Exception {
103        assertNotNull(mTestHelper.getWritableDatabase());
104        verifyLookasideStats(false);
105    }
106
107    @Test
108    public void testLookasideDisabled() throws Exception {
109        mTestHelper.setLookasideConfig(0, 0);
110        assertNotNull(mTestHelper.getWritableDatabase());
111        verifyLookasideStats(true);
112    }
113
114    @Test
115    public void testInMemoryLookasideDisabled() throws Exception {
116        TestHelper memHelper = new TestHelper(mContext);
117        mHelpersToClose.add(memHelper);
118        memHelper.setLookasideConfig(0, 0);
119        assertNotNull(memHelper.getWritableDatabase());
120        verifyLookasideStats(SQLiteDatabaseConfiguration.MEMORY_DB_PATH, true);
121    }
122
123    @Test
124    public void testInMemoryLookasideDefault() throws Exception {
125        TestHelper memHelper = new TestHelper(mContext);
126        mHelpersToClose.add(memHelper);
127        assertNotNull(memHelper.getWritableDatabase());
128        verifyLookasideStats(SQLiteDatabaseConfiguration.MEMORY_DB_PATH, false);
129    }
130
131    @Test
132    public void testSetLookasideConfigValidation() {
133        try {
134            mTestHelper.setLookasideConfig(-1, 0);
135            fail("Negative slot size should be rejected");
136        } catch (IllegalArgumentException expected) {
137        }
138        try {
139            mTestHelper.setLookasideConfig(0, -10);
140            fail("Negative slot count should be rejected");
141        } catch (IllegalArgumentException expected) {
142        }
143        try {
144            mTestHelper.setLookasideConfig(1, 0);
145            fail("Illegal config should be rejected");
146        } catch (IllegalArgumentException expected) {
147        }
148        try {
149            mTestHelper.setLookasideConfig(0, 1);
150            fail("Illegal config should be rejected");
151        } catch (IllegalArgumentException expected) {
152        }
153    }
154
155    private void verifyLookasideStats(boolean expectDisabled) {
156        verifyLookasideStats(mTestHelper.getDatabaseName(), expectDisabled);
157    }
158
159    private static void verifyLookasideStats(String dbName, boolean expectDisabled) {
160        boolean dbStatFound = false;
161        SQLiteDebug.PagerStats info = SQLiteDebug.getDatabaseInfo();
162        for (SQLiteDebug.DbStats dbStat : info.dbStats) {
163            if (dbStat.dbName.endsWith(dbName)) {
164                dbStatFound = true;
165                Log.i(TAG, "Lookaside for " + dbStat.dbName + " " + dbStat.lookaside);
166                if (expectDisabled) {
167                    assertTrue("lookaside slots count should be zero", dbStat.lookaside == 0);
168                } else {
169                    assertTrue("lookaside slots count should be greater than zero",
170                            dbStat.lookaside > 0);
171                }
172            }
173        }
174        assertTrue("No dbstat found for " + dbName, dbStatFound);
175    }
176
177    @Test
178    public void testOpenParamsConstructor() {
179        SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder()
180                .setJournalMode("DELETE")
181                .setSynchronousMode("OFF")
182                .build();
183
184        TestHelper helper = new TestHelper(mContext, "openhelper_test_constructor", 1, params);
185        mHelpersToClose.add(helper);
186
187        String journalMode = DatabaseUtils
188                .stringForQuery(helper.getReadableDatabase(), "PRAGMA journal_mode", null);
189
190        assertEquals("DELETE", journalMode.toUpperCase());
191        String syncMode = DatabaseUtils
192                .stringForQuery(helper.getReadableDatabase(), "PRAGMA synchronous", null);
193
194        assertEquals("0", syncMode);
195    }
196
197}
198