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  
29  /**
30   * TODO:
31   * <ol>
32   *   <li>Keep WebDriver dependencies out of this class, those should be in {@link WebDriverUtil}</li>
33   *   <li>Keep JUnit or TestNG dependencies out of in this class.</li>
34   *   <li>Extract Hub specific logic?/li>
35   *   <li>Rename to SmokeTestUtil or such</li>
36   * </ol>
37   * @author Kuali Rice Team (rice.collab@kuali.org)
38   */
39  public class ITUtil {
40  
41      /**
42       * http://localhost:8080/kr-dev
43       */
44      public static final String DEFAULT_BASE_URL = "http://localhost:8080/kr-dev";
45  
46      /**
47       * //div[@class='error']"
48       */
49      public static final String DIV_ERROR_LOCATOR = "//div[@class='error']";
50  
51      /**
52       * //div[@class='msg-excol']
53       */
54      public static final String DIV_EXCOL_LOCATOR = "//div[@class='msg-excol']";
55  
56      /**
57       * remote.driver.dontTearDown
58       */
59      public static final String DONT_TEAR_DOWN_PROPERTY = "remote.driver.dontTearDown";
60  
61      /**
62       * Calendar.getInstance().getTimeInMillis() + ""
63       */
64      public static final String DTS = Calendar.getInstance().getTimeInMillis() + "";
65  
66      /**
67       * Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase()
68       * @Deprecated {@link ITUtil#createUniqueDtsPlusTwoRandomChars()}
69       */
70      public static final String DTS_TWO = Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase();
71  
72      /**
73       *  &hideReturnLink=true
74       */
75      public static final String HIDE_RETURN_LINK =  "&hideReturnLink=true";
76  
77      /**
78       * remote.public.hub
79       */
80      public static final String HUB_PROPERTY = "remote.public.hub";
81  
82      /**
83       * remote.public.driver
84       */
85      public static final String HUB_DRIVER_PROPERTY = "remote.public.driver";
86  
87      /**
88       * http://localhost:4444/wd/hub
89       */
90      public static final String HUB_URL_PROPERTY = "http://localhost:4444/wd/hub";
91  
92      /**
93       * /kr-krad/lookup?methodToCall=start&dataObjectClassName=
94       */
95      public static final String KRAD_LOOKUP_METHOD =  "/kr-krad/lookup?methodToCall=start&dataObjectClassName=";
96  
97      /**
98       * /kr/lookup.do?methodToCall=start&businessObjectClassName=
99       */
100     public static final String KNS_LOOKUP_METHOD =  "/kr/lookup.do?methodToCall=start&businessObjectClassName=";
101 
102     /**
103      * /kr-krad/kradsampleapp?viewId=KradSampleAppHome
104      */
105     public static final String KRAD_PORTAL = "/kr-krad/kradsampleapp?viewId=KradSampleAppHome";
106 
107     /**
108      * /kr-krad/kradsampleapp?viewId=KradSampleAppHome
109      */
110     public static final String KRAD_PORTAL_URL = ITUtil.getBaseUrlString() + KRAD_PORTAL;
111 
112     /**
113      * /kr-krad/labs?viewId=LabsMenuView
114      */
115     public static final  String LABS = "/kr-krad/labs?viewId=LabsMenuView";
116 
117     /**
118      * ITUtil.getBaseUrlString() + LABS
119      */
120     public static final String LABS_URL = ITUtil.getBaseUrlString() + LABS;
121 
122     /**
123      * /portal.do
124      */
125     public static final String PORTAL = "/portal.do";
126 
127     /**
128      * ITUtil.getBaseUrlString() + ITUtil.PORTAL
129      */
130     public static final String PORTAL_URL =  ITUtil.getBaseUrlString() + ITUtil.PORTAL;
131 
132     /**
133      * URLEncoder.encode(PORTAL_URL)
134      */
135     public static final String PORTAL_URL_ENCODED = URLEncoder.encode(PORTAL_URL);
136 
137     /**
138      *  &showMaintenanceLinks=true
139      */
140     public static final String SHOW_MAINTENANCE_LINKS =  "&showMaintenanceLinks=true";
141 
142     /**
143      * remote.public.url
144      */
145     public static final String REMOTE_PUBLIC_URL_PROPERTY = "remote.public.url";
146 
147     /**
148      * remote.autologin
149      */
150     public static final String REMOTE_AUTOLOGIN_PROPERTY = "remote.autologin";
151 
152     /**
153      * KRAD
154      */
155     public static final String REMOTE_UIF_KRAD = "KRAD";
156 
157     /**
158      * KNS
159      */
160     public static final String REMOTE_UIF_KNS  = "KNS";
161 
162     /**
163      * &docFormKey=
164      */
165     public static final String DOC_FORM_KEY = "&docFormKey=";
166     
167 
168     public static String blanketApprovalCleanUpErrorText(String errorText) {
169         errorText = errorText.replace("* required field", "").replace("\n", " ").trim(); // bit of extra ui text we don't care about
170         return errorText;
171     }
172 
173     public static String createUniqueDtsPlusTwoRandomChars() {
174         return Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase();
175     }
176 
177     // The Document Description contains 9 continuous digits or 9 digits grouped in the following pattern: ###-##-####, which may represent a Tax Number.
178     // The Document Description is not secure and its contents may be viewed by other application users. Please revise the Document Description to not contain digits in those patterns.
179     public static String createUniqueDtsPlusTwoRandomCharsNot9Digits() {
180         String dtsTwo = ITUtil.createUniqueDtsPlusTwoRandomChars();
181         dtsTwo = dtsTwo.substring(0, 5) + dtsTwo.substring(13, 14) + dtsTwo.substring(6, 12);
182         return dtsTwo;
183     }
184 
185     protected static void checkForIncidentReport(String contents, String linkLocator, Failable failable, String message) {
186         if (contents == null) { //guard clause
187             return;
188         }
189 
190         if (incidentReported(contents)) {
191             try {
192                 processIncidentReport(contents, linkLocator, failable, message);
193             } catch (IndexOutOfBoundsException e) {
194                 failable.fail(
195                         "\nIncident report detected "
196                                 + message
197                                 + " but there was an exception during processing: "
198                                 + e.getMessage()
199                                 + "\nStack Trace from processing exception"
200                                 + stackTrace(e)
201                                 + "\nContents that triggered exception: "
202                                 + deLinespace(contents));
203             }
204         }
205 
206         if (contents.contains("HTTP Status 404")) {
207             failable.fail("\nHTTP Status 404 " + linkLocator + " " + message + " " + "\ncontents:" + contents);
208         }
209 
210         if (contents.contains("Java backtrace for programmers:")) { // freemarker exception
211             try {
212                 processFreemarkerException(contents, linkLocator, failable, message);
213             } catch (IndexOutOfBoundsException e) {
214                 failable.fail("\nFreemarker exception detected "
215                         + message
216                         + " but there was an exception during processing: "
217                         + e.getMessage()
218                         + "\nStack Trace from processing exception"
219                         + stackTrace(e)
220                         + "\nContents that triggered exception: "
221                         + deLinespace(contents));
222             }
223         }
224 
225         if (contents.contains("Document Expired")) { // maybe Firefox specific
226             failable.fail("Document Expired message.");
227         }
228     }
229 
230     public static String deLinespace(String contents) {
231         while (contents.contains("\n\n")) {
232             contents = contents.replaceAll("\n\n", "\n");
233         }
234         return contents;
235     }
236 
237     /**
238      * 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.
239      * 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.
240      * {@code }
241      * @return true if the dontTearDownProperty is not set.
242      */
243     public static boolean dontTearDownPropertyNotSet() {
244         return System.getProperty(DONT_TEAR_DOWN_PROPERTY) == null ||
245                 "f".startsWith(System.getProperty(DONT_TEAR_DOWN_PROPERTY).toLowerCase()) ||
246                 "n".startsWith(System.getProperty(DONT_TEAR_DOWN_PROPERTY).toLowerCase());
247     }
248 
249     private static String extractIncidentReportInfo(String contents, String linkLocator, String message) {
250         String chunk =  contents.substring(contents.indexOf("Incident Feedback"), contents.lastIndexOf("</div>") );
251         String docId = chunk.substring(chunk.lastIndexOf("Document Id"), chunk.indexOf("View Id"));
252         docId = docId.substring(0, docId.indexOf("</span>"));
253         docId = docId.substring(docId.lastIndexOf(">") + 2, docId.length());
254 
255         String viewId = chunk.substring(chunk.lastIndexOf("View Id"), chunk.indexOf("Error Message"));
256         viewId = viewId.substring(0, viewId.indexOf("</span>"));
257         viewId = viewId.substring(viewId.lastIndexOf(">") + 2, viewId.length());
258 
259         String stackTrace = chunk.substring(chunk.lastIndexOf("(only in dev mode)"), chunk.length());
260         stackTrace = stackTrace.substring(stackTrace.indexOf("<pre>") + 5, stackTrace.length());
261         stackTrace = stackTrace.substring(0, stackTrace.indexOf("</"));
262 
263         //            System.out.println(docId);
264         //            System.out.println(viewId);
265         //            System.out.println(stackTrace);
266         return "\nIncident report "
267                 + message
268                 + " navigating to "
269                 + linkLocator
270                 + " : View Id: "
271                 + viewId.trim()
272                 + " Doc Id: "
273                 + docId.trim()
274                 + "\nStackTrace: "
275                 + stackTrace.trim().replace(" at ", "");
276     }
277 
278     private static String extractIncidentReportKim(String contents, String linkLocator, String message) {
279         String chunk =  contents.substring(contents.indexOf("id=\"headerarea\""), contents.lastIndexOf("</div>") );
280         String docIdPre = "type=\"hidden\" value=\"";
281         String docId = chunk.substring(chunk.indexOf(docIdPre) + docIdPre.length(), chunk.indexOf("\" name=\"documentId\""));
282 
283         String stackTrace = chunk.substring(chunk.lastIndexOf("name=\"displayMessage\""), chunk.length());
284         String stackTracePre = "value=\"";
285         stackTrace = stackTrace.substring(stackTrace.indexOf(stackTracePre) + stackTracePre.length(), stackTrace.indexOf("name=\"stackTrace\"") - 2);
286 
287         return "\nIncident report "
288                 + message
289                 + " navigating to "
290                 + linkLocator
291                 + " Doc Id: "
292                 + docId.trim()
293                 + "\nStackTrace: "
294                 + stackTrace.trim().replace(" at ", "");
295     }
296 
297     public static void failOnInvalidUserName(String userName, String contents, Failable failable) {
298         if (contents.indexOf("Invalid username") > -1) {
299             failable.fail("Invalid username " + userName);
300         }
301     }
302 /*
303     public static void failOnMatchedJira(String contents) {
304         Iterator<String> iter = jiraMatches.keySet().iterator();
305         String key = null;
306 
307         while (iter.hasNext()) {
308             key = iter.next();
309             if (contents.contains(key)) {
310                 SeleneseTestBase.fail(JIRA_BROWSE_URL + jiraMatches.get(key));
311             }
312         }
313     }
314 */
315 
316     private static void failWithReportInfo(String contents, String linkLocator, Failable failable, String message) {
317         final String incidentReportInformation = extractIncidentReportInfo(contents, linkLocator, message);
318         failable.fail(incidentReportInformation);
319     }
320 
321 /*
322     private static void failWithReportInfoForKim(String contents, String linkLocator, String message) {
323         final String kimIncidentReport = extractIncidentReportKim(contents, linkLocator, message);
324         SeleneseTestBase.fail(kimIncidentReport);
325     }
326 */
327     private static void failWithReportInfoForKim(String contents, String linkLocator, Failable failable, String message) {
328         final String kimIncidentReport = extractIncidentReportKim(contents, linkLocator, message);
329         failable.fail(kimIncidentReport);
330     }
331 
332     /**
333      * In order to run as a smoke test the ability to set the baseUrl via the JVM arg remote.public.url is required.
334      * Trailing slashes are trimmed.  If the remote.public.url does not start with http:// it will be added.
335      * @return http://localhost:8080/kr-dev by default else the value of remote.public.url
336      */
337     public static String getBaseUrlString() {
338         String baseUrl = System.getProperty(REMOTE_PUBLIC_URL_PROPERTY);
339         if (baseUrl == null) {
340             baseUrl = DEFAULT_BASE_URL;
341         }
342         baseUrl = prettyHttp(baseUrl);
343         return baseUrl;
344     }
345 
346     public static String getHTML(String urlToRead) {
347         URL url;
348         HttpURLConnection conn;
349         BufferedReader rd;
350         String line;
351         String result = "";
352 
353         try {
354             url = new URL(urlToRead);
355             conn = (HttpURLConnection) url.openConnection();
356             conn.setRequestMethod("GET");
357             rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
358             while ((line = rd.readLine()) != null) {
359                 result += line;
360             }
361             rd.close();
362         } catch (Exception e) {
363             e.printStackTrace();
364         }
365 
366         return result;
367     }
368 
369     /**
370      * 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.
371      * Trailing slashes are trimmed.  If the remote.public.hub does not start with http:// it will be added.
372      * @return http://localhost:4444/wd/hub by default else the value of remote.public.hub
373      */
374     public static String getHubUrlString() {
375         String hubUrl = System.getProperty(HUB_PROPERTY);
376         if (hubUrl == null) {
377             hubUrl = HUB_URL_PROPERTY;
378         }
379         hubUrl = prettyHttp(hubUrl);
380         if (!hubUrl.endsWith("/wd/hub")) {
381             hubUrl = hubUrl + "/wd/hub";
382         }
383         return hubUrl;
384     }
385 
386     private static boolean incidentReported(String contents) {
387         return contents != null &&
388                 contents.contains("Incident Report") &&
389                 !contents.contains("portal.do?channelTitle=Incident%20Report") && // Incident Report link on sampleapp KRAD tab
390                 !contents.contains("portal.do?channelTitle=Incident Report") &&   // Incident Report link on sampleapp KRAD tab IE8
391                 !contents.contains("uitest?viewId=Travel-testView2") &&
392                 !contents.contains("SeleniumException"); // selenium timeouts have Incident Report in them
393     }
394 
395     /**
396      * Append http:// if not present.  Remove trailing /
397      * @param baseUrl
398      * @return
399      */
400     public static String prettyHttp(String baseUrl) {
401 
402         if (baseUrl.endsWith("/")) {
403             baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
404         }
405 
406         if (!baseUrl.startsWith("http")) {
407             baseUrl = "http://" + baseUrl;
408         }
409 
410         return baseUrl;
411     }
412 
413     private static void processFreemarkerException(String contents, String linkLocator, Failable failable, String message) {
414         JiraAwareFailureUtil.failOnMatchedJira(contents, failable);
415         String stackTrace = contents.substring(contents.indexOf("Error: on line"), contents.indexOf("more<") - 1);
416         failable.fail(
417                 "\nFreemarker Exception " + message + " navigating to " + linkLocator + "\nStackTrace: " + stackTrace
418                         .trim().replace(" at ", ""));
419     }
420 
421 /*
422     private static void processIncidentReport(String contents, String linkLocator, String message) {
423         failOnMatchedJira(contents);
424 
425         if (contents.indexOf("Incident Feedback") > -1) {
426             failWithReportInfo(contents, linkLocator, message);
427         }
428 
429         if (contents.indexOf("Incident Report") > -1) { // KIM incident report
430             failWithReportInfoForKim(contents, linkLocator, message);
431         }
432 
433         SeleneseTestBase.fail("\nIncident report detected " + message + "\n Unable to parse out details for the contents that triggered exception: " + deLinespace(
434                 contents));
435     }
436 
437     private static void failWithReportInfo(String contents, String linkLocator, String message) {
438         final String incidentReportInformation = extractIncidentReportInfo(contents, linkLocator, message);
439         SeleneseTestBase.fail(incidentReportInformation);
440     }
441 */
442 
443     protected static void processIncidentReport(String contents, String linkLocator, Failable failable, String message) {
444         JiraAwareFailureUtil.failOnMatchedJira(contents, failable);
445 
446         if (contents.indexOf("Incident Feedback") > -1) {
447             failWithReportInfo(contents, linkLocator, failable, message);
448         }
449 
450         if (contents.indexOf("Incident Report") > -1) { // KIM incident report
451             failWithReportInfoForKim(contents, linkLocator, failable, message);
452         }
453 
454         failable.fail("\nIncident report detected "
455                 + message
456                 + "\n Unable to parse out details for the contents that triggered exception: "
457                 + deLinespace(contents));
458     }
459 
460     /**
461      * Write the given stack trace into a String remove the ats in an attempt to not cause Jenkins problems.
462      * @param throwable whose stack trace to return
463      * @return String of the given throwable's stack trace.
464      */
465     public static String stackTrace(Throwable throwable) {
466         StringWriter wrt = new StringWriter();
467         PrintWriter pw = new PrintWriter(wrt);
468         throwable.printStackTrace(pw);
469         pw.flush();
470         return wrt.toString().replace(" at " ,"");
471     }
472 }