1/*
2 * Copyright (C) 2006 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.sqlite;
18
19import android.content.Context;
20import android.test.AndroidTestCase;
21import android.test.FlakyTest;
22import android.test.suitebuilder.annotation.LargeTest;
23
24import java.io.File;
25
26public class SQLiteGeneralTest extends AndroidTestCase {
27
28    private SQLiteDatabase mDatabase;
29    private File mDatabaseFile;
30    Boolean exceptionRecvd = false;
31
32    @Override
33    protected void setUp() throws Exception {
34        super.setUp();
35        exceptionRecvd = false;
36        File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
37        mDatabaseFile = new File(dbDir, "database_test.db");
38        if (mDatabaseFile.exists()) {
39            mDatabaseFile.delete();
40        }
41        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
42        assertNotNull(mDatabase);
43    }
44
45    @Override
46    protected void tearDown() throws Exception {
47        mDatabase.close();
48        mDatabaseFile.delete();
49        super.tearDown();
50    }
51
52    @LargeTest
53    public void testUseOfSameSqlStatementBy2Threads() throws Exception {
54        mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);");
55
56        // thread 1 creates a prepared statement
57        final String stmt = "SELECT * FROM test_pstmt WHERE i = ?";
58
59        // start 2 threads to do repeatedly execute "stmt"
60        // since these 2 threads are executing the same sql, they each should get
61        // their own copy and
62        // there SHOULD NOT be an error from sqlite: "prepared statement is busy"
63        class RunStmtThread extends Thread {
64            private static final int N = 1000;
65            @Override public void run() {
66                int i = 0;
67                try {
68                    // execute many times
69                    for (i = 0; i < N; i++) {
70                        SQLiteStatement s1 = mDatabase.compileStatement(stmt);
71                        s1.bindLong(1, i);
72                        s1.execute();
73                        s1.close();
74                    }
75                } catch (SQLiteException e) {
76                    fail("SQLiteException: " + e.getMessage());
77                    return;
78                } catch (Exception e) {
79                    e.printStackTrace();
80                    fail("random unexpected exception: " + e.getMessage());
81                    return;
82                }
83            }
84        }
85        RunStmtThread t1 = new RunStmtThread();
86        t1.start();
87        RunStmtThread t2 = new RunStmtThread();
88        t2.start();
89        while (t1.isAlive() || t2.isAlive()) {
90            Thread.sleep(1000);
91        }
92    }
93
94    @FlakyTest
95    public void testUseOfSamePreparedStatementBy2Threads() throws Exception {
96        mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);");
97
98        // thread 1 creates a prepared statement
99        final String stmt = "SELECT * FROM test_pstmt WHERE i = ?";
100        final SQLiteStatement s1 = mDatabase.compileStatement(stmt);
101
102        // start 2 threads to do repeatedly execute "stmt"
103        // since these 2 threads are executing the same prepared statement,
104        // should see an error from sqlite: "prepared statement is busy"
105        class RunStmtThread extends Thread {
106            private static final int N = 1000;
107            @Override public void run() {
108                int i = 0;
109                try {
110                    // execute many times
111                    for (i = 0; i < N; i++) {
112                        s1.bindLong(1, i);
113                        s1.execute();
114                    }
115                } catch (SQLiteException e) {
116                    // expect it
117                    assertTrue(e.getMessage().contains("library routine called out of sequence:"));
118                    exceptionRecvd = true;
119                    return;
120                } catch (Exception e) {
121                    e.printStackTrace();
122                    fail("random unexpected exception: " + e.getMessage());
123                    return;
124                }
125            }
126        }
127        RunStmtThread t1 = new RunStmtThread();
128        t1.start();
129        RunStmtThread t2 = new RunStmtThread();
130        t2.start();
131        while (t1.isAlive() || t2.isAlive()) {
132            Thread.sleep(1000);
133        }
134        assertTrue(exceptionRecvd);
135    }
136}
137