1bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori/*
2bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * Copyright (C) 2010 The Android Open Source Project
3bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori *
4bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * Licensed under the Apache License, Version 2.0 (the "License");
5bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * you may not use this file except in compliance with the License.
6bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * You may obtain a copy of the License at
7bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori *
8bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori *      http://www.apache.org/licenses/LICENSE-2.0
9bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori *
10bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * Unless required by applicable law or agreed to in writing, software
11bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * distributed under the License is distributed on an "AS IS" BASIS,
12bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * See the License for the specific language governing permissions and
14bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori * limitations under the License.
15bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori */
16bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
17bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noripackage android.database;
18bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
19bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noriimport android.content.Context;
20bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noriimport android.database.sqlite.SQLiteDatabase;
21e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Noriimport android.database.sqlite.SQLiteDiskIOException;
22bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noriimport android.database.sqlite.SQLiteException;
23bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noriimport android.test.AndroidTestCase;
24bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noriimport android.util.Log;
25bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
26bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noriimport java.io.BufferedWriter;
27bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noriimport java.io.File;
28bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noriimport java.io.FileWriter;
29bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noriimport java.io.IOException;
30bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
31bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Noripublic class DatabaseErrorHandlerTest extends AndroidTestCase {
32bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
33bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    private SQLiteDatabase mDatabase;
34bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    private File mDatabaseFile;
35bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    private static final String DB_NAME = "database_test.db";
36bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    private File dbDir;
37bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
38bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    @Override
39bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    protected void setUp() throws Exception {
40bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        super.setUp();
41bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
42bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        mDatabaseFile = new File(dbDir, DB_NAME);
43bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        if (mDatabaseFile.exists()) {
44bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            mDatabaseFile.delete();
45bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        }
46bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null,
47bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                new MyDatabaseCorruptionHandler());
48bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        assertNotNull(mDatabase);
49bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    }
50bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
51bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    @Override
52bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    protected void tearDown() throws Exception {
53bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        mDatabase.close();
54bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        mDatabaseFile.delete();
55bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        super.tearDown();
56bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    }
57bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
58bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    public void testNoCorruptionCase() {
59bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        new MyDatabaseCorruptionHandler().onCorruption(mDatabase);
60bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        // database file should still exist
61bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        assertTrue(mDatabaseFile.exists());
62bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    }
63bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
64e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori
65bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    public void testDatabaseIsCorrupt() throws IOException {
66bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        mDatabase.execSQL("create table t (i int);");
67bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        // write junk into the database file
68bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        BufferedWriter writer = new BufferedWriter(new FileWriter(mDatabaseFile.getPath()));
69bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        writer.write("blah");
70bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        writer.close();
71bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        assertTrue(mDatabaseFile.exists());
72bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        // since the database file is now corrupt, doing any sql on this database connection
73bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        // should trigger call to MyDatabaseCorruptionHandler.onCorruption
74bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        try {
75bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            mDatabase.execSQL("select * from t;");
76bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            fail("expected exception");
77e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori        } catch (SQLiteDiskIOException e) {
78e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori            /**
79e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori             * this test used to produce a corrupted db. but with new sqlite it instead reports
80e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori             * Disk I/O error. meh..
81e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori             * need to figure out how to cause corruption in db
82e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori             */
83bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            // expected
84e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori            if (mDatabaseFile.exists()) {
85e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori                mDatabaseFile.delete();
86e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori            }
87e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori        } catch (SQLiteException e) {
88e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori
89bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        }
90e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori        // database file should be gone
91e7dea4ec2479002f5ee15bc6fc98d8c8acd123a6Vasu Nori        assertFalse(mDatabaseFile.exists());
92bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        // after corruption handler is called, the database file should be free of
93bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        // database corruption
94bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null,
95bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                new MyDatabaseCorruptionHandler());
96bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        assertTrue(db.isDatabaseIntegrityOk());
97bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    }
98bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori
99bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    /**
100bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori     * An example implementation of {@link DatabaseErrorHandler} to demonstrate
101bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori     * database corruption handler which checks to make sure database is indeed
102bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori     * corrupt before deleting the file.
103bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori     */
104bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    public class MyDatabaseCorruptionHandler implements DatabaseErrorHandler {
105bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        public void onCorruption(SQLiteDatabase dbObj) {
106bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            boolean databaseOk = dbObj.isDatabaseIntegrityOk();
107bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            // close the database
108bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            try {
109bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                dbObj.close();
110bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            } catch (SQLiteException e) {
111bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                /* ignore */
112bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            }
113bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            if (databaseOk) {
114bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                // database is just fine. no need to delete the database file
115bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                Log.e("MyDatabaseCorruptionHandler", "no corruption in the database: " +
116bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                        mDatabaseFile.getPath());
117bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            } else {
118bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                // database is corrupt. delete the database file
119bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                Log.e("MyDatabaseCorruptionHandler", "deleting the database file: " +
120bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                        mDatabaseFile.getPath());
121bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori                new File(dbDir, DB_NAME).delete();
122bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori            }
123bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori        }
124bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori    }
125bfe1dc27944c80dcb81f0eb313987999ecd7b6faVasu Nori}