001
014
015 package com.liferay.portal.test.log;
016
017 import com.liferay.portal.kernel.test.BaseTestRule;
018 import com.liferay.portal.kernel.util.StringPool;
019 import com.liferay.portal.log.CaptureAppender;
020 import com.liferay.portal.log.Log4JLoggerTestUtil;
021
022 import java.util.Map;
023 import java.util.concurrent.ConcurrentHashMap;
024 import java.util.logging.Logger;
025
026 import org.apache.log4j.Level;
027 import org.apache.log4j.spi.LoggingEvent;
028
029 import org.junit.Assert;
030 import org.junit.runner.Description;
031
032
035 public class LogAssertionTestRule
036 extends BaseTestRule<CaptureAppender, CaptureAppender> {
037
038 public static final LogAssertionTestRule INSTANCE =
039 new LogAssertionTestRule();
040
041 public static void caughtFailure(Error error) {
042 Thread currentThread = Thread.currentThread();
043
044 if (currentThread != _thread) {
045 _concurrentFailures.put(currentThread, error);
046
047 _thread.interrupt();
048 }
049 else {
050 throw error;
051 }
052 }
053
054 protected static void endAssert(
055 ExpectedLogs expectedLogs, CaptureAppender captureAppender) {
056
057 if (expectedLogs != null) {
058 try {
059 for (LoggingEvent loggingEvent :
060 captureAppender.getLoggingEvents()) {
061
062 String renderedMessage = loggingEvent.getRenderedMessage();
063
064 if (!isExpected(expectedLogs, renderedMessage)) {
065 Assert.fail(renderedMessage);
066 }
067 }
068 }
069 finally {
070 captureAppender.close();
071 }
072 }
073
074 _thread = null;
075
076 try {
077 for (Map.Entry<Thread, Error> entry :
078 _concurrentFailures.entrySet()) {
079
080 Thread thread = entry.getKey();
081 Error error = entry.getValue();
082
083 Assert.fail(
084 "Thread " + thread + " caught concurrent failure: " +
085 error);
086
087 throw error;
088 }
089 }
090 finally {
091 _concurrentFailures.clear();
092 }
093 }
094
095 protected static void installJdk14Handler() {
096 Logger logger = Logger.getLogger(StringPool.BLANK);
097
098 logger.removeHandler(LogAssertionHandler.INSTANCE);
099
100 logger.addHandler(LogAssertionHandler.INSTANCE);
101 }
102
103 protected static void installLog4jAppender() {
104 org.apache.log4j.Logger logger =
105 org.apache.log4j.Logger.getRootLogger();
106
107 logger.removeAppender(LogAssertionAppender.INSTANCE);
108
109 logger.addAppender(LogAssertionAppender.INSTANCE);
110 }
111
112 protected static boolean isExpected(
113 ExpectedLogs expectedLogs, String renderedMessage) {
114
115 for (ExpectedLog expectedLog : expectedLogs.expectedLogs()) {
116 ExpectedType expectedType = expectedLog.expectedType();
117
118 if (expectedType == ExpectedType.EXACT) {
119 if (renderedMessage.equals(expectedLog.expectedLog())) {
120 return true;
121 }
122 }
123 else if (expectedType == ExpectedType.POSTFIX) {
124 if (renderedMessage.endsWith(expectedLog.expectedLog())) {
125 return true;
126 }
127 }
128 else if (expectedType == ExpectedType.PREFIX) {
129 if (renderedMessage.startsWith(expectedLog.expectedLog())) {
130 return true;
131 }
132 }
133 }
134
135 return false;
136 }
137
138 protected static CaptureAppender startAssert(ExpectedLogs expectedLogs) {
139 _thread = Thread.currentThread();
140
141 CaptureAppender captureAppender = null;
142
143 if (expectedLogs != null) {
144 Class<?> clazz = expectedLogs.loggerClass();
145
146 captureAppender = Log4JLoggerTestUtil.configureLog4JLogger(
147 clazz.getName(), Level.toLevel(expectedLogs.level()));
148 }
149
150 installJdk14Handler();
151 installLog4jAppender();
152
153 return captureAppender;
154 }
155
156 @Override
157 protected void afterClass(
158 Description description, CaptureAppender captureAppender) {
159
160 ExpectedLogs expectedLogs = description.getAnnotation(
161 ExpectedLogs.class);
162
163 endAssert(expectedLogs, captureAppender);
164 }
165
166 @Override
167 protected void afterMethod(
168 Description description, CaptureAppender captureAppender) {
169
170 afterClass(description, captureAppender);
171 }
172
173 @Override
174 protected CaptureAppender beforeClass(Description description) {
175 ExpectedLogs expectedLogs = description.getAnnotation(
176 ExpectedLogs.class);
177
178 return startAssert(expectedLogs);
179 }
180
181 @Override
182 protected CaptureAppender beforeMethod(Description description) {
183 return beforeClass(description);
184 }
185
186 private LogAssertionTestRule() {
187 }
188
189 private static final Map<Thread, Error> _concurrentFailures =
190 new ConcurrentHashMap<Thread, Error>();
191 private static volatile Thread _thread;
192
193 }