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 */ 069 public static final String DTS_TWO = Calendar.getInstance().getTimeInMillis() + "" + RandomStringUtils.randomAlphabetic(2).toLowerCase(); 070 071 /** 072 * &hideReturnLink=true 073 */ 074 public static final String HIDE_RETURN_LINK = "&hideReturnLink=true"; 075 076 /** 077 * remote.public.hub 078 */ 079 public static final String HUB_PROPERTY = "remote.public.hub"; 080 081 /** 082 * remote.public.driver 083 */ 084 public static final String HUB_DRIVER_PROPERTY = "remote.public.driver"; 085 086 /** 087 * http://localhost:4444/wd/hub 088 */ 089 public static final String HUB_URL_PROPERTY = "http://localhost:4444/wd/hub"; 090 091 /** 092 * /kr-krad/lookup?methodToCall=start&dataObjectClassName= 093 */ 094 public static final String KRAD_LOOKUP_METHOD = "/kr-krad/lookup?methodToCall=start&dataObjectClassName="; 095 096 /** 097 * /kr/lookup.do?methodToCall=start&businessObjectClassName= 098 */ 099 public static final String KNS_LOOKUP_METHOD = "/kr/lookup.do?methodToCall=start&businessObjectClassName="; 100 101 /** 102 * /portal.do 103 */ 104 public static final String PORTAL = "/portal.do"; 105 106 /** 107 * ITUtil.getBaseUrlString() + ITUtil.PORTAL 108 */ 109 public static final String PORTAL_URL = ITUtil.getBaseUrlString() + ITUtil.PORTAL; 110 111 /** 112 * URLEncoder.encode(PORTAL_URL) 113 */ 114 public static final String PORTAL_URL_ENCODED = URLEncoder.encode(PORTAL_URL); 115 116 /** 117 * &showMaintenanceLinks=true 118 */ 119 public static final String SHOW_MAINTENANCE_LINKS = "&showMaintenanceLinks=true"; 120 121 /** 122 * remote.public.url 123 */ 124 public static final String REMOTE_PUBLIC_URL_PROPERTY = "remote.public.url"; 125 126 /** 127 * remote.autologin 128 */ 129 public static final String REMOTE_AUTOLOGIN_PROPERTY = "remote.autologin"; 130 131 /** 132 * &docFormKey= 133 */ 134 public static final String DOC_FORM_KEY = "&docFormKey="; 135 136 137 public static String blanketApprovalCleanUpErrorText(String errorText) { 138 errorText = errorText.replace("* required field", "").replace("\n", " ").trim(); // bit of extra ui text we don't care about 139 return errorText; 140 } 141 142 protected static void checkForIncidentReport(String contents, String linkLocator, Failable failable, String message) { 143 if (contents == null) { //guard clause 144 return; 145 } 146 147 if (incidentReported(contents)) { 148 try { 149 processIncidentReport(contents, linkLocator, failable, message); 150 } catch (IndexOutOfBoundsException e) { 151 failable.fail( 152 "\nIncident report detected " 153 + message 154 + " but there was an exception during processing: " 155 + e.getMessage() 156 + "\nStack Trace from processing exception" 157 + stackTrace(e) 158 + "\nContents that triggered exception: " 159 + deLinespace(contents)); 160 } 161 } 162 163 if (contents.contains("HTTP Status 404")) { 164 failable.fail("\nHTTP Status 404 " + linkLocator + " " + message + " " + "\ncontents:" + contents); 165 } 166 167 if (contents.contains("Java backtrace for programmers:")) { // freemarker exception 168 try { 169 processFreemarkerException(contents, linkLocator, failable, message); 170 } catch (IndexOutOfBoundsException e) { 171 failable.fail("\nFreemarker exception 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 } 183 184 public static String deLinespace(String contents) { 185 while (contents.contains("\n\n")) { 186 contents = contents.replaceAll("\n\n", "\n"); 187 } 188 return contents; 189 } 190 191 /** 192 * 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. 193 * 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. 194 * {@code } 195 * @return true if the dontTearDownProperty is not set. 196 */ 197 public static boolean dontTearDownPropertyNotSet() { 198 return System.getProperty(DONT_TEAR_DOWN_PROPERTY) == null || 199 "f".startsWith(System.getProperty(DONT_TEAR_DOWN_PROPERTY).toLowerCase()) || 200 "n".startsWith(System.getProperty(DONT_TEAR_DOWN_PROPERTY).toLowerCase()); 201 } 202 203 private static String extractIncidentReportInfo(String contents, String linkLocator, String message) { 204 String chunk = contents.substring(contents.indexOf("Incident Feedback"), contents.lastIndexOf("</div>") ); 205 String docId = chunk.substring(chunk.lastIndexOf("Document Id"), chunk.indexOf("View Id")); 206 docId = docId.substring(0, docId.indexOf("</span>")); 207 docId = docId.substring(docId.lastIndexOf(">") + 2, docId.length()); 208 209 String viewId = chunk.substring(chunk.lastIndexOf("View Id"), chunk.indexOf("Error Message")); 210 viewId = viewId.substring(0, viewId.indexOf("</span>")); 211 viewId = viewId.substring(viewId.lastIndexOf(">") + 2, viewId.length()); 212 213 String stackTrace = chunk.substring(chunk.lastIndexOf("(only in dev mode)"), chunk.length()); 214 stackTrace = stackTrace.substring(stackTrace.indexOf("<span id=\"") + 3, stackTrace.length()); 215 stackTrace = stackTrace.substring(stackTrace.indexOf("\">") + 2, stackTrace.indexOf("</span>")); 216 217 // System.out.println(docId); 218 // System.out.println(viewId); 219 // System.out.println(stackTrace); 220 return "\nIncident report " 221 + message 222 + " navigating to " 223 + linkLocator 224 + " : View Id: " 225 + viewId.trim() 226 + " Doc Id: " 227 + docId.trim() 228 + "\nStackTrace: " 229 + stackTrace.trim(); 230 } 231 232 private static String extractIncidentReportKim(String contents, String linkLocator, String message) { 233 String chunk = contents.substring(contents.indexOf("id=\"headerarea\""), contents.lastIndexOf("</div>") ); 234 String docIdPre = "type=\"hidden\" value=\""; 235 String docId = chunk.substring(chunk.indexOf(docIdPre) + docIdPre.length(), chunk.indexOf("\" name=\"documentId\"")); 236 237 String stackTrace = chunk.substring(chunk.lastIndexOf("name=\"displayMessage\""), chunk.length()); 238 String stackTracePre = "value=\""; 239 stackTrace = stackTrace.substring(stackTrace.indexOf(stackTracePre) + stackTracePre.length(), stackTrace.indexOf("name=\"stackTrace\"") - 2); 240 241 return "\nIncident report " 242 + message 243 + " navigating to " 244 + linkLocator 245 + " Doc Id: " 246 + docId.trim() 247 + "\nStackTrace: " 248 + stackTrace.trim(); 249 } 250 251 public static void failOnInvalidUserName(String userName, String contents, Failable failable) { 252 if (contents.indexOf("Invalid username") > -1) { 253 failable.fail("Invalid username " + userName); 254 } 255 } 256 /* 257 public static void failOnMatchedJira(String contents) { 258 Iterator<String> iter = jiraMatches.keySet().iterator(); 259 String key = null; 260 261 while (iter.hasNext()) { 262 key = iter.next(); 263 if (contents.contains(key)) { 264 SeleneseTestBase.fail(JIRA_BROWSE_URL + jiraMatches.get(key)); 265 } 266 } 267 } 268 */ 269 270 private static void failWithReportInfo(String contents, String linkLocator, Failable failable, String message) { 271 final String incidentReportInformation = extractIncidentReportInfo(contents, linkLocator, message); 272 failable.fail(incidentReportInformation); 273 } 274 275 /* 276 private static void failWithReportInfoForKim(String contents, String linkLocator, String message) { 277 final String kimIncidentReport = extractIncidentReportKim(contents, linkLocator, message); 278 SeleneseTestBase.fail(kimIncidentReport); 279 } 280 */ 281 private static void failWithReportInfoForKim(String contents, String linkLocator, Failable failable, String message) { 282 final String kimIncidentReport = extractIncidentReportKim(contents, linkLocator, message); 283 failable.fail(kimIncidentReport); 284 } 285 286 /** 287 * In order to run as a smoke test the ability to set the baseUrl via the JVM arg remote.public.url is required. 288 * Trailing slashes are trimmed. If the remote.public.url does not start with http:// it will be added. 289 * @return http://localhost:8080/kr-dev by default else the value of remote.public.url 290 */ 291 public static String getBaseUrlString() { 292 String baseUrl = System.getProperty(REMOTE_PUBLIC_URL_PROPERTY); 293 if (baseUrl == null) { 294 baseUrl = DEFAULT_BASE_URL; 295 } 296 baseUrl = prettyHttp(baseUrl); 297 return baseUrl; 298 } 299 300 public static String getHTML(String urlToRead) { 301 URL url; 302 HttpURLConnection conn; 303 BufferedReader rd; 304 String line; 305 String result = ""; 306 307 try { 308 url = new URL(urlToRead); 309 conn = (HttpURLConnection) url.openConnection(); 310 conn.setRequestMethod("GET"); 311 rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); 312 while ((line = rd.readLine()) != null) { 313 result += line; 314 } 315 rd.close(); 316 } catch (Exception e) { 317 e.printStackTrace(); 318 } 319 320 return result; 321 } 322 323 /** 324 * 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. 325 * Trailing slashes are trimmed. If the remote.public.hub does not start with http:// it will be added. 326 * @return http://localhost:4444/wd/hub by default else the value of remote.public.hub 327 */ 328 public static String getHubUrlString() { 329 String hubUrl = System.getProperty(HUB_PROPERTY); 330 if (hubUrl == null) { 331 hubUrl = HUB_URL_PROPERTY; 332 } 333 hubUrl = prettyHttp(hubUrl); 334 if (!hubUrl.endsWith("/wd/hub")) { 335 hubUrl = hubUrl + "/wd/hub"; 336 } 337 return hubUrl; 338 } 339 340 private static boolean incidentReported(String contents) { 341 return contents != null && 342 contents.contains("Incident Report") && 343 !contents.contains("portal.do?channelTitle=Incident%20Report") && // Incident Report link on sampleapp KRAD tab 344 !contents.contains("portal.do?channelTitle=Incident Report") && // Incident Report link on sampleapp KRAD tab IE8 345 !contents.contains("uitest?viewId=Travel-testView2") && 346 !contents.contains("SeleniumException"); // selenium timeouts have Incident Report in them 347 } 348 349 /** 350 * Append http:// if not present. Remove trailing / 351 * @param baseUrl 352 * @return 353 */ 354 public static String prettyHttp(String baseUrl) { 355 356 if (baseUrl.endsWith("/")) { 357 baseUrl = baseUrl.substring(0, baseUrl.length() - 1); 358 } 359 360 if (!baseUrl.startsWith("http")) { 361 baseUrl = "http://" + baseUrl; 362 } 363 364 return baseUrl; 365 } 366 367 private static void processFreemarkerException(String contents, String linkLocator, Failable failable, String message) { 368 JiraAwareFailureUtil.failOnMatchedJira(contents, failable); 369 String stackTrace = contents.substring(contents.indexOf("Error: on line"), contents.indexOf("more<") - 1); 370 failable.fail( 371 "\nFreemarker Exception " + message + " navigating to " + linkLocator + "\nStackTrace: " + stackTrace 372 .trim()); 373 } 374 375 /* 376 private static void processIncidentReport(String contents, String linkLocator, String message) { 377 failOnMatchedJira(contents); 378 379 if (contents.indexOf("Incident Feedback") > -1) { 380 failWithReportInfo(contents, linkLocator, message); 381 } 382 383 if (contents.indexOf("Incident Report") > -1) { // KIM incident report 384 failWithReportInfoForKim(contents, linkLocator, message); 385 } 386 387 SeleneseTestBase.fail("\nIncident report detected " + message + "\n Unable to parse out details for the contents that triggered exception: " + deLinespace( 388 contents)); 389 } 390 391 private static void failWithReportInfo(String contents, String linkLocator, String message) { 392 final String incidentReportInformation = extractIncidentReportInfo(contents, linkLocator, message); 393 SeleneseTestBase.fail(incidentReportInformation); 394 } 395 */ 396 397 protected static void processIncidentReport(String contents, String linkLocator, Failable failable, String message) { 398 JiraAwareFailureUtil.failOnMatchedJira(contents, failable); 399 400 if (contents.indexOf("Incident Feedback") > -1) { 401 failWithReportInfo(contents, linkLocator, failable, message); 402 } 403 404 if (contents.indexOf("Incident Report") > -1) { // KIM incident report 405 failWithReportInfoForKim(contents, linkLocator, failable, message); 406 } 407 408 failable.fail("\nIncident report detected " 409 + message 410 + "\n Unable to parse out details for the contents that triggered exception: " 411 + deLinespace(contents)); 412 } 413 414 /** 415 * Write the given stack trace into a String 416 * @param throwable whose stack trace to return 417 * @return String of the given throwable's stack trace. 418 */ 419 public static String stackTrace(Throwable throwable) { 420 StringWriter wrt = new StringWriter(); 421 PrintWriter pw = new PrintWriter(wrt); 422 throwable.printStackTrace(pw); 423 pw.flush(); 424 return wrt.toString(); 425 } 426 427 }