View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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  package edu.samplu.common;
17  
18  import org.apache.commons.lang.RandomStringUtils;
19  
20  import java.io.BufferedReader;
21  import java.io.InputStreamReader;
22  import java.io.PrintWriter;
23  import java.io.StringWriter;
24  import java.net.HttpURLConnection;
25  import java.net.URL;
26  import java.net.URLEncoder;
27  import java.util.Calendar;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.Map;
31  
32  /**
33   * TODO:
34   * <ol>
35   *   <li>Keep JUnit or TestNG dependencies out of in this class.</li>
36   *   <li>Once and Only Once WAIT_DEFAULT_SECONDS and WebDriverLegacyITBase.DEFAULT_WAIT_SEC</li>
37   *   <li>Rename to SmokeTestUtil or such</li>
38   *   <li>Extract jiraMatches data to property file</li>
39   * </ol>
40   * @author Kuali Rice Team (rice.collab@kuali.org)
41   */
42  
43  public class ITUtil {
44  
45      /**
46       * http://localhost:8080/kr-dev
47       */
48      public static final String DEFAULT_BASE_URL = "http://localhost:8080/kr-dev";
49  
50      /**
51       * /portal.do
52       */
53      public static final  String PORTAL = "/portal.do";
54  
55      /**
56       * ITUtil.getBaseUrlString() + ITUtil.PORTAL
57       */
58      public static final String PORTAL_URL =  ITUtil.getBaseUrlString() + ITUtil.PORTAL;
59  
60      /**
61       * URLEncoder.encode(PORTAL_URL)
62       */
63      public static final String PORTAL_URL_ENCODED = URLEncoder.encode(PORTAL_URL);
64  
65      /**
66       * Calendar.getInstance().getTimeInMillis() + ""
67       */
68      public static final String DTS = Calendar.getInstance().getTimeInMillis() + "";
69  
70      /**
71       * Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase()
72       */
73      public static final String DTS_TWO = Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase();
74  
75      /**
76       * //div[@class='error']"
77       */
78      public static final String DIV_ERROR_LOCATOR = "//div[@class='error']";
79  
80      /**
81       * //div[@class='msg-excol']
82       */
83      public static final String DIV_EXCOL_LOCATOR = "//div[@class='msg-excol']";
84  
85      /**
86       * 60
87       */
88      public static final int WAIT_DEFAULT_SECONDS = 60;
89  
90      /**
91       * "30000"
92       */
93      public static final String DEFAULT_WAIT_FOR_PAGE_TO_LOAD_TIMEOUT = "30000";
94  
95      /**
96       * remote.public.url
97       */
98      public static final String REMOTE_PUBLIC_URL_PROPERTY = "remote.public.url";
99  
100     /**
101      * remote.autologin
102      */
103     public static final String REMOTE_AUTOLOGIN_PROPERTY = "remote.autologin";
104 
105     /**
106      * remote.public.hub
107      */
108     public static final String HUB_PROPERTY = "remote.public.hub";
109 
110     /**
111      * remote.public.driver
112      */
113     public static final String HUB_DRIVER_PROPERTY = "remote.public.driver";
114 
115     /**
116      * http://localhost:4444/wd/hub
117      */
118     public static final String HUB_URL_PROPERTY = "http://localhost:4444/wd/hub";
119 
120     /**
121      * remote.driver.dontTearDown
122      */
123     public static final String DONT_TEAR_DOWN_PROPERTY = "remote.driver.dontTearDown";
124 
125     /**
126      * https://jira.kuali.org/browse/
127      */
128     public static final String JIRA_BROWSE_URL = "https://jira.kuali.org/browse/";
129     static Map<String, String> jiraMatches;
130     static {
131         jiraMatches = new HashMap<String, String>();
132         jiraMatches.put("Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'refreshWhenChanged' of bean class [org.kuali.rice.krad.uif.element.Action]: Bean property 'refreshWhenChanged' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?",
133                 "KULRICE-8137 Agenda Rule edit Incident report Invalid property 'refreshWhenChanged'");
134 
135         jiraMatches.put("org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase.processAddCollectionLineBusinessRules(MaintenanceDocumentRuleBase.",
136                 "KULRICE-8142 NPE in MaintenanceDocumentRuleBase.processAddCollectionLineBusinessRules");
137 
138         jiraMatches.put("at org.kuali.rice.krad.rules.DocumentRuleBase.isDocumentOverviewValid(DocumentRuleBase.",
139                 "KULRICE-8134 NPE in DocumentRuleBase.isDocumentOverviewValid(DocumentRuleBase");
140 
141         jiraMatches.put("org.kuali.rice.krad.uif.layout.TableLayoutManager.buildLine(TableLayoutManager.",
142                 "KULRICE-8160 NPE at TableLayoutManager.buildLine(TableLayoutManager");
143 
144         jiraMatches.put("Bean property 'configFileLocations' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?",
145                 "KULRICE-8173 Bean property 'configFileLocations' is not writable or has an invalid setter method");
146 
147         jiraMatches.put("Bean property 'componentSecurity' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?",
148                 "KULRICE-8182 JDK7 Bean property 'componentSecurity' is not readable...");
149 
150         jiraMatches.put("java.sql.SQLSyntaxErrorException: ORA-00904: \"ROUTEHEADERID\": invalid identifier",
151                 "KULRICE-8277 Several ITs fail with OJB operation; bad SQL grammar []; nested exception is java.sql.SQLException: ORA-00904: \"ROUTEHEADERID\": invalid identifier");
152 
153         jiraMatches.put("By.xpath: //button[@data-loadingmessage='Adding Line...']",
154                 "KULRICE-9044 KRAD \"stacked\" collection elements are not rendering add/delete buttons ");
155 
156         jiraMatches.put("Error: on line 135, column 39 in krad/WEB-INF/ftl/lib/grid.ftl",
157                 "KULRICE-9047 Term maintenance freemarker exception ");
158 
159         //        jiraMatches.put("",
160 //                "");
161 
162     }
163 
164     public static String blanketApprovalCleanUpErrorText(String errorText) {
165         errorText = errorText.replace("* required field", "").replace("\n", " ").trim(); // bit of extra ui text we don't care about
166         return errorText;
167     }
168 
169     protected static void checkForIncidentReport(String contents, String linkLocator, Failable failable, String message) {
170         if (contents == null) { //guard clause
171             return;
172         }
173 
174         if (incidentReported(contents)) {
175             try {
176                 processIncidentReport(contents, linkLocator, failable, message);
177             } catch (IndexOutOfBoundsException e) {
178                 failable.fail(
179                         "\nIncident report detected "
180                                 + message
181                                 + " but there was an exception during processing: "
182                                 + e.getMessage()
183                                 + "\nStack Trace from processing exception"
184                                 + stackTrace(e)
185                                 + "\nContents that triggered exception: "
186                                 + deLinespace(contents));
187             }
188         }
189 
190         if (contents.contains("HTTP Status 404")) {
191             failable.fail("\nHTTP Status 404 " + linkLocator + " " + message + " " + "\ncontents:" + contents);
192         }
193 
194         if (contents.contains("Java backtrace for programmers:")) { // freemarker exception
195             try {
196                 processFreemarkerException(contents, linkLocator, failable, message);
197             } catch (IndexOutOfBoundsException e) {
198                 failable.fail("\nFreemarker exception detected "
199                         + message
200                         + " but there was an exception during processing: "
201                         + e.getMessage()
202                         + "\nStack Trace from processing exception"
203                         + stackTrace(e)
204                         + "\nContents that triggered exception: "
205                         + deLinespace(contents));
206             }
207 
208         }
209     }
210 
211     public static String deLinespace(String contents) {
212         while (contents.contains("\n\n")) {
213             contents = contents.replaceAll("\n\n", "\n");
214         }
215         return contents;
216     }
217 
218     /**
219      * Setting the JVM arg remote.driver.dontTearDown to y or t leaves the browser window open when the test has completed.  Valuable when debugging, updating, or creating new tests.
220      * When implementing your own tearDown method rather than an inherited one, it is a common courtesy to include this check and not stop and shutdown the browser window to make it easy debug or update your test.
221      * {@code }
222      * @return true if the dontTearDownProperty is not set.
223      */
224     public static boolean dontTearDownPropertyNotSet() {
225         return System.getProperty(DONT_TEAR_DOWN_PROPERTY) == null ||
226                 "f".startsWith(System.getProperty(DONT_TEAR_DOWN_PROPERTY).toLowerCase()) ||
227                 "n".startsWith(System.getProperty(DONT_TEAR_DOWN_PROPERTY).toLowerCase());
228     }
229 
230     private static String extractIncidentReportInfo(String contents, String linkLocator, String message) {
231         String chunk =  contents.substring(contents.indexOf("Incident Feedback"), contents.lastIndexOf("</div>") );
232         String docId = chunk.substring(chunk.lastIndexOf("Document Id"), chunk.indexOf("View Id"));
233         docId = docId.substring(0, docId.indexOf("</span>"));
234         docId = docId.substring(docId.lastIndexOf(">") + 2, docId.length());
235 
236         String viewId = chunk.substring(chunk.lastIndexOf("View Id"), chunk.indexOf("Error Message"));
237         viewId = viewId.substring(0, viewId.indexOf("</span>"));
238         viewId = viewId.substring(viewId.lastIndexOf(">") + 2, viewId.length());
239 
240         String stackTrace = chunk.substring(chunk.lastIndexOf("(only in dev mode)"), chunk.length());
241         stackTrace = stackTrace.substring(stackTrace.indexOf("<span id=\"") + 3, stackTrace.length());
242         stackTrace = stackTrace.substring(stackTrace.indexOf("\">") + 2, stackTrace.indexOf("</span>"));
243 
244         //            System.out.println(docId);
245         //            System.out.println(viewId);
246         //            System.out.println(stackTrace);
247         return "\nIncident report "
248                 + message
249                 + " navigating to "
250                 + linkLocator
251                 + " : View Id: "
252                 + viewId.trim()
253                 + " Doc Id: "
254                 + docId.trim()
255                 + "\nStackTrace: "
256                 + stackTrace.trim();
257     }
258 
259     private static String extractIncidentReportKim(String contents, String linkLocator, String message) {
260         String chunk =  contents.substring(contents.indexOf("id=\"headerarea\""), contents.lastIndexOf("</div>") );
261         String docIdPre = "type=\"hidden\" value=\"";
262         String docId = chunk.substring(chunk.indexOf(docIdPre) + docIdPre.length(), chunk.indexOf("\" name=\"documentId\""));
263 
264         String stackTrace = chunk.substring(chunk.lastIndexOf("name=\"displayMessage\""), chunk.length());
265         String stackTracePre = "value=\"";
266         stackTrace = stackTrace.substring(stackTrace.indexOf(stackTracePre) + stackTracePre.length(), stackTrace.indexOf("name=\"stackTrace\"") - 2);
267 
268         return "\nIncident report "
269                 + message
270                 + " navigating to "
271                 + linkLocator
272                 + " Doc Id: "
273                 + docId.trim()
274                 + "\nStackTrace: "
275                 + stackTrace.trim();
276     }
277 
278     public static void failOnInvalidUserName(String userName, String contents, Failable failable) {
279         if (contents.indexOf("Invalid username") > -1) {
280             failable.fail("Invalid username " + userName);
281         }
282     }
283 /*
284     public static void failOnMatchedJira(String contents) {
285         Iterator<String> iter = jiraMatches.keySet().iterator();
286         String key = null;
287 
288         while (iter.hasNext()) {
289             key = iter.next();
290             if (contents.contains(key)) {
291                 SeleneseTestBase.fail(JIRA_BROWSE_URL + jiraMatches.get(key));
292             }
293         }
294     }
295 */
296     public static void failOnMatchedJira(String contents, Failable failable) {
297         Iterator<String> iter = jiraMatches.keySet().iterator();
298         String key = null;
299 
300         while (iter.hasNext()) {
301             key = iter.next();
302             if (contents.contains(key)) {
303                 failable.fail(JIRA_BROWSE_URL + jiraMatches.get(key));
304             }
305         }
306     }
307 
308     private static void failWithReportInfo(String contents, String linkLocator, Failable failable, String message) {
309         final String incidentReportInformation = extractIncidentReportInfo(contents, linkLocator, message);
310         failable.fail(incidentReportInformation);
311     }
312 
313 /*
314     private static void failWithReportInfoForKim(String contents, String linkLocator, String message) {
315         final String kimIncidentReport = extractIncidentReportKim(contents, linkLocator, message);
316         SeleneseTestBase.fail(kimIncidentReport);
317     }
318 */
319     private static void failWithReportInfoForKim(String contents, String linkLocator, Failable failable, String message) {
320         final String kimIncidentReport = extractIncidentReportKim(contents, linkLocator, message);
321         failable.fail(kimIncidentReport);
322     }
323 
324     /**
325      * In order to run as a smoke test the ability to set the baseUrl via the JVM arg remote.public.url is required.
326      * Trailing slashes are trimmed.  If the remote.public.url does not start with http:// it will be added.
327      * @return http://localhost:8080/kr-dev by default else the value of remote.public.url
328      */
329     public static String getBaseUrlString() {
330         String baseUrl = System.getProperty(REMOTE_PUBLIC_URL_PROPERTY);
331         if (baseUrl == null) {
332             baseUrl = DEFAULT_BASE_URL;
333         }
334         baseUrl = prettyHttp(baseUrl);
335         return baseUrl;
336     }
337 
338     public static String getHTML(String urlToRead) {
339         URL url;
340         HttpURLConnection conn;
341         BufferedReader rd;
342         String line;
343         String result = "";
344 
345         try {
346             url = new URL(urlToRead);
347             conn = (HttpURLConnection) url.openConnection();
348             conn.setRequestMethod("GET");
349             rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
350             while ((line = rd.readLine()) != null) {
351                 result += line;
352             }
353             rd.close();
354         } catch (Exception e) {
355             e.printStackTrace();
356         }
357 
358         return result;
359     }
360 
361     /**
362      * In order to run as a smoke test under selenium grid the ability to set the hubUrl via the JVM arg remote.public.hub is required.
363      * Trailing slashes are trimmed.  If the remote.public.hub does not start with http:// it will be added.
364      * @return http://localhost:4444/wd/hub by default else the value of remote.public.hub
365      */
366     public static String getHubUrlString() {
367         String hubUrl = System.getProperty(HUB_PROPERTY);
368         if (hubUrl == null) {
369             hubUrl = HUB_URL_PROPERTY;
370         }
371         hubUrl = prettyHttp(hubUrl);
372         if (!hubUrl.endsWith("/wd/hub")) {
373             hubUrl = hubUrl + "/wd/hub";
374         }
375         return hubUrl;
376     }
377 
378     private static boolean incidentReported(String contents) {
379         return contents != null &&
380                 contents.contains("Incident Report") &&
381                 !contents.contains("portal.do?channelTitle=Incident%20Report") && // Incident Report link on sampleapp KRAD tab
382                 !contents.contains("portal.do?channelTitle=Incident Report") &&   // Incident Report link on sampleapp KRAD tab IE8
383                 !contents.contains("uitest?viewId=Travel-testView2") &&
384                 !contents.contains("SeleniumException"); // selenium timeouts have Incident Report in them
385     }
386 
387     /**
388      * Append http:// if not present.  Remove trailing /
389      * @param baseUrl
390      * @return
391      */
392     public static String prettyHttp(String baseUrl) {
393         if (baseUrl.endsWith("/")) {
394             baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
395         }
396         if (!baseUrl.startsWith("http")) {
397             baseUrl = "http://" + baseUrl;
398         }
399         return baseUrl;
400     }
401 
402     private static void processFreemarkerException(String contents, String linkLocator, Failable failable, String message) {
403         failOnMatchedJira(contents, failable);
404         String stackTrace = contents.substring(contents.indexOf("Error: on line"), contents.indexOf("more<") - 1);
405         failable.fail(
406                 "\nFreemarker Exception " + message + " navigating to " + linkLocator + "\nStackTrace: " + stackTrace
407                         .trim());
408     }
409 
410 /*
411     private static void processIncidentReport(String contents, String linkLocator, String message) {
412         failOnMatchedJira(contents);
413 
414         if (contents.indexOf("Incident Feedback") > -1) {
415             failWithReportInfo(contents, linkLocator, message);
416         }
417 
418         if (contents.indexOf("Incident Report") > -1) { // KIM incident report
419             failWithReportInfoForKim(contents, linkLocator, message);
420         }
421 
422         SeleneseTestBase.fail("\nIncident report detected " + message + "\n Unable to parse out details for the contents that triggered exception: " + deLinespace(
423                 contents));
424     }
425 
426     private static void failWithReportInfo(String contents, String linkLocator, String message) {
427         final String incidentReportInformation = extractIncidentReportInfo(contents, linkLocator, message);
428         SeleneseTestBase.fail(incidentReportInformation);
429     }
430 */
431 
432     protected static void processIncidentReport(String contents, String linkLocator, Failable failable, String message) {
433         failOnMatchedJira(contents, failable);
434 
435         if (contents.indexOf("Incident Feedback") > -1) {
436             failWithReportInfo(contents, linkLocator, failable, message);
437         }
438 
439         if (contents.indexOf("Incident Report") > -1) { // KIM incident report
440             failWithReportInfoForKim(contents, linkLocator, failable, message);
441         }
442 
443         failable.fail("\nIncident report detected "
444                 + message
445                 + "\n Unable to parse out details for the contents that triggered exception: "
446                 + deLinespace(contents));
447     }
448 
449     /**
450      * Write the given stack trace into a String
451      * @param throwable whose stack trace to return
452      * @return String of the given throwable's stack trace.
453      */
454     public static String stackTrace(Throwable throwable) {
455         StringWriter wrt = new StringWriter();
456         PrintWriter pw = new PrintWriter(wrt);
457         throwable.printStackTrace(pw);
458         pw.flush();
459         return wrt.toString();
460     }
461 
462 }