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