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