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