001/** 002 * Copyright 2005-2015 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.testtools.selenium; 017 018import org.apache.commons.lang.RandomStringUtils; 019import org.kuali.rice.testtools.common.JiraAwareFailable; 020import org.kuali.rice.testtools.common.JiraAwareFailureUtils; 021 022import java.io.BufferedReader; 023import java.io.InputStreamReader; 024import java.io.PrintWriter; 025import java.io.StringWriter; 026import java.net.HttpURLConnection; 027import java.net.URL; 028import java.net.URLEncoder; 029import java.util.Calendar; 030 031/** 032 * For Rice specific sampleapp testing code. 033 * <ol> 034 * <li>Keep test framework methods (WebDriver, Assert) dependencies out of this class, those should be in 035 * {@link WebDriverUtils}</li> 036 * <li>Move JiraAware calls out of this class, those should be in {@see JiraAwareFailureUtils} or modified to be failed 037 * in another class</li> 038 * </ol> 039 * @author Kuali Rice Team (rice.collab@kuali.org) 040 */ 041public class AutomatedFunctionalTestUtils { 042 043 /** 044 * Calendar.getInstance().getTimeInMillis() + "" 045 */ 046 public static final String DTS = Calendar.getInstance().getTimeInMillis() + ""; 047 048 /** 049 * Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase() 050 * @Deprecated {@link AutomatedFunctionalTestUtils#createUniqueDtsPlusTwoRandomChars()} 051 */ 052 public static final String DTS_TWO = Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase(); 053 054 /** 055 * &hideReturnLink=true 056 */ 057 public static final String HIDE_RETURN_LINK = "&hideReturnLink=true"; 058 059 /** 060 * &hideReturnLink=false 061 */ 062 public static final String HIDE_RETURN_LINK_FALSE = "&hideReturnLink=false"; 063 064 /** 065 * /kr-krad/lookup?methodToCall=start&dataObjectClassName= 066 */ 067 public static final String KRAD_LOOKUP_METHOD = "/kr-krad/lookup?methodToCall=start&dataObjectClassName="; 068 069 /** 070 * /kr/lookup.do?methodToCall=start&businessObjectClassName= 071 */ 072 public static final String KNS_LOOKUP_METHOD = "/kr/lookup.do?methodToCall=start&businessObjectClassName="; 073 074 /** 075 * /kr-krad/kradsampleapp?viewId=KradSampleAppHome 076 */ 077 public static final String KRAD_PORTAL = "/kr-krad/kradsampleapp?viewId=KradSampleAppHome"; 078 079 /** 080 * /kr-krad/kradsampleapp?viewId=KradSampleAppHome 081 */ 082 public static final String KRAD_PORTAL_URL = WebDriverUtils.getBaseUrlString() + KRAD_PORTAL; 083 084 /** 085 * /kr-krad/labs?viewId=LabsMenuView 086 */ 087 public static final String LABS = "/kr-krad/labs?viewId=LabsMenuView"; 088 089 /** 090 * WebDriverUtils.getBaseUrlString() + LABS 091 */ 092 public static final String LABS_URL = WebDriverUtils.getBaseUrlString() + LABS; 093 094 /** 095 * /portal.do 096 */ 097 public static final String PORTAL = "/portal.do"; 098 099 /** 100 * WebDriverUtils.getBaseUrlString() + ITUtil.PORTAL 101 */ 102 public static final String PORTAL_URL = WebDriverUtils.getBaseUrlString() + AutomatedFunctionalTestUtils.PORTAL; 103 104 /** 105 * URLEncoder.encode(PORTAL_URL) 106 */ 107 public static final String PORTAL_URL_ENCODED = URLEncoder.encode(PORTAL_URL); 108 109 /** 110 * &showMaintenanceLinks=true 111 */ 112 public static final String SHOW_MAINTENANCE_LINKS = "&showMaintenanceLinks=true"; 113 114 /** 115 * KRAD 116 */ 117 public static final String REMOTE_UIF_KRAD = "KRAD"; 118 119 /** 120 * KNS 121 */ 122 public static final String REMOTE_UIF_KNS = "KNS"; 123 124 /** 125 * &docFormKey= 126 */ 127 public static final String DOC_FORM_KEY = "&docFormKey="; 128 129 /** 130 * Creates a 13 digit time stamp with two random characters appended for use with fields that require unique values. 131 * 132 * Some fields have built in validation to not allow 9 continuous digits for those cases {@see #createUniqueDtsPlusTwoRandomCharsNot9Digits} 133 * @return 134 */ 135 public static String createUniqueDtsPlusTwoRandomChars() { 136 return Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase(); 137 } 138 139 /** 140 * Creates a 13 digit time stamp with two random characters inserted into it to avoid the 9 continuous digit verification some fields use. 141 * 142 * @return 143 */ 144 public static String createUniqueDtsPlusTwoRandomCharsNot9Digits() { 145 String dtsTwo = AutomatedFunctionalTestUtils.createUniqueDtsPlusTwoRandomChars(); 146 dtsTwo = dtsTwo.substring(0, 5) + dtsTwo.substring(13, 15) + dtsTwo.substring(6, 12); 147 return dtsTwo; 148 } 149 150 protected static void checkForIncidentReport(String contents, String linkLocator, String message, JiraAwareFailable failable) { 151 if (contents == null) { //guard clause 152 return; 153 } 154 155 String errorMessage = incidentReportMessage(contents, linkLocator, message); 156 157 if (errorMessage != null) { 158 if (message != null && !message.isEmpty()) { 159 failable.jiraAwareFail(errorMessage, message); 160 } else { 161 failable.jiraAwareFail(errorMessage, contents); 162 } 163 } 164 } 165 166 protected static String incidentReportMessage(String contents, String linkLocator, String message) { 167 if (incidentReported(contents)) { 168 try { 169 return processIncidentReport(contents, linkLocator, message); 170 } catch (IndexOutOfBoundsException e) { 171 return "\nIncident report detected " 172 + message 173 + " but there was an exception during processing: " 174 + e.getMessage() 175 + "\nStack Trace from processing exception" 176 + stackTrace(e) 177 + "\nContents that triggered exception: " 178 + deLinespace(contents); 179 } 180 } 181 182 if (contents.contains("HTTP Status 404")) { 183 return "HTTP Status 404 contents: " + contents; 184 } 185 186 if (contents.contains("HTTP Status 500")) { 187 return "\nHTTP Status 500 stacktrace: " + extract500Exception(contents); 188 } 189 190 // freemarker exception 191 if (contents.contains("Java backtrace for programmers:") 192 || contents.contains("Java stack trace (for programmers):") 193 || contents.contains("FreeMarker template error:")) { 194 try { 195 return freemarkerExceptionMessage(contents, linkLocator, message); 196 } catch (IndexOutOfBoundsException e) { 197 return "\nFreemarker exception detected " 198 + message 199 + " but there was an exception during processing: " 200 + e.getMessage() 201 + "\nStack Trace from processing exception" 202 + stackTrace(e) 203 + "\nContents that triggered exception: " 204 + deLinespace(contents); 205 } 206 } 207 208 if (contents.contains("Document Expired")) { // maybe Firefox specific 209 return "Document Expired message."; 210 } 211 212 return null; 213 } 214 215 public static String deLinespace(String contents) { 216 while (contents.contains("\n\n")) { 217 contents = contents.replaceAll("\n\n", "\n"); 218 } 219 return contents; 220 } 221 222 private static String extractIncidentReportInfo(String contents, String linkLocator, String message) { 223 String chunk = contents.substring(contents.indexOf("Incident Feedback"), contents.lastIndexOf("</div>") ); 224 String docId = chunk.substring(chunk.lastIndexOf("Document Id"), chunk.indexOf("View Id")); 225 docId = docId.substring(0, docId.indexOf("</div>")); 226 docId = docId.substring(docId.lastIndexOf(">") + 2, docId.length()).trim(); 227 228 String viewId = chunk.substring(chunk.lastIndexOf("View Id"), chunk.indexOf("Error Message")); 229 viewId = viewId.substring(0, viewId.indexOf("</div>")); 230 viewId = viewId.substring(viewId.lastIndexOf(">") + 2, viewId.length()).trim(); 231 232 String stackTrace = chunk.substring(chunk.lastIndexOf("(only in dev mode)"), chunk.length()); 233 stackTrace = stackTrace.substring(stackTrace.indexOf("<pre") + 4, stackTrace.length()); 234 stackTrace = stackTrace.substring(stackTrace.indexOf(">") + 1, stackTrace.indexOf("</")); 235 236 return "\nIncident report " 237 + message 238 + " navigating to " 239 + linkLocator 240 + " : View Id: " 241 + viewId.trim() 242 + " Doc Id: " 243 + docId.trim() 244 + "\nStackTrace: " 245 + stackTrace.trim(); 246 } 247 248 private static String extractIncidentReportKim(String contents, String linkLocator, String message) { 249 if (contents.indexOf("id=\"headerarea\"") > -1) { 250 String chunk = contents.substring(contents.indexOf("id=\"headerarea\""), contents.lastIndexOf("</div>") ); 251 String docIdPre = "type=\"hidden\" value=\""; 252 String docId = chunk.substring(chunk.indexOf(docIdPre) + docIdPre.length(), chunk.indexOf("\" name=\"documentId\"")); 253 254 String stackTrace = chunk.substring(chunk.lastIndexOf("name=\"displayMessage\""), chunk.length()); 255 String stackTracePre = "value=\""; 256 stackTrace = stackTrace.substring(stackTrace.indexOf(stackTracePre) + stackTracePre.length(), stackTrace.indexOf("name=\"stackTrace\"") - 2); 257 258 return "\nIncident report " 259 + message 260 + " navigating to " 261 + linkLocator 262 + " Doc Id: " 263 + docId.trim() 264 + "\nStackTrace: " 265 + stackTrace.trim(); 266 } 267 return "\nIncident report detected for " + linkLocator + " but not able to parse. " + message; 268 } 269 270 public static void failOnInvalidUserName(String userName, String contents, JiraAwareFailable failable) { 271 if (contents.indexOf("Invalid") > -1) { 272 failable.fail("Invalid Login " + userName); 273 } 274 } 275 276 277 private static void failWithInfo(String contents, String linkLocator, JiraAwareFailable failable, String message) { 278 JiraAwareFailureUtils.failOnMatchedJira(contents, linkLocator, failable); 279 failable.fail(contents); 280 } 281 282 private static void failWithReportInfo(String contents, String linkLocator, JiraAwareFailable failable, String message) { 283 final String incidentReportInformation = extractIncidentReportInfo(contents, linkLocator, message); 284 JiraAwareFailureUtils.failOnMatchedJira(incidentReportInformation, failable); 285 failWithInfo(incidentReportInformation, linkLocator, failable, message); 286 } 287 288 289 private static void failWithReportInfoForKim(String contents, String linkLocator, JiraAwareFailable failable, String message) { 290 final String kimIncidentReport = extractIncidentReportKim(contents, linkLocator, message); 291 JiraAwareFailureUtils.failOnMatchedJira(kimIncidentReport, failable); 292 failable.fail(kimIncidentReport); 293 } 294 295 public static String getHTML(String urlToRead) { 296 URL url; 297 HttpURLConnection conn; 298 BufferedReader rd; 299 String line; 300 String result = ""; 301 302 try { 303 url = new URL(urlToRead); 304 conn = (HttpURLConnection) url.openConnection(); 305 conn.setRequestMethod("GET"); 306 rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); 307 while ((line = rd.readLine()) != null) { 308 result += line; 309 } 310 rd.close(); 311 } catch (Exception e) { 312 e.printStackTrace(); 313 } 314 315 return result; 316 } 317 318 private static boolean incidentReported(String contents) { 319 return contents != null && 320 contents.contains("Incident Report") && 321 !contents.contains("portal.do?channelTitle=Incident%20Report") && // Incident Report link on sampleapp KRAD tab 322 !contents.contains("portal.do?channelTitle=Incident Report") && // Incident Report link on sampleapp KRAD tab IE8 323 !contents.contains("uitest?viewId=Travel-testView2") && 324 !contents.contains("SeleniumException"); // selenium timeouts have Incident Report in them 325 } 326 327 /** 328 * Append http:// if not present, remove trailing /. 329 * 330 * @param baseUrl 331 * @return 332 */ 333 public static String prettyHttp(String baseUrl) { 334 335 if (baseUrl.endsWith("/")) { 336 baseUrl = baseUrl.substring(0, baseUrl.length() - 1); 337 } 338 339 if (!baseUrl.startsWith("http")) { 340 baseUrl = "http://" + baseUrl; 341 } 342 343 return baseUrl; 344 } 345 346 private static String extract500Exception(String contents) { 347 return contents.substring(contents.indexOf("<b>exception</b> </p><pre>") +26, 348 contents.indexOf("</pre><p></p><p><b>note</b>")); 349 } 350 351 private static void processFreemarkerException(String contents, String linkLocator, JiraAwareFailable failable, String message) { 352 JiraAwareFailureUtils.failOnMatchedJira(contents, failable); 353 String errorMessage = freemarkerExceptionMessage(contents, linkLocator, message); 354 355 JiraAwareFailureUtils.failOnMatchedJira(errorMessage, linkLocator, failable); 356 failable.fail(errorMessage); 357 } 358 359 protected static String freemarkerExceptionMessage(String contents, String linkLocator, String message) { 360 String ftlStackTrace = null; 361 if (contents.contains("more<")) { 362 ftlStackTrace = contents.substring(contents.indexOf("----------"), contents.indexOf("more<") - 1); 363 } else if (contents.contains("at java.lang.Thread.run(Thread.java:")) { 364 if (contents.indexOf("Error: on line") > -1) { 365 ftlStackTrace = contents.substring(contents.indexOf("Error: on line"), contents.indexOf("at java.lang.Thread.run(Thread.java:") + 39 ); 366 } else { 367 ftlStackTrace = contents.substring(contents.indexOf("FreeMarker template error:"), contents.indexOf("at java.lang.Thread.run(Thread.java:") + 39 ); 368 } 369 } 370 return "\nFreemarker Exception " + message + " navigating to " + linkLocator + "\nStackTrace: " + ftlStackTrace.trim(); 371 } 372 373 374 protected static String processIncidentReport(String contents, String linkLocator, String message) { 375 376 if (contents.indexOf("Incident Feedback") > -1) { 377 return extractIncidentReportInfo(contents, linkLocator, message); 378 } 379 380 if (contents.indexOf("Incident Report") > -1) { // KIM incident report 381 return extractIncidentReportKim(contents, linkLocator, message); 382 } 383 384 return "\nIncident report detected " 385 + message 386 + "\n Unable to parse out details for the contents that triggered exception: " 387 + deLinespace(contents); 388 } 389 390 /** 391 * Write the given stack trace into a String remove the ats in an attempt to not cause Jenkins problems. 392 * @param throwable whose stack trace to return 393 * @return String of the given throwable's stack trace. 394 */ 395 public static String stackTrace(Throwable throwable) { 396 StringWriter wrt = new StringWriter(); 397 PrintWriter pw = new PrintWriter(wrt); 398 throwable.printStackTrace(pw); 399 pw.flush(); 400 return wrt.toString(); 401 } 402 403 /** 404 * <p> 405 * Use the KRAD Login Screen or the old KNS Login Screen 406 * </p> 407 * 408 * @return true if Krad login 409 */ 410 public static boolean isKradLogin(){ 411 // check system property, default to KRAD 412 String loginUif = System.getProperty(WebDriverUtils.REMOTE_LOGIN_UIF); 413 if (loginUif == null) { 414 loginUif = REMOTE_UIF_KRAD; 415 } 416 417 return (REMOTE_UIF_KRAD.equalsIgnoreCase(loginUif)); 418 } 419}