package standalone; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import org.sharegov.cirm.StartupUtils; import org.sharegov.cirm.utils.GenUtils; import org.sharegov.cirm.utils.ThreadLocalStopwatch; import mjson.Json; /** * Continuously simulates a couple users querying WCS in WCS tab, while printing results every minute.<br> * This calls 6 WCS CICS web service endpoints with the exact same data each time.<br> * <br> * Warning: Intentionally does not terminate!<br> * <br> * Rationale for test:<br> * Call center repeatedly reported problems in Jan 2016 with the WCS tab and we say higher than usual error responses from the<br> * WCS CICS web services. <br> * <br> * @author Thomas Hilpold */ public class AT_001_WcsCicsWebServiceAvailabilityTest { public static final int NR_OF_USERS_SIMULATED = 1; @Test public void test() { StartupUtils.disableCertificateValidation(); List<Thread> simulatedUsers = new ArrayList<>(); for (int i = 0; i < NR_OF_USERS_SIMULATED; i++) { Thread t = new Thread(new WcsAccountQueryCaller()); simulatedUsers.add(t); t.start(); } for(;;) { try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Test exiting."); } } } /** * Runnable that simulates a user that continuously calls all Query URLS and keeps statistics (across users) on success/error. * * * @author Thomas Hilpold * */ public static class WcsAccountQueryCaller implements Runnable { public static final long SLEEP_MS = 1000; //Must sync formats private static final DateFormat DFORMAT = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); private static List<String[]> errors = new LinkedList<>(); private static volatile AtomicInteger successCount = new AtomicInteger(0); private static final String[] QUERY_URLS = getTestUrls(); @Override public void run() { int runCount = 1; while (true) { runAllQueries(runCount); try { Thread.sleep(SLEEP_MS); } catch (InterruptedException e) {}; runCount++; } } void runAllQueries(int runCount) { for (int i = 0; i < QUERY_URLS.length; i++) { runQuery(QUERY_URLS[i], i, runCount); } } void runQuery(String queryUrl, int idx, int runCount) { try { Json result = GenUtils.httpGetJson(queryUrl); if (result.toString().contains("error")) throw new RuntimeException("error in result"); successCount.incrementAndGet(); } catch (Exception e) { String thread = ThreadLocalStopwatch.getThreadName(); addError(new String[] {thread, "" +runCount, now(), "" + idx, "" + e.getMessage()}); printResultsNow(); } } // Thread, run, time, endpointIdx, error public synchronized static List<String[]> getErrors() { return errors; } synchronized static void addError(String[] error) { errors.add(error); } static synchronized String now() { return DFORMAT.format(new Date()); } /** * Prints results so far including all error occurances in all threads/users. * Thread safe. */ public synchronized static void printResultsNow() { List<String[]> e = getErrors(); NumberFormat df = DecimalFormat.getPercentInstance(); int totalExecutions = successCount.get() + e.size(); double errorPercent = e.size() / (double) totalExecutions; ThreadLocalStopwatch.now("Printing Results until, " + now() + " Error rate (Error/Total %): " + df.format(errorPercent) + " Success: " + successCount.get() + " Errors: " + e.size() + " Total: " + totalExecutions); System.out.println("Thread\tRun\ttime\tendpoint\terror"); for (String[] row : e) { System.out.println(row[0] + "\t" + row[1] + "\t" + row[2] + "\t" + row[3] + "\t" + row[4]); } ThreadLocalStopwatch.now("Printing Results completed."); } /** * These are the test endpoints with test data included. * @return */ public static String[] getTestUrls() { String endpoint1 = "https://localhost:8183/legacy/ws/WCSAccountQueryByFolio?arg=3078110060150&_=1453258848334"; //String result1 = "{"result":{"WCS":{"RETURNMSG":"INVALID"}},"server":"77","ok":true}"; String endpoint2 = "https://localhost:8183/legacy/ws/WCSAccountQueryByAddress?arg=18911%20SW%20312TH%20ST&_=1453258848573"; // {"result":{"WCS":{"RETURNMSG":"MULTIPLE ADDRESSES","Accounts":[{"Account":{"AccountCode":"UH","AccountAddress":"18911 SW 312 ST","FolioNumber":3078110060150,"AccountNumber":12671668,"AccountName":"JOEL A LOBO"}},{"Account":{"AccountCode":"OR","AccountAddress":"18911 SW 312 ST","FolioNumber":3078110060150,"AccountNumber":40099549,"AccountName":"ANTONIO L BARRIENTOS & BARBARA"}}]}},"server":"77","ok":true} String endpoint3 = "https://localhost:8183/legacy/ws/WCSAccountQueryByAccount?arg=12671668&_=1453259120062"; //{"result":{"WCS":{"RETURNMSG":"QUERY SUCCESSFUL","Accounts":{"Account":{"TotalDue":0.0,"CurrentFee":0.0,"GrandTotalDue":0.0,"MailZip":"33030-3842","AccountAddress":"18911 SW 312 ST","MonthlyDeliquent":0.0,"AccountStatus":null,"MailState":"FL","Book":23,"AccountCode":"UH","BadCheckFee":0.0,"Trips":2,"FolioNumber":3078110060150,"MiscMail":null,"Route":7208,"Handicap":"N","BillStatus":"T","WasteUnit":1,"CreatedDate":"03/26/1997","CanRollCode":null,"AccountName":"JOEL A LOBO","OwnerName":"JOEL A LOBO","Paid":0.0,"BillingDate":"10/01/1997","AccountCodeDescription":"GARB,TRASH,TRC,RECYCLE","MailCo":null,"PriorYearAmount":0.0,"RegFeeCredit":0.0,"Phone":"000000-0000","MailCity":"MIAMI","OutServ":"N","CurrentServTax":0.0,"Bulky":0.0,"SrvStart":"SERVICE DATE","MailAddress":"18911 SW 312 ST","Delinquent":0.0,"Pickup":"TU & FR","Dist":8,"SrvDate":"03/26/1997","AccountType":"HOUSEHOLD","MailPhone":"000000-0000","Penalty":"00/0000 0.00","AccountNumber":12671668,"MailApt":null,"PreviousPenalty":"00/0000 0.00","Judgement":null,"Reg":7,"Cluc":"SINGLE","PriorYearTax":0.0,"OCL":0,"TaxUnit":1,"PenCode":"Y"}}}},"server":"77","ok":true} String endpoint4 = "https://localhost:8183/legacy/ws/WCSBulkyQueryByAccount?arg=12671668&_=1453259120320"; //1 {"result":{"WCS":{"WorkOrders":[{"WorkOrder":{"SchActDate":"10/2012","OrderStatus":"FR","BulkyFee":0,"BulkyFeePaid":0,"WorkOrderNumber":55389200,"EstAct":5,"TotalFeeDue":0,"OrderDate":"10/12/2012"}},{"WorkOrder":{"SchActDate":"06/2013","OrderStatus":"FR","BulkyFee":0,"BulkyFeePaid":0,"WorkOrderNumber":60662900,"EstAct":6,"TotalFeeDue":0,"OrderDate":"06/18/2013"}},{"WorkOrder":{"SchActDate":"01/2015","OrderStatus":"FR","BulkyFee":0,"BulkyFeePaid":0,"WorkOrderNumber":75335400,"EstAct":5,"TotalFeeDue":0,"OrderDate":"01/08/2015"}},{"WorkOrder":{"SchActDate":"05/2015","OrderStatus":"FR","BulkyFee":0,"BulkyFeePaid":0,"WorkOrderNumber":78756900,"EstAct":8,"TotalFeeDue":0,"OrderDate":"05/19/2015"}},{"WorkOrder":{"SchActDate":"01/2016","OrderStatus":"PP","BulkyFee":0,"BulkyFeePaid":0,"WorkOrderNumber":85760700,"EstAct":0,"TotalFeeDue":0,"OrderDate":"01/19/2016"}}],"Address":"18911 SW 312 ST","RETURNMSG":"MULTIPLE BULKIES","Name":"JOEL A LOBO"}},"server":"77","ok":true} //4 {"result":{"WCS":{"RETURNMSG":"EMPTY"}},"server":"77","ok":true} String endpoint5 = "https://localhost:8183/legacy/ws/WCSPublicComplaintQueryByAccount?arg=12671668&_=1453259120485"; //1 {"result":{"WCS":{"RETURNMSG":"EMPTY"}},"server":"77","ok":true} //4 {result: {WCS: {RETURNMSG: "EMPTY"}}, server: "77", ok: true} String endpoint6 = "https://localhost:8183/legacy/ws/WCSEnforcementComplaintQueryByAccount?arg=12671668&_=1453259120643"; //1 {"result":{"WCS":{"EnforcementComplaints":[{"EnforcementComplaint":{"Status":"BC","CDate":" 1/ 7/2015","StatusDescription":"BULKY CLOSE","ComplaintNumber":10687191,"CDetails1":"T/C, M/T","BulkyOrderNumber":"753354 00"}},{"EnforcementComplaint":{"Status":"CO","CDate":" 4/ 8/2014","StatusDescription":"CLOSED","ComplaintNumber":10670225,"CDetails1":"FURN ITEMS, MISC.","BulkyOrderNumber":"000000 00"}},{"EnforcementComplaint":{"Status":"CO","CDate":" 1/28/2014","StatusDescription":"CLOSED","ComplaintNumber":10665376,"CDetails1":"W/C","BulkyOrderNumber":"000000 00"}}],"RETURNMSG":"MULTIPLE ENFORCEMENT COMPLAINTS"}},"server":"77","ok":true} //4 {"result":{"WCS":{"RETURNMSG":"EMPTY"}},"server":"77","ok":true} return new String[] { endpoint1, endpoint2, endpoint3, endpoint4, endpoint5, endpoint6 }; } } }