/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.database.sqlite; import android.content.Context; import android.test.AndroidTestCase; import android.test.FlakyTest; import android.test.suitebuilder.annotation.LargeTest; import java.io.File; public class SQLiteGeneralTest extends AndroidTestCase { private SQLiteDatabase mDatabase; private File mDatabaseFile; Boolean exceptionRecvd = false; @Override protected void setUp() throws Exception { super.setUp(); exceptionRecvd = false; File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE); mDatabaseFile = new File(dbDir, "database_test.db"); if (mDatabaseFile.exists()) { mDatabaseFile.delete(); } mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); assertNotNull(mDatabase); } @Override protected void tearDown() throws Exception { mDatabase.close(); mDatabaseFile.delete(); super.tearDown(); } @LargeTest public void testUseOfSameSqlStatementBy2Threads() throws Exception { mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);"); // thread 1 creates a prepared statement final String stmt = "SELECT * FROM test_pstmt WHERE i = ?"; // start 2 threads to do repeatedly execute "stmt" // since these 2 threads are executing the same sql, they each should get // their own copy and // there SHOULD NOT be an error from sqlite: "prepared statement is busy" class RunStmtThread extends Thread { private static final int N = 1000; @Override public void run() { int i = 0; try { // execute many times for (i = 0; i < N; i++) { SQLiteStatement s1 = mDatabase.compileStatement(stmt); s1.bindLong(1, i); s1.execute(); s1.close(); } } catch (SQLiteException e) { fail("SQLiteException: " + e.getMessage()); return; } catch (Exception e) { e.printStackTrace(); fail("random unexpected exception: " + e.getMessage()); return; } } } RunStmtThread t1 = new RunStmtThread(); t1.start(); RunStmtThread t2 = new RunStmtThread(); t2.start(); while (t1.isAlive() || t2.isAlive()) { Thread.sleep(1000); } } @FlakyTest public void testUseOfSamePreparedStatementBy2Threads() throws Exception { mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);"); // thread 1 creates a prepared statement final String stmt = "SELECT * FROM test_pstmt WHERE i = ?"; final SQLiteStatement s1 = mDatabase.compileStatement(stmt); // start 2 threads to do repeatedly execute "stmt" // since these 2 threads are executing the same prepared statement, // should see an error from sqlite: "prepared statement is busy" class RunStmtThread extends Thread { private static final int N = 1000; @Override public void run() { int i = 0; try { // execute many times for (i = 0; i < N; i++) { s1.bindLong(1, i); s1.execute(); } } catch (SQLiteException e) { // expect it assertTrue(e.getMessage().contains("library routine called out of sequence:")); exceptionRecvd = true; return; } catch (Exception e) { e.printStackTrace(); fail("random unexpected exception: " + e.getMessage()); return; } } } RunStmtThread t1 = new RunStmtThread(); t1.start(); RunStmtThread t2 = new RunStmtThread(); t2.start(); while (t1.isAlive() || t2.isAlive()) { Thread.sleep(1000); } assertTrue(exceptionRecvd); } }