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