001 /** 002 * Copyright 2005-2013 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 */ 016 package edu.samplu.common; 017 018 import org.apache.commons.lang.RandomStringUtils; 019 020 import java.io.BufferedReader; 021 import java.io.InputStreamReader; 022 import java.io.PrintWriter; 023 import java.io.StringWriter; 024 import java.net.HttpURLConnection; 025 import java.net.URL; 026 import java.net.URLEncoder; 027 import java.util.Calendar; 028 029 /** 030 * TODO: 031 * <ol> 032 * <li>Keep WebDriver dependencies out of this class, those should be in {@link WebDriverUtil}</li> 033 * <li>Keep JUnit or TestNG dependencies out of in this class.</li> 034 * <li>Extract Hub specific logic?/li> 035 * <li>Rename to SmokeTestUtil or such</li> 036 * </ol> 037 * @author Kuali Rice Team (rice.collab@kuali.org) 038 */ 039 public class ITUtil { 040 041 /** 042 * http://localhost:8080/kr-dev 043 */ 044 public static final String DEFAULT_BASE_URL = "http://localhost:8080/kr-dev"; 045 046 /** 047 * //div[@class='error']" 048 */ 049 public static final String DIV_ERROR_LOCATOR = "//div[@class='error']"; 050 051 /** 052 * //div[@class='msg-excol'] 053 */ 054 public static final String DIV_EXCOL_LOCATOR = "//div[@class='msg-excol']"; 055 056 /** 057 * remote.driver.dontTearDown 058 */ 059 public static final String DONT_TEAR_DOWN_PROPERTY = "remote.driver.dontTearDown"; 060 061 /** 062 * Calendar.getInstance().getTimeInMillis() + "" 063 */ 064 public static final String DTS = Calendar.getInstance().getTimeInMillis() + ""; 065 066 /** 067 * Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase() 068 * @Deprecated {@link ITUtil#createUniqueDtsPlusTwoRandomChars()} 069 */ 070 public static final String DTS_TWO = Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase(); 071 072 /** 073 * &hideReturnLink=true 074 */ 075 public static final String HIDE_RETURN_LINK = "&hideReturnLink=true"; 076 077 /** 078 * remote.public.hub 079 */ 080 public static final String HUB_PROPERTY = "remote.public.hub"; 081 082 /** 083 * remote.public.driver 084 */ 085 public static final String HUB_DRIVER_PROPERTY = "remote.public.driver"; 086 087 /** 088 * http://localhost:4444/wd/hub 089 */ 090 public static final String HUB_URL_PROPERTY = "http://localhost:4444/wd/hub"; 091 092 /** 093 * /kr-krad/lookup?methodToCall=start&dataObjectClassName= 094 */ 095 public static final String KRAD_LOOKUP_METHOD = "/kr-krad/lookup?methodToCall=start&dataObjectClassName="; 096 097 /** 098 * /kr/lookup.do?methodToCall=start&businessObjectClassName= 099 */ 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 }