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    }