001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (license2)
004: * Initial Developer: H2 Group
005: */
006: package org.h2.test;
007:
008: import java.io.File;
009: import java.io.FileWriter;
010: import java.io.PrintWriter;
011: import java.io.Reader;
012: import java.sql.Connection;
013: import java.sql.DriverManager;
014: import java.sql.ResultSet;
015: import java.sql.ResultSetMetaData;
016: import java.sql.SQLException;
017: import java.sql.Statement;
018: import java.sql.Types;
019: import java.text.SimpleDateFormat;
020: import java.util.ArrayList;
021: import java.util.Properties;
022:
023: import org.h2.jdbc.JdbcConnection;
024: import org.h2.message.TraceSystem;
025: import org.h2.store.FileLock;
026: import org.h2.tools.DeleteDbFiles;
027:
028: /**
029: * The base class for all tests.
030: */
031: public abstract class TestBase {
032:
033: // private static final String BASE_TEST_DIR =
034: // System.getProperty("java.io.tmpdir") + "/h2";
035: private static final String BASE_TEST_DIR = "data";
036:
037: public static String getTestDir(String name) {
038: return BASE_TEST_DIR + "/test" + name;
039: }
040:
041: protected static String baseDir = getTestDir("");
042:
043: protected TestAll config;
044: private long start;
045:
046: protected void startServerIfRequired() throws SQLException {
047: config.beforeTest();
048: }
049:
050: public TestBase init(TestAll conf) throws Exception {
051: baseDir = getTestDir("");
052: this .config = conf;
053: return this ;
054: }
055:
056: public void testCase(int i) throws Exception {
057: // do nothing
058: }
059:
060: public void runTest(TestAll conf) {
061: try {
062: init(conf);
063: start = System.currentTimeMillis();
064: test();
065: println("");
066: } catch (Exception e) {
067: fail("FAIL " + e.toString(), e);
068: if (config.stopOnError) {
069: throw new Error("ERROR");
070: }
071: }
072: }
073:
074: public Connection getConnection(String name) throws Exception {
075: return getConnectionInternal(getURL(name, true), getUser(),
076: getPassword());
077: }
078:
079: protected Connection getConnection(String name, String user,
080: String password) throws Exception {
081: return getConnectionInternal(getURL(name, false), user,
082: password);
083: }
084:
085: protected String getPassword() {
086: return "123";
087: }
088:
089: private void deleteIndexFiles(String name) throws SQLException {
090: if (name.indexOf(";") > 0) {
091: name = name.substring(0, name.indexOf(';'));
092: }
093: name += ".index.db";
094: if (new File(name).canWrite()) {
095: new File(name).delete();
096: }
097: }
098:
099: protected String getURL(String name, boolean admin)
100: throws SQLException {
101: String url;
102: if (name.startsWith("jdbc:")) {
103: return name;
104: }
105: if (config.memory) {
106: url = "mem:" + name;
107: } else {
108: if (!name.startsWith("memFS:")
109: && !name.startsWith(baseDir + "/")) {
110: name = baseDir + "/" + name;
111: }
112: if (config.deleteIndex) {
113: deleteIndexFiles(name);
114: }
115: if (config.networked) {
116: if (config.ssl) {
117: url = "ssl://localhost:9192/" + name;
118: } else {
119: url = "tcp://localhost:9192/" + name;
120: }
121: } else {
122: url = name;
123: }
124: if (config.traceSystemOut) {
125: url += ";TRACE_LEVEL_SYSTEM_OUT=2";
126: }
127: if (config.traceLevelFile > 0 && admin) {
128: url += ";TRACE_LEVEL_FILE=" + config.traceLevelFile;
129: }
130: }
131: if (config.throttle > 0) {
132: url += ";THROTTLE=" + config.throttle;
133: }
134: if (config.textStorage) {
135: url += ";STORAGE=TEXT";
136: }
137: url += ";LOCK_TIMEOUT=50";
138: if (admin) {
139: url += ";LOG=" + config.logMode;
140: }
141: if (config.smallLog && admin) {
142: url += ";MAX_LOG_SIZE=1";
143: }
144: if (config.diskUndo && admin) {
145: url += ";MAX_MEMORY_UNDO=3";
146: }
147: if (config.big && admin) {
148: // force operations to disk
149: url += ";MAX_OPERATION_MEMORY=1";
150: }
151: if (config.mvcc) {
152: url += ";MVCC=TRUE";
153: }
154: if (config.cache2Q) {
155: url += ";CACHE_TYPE=TQ";
156: }
157: if (config.diskResult && admin) {
158: url += ";MAX_MEMORY_ROWS=100;CACHE_SIZE=0";
159: }
160: return "jdbc:h2:" + url;
161: }
162:
163: private Connection getConnectionInternal(String url, String user,
164: String password) throws Exception {
165: Class.forName("org.h2.Driver");
166: // url += ";DEFAULT_TABLE_TYPE=1";
167: // Class.forName("org.hsqldb.jdbcDriver");
168: // return DriverManager.getConnection("jdbc:hsqldb:" + name, "sa", "");
169: Connection conn;
170: if (config.cipher != null) {
171: url += ";cipher=" + config.cipher;
172: password = "filePassword " + password;
173: Properties info = new Properties();
174: info.setProperty("user", user);
175: info.setProperty("password", password);
176: // a bug in the PostgreSQL driver: throws a NullPointerException if we do this
177: // info.put("password", password.toCharArray());
178: conn = DriverManager.getConnection(url, info);
179: } else {
180: conn = DriverManager.getConnection(url, user, password);
181: }
182: return conn;
183: }
184:
185: protected int getSize(int small, int big) throws Exception {
186: return config.endless ? Integer.MAX_VALUE : config.big ? big
187: : small;
188: }
189:
190: protected String getUser() {
191: return "sa";
192: }
193:
194: protected void trace(int x) {
195: trace("" + x);
196: }
197:
198: public void trace(String s) {
199: if (config.traceTest) {
200: println(s);
201: }
202: }
203:
204: protected void traceMemory() {
205: if (config.traceTest) {
206: trace("mem=" + getMemoryUsed());
207: }
208: }
209:
210: public void printTimeMemory(String s, long time) {
211: if (config.big) {
212: println(getMemoryUsed() + " MB: " + s);
213: }
214: }
215:
216: public static int getMemoryUsed() {
217: Runtime rt = Runtime.getRuntime();
218: long memory = Long.MAX_VALUE;
219: for (int i = 0; i < 8; i++) {
220: rt.gc();
221: long memNow = rt.totalMemory() - rt.freeMemory();
222: if (memNow >= memory) {
223: break;
224: }
225: memory = memNow;
226: }
227: int mb = (int) (memory / 1024 / 1024);
228: return mb;
229: }
230:
231: protected void error() throws Exception {
232: error("Unexpected success");
233: }
234:
235: protected void error(String string) throws Exception {
236: println(string);
237: throw new Exception(string);
238: }
239:
240: protected void fail(String s, Throwable e) {
241: println(s);
242: logError(s, e);
243: }
244:
245: public static void logError(String s, Throwable e) {
246: if (e == null) {
247: e = new Exception(s);
248: }
249: System.out.println("ERROR: " + s + " " + e.toString()
250: + " ------------------------------");
251: e.printStackTrace();
252: try {
253: TraceSystem ts = new TraceSystem(null, false);
254: FileLock lock = new FileLock(ts, 1000);
255: lock.lock("error.lock", false);
256: FileWriter fw = new FileWriter("ERROR.txt", true);
257: PrintWriter pw = new PrintWriter(fw);
258: e.printStackTrace(pw);
259: pw.close();
260: fw.close();
261: lock.unlock();
262: } catch (Throwable t) {
263: t.printStackTrace();
264: }
265: }
266:
267: protected void println(String s) {
268: long time = System.currentTimeMillis() - start;
269: printlnWithTime(time, getClass().getName() + " " + s);
270: }
271:
272: static void printlnWithTime(long time, String s) {
273: String t = "0000000000" + time;
274: t = t.substring(t.length() - 6);
275: System.out.println(t + " " + s);
276: }
277:
278: protected void printTime(String s) {
279: SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
280: println(dateFormat.format(new java.util.Date()) + " " + s);
281: }
282:
283: protected void deleteDb(String name) throws Exception {
284: DeleteDbFiles.execute(baseDir, name, true);
285: }
286:
287: protected void deleteDb(String dir, String name) throws Exception {
288: DeleteDbFiles.execute(dir, name, true);
289: }
290:
291: public abstract void test() throws Exception;
292:
293: public void check(int a, int b) throws Exception {
294: if (a != b) {
295: error("int a: " + a + " b: " + b);
296: }
297: }
298:
299: protected void check(byte[] a, byte[] b) throws Exception {
300: check(a.length == b.length);
301: for (int i = 0; i < a.length; i++) {
302: if (a[i] != b[i]) {
303: error("byte[" + i + "]: a=" + (int) a[i] + " b="
304: + (int) b[i]);
305: }
306: }
307: }
308:
309: protected void check(String a, String b) throws Exception {
310: if (a == null && b == null) {
311: return;
312: } else if (a == null || b == null) {
313: error("string a: " + a + " b: " + b);
314: }
315: if (!a.equals(b)) {
316: for (int i = 0; i < a.length(); i++) {
317: String s = a.substring(0, i);
318: if (!b.startsWith(s)) {
319: a = a.substring(0, i) + "<*>" + a.substring(i);
320: break;
321: }
322: }
323: error("string a: " + a + " (" + a.length() + ") b: " + b
324: + " (" + b.length() + ")");
325: }
326: }
327:
328: protected void checkFalse(String a, String b) throws Exception {
329: if (a.equals(b)) {
330: error("string false a: " + a + " b: " + b);
331: }
332: }
333:
334: protected void check(long a, long b) throws Exception {
335: if (a != b) {
336: error("long a: " + a + " b: " + b);
337: }
338: }
339:
340: protected void checkSmaller(long a, long b) throws Exception {
341: if (a >= b) {
342: error("a: " + a + " is not smaller than b: " + b);
343: }
344: }
345:
346: protected void checkContains(String result, String contains)
347: throws Exception {
348: if (result.indexOf(contains) < 0) {
349: error(result + " does not contain: " + contains);
350: }
351: }
352:
353: protected void check(double a, double b) throws Exception {
354: if (a != b) {
355: error("double a: " + a + " b: " + b);
356: }
357: }
358:
359: protected void check(float a, float b) throws Exception {
360: if (a != b) {
361: error("float a: " + a + " b: " + b);
362: }
363: }
364:
365: protected void check(boolean a, boolean b) throws Exception {
366: if (a != b) {
367: error("boolean a: " + a + " b: " + b);
368: }
369: }
370:
371: protected void check(boolean value) throws Exception {
372: if (!value) {
373: error("expected: true got: false");
374: }
375: }
376:
377: protected void checkFalse(boolean value) throws Exception {
378: if (value) {
379: error("expected: false got: true");
380: }
381: }
382:
383: protected void checkResultRowCount(ResultSet rs, int expected)
384: throws Exception {
385: int i = 0;
386: while (rs.next()) {
387: i++;
388: }
389: check(i, expected);
390: }
391:
392: protected void checkSingleValue(Statement stat, String sql,
393: int value) throws Exception {
394: ResultSet rs = stat.executeQuery(sql);
395: check(rs.next());
396: check(rs.getInt(1), value);
397: checkFalse(rs.next());
398: }
399:
400: protected void testResultSetMeta(ResultSet rs, int columnCount,
401: String[] labels, int[] datatypes, int[] precision,
402: int[] scale) throws Exception {
403: ResultSetMetaData meta = rs.getMetaData();
404: int cc = meta.getColumnCount();
405: if (cc != columnCount) {
406: error("result set contains " + cc + " columns not "
407: + columnCount);
408: }
409: for (int i = 0; i < columnCount; i++) {
410: if (labels != null) {
411: String l = meta.getColumnLabel(i + 1);
412: if (!labels[i].equals(l)) {
413: error("column label " + i + " is " + l + " not "
414: + labels[i]);
415: }
416: }
417: if (datatypes != null) {
418: int t = meta.getColumnType(i + 1);
419: if (datatypes[i] != t) {
420: error("column datatype " + i + " is " + t + " not "
421: + datatypes[i] + " (prec="
422: + meta.getPrecision(i + 1) + " scale="
423: + meta.getScale(i + 1) + ")");
424: }
425: String typeName = meta.getColumnTypeName(i + 1);
426: String className = meta.getColumnClassName(i + 1);
427: switch (t) {
428: case Types.INTEGER:
429: check(typeName, "INTEGER");
430: check(className, "java.lang.Integer");
431: break;
432: case Types.VARCHAR:
433: check(typeName, "VARCHAR");
434: check(className, "java.lang.String");
435: break;
436: case Types.SMALLINT:
437: check(typeName, "SMALLINT");
438: check(className, "java.lang.Short");
439: break;
440: case Types.TIMESTAMP:
441: check(typeName, "TIMESTAMP");
442: check(className, "java.sql.Timestamp");
443: break;
444: case Types.DECIMAL:
445: check(typeName, "DECIMAL");
446: check(className, "java.math.BigDecimal");
447: break;
448: default:
449: }
450: }
451: if (precision != null) {
452: int p = meta.getPrecision(i + 1);
453: if (precision[i] != p) {
454: error("column precision " + i + " is " + p
455: + " not " + precision[i]);
456: }
457: }
458: if (scale != null) {
459: int s = meta.getScale(i + 1);
460: if (scale[i] != s) {
461: error("column scale " + i + " is " + s + " not "
462: + scale[i]);
463: }
464: }
465:
466: }
467: }
468:
469: protected void testResultSetOrdered(ResultSet rs, String[][] data)
470: throws Exception {
471: testResultSet(true, rs, data);
472: }
473:
474: void testResultSetUnordered(ResultSet rs, String[][] data)
475: throws Exception {
476: testResultSet(false, rs, data);
477: }
478:
479: void testResultSet(boolean ordered, ResultSet rs, String[][] data)
480: throws Exception {
481: int len = rs.getMetaData().getColumnCount();
482: int rows = data.length;
483: if (rows == 0) {
484: // special case: no rows
485: if (rs.next()) {
486: error("testResultSet expected rowCount:" + rows
487: + " got:0");
488: }
489: }
490: int len2 = data[0].length;
491: if (len < len2) {
492: error("testResultSet expected columnCount:" + len2
493: + " got:" + len);
494: }
495: for (int i = 0; i < rows; i++) {
496: if (!rs.next()) {
497: error("testResultSet expected rowCount:" + rows
498: + " got:" + i);
499: }
500: String[] row = getData(rs, len);
501: if (ordered) {
502: String[] good = data[i];
503: if (!testRow(good, row, good.length)) {
504: error("testResultSet row not equal, got:\n"
505: + formatRow(row) + "\n" + formatRow(good));
506: }
507: } else {
508: boolean found = false;
509: for (int j = 0; j < rows; j++) {
510: String[] good = data[i];
511: if (testRow(good, row, good.length)) {
512: found = true;
513: break;
514: }
515: }
516: if (!found) {
517: error("testResultSet no match for row:"
518: + formatRow(row));
519: }
520: }
521: }
522: if (rs.next()) {
523: String[] row = getData(rs, len);
524: error("testResultSet expected rowcount:" + rows + " got:>="
525: + (rows + 1) + " data:" + formatRow(row));
526: }
527: }
528:
529: boolean testRow(String[] a, String[] b, int len) {
530: for (int i = 0; i < len; i++) {
531: String sa = a[i];
532: String sb = b[i];
533: if (sa == null || sb == null) {
534: if (sa != sb) {
535: return false;
536: }
537: } else {
538: if (!sa.equals(sb)) {
539: return false;
540: }
541: }
542: }
543: return true;
544: }
545:
546: String[] getData(ResultSet rs, int len) throws SQLException {
547: String[] data = new String[len];
548: for (int i = 0; i < len; i++) {
549: data[i] = rs.getString(i + 1);
550: // just check if it works
551: rs.getObject(i + 1);
552: }
553: return data;
554: }
555:
556: String formatRow(String[] row) {
557: String sb = "";
558: for (int i = 0; i < row.length; i++) {
559: sb += "{" + row[i] + "}";
560: }
561: return "{" + sb + "}";
562: }
563:
564: protected void crash(Connection conn) throws Exception {
565: ((JdbcConnection) conn).setPowerOffCount(1);
566: try {
567: conn.createStatement().execute("SET WRITE_DELAY 0");
568: conn.createStatement().execute(
569: "CREATE TABLE TEST_A(ID INT)");
570: error("should be crashed already");
571: } catch (SQLException e) {
572: // expected
573: }
574: try {
575: conn.close();
576: } catch (SQLException e) {
577: // ignore
578: }
579: }
580:
581: protected String readString(Reader reader) throws Exception {
582: if (reader == null) {
583: return null;
584: }
585: StringBuffer buffer = new StringBuffer();
586: try {
587: while (true) {
588: int c = reader.read();
589: if (c == -1) {
590: break;
591: }
592: buffer.append((char) c);
593: }
594: return buffer.toString();
595: } catch (Exception e) {
596: check(false);
597: return null;
598: }
599: }
600:
601: protected void checkNotGeneralException(SQLException e)
602: throws Exception {
603: if (e != null && e.getSQLState().startsWith("HY000")) {
604: TestBase.logError("Unexpected General error", e);
605: }
606: }
607:
608: protected void check(Integer a, Integer b) throws Exception {
609: if (a == null || b == null) {
610: check(a == b);
611: } else {
612: check(a.intValue(), b.intValue());
613: }
614: }
615:
616: protected void compareDatabases(Statement stat1, Statement stat2)
617: throws Exception {
618: ResultSet rs1 = stat1.executeQuery("SCRIPT NOPASSWORDS");
619: ResultSet rs2 = stat2.executeQuery("SCRIPT NOPASSWORDS");
620: ArrayList list1 = new ArrayList();
621: ArrayList list2 = new ArrayList();
622: while (rs1.next()) {
623: check(rs2.next());
624: String s1 = rs1.getString(1);
625: list1.add(s1);
626: String s2 = rs2.getString(1);
627: list2.add(s2);
628: }
629: for (int i = 0; i < list1.size(); i++) {
630: String s = (String) list1.get(i);
631: if (!list2.remove(s)) {
632: error("not found: " + s);
633: }
634: }
635: check(list2.size(), 0);
636: checkFalse(rs2.next());
637: }
638:
639: }
|