001
014
015 package com.liferay.portal.test.rule.callback;
016
017 import com.liferay.portal.kernel.dao.db.DB;
018 import com.liferay.portal.kernel.dao.db.DBManagerUtil;
019 import com.liferay.portal.kernel.test.rule.callback.TestCallback;
020 import com.liferay.portal.kernel.util.StringPool;
021 import com.liferay.portal.test.log.CaptureAppender;
022 import com.liferay.portal.test.log.Log4JLoggerTestUtil;
023 import com.liferay.portal.test.rule.ExpectedDBType;
024 import com.liferay.portal.test.rule.ExpectedLog;
025 import com.liferay.portal.test.rule.ExpectedLogs;
026 import com.liferay.portal.test.rule.ExpectedMultipleLogs;
027 import com.liferay.portal.test.rule.ExpectedType;
028 import com.liferay.portal.test.rule.LogAssertionAppender;
029 import com.liferay.portal.test.rule.LogAssertionHandler;
030 import com.liferay.portal.test.rule.LogAssertionUncaughtExceptionHandler;
031
032 import java.lang.Thread.UncaughtExceptionHandler;
033
034 import java.util.ArrayList;
035 import java.util.Arrays;
036 import java.util.List;
037 import java.util.Map;
038 import java.util.concurrent.ConcurrentHashMap;
039 import java.util.logging.Logger;
040
041 import org.apache.log4j.Level;
042 import org.apache.log4j.spi.LoggingEvent;
043
044 import org.junit.Assert;
045 import org.junit.runner.Description;
046
047
050 public class LogAssertionTestCallback
051 implements TestCallback<List<CaptureAppender>, List<CaptureAppender>> {
052
053 public static final LogAssertionTestCallback INSTANCE =
054 new LogAssertionTestCallback();
055
056 public static void caughtFailure(Error error) {
057 Thread currentThread = Thread.currentThread();
058
059 if (currentThread != _thread) {
060 _concurrentFailures.put(currentThread, error);
061
062 _thread.interrupt();
063 }
064 else {
065 throw error;
066 }
067 }
068
069 public static void endAssert(
070 List<ExpectedLogs> expectedLogsList,
071 List<CaptureAppender> captureAppenders) {
072
073 for (CaptureAppender captureAppender : captureAppenders) {
074 try {
075 for (LoggingEvent loggingEvent :
076 captureAppender.getLoggingEvents()) {
077
078 String renderedMessage = loggingEvent.getRenderedMessage();
079
080 if (!isExpected(expectedLogsList, renderedMessage)) {
081 Assert.fail(renderedMessage);
082 }
083 }
084 }
085 finally {
086 captureAppender.close();
087 }
088 }
089
090 Thread.setDefaultUncaughtExceptionHandler(_uncaughtExceptionHandler);
091
092 _thread = null;
093
094 try {
095 for (Map.Entry<Thread, Error> entry :
096 _concurrentFailures.entrySet()) {
097
098 Thread thread = entry.getKey();
099 Error error = entry.getValue();
100
101 Assert.fail(
102 "Thread " + thread + " caught concurrent failure: " +
103 error);
104
105 throw error;
106 }
107 }
108 finally {
109 _concurrentFailures.clear();
110 }
111 }
112
113 public static List<CaptureAppender> startAssert(
114 List<ExpectedLogs> expectedLogsList) {
115
116 _thread = Thread.currentThread();
117 _uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
118
119 Thread.setDefaultUncaughtExceptionHandler(
120 new LogAssertionUncaughtExceptionHandler(
121 _uncaughtExceptionHandler));
122
123 List<CaptureAppender> captureAppenders = new ArrayList<>(
124 expectedLogsList.size());
125
126 for (ExpectedLogs expectedLogs : expectedLogsList) {
127 Class<?> clazz = expectedLogs.loggerClass();
128
129 captureAppenders.add(
130 Log4JLoggerTestUtil.configureLog4JLogger(
131 clazz.getName(), Level.toLevel(expectedLogs.level())));
132 }
133
134 installJdk14Handler();
135 installLog4jAppender();
136
137 return captureAppenders;
138 }
139
140 @Override
141 public void afterClass(
142 Description description, List<CaptureAppender> captureAppenders) {
143
144 ExpectedMultipleLogs expectedMultipleLogs = description.getAnnotation(
145 ExpectedMultipleLogs.class);
146
147 List<ExpectedLogs> expectedLogsList = new ArrayList<>();
148
149 if (expectedMultipleLogs == null) {
150 ExpectedLogs expectedLogs = description.getAnnotation(
151 ExpectedLogs.class);
152
153 if (expectedLogs != null) {
154 expectedLogsList.add(expectedLogs);
155 }
156 }
157 else {
158 expectedLogsList.addAll(
159 Arrays.asList(expectedMultipleLogs.expectedMultipleLogs()));
160 }
161
162 endAssert(expectedLogsList, captureAppenders);
163 }
164
165 @Override
166 public void afterMethod(
167 Description description, List<CaptureAppender> captureAppenders,
168 Object target) {
169
170 afterClass(description, captureAppenders);
171 }
172
173 @Override
174 public List<CaptureAppender> beforeClass(Description description) {
175 ExpectedMultipleLogs expectedMultipleLogs = description.getAnnotation(
176 ExpectedMultipleLogs.class);
177
178 List<ExpectedLogs> expectedLogsList = new ArrayList<>();
179
180 if (expectedMultipleLogs == null) {
181 ExpectedLogs expectedLogs = description.getAnnotation(
182 ExpectedLogs.class);
183
184 if (expectedLogs != null) {
185 expectedLogsList.add(expectedLogs);
186 }
187 }
188 else {
189 expectedLogsList.addAll(
190 Arrays.asList(expectedMultipleLogs.expectedMultipleLogs()));
191 }
192
193 return startAssert(expectedLogsList);
194 }
195
196 @Override
197 public List<CaptureAppender> beforeMethod(
198 Description description, Object target) {
199
200 return beforeClass(description);
201 }
202
203 protected static void installJdk14Handler() {
204 Logger logger = Logger.getLogger(StringPool.BLANK);
205
206 logger.removeHandler(LogAssertionHandler.INSTANCE);
207
208 logger.addHandler(LogAssertionHandler.INSTANCE);
209 }
210
211 protected static void installLog4jAppender() {
212 org.apache.log4j.Logger logger =
213 org.apache.log4j.Logger.getRootLogger();
214
215 logger.removeAppender(LogAssertionAppender.INSTANCE);
216
217 logger.addAppender(LogAssertionAppender.INSTANCE);
218 }
219
220 protected static boolean isExpected(
221 List<ExpectedLogs> expectedLogsList, String renderedMessage) {
222
223 for (ExpectedLogs expectedLogs : expectedLogsList) {
224 for (ExpectedLog expectedLog : expectedLogs.expectedLogs()) {
225 ExpectedDBType expectedDBType = expectedLog.expectedDBType();
226
227 if (expectedDBType != ExpectedDBType.NONE) {
228 DB db = DBManagerUtil.getDB();
229
230 if (expectedDBType.getDBType() != db.getDBType()) {
231 continue;
232 }
233 }
234
235 ExpectedType expectedType = expectedLog.expectedType();
236
237 if (expectedType == ExpectedType.CONTAINS) {
238 if (renderedMessage.contains(expectedLog.expectedLog())) {
239 return true;
240 }
241 }
242 else if (expectedType == ExpectedType.EXACT) {
243 if (renderedMessage.equals(expectedLog.expectedLog())) {
244 return true;
245 }
246 }
247 else if (expectedType == ExpectedType.POSTFIX) {
248 if (renderedMessage.endsWith(expectedLog.expectedLog())) {
249 return true;
250 }
251 }
252 else if (expectedType == ExpectedType.PREFIX) {
253 if (renderedMessage.startsWith(expectedLog.expectedLog())) {
254 return true;
255 }
256 }
257 }
258 }
259
260 return false;
261 }
262
263 private LogAssertionTestCallback() {
264 }
265
266 private static final Map<Thread, Error> _concurrentFailures =
267 new ConcurrentHashMap<>();
268 private static volatile Thread _thread;
269 private static volatile UncaughtExceptionHandler _uncaughtExceptionHandler;
270
271 }