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