1 5 package org.h2.test.synth; 6 7 import java.io.PrintWriter ; 8 import java.io.StringWriter ; 9 import java.lang.reflect.InvocationTargetException ; 10 import java.lang.reflect.Method ; 11 import java.sql.BatchUpdateException ; 12 import java.sql.Connection ; 13 import java.sql.DriverManager ; 14 import java.sql.PreparedStatement ; 15 import java.sql.ResultSet ; 16 import java.sql.ResultSetMetaData ; 17 import java.sql.SQLException ; 18 import java.sql.Savepoint ; 19 import java.sql.Statement ; 20 import java.util.ArrayList ; 21 import java.util.Calendar ; 22 import java.util.HashMap ; 23 import java.util.Map ; 24 25 import org.h2.jdbc.JdbcConnection; 26 import org.h2.test.TestAll; 27 import org.h2.test.TestBase; 28 import org.h2.test.db.TestScript; 29 import org.h2.util.RandomUtils; 30 31 34 public class TestCrashAPI extends TestBase { 35 public static final Class [] INTERFACES = { 36 Connection .class, 37 PreparedStatement .class, 38 Statement .class, 39 ResultSet .class, 40 ResultSetMetaData .class, 41 Savepoint .class 42 }; 43 private ArrayList objects = new ArrayList (); 44 private HashMap classMethods = new HashMap (); 45 private RandomGen random = new RandomGen(null); 46 private ArrayList statements = new ArrayList (); 47 private int openCount; 48 private long callCount; 49 private String DIR = "synth"; 50 51 private void deleteDb() { 52 try { 53 deleteDb(BASE_DIR + "/" + DIR, null); 54 } catch(Exception e) { 55 } 57 } 58 59 private Connection getConnection(int seed, boolean delete) throws Exception { 60 openCount++; 61 if(delete) { 62 deleteDb(); 63 } 64 String add = ""; 67 if(openCount>=42 && callCount>1200 && seed == 437623957) { 70 System.exit(1); 71 } 72 78 String url = getURL(DIR + "/crashapi" + seed, true) + add; 79 80 Connection conn = null; 81 conn = DriverManager.getConnection(url, "sa", ""); 83 int len = random.getInt(50); 84 int start = random.getInt(statements.size() - len); 85 int end = start + len; 86 Statement stat = conn.createStatement(); 87 stat.execute("SET LOCK_TIMEOUT 10"); 88 stat.execute("SET WRITE_DELAY 0"); 89 stat.execute("SCRIPT NOPASSWORDS NOSETTINGS"); 90 for(int i=start; i<end && i<statements.size(); i++) { 91 try { 92 stat.execute("SELECT * FROM TEST WHERE ID=1"); 93 } catch(Throwable t) { 94 printIfBad(seed, -i, -1, t); 95 } 96 try { 97 stat.execute("SELECT * FROM TEST WHERE ID=1 OR ID=1"); 98 } catch(Throwable t) { 99 printIfBad(seed, -i, -1, t); 100 } 101 102 String sql = (String ) statements.get(i); 103 try { 104 stat.execute(sql); 105 } catch(Throwable t) { 106 printIfBad(seed, -i, -1, t); 107 } 108 } 109 if(random.nextBoolean()) { 110 try { 111 conn.commit(); 112 } catch(Throwable t) { 113 printIfBad(seed, 0, -1, t); 114 } 115 } 116 return conn; 117 } 118 119 private void testOne(int seed) throws Exception { 120 printTime("TestCrashAPI " + seed); 121 callCount = 0; 122 openCount=0; 123 random = new RandomGen(null); 124 random.setSeed(seed); 125 Connection c1 = getConnection(seed, true); 126 Connection conn = null; 127 for(int i=0; i<2000; i++) { 128 137 138 if(objects.size() == 0) { 139 try { 140 conn = getConnection(seed, false); 141 } catch(SQLException e) { 142 if(e.getSQLState().equals("08004")) { 143 try { 145 c1.createStatement().execute("SET PASSWORD ''"); 146 } catch(Throwable t) { 147 break; 149 } 150 try { 151 conn = getConnection(seed, false); 152 } catch(Throwable t) { 153 printIfBad(seed, -i, -1, t); 154 } 155 } else if(e.getSQLState().equals("90098")){ 156 break; 158 } else { 159 printIfBad(seed, -i, -1, e); 160 } 161 } 162 objects.add(conn); 163 } 164 int objectId = random.getInt(objects.size()); 165 if(random.getBoolean(1)) { 166 objects.remove(objectId); 167 continue; 168 } 169 if(random.getInt(2000) == 0 && conn != null) { 170 ((JdbcConnection)conn).setPowerOffCount(random.getInt(50)); 171 } 172 Object o = objects.get(objectId); 173 if(o==null) { 174 objects.remove(objectId); 175 continue; 176 } 177 Class in = getJdbcInterface(o); 178 ArrayList methods = (ArrayList )classMethods.get(in); 179 Method m = (Method ) methods.get(random.getInt(methods.size())); 180 Object o2 = callRandom(seed, i, objectId, o, m); 181 if(o2 != null) { 182 objects.add(o2); 183 } 184 } 185 try { 186 if(conn != null) { 187 conn.close(); 188 } 189 c1.close(); 190 } catch(Throwable t) { 191 printIfBad(seed, -101010, -1, t); 192 try { 193 deleteDb(null, "test"); 194 } catch(Throwable t2) { 195 printIfBad(seed, -101010, -1, t2); 196 } 197 } 198 objects.clear(); 199 } 200 201 private void printError(int seed, int id, Throwable t) { 202 StringWriter writer = new StringWriter (); 203 t.printStackTrace(new PrintWriter (writer)); 204 String s = writer.toString(); 205 TestBase.logError("new TestCrashAPI().init(test).testCase("+seed+"); // Bug " + s.hashCode()+" seed="+seed+" id=" + id + " callCount=" + callCount+" openCount="+openCount + " " + t.getMessage(), t); 206 } 207 208 private Object callRandom(int seed, int id, int objectId, Object o, Method m) throws Exception { 209 Class [] paramClasses = m.getParameterTypes(); 210 Object [] params = new Object [paramClasses.length]; 211 for(int i=0; i<params.length; i++) { 212 params[i] = getRandomParam(id, paramClasses[i]); 213 } 214 Object result = null; 215 try { 216 callCount++; 217 result = m.invoke(o, params); 218 } catch (IllegalArgumentException e) { 219 TestBase.logError("error", e); 220 } catch (IllegalAccessException e) { 221 TestBase.logError("error", e); 222 } catch (InvocationTargetException e) { 223 Throwable t = e.getTargetException(); 224 printIfBad(seed, id, objectId, t); 225 } 226 if(result == null) { 227 return null; 228 } 229 Class in = getJdbcInterface(result); 230 if(in == null) { 231 return null; 232 } 233 return result; 234 } 235 236 private void printIfBad(int seed, int id, int objectId, Throwable t) { 237 if(t instanceof BatchUpdateException ) { 238 } else if(t instanceof SQLException ) { 240 SQLException s = (SQLException ) t; 241 String state = s.getSQLState(); 242 if(state == null) { 243 printError(seed, id, s); 244 } else if(state.equals("90008")) { 245 if(objectId >= 0) { 246 objects.remove(objectId); 249 } 250 } else if(state.equals("HY000")) { 251 printError(seed, id, s); 253 } 254 } else { 255 printError(seed, id, t); 256 } 257 } 258 259 private Object getRandomParam(int id, Class type) { 260 if(type == int.class) { 261 return new Integer (random.getRandomInt()); 262 } else if(type == byte.class) { 263 return new Byte ((byte)random.getRandomInt()); 264 } else if(type == short.class) { 265 return new Short ((short)random.getRandomInt()); 266 } else if(type == long.class) { 267 return new Long (random.getRandomLong()); 268 } else if(type == float.class) { 269 return new Float (random.getRandomDouble()); 270 } else if(type == boolean.class) { 271 return new Boolean (random.nextBoolean()); 272 } else if(type == double.class) { 273 return new Double (random.getRandomDouble()); 274 } else if(type == String .class) { 275 if(random.getInt(10) == 0) { 276 return null; 277 } else { 278 int randomId = random.getInt(statements.size()); 279 String sql = (String )statements.get(randomId); 280 if(random.getInt(10)==0) { 281 sql = random.modify(sql); 282 } 283 return sql; 284 } 285 } else if(type == int[].class) { 286 return random.getIntArray(); 288 } else if(type == java.io.Reader .class) { 289 return null; 290 } else if(type == java.sql.Array .class) { 291 return null; 292 } else if(type == byte[].class) { 293 return random.getByteArray(); 295 } else if(type == Map .class) { 296 return null; 297 } else if(type == Object .class) { 298 return null; 299 } else if(type == java.sql.Date .class) { 300 return random.randomDate(); 301 } else if(type == java.sql.Time .class) { 302 return random.randomTime(); 303 } else if(type == java.sql.Timestamp .class) { 304 return random.randomTimestamp(); 305 } else if(type == java.io.InputStream .class) { 306 return null; 307 } else if(type == String [].class) { 308 return null; 309 } else if(type == java.sql.Clob .class) { 310 return null; 311 } else if(type == java.sql.Blob .class) { 312 return null; 313 } else if(type == Savepoint .class) { 314 return null; 316 } else if(type == Calendar .class) { 317 return Calendar.getInstance(); 318 } else if(type == java.net.URL .class) { 319 return null; 320 } else if(type == java.math.BigDecimal .class) { 321 return new java.math.BigDecimal ("" + random.getRandomDouble()); 322 } else if(type == java.sql.Ref .class) { 323 return null; 324 } 325 return null; 326 } 327 328 private Class getJdbcInterface(Object o) { 329 Class [] list = o.getClass().getInterfaces(); 330 for(int i=0; i<list.length; i++) { 331 Class in = list[i]; 332 if(classMethods.get(in) != null) { 333 return in; 334 } 335 } 336 return null; 337 } 338 339 private void initMethods() { 340 for(int i=0; i<INTERFACES.length; i++) { 341 Class inter = INTERFACES[i]; 342 classMethods.put(inter, new ArrayList ()); 343 } 344 for(int i=0; i<INTERFACES.length; i++) { 345 Class inter = INTERFACES[i]; 346 ArrayList list = (ArrayList ) classMethods.get(inter); 347 Method [] methods = inter.getMethods(); 348 for(int j=0; j<methods.length; j++) { 349 Method m = methods[j]; 350 list.add(m); 351 } 352 } 353 } 354 355 public TestBase init(TestAll conf) throws Exception { 356 super.init(conf); 357 if (config.logMode == 0) { 358 error("Log mode 0 may corrupt the db, can't test"); 359 } 360 BASE_DIR = "dataCrash"; 361 startServerIfRequired(); 362 TestScript script = new TestScript(); 363 ArrayList add = script.getAllStatements(config, "org/h2/test/test.in.txt"); 364 initMethods(); 365 Class.forName("org.h2.Driver"); 366 statements.addAll(add); 367 return this; 368 } 369 370 public void testCase(int i) throws Exception { 371 BASE_DIR = "dataCrash"; 372 testOne(i); 373 BASE_DIR = "data"; 374 } 375 376 public void test() throws Exception { 377 while(true) { 378 int seed = RandomUtils.nextInt(Integer.MAX_VALUE); 379 testCase(seed); 380 deleteDb(); 381 } 382 } 383 384 } 385 | Popular Tags |