1 package emissary.test.core.junit5; 2 3 import ch.qos.logback.classic.Level; 4 import ch.qos.logback.classic.Logger; 5 import ch.qos.logback.classic.spi.ILoggingEvent; 6 import ch.qos.logback.classic.spi.IThrowableProxy; 7 import ch.qos.logback.core.read.ListAppender; 8 import org.apache.commons.lang3.Validate; 9 import org.slf4j.LoggerFactory; 10 11 import java.io.Closeable; 12 import java.io.IOException; 13 import java.util.ArrayList; 14 import java.util.List; 15 import java.util.Objects; 16 import javax.annotation.Nullable; 17 18 import static org.junit.jupiter.api.Assertions.assertEquals; 19 import static org.junit.jupiter.api.Assertions.assertNotNull; 20 import static org.junit.jupiter.api.Assertions.assertNull; 21 22 public class LogbackTester implements Closeable { 23 public final String name; 24 public final Logger logger; 25 public final ListAppender<ILoggingEvent> appender; 26 27 public LogbackTester(final String name) { 28 Validate.notNull(name, "Required: name != null"); 29 30 this.name = name; 31 logger = (Logger) LoggerFactory.getLogger(name); 32 appender = new ListAppender<>(); 33 34 appender.setContext(logger.getLoggerContext()); 35 appender.start(); 36 logger.addAppender(appender); 37 logger.setAdditive(false); 38 } 39 40 public void checkLogList(List<SimplifiedLogEvent> events) { 41 Validate.notNull(events, "Required: events != null"); 42 43 assertEquals(events.size(), appender.list.size(), "Expected event count does not match actual event count"); 44 45 for (int i = 0; i < appender.list.size(); i++) { 46 final ILoggingEvent item = appender.list.get(i); 47 final SimplifiedLogEvent event = events.get(i); 48 assertEquals(event.level, item.getLevel(), "Levels not equal for element " + i); 49 assertEquals(event.message, item.getFormattedMessage(), "Messages not equal for element " + i); 50 if (event.throwableClassName == null) { 51 assertNull(item.getThrowableProxy(), "Expected no exception for element " + i); 52 } else { 53 assertNotNull(item.getThrowableProxy(), "Expected an exception for element " + i); 54 IThrowableProxy proxy = item.getThrowableProxy(); 55 assertEquals(event.throwableClassName, proxy.getClassName(), "Exception class name not equal for element " + i); 56 assertEquals(event.throwableMessage, proxy.getMessage(), "Exception message not equal for element " + i); 57 } 58 } 59 } 60 61 public List<SimplifiedLogEvent> getSimplifiedLogEvents() { 62 final List<SimplifiedLogEvent> simplifiedLogEvents = new ArrayList<>(); 63 64 for (int i = 0; i < appender.list.size(); i++) { 65 final ILoggingEvent event = appender.list.get(i); 66 67 if (event.getThrowableProxy() == null) { 68 simplifiedLogEvents.add(new SimplifiedLogEvent(event.getLevel(), event.getFormattedMessage(), 69 null, null)); 70 } else { 71 simplifiedLogEvents.add(new SimplifiedLogEvent(event.getLevel(), event.getFormattedMessage(), 72 event.getThrowableProxy().getClassName(), event.getThrowableProxy().getMessage())); 73 } 74 } 75 76 return simplifiedLogEvents; 77 } 78 79 @Override 80 public void close() throws IOException { 81 logger.detachAndStopAllAppenders(); 82 } 83 84 public static class SimplifiedLogEvent { 85 public final Level level; 86 public final String message; 87 @Nullable 88 public final String throwableClassName; 89 @Nullable 90 public final String throwableMessage; 91 92 public SimplifiedLogEvent(Level level, String message, @Nullable Throwable throwable) { 93 this(level, message, 94 throwable == null ? null : throwable.getClass().getName(), 95 throwable == null ? null : throwable.getLocalizedMessage()); 96 } 97 98 public SimplifiedLogEvent(Level level, String message, @Nullable String throwableClassName, @Nullable String throwableMessage) { 99 Validate.notNull(level, "Required: level != null!"); 100 Validate.notNull(message, "Required: message != null!"); 101 102 this.level = level; 103 this.message = message; 104 this.throwableClassName = throwableClassName; 105 this.throwableMessage = throwableMessage; 106 } 107 108 @Override 109 public int hashCode() { 110 return Objects.hash(level, message, throwableClassName, throwableMessage); 111 } 112 113 @Override 114 public boolean equals(Object obj) { 115 if (this == obj) { 116 return true; 117 } 118 119 if (!(obj instanceof SimplifiedLogEvent)) { 120 return false; 121 } 122 SimplifiedLogEvent other = (SimplifiedLogEvent) obj; 123 124 return Objects.equals(level, other.level) && 125 Objects.equals(message, other.message) && 126 Objects.equals(throwableClassName, other.throwableClassName) && 127 Objects.equals(throwableMessage, other.throwableMessage); 128 } 129 130 @Override 131 public String toString() { 132 return super.toString() + " [level=" + level + ", message=" + message + ", throwableClassName=" 133 + throwableClassName + ", throwableMessage=" + throwableMessage + "]"; 134 } 135 } 136 }