/* (c) 2014 - 2015 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.util; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import org.geotools.util.logging.LoggerAdapter; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.StringDescription; import org.junit.Assume; import org.junit.rules.TestRule; import org.junit.runners.model.Statement; /** * JUnit Rule to test that logging occurs. The instrumentation will be removed when complete and * any changes to log level will be reverted. * <p/> * Note: that this works by adding a Handler to the Logger. * * @author Kevin Smith, Boundless * */ public class LoggerRule extends java.util.logging.Handler implements TestRule { private Logger log; private LinkedList<LogRecord> records = new LinkedList<>(); private Level newLevel = null; private Level oldLevel = null; /** * Test logging for the given logger * @param log Logger to monitor */ public LoggerRule(Logger log) { super(); this.log = log; } /** * Test logging for the given logger * @param log Logger to monitor * @param level Set the log level for the tests */ public LoggerRule(Logger log, Level level) { super(); this.log = log; super.setLevel(level); this.newLevel = level; } @Override public boolean isLoggable(LogRecord record) { return true; } @Override public Statement apply(final Statement base, final org.junit.runner.Description description) { return new Statement() { @Override public void evaluate() throws Throwable { oldLevel=log.getLevel(); if(newLevel!=null){ log.setLevel(newLevel); } log.addHandler(LoggerRule.this); try { base.evaluate(); } finally { log.removeHandler(LoggerRule.this); log.setLevel(oldLevel); oldLevel=null; } } }; } @Override public void publish(LogRecord record) { records.add(record); } @Override public void flush() { // Do Nothing } @Override public void close() throws SecurityException { // Do Nothing } /** * Clear all recorded log records */ public void clear() { records.clear(); } private void assumeCaptureWorks() { // FIXME: LoggerAdapter overrides addHandler to do nothing which prevents LoggerRule from // capturing records. Assume.assumeFalse("LoggerRule can't capture logs for LoggerAdapter", log instanceof LoggerAdapter); } /** * Get the captured log records * */ public List<LogRecord> records() { assumeCaptureWorks(); return records; } /** * Set the level of the logger. Will be reverted when the test is complete. */ public void setTestLevel(Level testLevel) { log.setLevel(testLevel); newLevel=testLevel; super.setLevel(testLevel); } /** * Assert that a record was logged that matches the given conditions * @param matcher Condition to match against */ public void assertLogged (Matcher<? super LogRecord> matcher) { assertLogged ("", matcher); } /** * Assert that a record was logged that matches the given conditions * @param reason Message to add to the failure report * @param matcher Condition to match against */ public void assertLogged (String reason, Matcher<? super LogRecord> matcher) { assumeCaptureWorks(); for(LogRecord r: records) { if(matcher.matches(r)){ return; } } Description desc = new StringDescription(); desc.appendText(reason); desc.appendText("\nExpected record: "); desc.appendDescriptionOf(matcher); desc.appendText("\n\tbut it was not logged"); throw new AssertionError(desc.toString()); } }