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 }