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 }