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 }