001: /*
002: * $Id: TestThreadedDML.java,v 1.19 2005/04/24 21:35:59 ahimanikya Exp $
003: * =======================================================================
004: * Copyright (c) 2002-2003 Axion Development Team. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above
011: * copyright notice, this list of conditions and the following
012: * disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The names "Tigris", "Axion", nor the names of its contributors may
020: * not be used to endorse or promote products derived from this
021: * software without specific prior written permission.
022: *
023: * 4. Products derived from this software may not be called "Axion", nor
024: * may "Tigris" or "Axion" appear in their names without specific prior
025: * written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
030: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
032: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
033: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
034: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
035: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
036: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
037: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
038: * =======================================================================
039: */
040:
041: package org.axiondb.functional;
042:
043: import java.io.File;
044: import java.sql.Connection;
045: import java.sql.DriverManager;
046: import java.sql.PreparedStatement;
047: import java.sql.ResultSet;
048: import java.sql.SQLException;
049: import java.sql.Statement;
050: import java.util.Random;
051:
052: import junit.framework.Test;
053: import junit.framework.TestCase;
054: import junit.framework.TestSuite;
055:
056: import org.axiondb.io.FileUtil;
057:
058: /**
059: * @version $Revision: 1.19 $ $Date: 2005/04/24 21:35:59 $
060: * @author Rodney Waldhoff
061: */
062: public class TestThreadedDML extends TestCase {
063: private static final int NUM_TEST_THREADS = 5;
064: private Connection _conn = null;
065: private Statement _stmt = null;
066:
067: protected String getConnectString() {
068: return "jdbc:axiondb:memdb";
069: }
070:
071: protected File getDatabaseDirectory() {
072: return null;
073: }
074:
075: //------------------------------------------------------------ Conventional
076:
077: public TestThreadedDML(String testName) {
078: super (testName);
079: }
080:
081: public static Test suite() {
082: return new TestSuite(TestThreadedDML.class);
083: }
084:
085: //--------------------------------------------------------------- Lifecycle
086:
087: public void setUp() throws Exception {
088: Class.forName("org.axiondb.jdbc.AxionDriver");
089: _conn = DriverManager.getConnection(getConnectString());
090: _stmt = _conn.createStatement();
091: }
092:
093: public void tearDown() throws Exception {
094: try {
095: _stmt.execute("shutdown");
096: } catch (Throwable e) {
097: //e.printStackTrace();
098: }
099:
100: try {
101: _stmt.close();
102: _conn.close();
103: } catch (Exception t) {
104: t.printStackTrace();
105: }
106: _stmt = null;
107: _conn = null;
108:
109: FileUtil.delete(getDatabaseDirectory());
110: }
111:
112: //------------------------------------------------------------------- Tests
113:
114: public void testWithAutocommit() throws Exception {
115: createTableFoo();
116: populateTableFoo();
117: runTests(true);
118: }
119:
120: public void testWithNoAutocommit() throws Exception {
121: createTableFoo();
122: populateTableFoo();
123: runTests(false);
124: }
125:
126: public void testIndexedWithAutocommit() throws Exception {
127: createTableFoo();
128: createIndexOnFoo();
129: populateTableFoo();
130: runTests(true);
131: }
132:
133: public void testIndexedWithNoAutocommit() throws Exception {
134: createTableFoo();
135: createIndexOnFoo();
136: populateTableFoo();
137: runTests(false);
138: }
139:
140: //----------------------------------------------------------- Inner Classes
141:
142: private void runTests(boolean autocommit) throws Exception {
143: TestThread[] tests = new TestThread[NUM_TEST_THREADS];
144: Thread[] threads = new Thread[NUM_TEST_THREADS];
145: for (int i = 0; i < NUM_TEST_THREADS; i++) {
146: tests[i] = new TestThread(autocommit);
147: threads[i] = new Thread(tests[i]);
148: }
149: for (int i = 0; i < NUM_TEST_THREADS; i++) {
150: threads[i].start();
151: }
152: for (int i = 0; i < NUM_TEST_THREADS; i++) {
153: while (!tests[i].done) {
154: try {
155: Thread.sleep(100L);
156: } catch (Exception e) {
157: }
158: }
159: if (!tests[i].success) {
160: throw tests[i].exception;
161: }
162: }
163: Thread.sleep(100L);
164: }
165:
166: class TestThread implements Runnable {
167: private Random _random = new Random();
168: private boolean _autocommit;
169: public boolean done = false;
170: public boolean success = true;
171: public Exception exception = null;
172:
173: public TestThread(boolean autocommit) {
174: _autocommit = autocommit;
175: }
176:
177: private Exception select(Connection conn) {
178: PreparedStatement stmt = null;
179: ResultSet rset = null;
180: try {
181: stmt = conn
182: .prepareStatement("select NUM, STR from FOO where NUM > ? and NUM < ?");
183: stmt.setInt(1, _random.nextInt(10));
184: stmt.setInt(2, _random.nextInt(100) + 10);
185: rset = stmt.executeQuery();
186: while (rset.next()) {
187: int num = rset.getInt(1);
188: String str = rset.getString(2);
189: if (!str.equals(String.valueOf(num))) {
190: return new RuntimeException(str + " != " + num);
191: }
192: }
193: return null;
194: } catch (Exception e) {
195: return e;
196: } finally {
197: try {
198: if (rset != null)
199: rset.close();
200: } catch (Exception t) {
201: }
202: try {
203: if (stmt != null)
204: stmt.close();
205: } catch (Exception t) {
206: }
207: }
208: }
209:
210: private Exception insert(Connection conn) {
211: PreparedStatement stmt = null;
212: try {
213: stmt = conn
214: .prepareStatement("insert into FOO ( NUM, STR, NUMTWO ) values ( ?, ?, ? )");
215: for (int i = 0; i < 5; i++) {
216: int num = _random.nextInt(100);
217: stmt.setInt(1, num);
218: stmt.setString(2, String.valueOf(num));
219: stmt.setInt(3, num / 2);
220: if (1 != stmt.executeUpdate()) {
221: return new RuntimeException("Expected 1");
222: }
223: }
224: return null;
225: } catch (Exception e) {
226: if (e instanceof SQLException
227: && ((SQLException) e).getErrorCode() == 51000) {
228: // ignored
229: return null;
230: }
231: return e;
232: } finally {
233: try {
234: stmt.close();
235: } catch (Exception t) {
236: }
237: }
238: }
239:
240: private Exception update(Connection conn) {
241: PreparedStatement stmt = null;
242: try {
243: stmt = conn
244: .prepareStatement("update FOO set NUM = ?, STR = ?, NUMTWO = ? where NUM = ? or NUMTWO = ?");
245: for (int i = 0; i < 5; i++) {
246: int num = _random.nextInt(100);
247: stmt.setInt(1, num);
248: stmt.setString(2, String.valueOf(num));
249: stmt.setInt(3, num / 2);
250: stmt.setInt(4, _random.nextInt(100));
251: stmt.setInt(5, _random.nextInt(100));
252: stmt.executeUpdate();
253: }
254: return null;
255: } catch (Exception e) {
256: if (e instanceof SQLException
257: && ((SQLException) e).getErrorCode() == 51000) {
258: // ignored
259: return null;
260: }
261: return e;
262: } finally {
263: try {
264: stmt.close();
265: } catch (Exception t) {
266: }
267: }
268: }
269:
270: private Exception delete(Connection conn) {
271: PreparedStatement stmt = null;
272: try {
273: stmt = conn
274: .prepareStatement("delete from FOO where NUM between ? and ?");
275: for (int i = 0; i < 5; i++) {
276: int num = _random.nextInt(100);
277: stmt.setInt(1, num);
278: stmt.setInt(2, num + _random.nextInt(10));
279: stmt.executeUpdate();
280: }
281: return null;
282: } catch (Exception e) {
283: if (e instanceof SQLException
284: && ((SQLException) e).getErrorCode() == 51000) {
285: // ignored
286: return null;
287: }
288: return e;
289: } finally {
290: try {
291: stmt.close();
292: } catch (Exception t) {
293: }
294: }
295: }
296:
297: public void run() {
298: Connection conn = null;
299: try {
300: conn = DriverManager.getConnection(getConnectString());
301: conn.setAutoCommit(_autocommit);
302: for (int i = 0; i < 50; i++) {
303: switch (_random.nextInt(4)) {
304: case 0:
305: exception = select(conn);
306: break;
307: case 1:
308: exception = insert(conn);
309: break;
310: case 2:
311: exception = update(conn);
312: break;
313: case 3:
314: exception = delete(conn);
315: break;
316: }
317: if (null != exception) {
318: success = false;
319: break;
320: }
321: }
322: } catch (Exception e) {
323: exception = e;
324: success = false;
325: } finally {
326: if (!_autocommit) {
327: try {
328: conn.commit();
329: } catch (SQLException e) {
330: }
331: }
332: try {
333: conn.close();
334: } catch (Exception t) {
335: }
336: done = true;
337: }
338: }
339: }
340:
341: //-------------------------------------------------------------------- Util
342:
343: private void createTableFoo() throws Exception {
344: _stmt
345: .execute("create table FOO ( NUM integer, STR varchar2(2), NUMTWO integer )");
346: }
347:
348: private void createIndexOnFoo() throws Exception {
349: _stmt.execute("create index FOO_NUM_NDX on FOO ( NUM )");
350: }
351:
352: private void populateTableFoo() throws Exception {
353: for (int i = 0; i < 30; i++) {
354: _stmt
355: .execute("insert into FOO ( NUM, STR, NUMTWO ) values ( "
356: + i + ", '" + i + "', " + (i / 2) + ")");
357: }
358: }
359:
360: }
|