View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.testtools.common;
17  
18  import org.apache.commons.lang3.exception.ExceptionUtils;
19  
20  import java.io.IOException;
21  import java.util.Iterator;
22  import java.util.Properties;
23  import java.util.regex.Matcher;
24  import java.util.regex.Pattern;
25  
26  /**
27   * <p>
28   * Link test failures to existing Jiras as a html link in Jenkins.
29   * </p><p>
30   * The more failures the more useful it is to not have to keep tracking down the same Jiras.
31   * </p><p>
32   * Set -Djira.aware.regex.failures.location and -Djira.aware.contains.failures.location to define file locations, else
33   * @{code JiraAwareRegexFailures.properties} and {@code JiraAwareContainsFailures.properties} will be read as a resource stream.  To
34   * override the Jira browse url set -Djira.aware.browse.url
35   * </p><p>
36   * To make use of JiraAwareFailureUtils implement {@see JiraAwareFailable} and call {@code JiraAwareFailureUtils.fail(contents, message, failable);} instead of
37   * asserts or Assert.fail().
38   * </p><p>
39   * TODO:
40   * <ol>
41   *   <li>Integration Test integration.  ITs often fail by the 10s tracking down existing Jiras is a huge time sink.</li>
42   * </ol>
43   * </p>
44   * @author Kuali Rice Team (rice.collab@kuali.org)
45   */
46  public class JiraAwareFailureUtils {
47  
48      /**
49       * <p>
50       * Set -Djira.aware.base.url to point your Jira url base (include trailing slash), defaults to
51       * https://jira.kuali.org/browse/
52       * </p>
53       */
54      public static final String JIRA_BROWSE_URL_PROPERTY = "jira.aware.browse.url";
55  
56      private static String JIRA_BROWSE_URL = System.getProperty(JIRA_BROWSE_URL_PROPERTY,"https://jira.kuali.org/browse/");
57  
58      private static String REGEX_DEFAULT_PROPS_LOCATION = "JiraAwareRegexFailures.properties";
59  
60      /**
61       * <p>
62       * Set -Djira.aware.regex.failures.location to point to the the regex failures properties, defaults to
63       * JiraAwareRegexFailures.properties
64       * </p>
65       */
66      public static final String REGEX_LOCATION_POPERTY = "jira.aware.regex.failures.location";
67  
68      private static String REGEX_PROPS_LOCATION = System.getProperty(REGEX_LOCATION_POPERTY, REGEX_DEFAULT_PROPS_LOCATION);
69  
70      private static String CONTAINS_DEFAULT_PROPS_LOCATION = "JiraAwareContainsFailures.properties";
71  
72      /**
73       * <p>
74       * Set -Djira.aware.contains.failures.location to point to the the regex failures properties, defaults to
75       * JiraAwareContainsFailures.properties
76       * </p>
77       */
78      public static final String CONTAINS_LOCATION_PROERTY = "jira.aware.contains.failures.location";
79  
80      private static String CONTAINS_PROPS_LOCATION = System.getProperty(CONTAINS_LOCATION_PROERTY, CONTAINS_DEFAULT_PROPS_LOCATION);
81  
82      static Properties regexJiraMatches; // for more powerful matching
83  
84      static Properties jiraMatches; // simple contains matching
85  
86      static {
87          try {
88              regexJiraMatches = new PropertiesUtils().loadProperties(REGEX_PROPS_LOCATION, REGEX_DEFAULT_PROPS_LOCATION);
89          } catch (IOException e) {
90              e.printStackTrace();
91          }
92  
93          try {
94              jiraMatches = new PropertiesUtils().loadProperties(CONTAINS_PROPS_LOCATION, CONTAINS_DEFAULT_PROPS_LOCATION);
95          } catch (IOException e) {
96              e.printStackTrace();
97          }
98      }
99  
100     private JiraAwareFailureUtils() {}
101 
102     /**
103      * <p>
104      * Calls {@see #failOnMatchedJira(String, JiraAwareFailable)} and calls fail on the {@see JiraAwareFailable#fail} if no matched jira failures.
105      * </p>
106      *
107      * @param message to pass to fail
108      * @param failable {@see JiraAwareFailable#fail}
109      */
110     public static void fail(String message, JiraAwareFailable failable) {
111         failOnMatchedJira(message, failable);
112         failable.fail(message);
113     }
114 
115     /**
116      * <p>
117      * Calls {@see #failOnMatchedJira(String, String, JiraAwareFailable)} and calls fail on the {@see JiraAwareFailable#fail} fails if no matched jira failures.
118      * </p>
119      *
120      * @param contents to check for jira matches on
121      * @param message to pass to fail, also checked for jira matches
122      * @param failable {@see JiraAwareFailable#fail}
123      */
124     public static void fail(String contents, String message, JiraAwareFailable failable) {
125         failOnMatchedJira(contents, message, failable);
126         failable.fail(contents + " " + message);
127     }
128 
129     /**
130      * <p>
131      * Calls {@see #failOnMatchedJira(String, String, JiraAwareFailable)} and calls fail on the {@see JiraAwareFailable#fail} fails if no matched jira failures.
132      * </p>
133      *
134      * @param contents to check for jira matches on
135      * @param message to pass to fail, also checked for jira matches
136      * @param failable {@see JiraAwareFailable#fail}
137      */
138     public static void fail(String contents, String message, Throwable throwable, JiraAwareFailable failable) {
139         failOnMatchedJira(contents, message, failable);
140         if (throwable != null) {
141             failOnMatchedJira(ExceptionUtils.getStackTrace(throwable), throwable.getMessage(), failable);
142             failable.fail(contents + " " + message + " " + throwable.getMessage() + "\n\t" + ExceptionUtils.getStackTrace(throwable));
143         }
144         failable.fail(message + "\n" + contents);
145     }
146 
147     /**
148      * <p>
149      * Calls {@see #failOnMatchedJira(String, JiraAwareFailable)} with the contents and if no match is detected then the message.
150      * </p>
151      *
152      * @param contents to check for containing of the jiraMatches keys.
153      * @param message to check for containing of the jiraMatches keys if contents doesn't
154      * @param failable to fail with the jiraMatches value if the contents or message is detected
155      */
156     public static void failOnMatchedJira(String contents, String message, JiraAwareFailable failable) {
157         if (message == null) {
158             message = ""; // prevent NPEs
159         }
160 
161         String match = findMatchedJiraContains(message);
162         if (match != null && !match.equals("")) {
163             failable.fail(match);
164         }
165 
166         match = findMatchedJiraContains(contents);
167         if (match != null && !match.equals("")) {
168             failable.fail(match);
169         }
170 
171         match = findMatchedJiraRegex(message);
172         if (match != null && !match.equals("")) {
173             failable.fail(match);
174         }
175 
176         match = findMatchedJiraRegex(contents);
177         if (match != null && !match.equals("")) {
178             failable.fail(match);
179         }
180     }
181 
182     /**
183      * <p>
184      * If the contents contains the jiraMatches key, calls fail on the {@see JiraAwareFailable#fail} passing in the jiraMatches value for the matched key.
185      * </p>
186      *
187      * @param contents to check for containing of the jiraMatches keys.
188      * @param failable to fail with the jiraMatches value if the jiraMatches key is contained in the contents
189      */
190     public static void failOnMatchedJira(String contents, JiraAwareFailable failable) {
191         String match = findMatchedJira(contents);
192         if (match != null && !match.equals("")) {
193             failable.fail(match);
194         }
195     }
196 
197     /**
198      * <p>
199      * Returns the value from the properties files for the key matching the contents or an empty string if no match is found.
200      * </p>
201      *
202      * @param contents to search for key in from properties file
203      * @return value for key which matches contents
204      */
205     public static String findMatchedJira(String contents) {
206         String match = findMatchedJiraContains(contents);
207         if (match != null && !"".equals(match)) {
208             return match;
209         }
210 
211         return findMatchedJiraRegex(contents);
212     }
213 
214     protected static String findMatchedJiraContains(String contents) {
215         if (jiraMatches == null || jiraMatches.keySet() == null) {
216             System.out.println("WARNING JiraAwareFailureUtils contains properties empty, findMatchesJira contains not available.");
217             return "";
218         }
219         String key = null;
220 
221         Iterator iter = jiraMatches.keySet().iterator();
222 
223         while (iter.hasNext()) {
224             key = (String)iter.next();
225             if (contents.contains(key)) {
226                 return("\n" + JIRA_BROWSE_URL + jiraMatches.get(key) + "\n\n" + contents);
227             }
228         }
229 
230         return "";
231     }
232 
233     protected static String findMatchedJiraRegex(String contents) {
234         if (regexJiraMatches == null || regexJiraMatches.keySet() == null) {
235             System.out.println("WARNING JiraAwareFailureUtils Regex properties empty, findMatchesJiraRegex not available.");
236             return "";
237         }
238         String key = null;
239         Pattern pattern = null;
240         Matcher matcher = null;
241 
242         Iterator iter = regexJiraMatches.keySet().iterator();
243 
244         while (iter.hasNext()) {
245             key = (String)iter.next();
246             pattern = Pattern.compile(key, Pattern.DOTALL); // match across line terminators
247             matcher = pattern.matcher(contents);
248 
249             if (matcher.find()) {
250                 return("\n" + JIRA_BROWSE_URL + regexJiraMatches.get(key) + "\n\n" + contents);
251             }
252         }
253 
254         return "";
255     }
256 
257 }