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") > -1) {
304 failable.fail("Invalid Login " + 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 }