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 * 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 * remote.public.hub 084 */ 085 public static final String HUB_PROPERTY = "remote.public.hub"; 086 087 /** 088 * remote.public.driver 089 */ 090 public static final String HUB_DRIVER_PROPERTY = "remote.public.driver"; 091 092 /** 093 * http://localhost:4444/wd/hub 094 */ 095 public static final String HUB_URL_PROPERTY = "http://localhost:4444/wd/hub"; 096 097 /** 098 * /kr-krad/lookup?methodToCall=start&dataObjectClassName= 099 */ 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 username") > -1) { 304 failable.fail("Invalid username " + 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 }