All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.renomad.minum.logging.TestLogger Maven / Gradle / Ivy

There is a newer version: 8.0.7
Show newest version
package com.renomad.minum.logging;

import com.renomad.minum.state.Constants;
import com.renomad.minum.utils.MyThread;

import java.util.List;
import java.util.Locale;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.ReentrantLock;

/**
 * This implementation of {@link Logger} has a few
 * extra functions that only apply to tests, like {@link #test(String)}
 */
public final class TestLogger extends Logger {

    private final Queue recentLogLines;
    public static final int MAX_CACHE_SIZE = 30;
    private final ReentrantLock loggingLock;
    private int testCount = 0;

    /**
     * See {@link TestLogger}
     */
    public TestLogger(Constants constants, ExecutorService executorService, String name) {
        super(constants, executorService, name);
        this.recentLogLines = new TestLoggerQueue(MAX_CACHE_SIZE);
        this.loggingLock = new ReentrantLock();
    }

    /**
     * A helper to get the string message value out of a
     * {@link ThrowingSupplier}
     */
    private String extractMessage(ThrowingSupplier msg) {
        String receivedMessage;
        try {
            receivedMessage = msg.get();
        } catch (Exception ex) {
            receivedMessage = "EXCEPTION DURING GET: " + ex;
        }
        return receivedMessage;
    }

    /**
     * Keeps a record of the recently-added log messages, which is
     * useful for some tests.
     */
    private void addToCache(ThrowingSupplier msg) {
        // put log messages into the tail of the queue
        String message = extractMessage(msg);
        String safeMessage = message == null ? "(null message)" : message;
        recentLogLines.add(safeMessage);
    }

    @Override
    public void logDebug(ThrowingSupplier msg) {
        loggingLock.lock();
        try {
            addToCache(msg);
            super.logDebug(msg);
        } finally {
            loggingLock.unlock();
        }
    }

    @Override
    public void logTrace(ThrowingSupplier msg) {
        loggingLock.lock();
        try {
            addToCache(msg);
            super.logTrace(msg);
        } finally {
            loggingLock.unlock();
        }
    }

    @Override
    public void logAudit(ThrowingSupplier msg) {
        loggingLock.lock();
        try {
            addToCache(msg);
            super.logAudit(msg);
        } finally {
            loggingLock.unlock();
        }
    }

    @Override
    public void logAsyncError(ThrowingSupplier msg) {
        loggingLock.lock();
        try {
            addToCache(msg);
            super.logAsyncError(msg);
        } finally {
            loggingLock.unlock();
        }
    }

    /**
     * Provides an ability to search over the recent past log messages,
     * case-insensitively.
     * @param lines number of lines of log messages to look back through,
     *              up to {@link #MAX_CACHE_SIZE}
     */
    public String findFirstMessageThatContains(String value, int lines) {
        List values = findMessage(value, lines, recentLogLines);
        List logsBeingSearched = logLinesToSearch(lines, recentLogLines);
        return checkValidityOfResults(value, values, logsBeingSearched);
    }

    /**
     * This is used in {@link #findFirstMessageThatContains(String, int)} to
     * handle exceptional situations with the results.  Specifically, exceptions
     * are:
     * 
    *
  1. If there were no results found
  2. *
  3. If there were multiple results found
  4. *
*/ static String checkValidityOfResults(String value, List values, List recentLogLines) { int size = values.size(); if (size == 0) { throw new TestLoggerException(value + " was not found in \n\t" + String.join("\n\t", recentLogLines)); } else if (size >= 2) { throw new TestLoggerException("multiple values of "+value+" found in: " + recentLogLines); } else { return values.getFirst(); } } /** * Whether the given string exists in the log messages. May * exist multiple times. * @param value a string to search in the log * @param lines how many lines back to examine * @return whether this string was found, even if there * were multiple places it was found. */ public boolean doesMessageExist(String value, int lines) { if (! findMessage(value, lines, recentLogLines).isEmpty()) { return true; } else { List logsBeingSearched = logLinesToSearch(lines, recentLogLines); throw new TestLoggerException(value + " was not found in \n\t" + String.join("\n\t", logsBeingSearched)); } } /** * Whether the given string exists in the log messages. May * exist multiple times. * @param value a string to search in the log * @return whether or not this string was found, even if there * were multiple places it was found. */ public boolean doesMessageExist(String value) { return doesMessageExist(value, 3); } static List findMessage(String value, int lines, Queue recentLogLines) { if (lines > MAX_CACHE_SIZE) { throw new TestLoggerException(String.format("Can only get up to %s lines from the log", MAX_CACHE_SIZE)); } if (lines <= 0) { throw new TestLoggerException("number of recent log lines must be a positive number"); } MyThread.sleep(20); var lineList = logLinesToSearch(lines, recentLogLines); return lineList.stream().filter(x -> x.toLowerCase(Locale.ROOT).contains(value.toLowerCase(Locale.ROOT))).toList(); } private static List logLinesToSearch(int lines, Queue recentLogLines) { var fromIndex = Math.max(recentLogLines.size() - lines, 0); return recentLogLines.stream().toList().subList(fromIndex, recentLogLines.size()); } /** * Looks back through the last 3 log messages for one that * contains the provided value. Returns the whole line if * found and an exception if not found. *

* See {@link #findFirstMessageThatContains(String, int)} if you * want to search through more than 3. However, it is only * possible to search up to {@link #MAX_CACHE_SIZE} *

*/ public String findFirstMessageThatContains(String value) { return findFirstMessageThatContains(value, 3); } /** * A helper function to log a test title prefixed with "TEST:" *
* Also collects data about the previously-run test */ public void test(String msg) { // put together some pretty-looking text graphics to show the suiteName of our test in log loggingLock.lock(); try { final var baseLength = 11; final var dashes = "-".repeat(msg.length() + baseLength); loggingActionQueue.enqueue("Testlogger#test("+msg+")", () -> { testCount += 1; System.out.printf("%n+%s+%n| TEST %d: %s |%n+%s+%n%n", dashes, testCount, msg, dashes); recentLogLines.add(msg); }); } finally { loggingLock.unlock(); } } public int getTestCount() { return testCount; } @Override public String toString() { return "TestLogger using queue: " + super.loggingActionQueue.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy