1 package com.atlassian.plugin.test;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import com.google.common.base.Function;
7 import com.google.common.collect.Lists;
8
9 import org.apache.log4j.Appender;
10 import org.apache.log4j.AppenderSkeleton;
11 import org.apache.log4j.Level;
12 import org.apache.log4j.LogManager;
13 import org.apache.log4j.Logger;
14 import org.apache.log4j.spi.LoggingEvent;
15 import org.hamcrest.Description;
16 import org.hamcrest.Matcher;
17 import org.hamcrest.TypeSafeMatcher;
18 import org.junit.rules.ExternalResource;
19
20 import static com.atlassian.plugin.test.Matchers.containsAllStrings;
21 import static org.hamcrest.CoreMatchers.allOf;
22 import static org.hamcrest.Matchers.hasItem;
23
24
25
26
27
28
29
30
31
32
33 public class CapturedLogging extends ExternalResource
34 {
35 private final Class logSource;
36 private Appender appender;
37 private List<LoggingEvent> loggingEvents;
38 private Logger logger;
39 private Level savedLoggerLevel;
40 private boolean savedLoggerAdditivity;
41
42 public CapturedLogging(final Class logSource)
43 {
44 this.logSource = logSource;
45 }
46
47 public List<LoggingEvent> getLoggingEvents()
48 {
49 return loggingEvents;
50 }
51
52 @Override
53 protected void before() throws Throwable
54 {
55 super.before();
56 loggingEvents = new ArrayList<LoggingEvent>();
57 appender = new AppenderSkeleton()
58 {
59 @Override
60 protected void append(final LoggingEvent event)
61 {
62 loggingEvents.add(event);
63 }
64
65 @Override
66 public void close()
67 {
68 }
69
70 @Override
71 public boolean requiresLayout()
72 {
73 return false;
74 }
75 };
76 logger = LogManager.getLogger(logSource);
77
78 savedLoggerLevel = logger.getLevel();
79 savedLoggerAdditivity = logger.getAdditivity();
80 logger.setLevel(Level.ALL);
81 logger.setAdditivity(false);
82 logger.addAppender(appender);
83 }
84
85 @Override
86 protected void after()
87 {
88 logger.setLevel(savedLoggerLevel);
89 logger.setAdditivity(savedLoggerAdditivity);
90 logger.removeAppender(appender);
91 super.after();
92 }
93
94 public static Matcher<CapturedLogging> didLog(final Matcher<LoggingEvent> loggingEventMatcher)
95 {
96 return new TypeSafeMatcher<CapturedLogging>()
97 {
98 @Override
99 protected boolean matchesSafely(final CapturedLogging capturedLogging)
100 {
101 return hasItem(loggingEventMatcher).matches(capturedLogging.getLoggingEvents());
102 }
103
104 @Override
105 public void describeTo(final Description description)
106 {
107 description.appendText("some LoggingEvent that ");
108 description.appendDescriptionOf(loggingEventMatcher);
109 }
110 };
111 }
112
113 public static Matcher<CapturedLogging> didLogWarn(final Matcher<String> messageMatcher)
114 {
115 return didLog(levelAndMessageMatch(Level.WARN, messageMatcher));
116 }
117
118 public static Matcher<CapturedLogging> didLogWarn(final String... substrings)
119 {
120 return didLogWarn(containsAllStrings(substrings));
121 }
122
123 public static Matcher<CapturedLogging> didLogDebug(final Matcher<String> messageMatcher)
124 {
125 return didLog(levelAndMessageMatch(Level.DEBUG, messageMatcher));
126 }
127
128 public static Matcher<CapturedLogging> didLogDebug(final String... substrings)
129 {
130 return didLogDebug(containsAllStrings(substrings));
131 }
132
133 public static Matcher<LoggingEvent> levelIs(final Level level)
134 {
135 return new TypeSafeMatcher<LoggingEvent>()
136 {
137 @Override
138 protected boolean matchesSafely(final LoggingEvent loggingEvent)
139 {
140 return level.equals(loggingEvent.getLevel());
141 }
142
143 @Override
144 public void describeTo(final Description description)
145 {
146 description.appendText("has level ");
147 description.appendValue(level);
148 }
149 };
150 }
151
152 public static Matcher<LoggingEvent> messageMatches(final Matcher<String> stringMatcher)
153 {
154 return new TypeSafeMatcher<LoggingEvent>()
155 {
156 @Override
157 protected boolean matchesSafely(final LoggingEvent loggingEvent)
158 {
159 return stringMatcher.matches(loggingEvent.getMessage());
160 }
161
162 @Override
163 public void describeTo(final Description description)
164 {
165 description.appendText("has message ");
166 description.appendDescriptionOf(stringMatcher);
167 }
168 };
169 }
170
171 public String toString()
172 {
173 final List<String> loggingEventsAsString = Lists.transform(loggingEvents, new Function<LoggingEvent, String>()
174 {
175 @Override
176 public String apply(final LoggingEvent loggingEvent)
177 {
178 return loggingEvent.getLevel() + ":" + loggingEvent.getMessage();
179 }
180 });
181 return "CapturedLogging( " + loggingEventsAsString + ")";
182 }
183
184 public static Matcher<LoggingEvent> levelAndMessageMatch(final Level level, final Matcher<String> messageMatcher)
185 {
186 return allOf(levelIs(level), messageMatches(messageMatcher));
187 }
188 }