1 /* 2 * Copyright (C) 2007 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 17 package tests.java.sql; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertTrue; 21 import static org.junit.Assert.fail; 22 23 import java.sql.Connection; 24 import java.sql.DatabaseMetaData; 25 import java.sql.PreparedStatement; 26 import java.sql.ResultSet; 27 import java.sql.SQLException; 28 import java.sql.Statement; 29 import java.util.Vector; 30 import java.util.logging.Logger; 31 32 import tests.support.DatabaseCreator; 33 import tests.support.Support_SQL; 34 import tests.support.ThreadPool; 35 36 import org.junit.After; 37 import org.junit.Assert; 38 import org.junit.Before; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 import org.junit.runners.JUnit4; 42 43 @RunWith(JUnit4.class) 44 public class StressTest { 45 Vector<Connection> vc = new Vector<Connection>(); 46 47 private static Connection conn; 48 49 private static Statement statement; 50 51 @Before setUp()52 public void setUp() throws Exception { 53 Support_SQL.loadDriver(); 54 conn = Support_SQL.getConnection(); 55 statement = conn.createStatement(); 56 createTestTables(); 57 vc.clear(); 58 } 59 60 @After tearDown()61 public void tearDown() throws Exception { 62 closeConnections(); 63 statement.close(); 64 conn.close(); 65 } 66 createTestTables()67 private void createTestTables() { 68 try { 69 DatabaseMetaData meta = conn.getMetaData(); 70 ResultSet userTab = meta.getTables(null, null, null, null); 71 72 while (userTab.next()) { 73 String tableName = userTab.getString("TABLE_NAME"); 74 if (tableName.equals(DatabaseCreator.TEST_TABLE2)) { 75 statement.execute(DatabaseCreator.DROP_TABLE2); 76 } 77 } 78 statement.execute(DatabaseCreator.CREATE_TABLE2); 79 } catch (SQLException sql) { 80 fail("Unexpected SQLException " + sql.toString()); 81 } 82 return; 83 } 84 dropTestTables()85 private void dropTestTables() { 86 try { 87 statement.execute(DatabaseCreator.DROP_TABLE2); 88 } catch (SQLException sql) { 89 fail("Unexpected SQLException " + sql.toString()); 90 } 91 return; 92 } 93 94 // /** 95 // * @see junit.framework.TestCase#setUp() 96 // */ 97 // @Override 98 // protected void setUp() throws Exception { 99 // super.setUp(); 100 // vc.clear(); 101 // } 102 // 103 // /** 104 // * @see junit.framework.TestCase#tearDown() 105 // */ 106 // @Override 107 // protected void tearDown() throws Exception { 108 // closeConnections(); 109 // statement.execute("DELETE FROM " + DatabaseCreator.TEST_TABLE2); 110 // super.tearDown(); 111 // } 112 113 /** 114 * StressTest#testManyConnectionsUsingOneThread(). Create many 115 * connections to the DataBase using one thread. 116 */ 117 @Test testManyConnectionsUsingOneThread()118 public void testManyConnectionsUsingOneThread() { 119 try { 120 int maxConnections = getConnectionNum(); 121 openConnections(maxConnections); 122 assertEquals("Incorrect number of created connections", 123 maxConnections, vc.size()); 124 } catch (Exception e) { 125 fail("Unexpected Exception " + e.toString()); 126 } 127 } 128 129 /** 130 * StressTest#testManyConnectionsUsingManyThreads(). Create many 131 * connections to the DataBase using some threads. 132 */ 133 @Test testManyConnectionsUsingManyThreads()134 public void testManyConnectionsUsingManyThreads() { 135 int numTasks = getConnectionNum(); 136 137 ThreadPool threadPool = new ThreadPool(numTasks); 138 139 // run example tasks 140 for (int i = 0; i < numTasks; i++) { 141 threadPool.runTask(createTask(i)); 142 } 143 // close the pool and wait for all tasks to finish. 144 threadPool.join(); 145 assertEquals("Unable to create a connection", numTasks, vc.size()); 146 if (numTasks != Support_SQL.sqlMaxConnections) { 147 try { 148 // try to create connection n + 1 149 Connection c = Support_SQL.getConnection(); 150 c.close(); 151 fail("It is possible to create more than " + numTasks 152 + "connections"); 153 } catch (SQLException sql) { 154 // expected 155 } 156 } 157 } 158 159 /** 160 * StressTest#testInsertOfManyRowsUsingOneThread(). Insert a lot of 161 * records to the Database using a maximum number of connections. 162 */ 163 @Test testInsertOfManyRowsUsingOneThread()164 public void testInsertOfManyRowsUsingOneThread() { 165 166 Logger.global 167 .info("java.sql stress test: single thread and many operations."); 168 int maxConnections = getConnectionNum(); 169 Logger.global.info("Opening " + maxConnections + " to database " 170 + Support_SQL.getFilename()); 171 openConnections(maxConnections); 172 173 int tasksPerConnection = Support_SQL.sqlMaxTasks / maxConnections; 174 Logger.global.info("TasksPerConnection = " + Support_SQL.sqlMaxTasks 175 + " by (maxConnections) " + maxConnections + " = " 176 + tasksPerConnection); 177 int pk = 1; 178 for (int i = 0; i < vc.size(); ++i) { 179 Logger.global.info(" creating " + tasksPerConnection 180 + "tasks for Connection " + i); 181 Connection c = vc.elementAt(i); 182 for (int j = 0; j < tasksPerConnection; ++j) { 183 insertNewRecord(c, pk++); 184 } 185 } 186 try { 187 ResultSet rs = statement 188 .executeQuery("SELECT COUNT(*) as counter FROM " 189 + DatabaseCreator.TEST_TABLE2); 190 assertTrue("RecordSet is empty", rs.next()); 191 assertEquals("Incorrect number of records", tasksPerConnection 192 * maxConnections, rs.getInt("counter")); 193 rs.close(); 194 } catch (SQLException sql) { 195 fail("Unexpected SQLException " + sql.toString()); 196 } 197 198 } 199 200 /** 201 * @tests 202 * TODO(b/169673091): Investigate why it could occasionally take 10min rather than 10s to 203 * finish. 204 */ 205 @Test testInsertOfManyRowsUsingManyThreads()206 public void testInsertOfManyRowsUsingManyThreads() { 207 Logger.global.info("java.sql stress test: multiple threads and many operations."); 208 209 int numConnections = getConnectionNum(); 210 int tasksPerConnection = Support_SQL.sqlMaxTasks / numConnections; 211 212 Logger.global.info("Opening "+numConnections+" to database "+Support_SQL.getFilename()); 213 214 ThreadPool threadPool = new ThreadPool(numConnections); 215 216 for (int i = 0; i < numConnections; ++i) { 217 Logger.global.info(" creating "+tasksPerConnection+ " tasks for Connection "+i); 218 threadPool.runTask(insertTask(numConnections, i)); 219 } 220 // close the pool and wait for all tasks to finish. 221 threadPool.join(); 222 Logger.global.info("All threads joined"); 223 assertEquals("Unable to create a connection", numConnections, vc.size()); 224 225 try { 226 ResultSet rs = statement 227 .executeQuery("SELECT COUNT(*) as counter FROM " 228 + DatabaseCreator.TEST_TABLE2); 229 assertTrue("RecordSet is empty", rs.next()); 230 Logger.global.info("Counting statement returned"); 231 232 assertEquals("Incorrect number of records", tasksPerConnection 233 * numConnections, rs.getInt("counter")); 234 rs.close(); 235 Logger.global.info("ResultSet closed"); 236 } catch (SQLException sql) { 237 fail("Unexpected SQLException " + sql.toString()); 238 239 } 240 241 } 242 getConnectionNum()243 private int getConnectionNum() { 244 int num = Support_SQL.sqlMaxConnections; 245 try { 246 int mc = conn.getMetaData().getMaxConnections(); 247 if (mc != 0) { 248 if (num != mc) { 249 System.err.println("Will be used no more than " + mc 250 + " connections to the DataBase"); 251 } 252 num = mc; 253 } 254 } catch (SQLException sql) { 255 fail("Unexpected SQLException " + sql.toString()); 256 } 257 return num; 258 } 259 openConnections(int maxConnections)260 private void openConnections(int maxConnections) { 261 int i = 0; 262 try { 263 for (; i < maxConnections; ++i) { 264 Connection c = Support_SQL.getConnection(); 265 if (c == null) { 266 assertEquals("Unable to create a connection", 267 maxConnections, i); 268 } 269 vc.add(c); 270 } 271 } catch (SQLException sql) { 272 assertEquals("Unable to create a connection", maxConnections, i); 273 } 274 return; 275 } 276 closeConnections()277 private void closeConnections() { 278 int i = 0; 279 try { 280 for (; i < vc.size(); ++i) { 281 vc.elementAt(i).close(); 282 } 283 } catch (SQLException sql) { 284 assertEquals("Unable to close a connection", vc.size(), i); 285 } 286 return; 287 } 288 createTask(final int taskID)289 private Runnable createTask(final int taskID) { 290 return new Runnable() { 291 public void run() { 292 try { 293 Connection c = Support_SQL.getConnection(); 294 if (c == null) { 295 return; 296 } 297 synchronized (this) { 298 vc.add(c); 299 } 300 } catch (SQLException sql) { 301 // nothing to do 302 } 303 } 304 }; 305 } 306 307 private Runnable insertTask(final int numConnections, final int taskID) { 308 return new Runnable() { 309 public void run() { 310 try { 311 Connection c = Support_SQL.getConnection(); 312 if (c == null) { 313 return; 314 } 315 synchronized (this) { 316 vc.add(c); 317 } 318 int tasksPerConnection = Support_SQL.sqlMaxTasks 319 / numConnections; 320 for (int i = 0; i < tasksPerConnection; ++i) { 321 insertNewRecord(c, (i + 1) + tasksPerConnection 322 * taskID); 323 } 324 } catch (SQLException sql) { 325 // do nothing 326 } 327 } 328 }; 329 } 330 331 private void insertNewRecord(Connection c, int pk) { 332 String query = "INSERT INTO " + DatabaseCreator.TEST_TABLE2 333 + "(finteger, ftext, fcharacter, fdecimal, fnumeric," 334 + " fsmallint, ffloat, freal, fdouble, fdate, ftime)" 335 + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; 336 try { 337 PreparedStatement ps = c.prepareStatement(query); 338 ps.setInt(1, pk); 339 ps.setString(2, "text"); 340 ps.setString(3, "chr"); 341 ps.setFloat(4, 0.1f); 342 ps.setFloat(5, 0.2f); 343 ps.setShort(6, (short) 3); 344 ps.setFloat(7, 0.4f); 345 ps.setDouble(8, 0.5); 346 ps.setDouble(9, 0.6); 347 ps.setDate(10, new java.sql.Date(System.currentTimeMillis())); 348 ps.setTime(11, new java.sql.Time(System.currentTimeMillis())); 349 ps.execute(); 350 ps.close(); 351 } catch (SQLException sql) { 352 fail("Unexpected SQLException " + sql.toString()); 353 } 354 return; 355 } 356 } 357