New multi-threaded test client script 51/90551/1
authorArthur Martella <arthur.martella.1@att.com>
Wed, 26 Jun 2019 20:03:25 +0000 (16:03 -0400)
committerArthur Martella <arthur.martella.1@att.com>
Wed, 26 Jun 2019 20:03:25 +0000 (16:03 -0400)
Issue-ID: MUSIC-420
Signed-off-by: Martella, Arthur <arthur.martella.1@att.com>
Change-Id: I275dce864ed1fc0922f0a2f7f0a4e6a3f5b976f7

mdbc-server/src/main/java/org/onap/music/mdbc/examples/MdbcTestMultiClient.java [new file with mode: 0755]

diff --git a/mdbc-server/src/main/java/org/onap/music/mdbc/examples/MdbcTestMultiClient.java b/mdbc-server/src/main/java/org/onap/music/mdbc/examples/MdbcTestMultiClient.java
new file mode 100755 (executable)
index 0000000..b2fb403
--- /dev/null
@@ -0,0 +1,609 @@
+/*\r
+ * ============LICENSE_START====================================================\r
+ * org.onap.music.mdbc\r
+ * =============================================================================\r
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+ * =============================================================================\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ============LICENSE_END======================================================\r
+ */\r
+package org.onap.music.mdbc.examples;\r
+\r
+import java.sql.*;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Random;\r
+\r
+public class MdbcTestMultiClient implements Runnable {\r
+    private static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");\r
+    \r
+    private String connectionString = null;\r
+    private int threadId = -1;\r
+    \r
+    private List<String> connectionStrings = new ArrayList<String>();\r
+    private static final String defaultConnection = "jdbc:avatica:remote:url=http://localhost:30000/test;serialization=protobuf";\r
+       private String lastName = "Lastname";\r
+       private int baseId = 700;\r
+       private int baseIdRange = 50;\r
+       private int maxCalls = 50; \r
+       private int maxTimeMs = 60000;\r
+       private int minDelayBetweenTestsMs = 1000;\r
+       private int additionalDelayBetweenTestsMs = 1000;\r
+       private boolean doDelete = true;\r
+       private boolean doUpdate = true;\r
+       private int connectionCloseChancePct = 50;\r
+       private int skipInitialSelectPct = 25;\r
+       private int selectInsteadOfUpdatePct = 25;\r
+       \r
+       private boolean explainConnection = true;\r
+       \r
+    public static class Employee {\r
+        public final int empid;\r
+        public String lastname;\r
+        public String firstname;\r
+        public String address;\r
+        public String city;\r
+        \r
+               public Employee(int empid, String lastname, String firstname, String address, String city) {\r
+                       super();\r
+                       this.empid = empid;\r
+                       this.lastname = lastname;\r
+                       this.firstname = firstname;\r
+                       this.address = address;\r
+                       this.city = city;\r
+               }\r
+\r
+               public String getLastname() {\r
+                       return lastname;\r
+               }\r
+\r
+               public void setLastname(String lastname) {\r
+                       this.lastname = lastname;\r
+               }\r
+\r
+               public String getFirstname() {\r
+                       return firstname;\r
+               }\r
+\r
+               public void setFirstname(String firstname) {\r
+                       this.firstname = firstname;\r
+               }\r
+\r
+               public String getAddress() {\r
+                       return address;\r
+               }\r
+\r
+               public void setAddress(String address) {\r
+                       this.address = address;\r
+               }\r
+\r
+               public String getCity() {\r
+                       return city;\r
+               }\r
+\r
+               public void setCity(String city) {\r
+                       this.city = city;\r
+               }\r
+\r
+               public int getEmpid() {\r
+                       return empid;\r
+               }\r
+\r
+               @Override\r
+               public String toString() {\r
+                       return "Employee: " + empid + ", " + lastname + ", " + firstname + ", " + address + ", " + city;\r
+               }\r
+\r
+        \r
+    }\r
+\r
+    public MdbcTestMultiClient(String[] args) {\r
+        char currState = (char)0, noState = (char)0;\r
+        for (String arg : args) {\r
+            if (currState==noState) {\r
+                switch (arg) {\r
+                    case "-?":\r
+                    case "--help":\r
+                        showHelp();\r
+                        break;\r
+                    case "-c":\r
+                    case "--connection": \r
+                        currState = 'c';\r
+                        break;\r
+                    case "-n":\r
+                    case "--name": \r
+                        currState = 'n';\r
+                        break;\r
+                    case "-b":\r
+                    case "--baseId": \r
+                        currState = 'b';\r
+                        break;\r
+                    case "-r":\r
+                    case "--baseRange": \r
+                        currState = 'r';\r
+                        break;\r
+                    case "-m":\r
+                    case "--maxCalls": \r
+                        currState = 'm';\r
+                        break;\r
+                    case "-t":\r
+                    case "--maxTime": \r
+                        currState = 't';\r
+                        break;\r
+                    case "-d":\r
+                    case "--minDelay": \r
+                        currState = 'd';\r
+                        break;\r
+                    case "-a":\r
+                    case "--addDelay": \r
+                        currState = 'a';\r
+                        break;\r
+                    case "-u":\r
+                    case "--update": \r
+                        currState = 'u';\r
+                        break;\r
+                    case "-x":\r
+                    case "--delete": \r
+                        currState = 'x';\r
+                        break;\r
+                    case "-l":\r
+                    case "--closeChance": \r
+                        currState = 'l';\r
+                        break;\r
+                    case "-s":\r
+                    case "--skipInitialSelect":\r
+                        currState = 's';\r
+                        break;\r
+                    case "-i":\r
+                    case "--selectNotUpdate":\r
+                        currState = 'i';\r
+                        break;\r
+                    default:\r
+                        System.out.println("Didn't understand switch " + arg);\r
+                }\r
+            } else {\r
+                try {\r
+                    switch (currState) {\r
+                        case 'c':\r
+                            connectionStrings.add(arg);\r
+                            break;\r
+                        case 'n':\r
+                            lastName = arg;\r
+                            break;\r
+                        case 'b':\r
+                            baseId = Integer.parseInt(arg);\r
+                            break;\r
+                        case 'r':\r
+                            baseIdRange = Integer.parseInt(arg);\r
+                            break;\r
+                        case 'm':\r
+                            maxCalls = Integer.parseInt(arg);\r
+                            break;\r
+                        case 't':\r
+                            maxTimeMs = Integer.parseInt(arg);\r
+                            break;\r
+                        case 'd':\r
+                            minDelayBetweenTestsMs = Integer.parseInt(arg);\r
+                            break;\r
+                        case 'a':\r
+                            additionalDelayBetweenTestsMs = Integer.parseInt(arg);\r
+                            break;\r
+                        case 'u':\r
+                            doUpdate = arg.toUpperCase().startsWith("Y");\r
+                            break;\r
+                        case 'x':\r
+                            doDelete = arg.toUpperCase().startsWith("Y");\r
+                            break;\r
+                        case 'l':\r
+                            connectionCloseChancePct = Integer.parseInt(arg);\r
+                            break;\r
+                        case 's':\r
+                            skipInitialSelectPct = Integer.parseInt(arg);\r
+                            break;\r
+                        case 'i': \r
+                            selectInsteadOfUpdatePct = Integer.parseInt(arg);\r
+                            break;\r
+                        default:\r
+                            System.out.println("Bad state " + currState + "????");\r
+                    }\r
+                } catch (NumberFormatException e) {\r
+                    System.out.println("Bad integer " + arg + " for switch " + currState);\r
+                }\r
+                currState = noState;\r
+            }\r
+        }\r
+        if (connectionStrings.isEmpty()) connectionStrings.add(defaultConnection);\r
+       }\r
+\r
+       private void showHelp() {\r
+           System.out.println(\r
+                   "-?; --help: Show help\n" + \r
+                           "-c; --connection: MDBC connection string, may appear multiple times\n" + \r
+                           "-n; --name: Last name in persons table, default \"Lastname\"\n" + \r
+                           "-b; --baseId: Base ID, default 700\n" + \r
+                           "-r; --baseRange: Range of ID, default 50\n" + \r
+                           "-m; --maxCalls: Max number of commits (each may be 1+ updates), default 50\n" + \r
+                           "-t; --maxTime: Max time in ms test will run, default 60000\n" + \r
+                           "-d; --minDelay: Min delay between tests in ms, default 1000\n" + \r
+                           "-a; --addDelay: Max randomized additional delay between tests in ms, default 1000\n" + \r
+                           "-u; --update: Generate update statements; default Y\n" + \r
+                           "-x; --delete: Generate delete statements; default Y\n" + \r
+                           "-l; --closeChance: Percent chance of closing connection after each commit, default 50\n" +\r
+                           "-s; --skipInitialSelect: Percent chance of skipping each initial select in a transaction, default 25\n" +\r
+                           "-i; --selectNotUpdate: Percent chance of each action in a transaction being a select instead of an update, default 25"\r
+           );\r
+        \r
+    }\r
+\r
+    public MdbcTestMultiClient(MdbcTestMultiClient that, int i) {\r
+        this.connectionString = that.connectionStrings.get(i);\r
+        this.threadId = i;\r
+        \r
+        this.lastName = that.lastName;\r
+        this.lastName = that.lastName;\r
+        this.baseId = that.baseId;\r
+        this.baseIdRange = that.baseIdRange;\r
+        this.maxCalls = that.maxCalls;\r
+        this.maxTimeMs = that.maxTimeMs;\r
+        this.minDelayBetweenTestsMs = that.minDelayBetweenTestsMs;\r
+        this.additionalDelayBetweenTestsMs = that.additionalDelayBetweenTestsMs;\r
+        this.doDelete = that.doDelete;\r
+        this.doUpdate = that.doUpdate;\r
+        this.connectionCloseChancePct = that.connectionCloseChancePct;\r
+        this.skipInitialSelectPct = that.skipInitialSelectPct;\r
+        this.selectInsteadOfUpdatePct = that.selectInsteadOfUpdatePct;\r
+       }\r
+    \r
+    private static String[] tableNames = {"persons", "persons2"};\r
+\r
+       private void doTest(Connection connection, Random r) throws SQLException {\r
+           doLog("skipInitialSelectPct = " + skipInitialSelectPct + ", selectInsteadOfUpdatePct = " + selectInsteadOfUpdatePct);\r
+           HashMap<String, HashMap<Integer, Employee>> employeeMaps = new HashMap<String, HashMap<Integer, Employee>> ();\r
+//     HashMap<Integer, Employee> employeeMap = new HashMap<Integer, Employee>();\r
+\r
+           for (String tableName : tableNames) {\r
+               if (r.nextInt(100)<skipInitialSelectPct) {\r
+                   doLog("Skipping select");\r
+//                 employeeMap = null;\r
+               } else {\r
+                   Statement querySt = connection.createStatement();\r
+                   if (explainConnection) {\r
+                       doLog("querySt is a: ");\r
+                       Class<?> qsClass = querySt.getClass();\r
+                       while (qsClass!=null) {\r
+                           doLog(">>> " + qsClass.getName());\r
+                           qsClass = qsClass.getSuperclass();\r
+                       }\r
+                       doLog("connection is a ");\r
+                       qsClass = connection.getClass();\r
+                       while (qsClass!=null) {\r
+                           doLog(">>> " + qsClass.getName());\r
+                           qsClass = qsClass.getSuperclass();\r
+                       }\r
+                       explainConnection = false;\r
+                   }\r
+\r
+                   HashMap<Integer, Employee> employeeMap = new HashMap<Integer, Employee>();\r
+                   employeeMaps.put(tableName, employeeMap);\r
+                   \r
+                   ResultSet rs = executeQueryTimed("select * from " + tableName, querySt, false);\r
+                   while (rs.next()) {\r
+                       //                      doLog("PersonId = " + rs.getInt("personId") + ", lastname = " + rs.getString("lastname") + ", firstname = " + rs.getString("firstname"));\r
+                       Employee emp = new Employee(rs.getInt("personId"), rs.getString("lastname"), rs.getString("firstname"), rs.getString("address"), rs.getString("city"));\r
+                       employeeMap.put(rs.getInt("personId"), emp);\r
+                       doLog("Found: " + emp);\r
+                   }\r
+                   querySt.close();\r
+               }\r
+           }\r
+\r
+       Statement insertStmt = connection.createStatement();\r
+       boolean firstTry = true;\r
+//     String tableName = tableNames[r.nextInt(tableNames.length)];\r
+//     HashMap<Integer, Employee> employeeMap = employeeMaps.get(tableName);\r
+//     executeUpdateTimed(generateStatement(employeeMap, r, tableName), insertStmt, true);\r
+\r
+       while (firstTry || r.nextBoolean()) {\r
+           firstTry = false;\r
+            String tableName = tableNames[r.nextInt(tableNames.length)];\r
+            HashMap<Integer, Employee> employeeMap = employeeMaps.get(tableName);\r
+            if (r.nextInt(100)<selectInsteadOfUpdatePct) {\r
+                Statement querySt = connection.createStatement();\r
+                ResultSet rs = executeQueryTimed("select count(*) x from " + tableName, querySt, false);\r
+                if (rs.next()) doLog("Select count returned " + rs.getInt("x")); else doLog("Didn't get response from select count!");\r
+                rs.close();\r
+                querySt.close();\r
+            } else {\r
+                executeUpdateTimed(generateStatement(employeeMap, r, tableName), insertStmt, true);\r
+            }\r
+       }\r
+\r
+       connection.commit();\r
+\r
+       insertStmt.close();\r
+    }\r
+    \r
+    private void executeUpdateTimed(String sql, Statement insertStmt, boolean swallowException) throws SQLException {\r
+        long beforeTime, afterTime;\r
+\r
+        beforeTime = new java.util.Date().getTime();\r
+        try {\r
+            insertStmt.execute(sql);\r
+        } catch (org.apache.calcite.avatica.AvaticaSqlException e) {\r
+            if (swallowException) {\r
+                doLog("Caught exception: " + e);\r
+            } else {\r
+                throw e;\r
+            }\r
+        }\r
+        afterTime = new java.util.Date().getTime();\r
+        doLog("After update, execution time = " + (afterTime-beforeTime) + " ms");\r
+    }\r
+\r
+    private ResultSet executeQueryTimed(String sql, Statement querySt, boolean swallowException) throws SQLException {\r
+        long beforeTime, afterTime;\r
+        \r
+        doLog("Before select: " + sql);\r
+        beforeTime = new java.util.Date().getTime();\r
+        ResultSet rs = null;\r
+        try {\r
+            rs = querySt.executeQuery(sql);\r
+        } catch (SQLException e) {\r
+            if (swallowException) {\r
+                doLog("Caught exception: " + e);\r
+            } else {\r
+                throw e;\r
+            }\r
+        }\r
+        afterTime = new java.util.Date().getTime();\r
+        doLog("After select, execution time = " + (afterTime-beforeTime) + " ms");\r
+        return rs;\r
+    }\r
+\r
+    private String generateStatement(HashMap<Integer, Employee> employeeMap, Random r, String tableName) {\r
+       String toRet = null;\r
+       \r
+       boolean pickInsert = ((employeeMap==null) || (r.nextInt(8) >= employeeMap.size()));\r
+       if (!pickInsert) {\r
+           if (doDelete && doUpdate) {\r
+               if (r.nextBoolean()) toRet = generateDelete(employeeMap, r, tableName); else toRet = generateUpdate(employeeMap, r, tableName);\r
+           } else if (doDelete) {\r
+               toRet = generateDelete(employeeMap, r, tableName);\r
+           } else if (doUpdate) {\r
+               toRet = generateUpdate(employeeMap, r, tableName);\r
+           }\r
+       }\r
+       if (toRet==null) {\r
+               toRet = generateInsert(employeeMap, r, tableName);\r
+       }\r
+       \r
+       doLog("Generated statement: " + toRet);\r
+       \r
+               return toRet;\r
+       }\r
+\r
+       private String generateInsert(HashMap<Integer, Employee> employeeMap, Random r, String tableName) {\r
+               String toRet = null;\r
+               \r
+               Integer id = null;\r
+               int range = baseIdRange;\r
+               while (id==null) {\r
+                       id = baseId + r.nextInt(range);\r
+                       if (employeeMap!=null && employeeMap.containsKey(id)) id = null;\r
+                       if (employeeMap==null) id+=baseIdRange;\r
+                       range+=(baseIdRange/5);\r
+               }\r
+               Employee newEmp = new Employee(id, lastName, Character.toUpperCase(randomLetter(r)) + generateLetters(r, 4+r.nextInt(4)), generateLetters(r, 4).toUpperCase(), generateLetters(r, 4).toUpperCase());\r
+               toRet = "insert into " + tableName + " values (" + id + ", '" + newEmp.getLastname() + "', '" + newEmp.getFirstname() + "', '" + newEmp.getAddress() + "', '" + newEmp.getCity() + "')";\r
+               if (employeeMap!=null) employeeMap.put(id, newEmp);\r
+               \r
+               return toRet;\r
+       }\r
+\r
+       private String generateUpdate(HashMap<Integer, Employee> employeeMap, Random r, String tableName) {\r
+               String toRet = null;\r
+               \r
+               Employee toUpd = chooseTarget(employeeMap, r);\r
+               if (toUpd!=null) {\r
+                       String newFirst = null;\r
+                       if (toUpd.getFirstname().length()<=3 || r.nextBoolean()) {\r
+                               newFirst = toUpd.getFirstname() + randomLetter(r);\r
+                       } else {\r
+                               newFirst = toUpd.getFirstname().substring(0, toUpd.getFirstname().length()-1);\r
+                       }\r
+//                     toRet = "update " + tableName + " set firstname = '" + newFirst + "' where personid = " + toUpd.getEmpid();\r
+                       toRet = "update " + tableName + " set firstname = '" + newFirst + "' where personid = " + toUpd.getEmpid() + " and lastname = '" + toUpd.getLastname() + "'";\r
+                       toUpd.setFirstname(newFirst);\r
+               }\r
+               \r
+               return toRet;\r
+       }\r
+\r
+       private String generateLetters(Random r, int count) {\r
+               StringBuffer toRet = new StringBuffer();\r
+               for (int i=0; i<count; i++) {\r
+                       Character c = null;\r
+                       while (c==null) {\r
+                               c = randomLetter(r);\r
+                               char cc = c.charValue();\r
+                               if ( (cc=='a' || cc=='e' || cc=='i' || cc=='o' || cc=='u') ^ (i%2==0) ) c = null;\r
+                       }\r
+                       toRet.append(c);\r
+               }\r
+               return toRet.toString();\r
+       }\r
+\r
+       private char randomLetter(Random r) {\r
+               int a = (int)'a';\r
+               return (char)(a+r.nextInt(26));\r
+       }\r
+\r
+       private String generateDelete(HashMap<Integer, Employee> employeeMap, Random r, String tableName) {\r
+               String toRet = null;\r
+               \r
+               Employee toDel = chooseTarget(employeeMap, r);\r
+               if (toDel!=null) {\r
+                       toRet = "delete from " + tableName + " where personid = " + toDel.getEmpid() + " and lastname = '" + toDel.getLastname() + "'";\r
+                       employeeMap.remove(toDel.getEmpid());\r
+               }\r
+               \r
+               return toRet;\r
+       }\r
+\r
+       \r
+       \r
+       private Employee chooseTarget(HashMap<Integer, Employee> employeeMap, Random r) {\r
+               Employee toPick = null;\r
+               int count = 0;\r
+               for (int id : employeeMap.keySet()) {\r
+                       Employee emp = employeeMap.get(id);\r
+                       if (!emp.getLastname().equals(lastName)) continue;\r
+                       count++;\r
+                       if (r.nextInt(count)==0) toPick = emp;\r
+               }\r
+               return toPick;\r
+       }\r
+\r
+       public void run() {\r
+           try {\r
+            Class.forName("org.apache.calcite.avatica.remote.Driver");\r
+        } catch (ClassNotFoundException e) {\r
+            e.printStackTrace();\r
+            System.exit(1);\r
+        }\r
+               \r
+        Connection connection = null;\r
+\r
+        int calls = 0;\r
+        long startTime = new java.util.Date().getTime();\r
+        Random r = new Random();\r
+        boolean done = false;\r
+\r
+        while (!done) {\r
+               if (connection==null) {\r
+                try {\r
+                       doLog("Opening new connection");\r
+                    connection = DriverManager.getConnection(connectionString);\r
+                    connection.setAutoCommit(false);\r
+                } catch (SQLException e) {\r
+                    e.printStackTrace();\r
+                    return;\r
+                }\r
+               } else {\r
+                       doLog("Keeping open connection");\r
+               }\r
+\r
+               if (calls==0) {\r
+                long initialDelay = 1 + (1000*threadId);\r
+                synchronized(Thread.currentThread()) {\r
+                    doLog("Delaying for " + initialDelay);\r
+                    try {\r
+                        Thread.currentThread().wait(initialDelay);\r
+                    } catch (InterruptedException e) {\r
+                        e.printStackTrace();\r
+                        done = true;\r
+                    }\r
+                    doLog("Done");\r
+                }\r
+               }\r
+               \r
+               try {\r
+                               doLog("Running test");\r
+                               doTest(connection, r);\r
+                               doLog("Test complete");\r
+                       } catch (SQLException e1) {\r
+                               e1.printStackTrace();\r
+                               done = true;\r
+                               if (connection!=null) {\r
+                                       try {\r
+                                               doLog("Closing connection in catch block");\r
+                                               connection.close();\r
+                                       } catch (SQLException e) {\r
+                                               e.printStackTrace();\r
+                                               done = true;\r
+                                       } finally {\r
+                                               connection = null;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+               if (!done && connection!=null && r.nextInt(100)<connectionCloseChancePct) {\r
+                       try {\r
+                               doLog("Closing connection");\r
+                               connection.close();\r
+                               connection = null;\r
+                       doLog("Connection closed.");\r
+                       } catch (SQLException e) {\r
+                               e.printStackTrace();\r
+                               done = true;\r
+                       }\r
+               } else {\r
+                       doLog("Not closing connection");\r
+               }\r
+               \r
+               calls++;\r
+               long msElapsed = (new java.util.Date().getTime()) - startTime;\r
+               if (calls>maxCalls || msElapsed > maxTimeMs) done = true;\r
+               \r
+               if (!done) {\r
+                       long delay = r.nextInt(minDelayBetweenTestsMs);\r
+                       while (r.nextBoolean()) delay += r.nextInt(additionalDelayBetweenTestsMs);\r
+                       if (delay>0) {\r
+                           doLog("Delaying for " + delay + " ms");\r
+                           synchronized(Thread.currentThread()) {\r
+                               try {\r
+                                   Thread.currentThread().wait(delay);\r
+                               } catch (InterruptedException e) {\r
+                                   e.printStackTrace();\r
+                                   done = true;\r
+                               }\r
+                           }\r
+                    doLog("Delaying done");\r
+                       }\r
+               }\r
+               \r
+               doLog("");\r
+        }\r
+\r
+        if (connection!=null) {\r
+               try {\r
+                       doLog("Closing connection at end");\r
+                               connection.close();\r
+                       } catch (SQLException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+        }\r
+\r
+        doLog("All done.");\r
+    }\r
+\r
+       private void doLog(String string) {\r
+               System.out.println(">> Thread " + threadId + " " + sdf.format(new java.util.Date()) + " >> " + string);\r
+       }\r
+       \r
+       public static void main(String[] args) {\r
+               MdbcTestMultiClient mtc = new MdbcTestMultiClient(args);\r
+               mtc.runTests(); \r
+       }\r
+\r
+    private void runTests() {\r
+        for (int i=0; i<connectionStrings.size(); i++) {\r
+            MdbcTestMultiClient mt = new MdbcTestMultiClient(this, i);\r
+            Thread t = new Thread(mt);\r
+            t.start();\r
+        }\r
+    }\r
+               \r
+}\r