001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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    /**
033     * @author Shuyang Zhou
034     */
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    }