content: /*
   * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
   * (the "License"). You may not use this work except in compliance with the License, which is
   * available at www.apache.org/licenses/LICENSE-2.0
   *
   * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
   * either express or implied, as more fully set forth in the License.
   *
   * See the NOTICE file distributed with this work for information regarding copyright ownership.
   */
  
  package alluxio;
  
  import org.apache.log4j.AppenderSkeleton;
  import org.apache.log4j.Level;
  import org.apache.log4j.Logger;
  import org.apache.log4j.spi.LoggingEvent;
  import org.junit.After;
  import org.junit.Before;
  
  import java.io.PrintStream;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.regex.Pattern;
  import javax.annotation.concurrent.GuardedBy;
  
  public class TestLoggerRule extends AbstractResourceRule {
  
    private TestAppender mAppender;
  
    @Before
    public void before() {
      mAppender = new TestAppender();
      Logger.getRootLogger().addAppender(mAppender);
    }
  
    @After
    public void after() {
      Logger.getRootLogger().removeAppender(mAppender);
    }
  
    /**
     * Determine if a specific pattern appears in log output.
     *
     * @param pattern a pattern text to search for in log events
     * @return true if a log message containing the pattern exists, false otherwise
     */
    public boolean wasLogged(String pattern) {
      return mAppender.wasLogged(Pattern.compile(".*" + pattern + ".*"));
    }
  
    /**
     * Determine if a specific pattern appears in log output with the specified level.
     *
     * @param pattern a pattern text to search for in log events
     * @return true if a log message containing the pattern exists, false otherwise
     */
    public boolean wasLoggedWithLevel(String pattern, Level level) {
      return mAppender.wasLoggedWithLevel(Pattern.compile(".*" + pattern + ".*"), level);
    }
  
    /**
     * Count the number of times a specific pattern appears in log messages.
     *
     * @param pattern Pattern to search for in log events
     * @return The number of log messages which match the pattern
     */
    public int logCount(String pattern) {
      // [\s\S] will match all character include line break
      return mAppender.logCount(Pattern.compile("[\\s\\S]*" + pattern + "[\\s\\S]*"));
    }
  
    /**
     * Writes all log messages to the given stream, useful for debugging.
     *
     * @param stream the stream to write to
     */
    public void dumpLogs(PrintStream stream) {
      for (LoggingEvent event : mAppender.mEvents) {
        stream.println(event.getRenderedMessage());
      }
    }
  
    public class TestAppender extends AppenderSkeleton {
      @GuardedBy("this")
      private final List<LoggingEvent> mEvents = new ArrayList<>();
  
      public void close() { }
  
      /**
       * Determines whether a message with the given pattern was logged.
       */
      public synchronized boolean wasLogged(Pattern pattern) {
        for (LoggingEvent e : mEvents) {
          if (pattern.matcher(e.getRenderedMessage()).matches()) {
            return true;
          }
        }
        return false;
      }
  
      /**
       * Determines whether a message with the given pattern was logged.
       */
      public synchronized boolean wasLoggedWithLevel(Pattern pattern, Level level) {
        for (LoggingEvent e : mEvents) {
          if (e.getLevel().equals(level) && pattern.matcher(e.getRenderedMessage()).matches()) {
            return true;
          }
        }
        return false;
      }
  
      /**
       * Counts the number of log message with a given pattern.
       */
      public synchronized int logCount(Pattern pattern) {
        int logCount = 0;
        for (LoggingEvent e: mEvents) {
          if (pattern.matcher(e.getRenderedMessage()).matches()) {
            logCount++;
          }
        }
        return logCount;
      }
  
      @Override
      public boolean requiresLayout() {
        return false;
      }
  
      @Override
      protected synchronized void append(LoggingEvent event) {
        mEvents.add(event);
      }
    }
  }
  