| /* |
| * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Tomas Kraus - Initial implementation |
| package org.eclipse.persistence.testing.tests.logging.slf4j; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.logging.AbstractSessionLog; |
| import org.eclipse.persistence.logging.LogCategory; |
| import org.eclipse.persistence.logging.LogLevel; |
| import org.eclipse.persistence.logging.SessionLogEntry; |
| import org.eclipse.persistence.logging.slf4j.SLF4JLogger; |
| |
| import ch.qos.logback.classic.Level; |
| import ch.qos.logback.classic.Logger; |
| import ch.qos.logback.classic.LoggerContext; |
| import ch.qos.logback.classic.spi.ILoggingEvent; |
| import ch.qos.logback.core.read.ListAppender; |
| |
| /** |
| * {@code SLF4JLogger} jUnit tests helper that allows {@link org.eclipse.persistence.logging.LogCategory} |
| * and {@link org.eclipse.persistence.logging.LogLevel} methods access. |
| */ |
| public class SLF4JLoggerHelper { |
| |
| /** Current EclipseLink session. */ |
| private final AbstractSession session; |
| |
| /** Logback logger context. */ |
| private final LoggerContext loggerContext; |
| |
| /** SLF4J logger used in tests. */ |
| private final SLF4JLogger logger; |
| |
| /** |
| * Creates an instance of {@code SLF4JLogger} jUnit tests helper. |
| * @param session Current EclipseLink session. |
| * @param loggerContext Logback logger context. |
| * @param logger SLF4J logger used in tests. |
| */ |
| public SLF4JLoggerHelper( |
| final AbstractSession session, final LoggerContext loggerContext, final SLF4JLogger logger) { |
| this.session = session; |
| this.loggerContext = loggerContext; |
| this.logger = logger; |
| } |
| |
| /** |
| * Create a new instance of {@link SessionLogEntry} class and set provided session, log level and logging category |
| * to it. |
| * @param level Log level of the new log entry. |
| * @param category Logging category of the new log entry. |
| * @return The new instance of {@link SessionLogEntry} class with all provided values set. |
| */ |
| private SessionLogEntry initLogEntry( |
| final LogCategory category, final LogLevel level) { |
| final SessionLogEntry logEntry = new SessionLogEntry(session); |
| logEntry.setLevel(level.getId()); |
| logEntry.setNameSpace(category.getName()); |
| return logEntry; |
| } |
| |
| /** |
| * Create a new instance of {@link SessionLogEntry} class and set provided session, log level, logging category |
| * and {@link Throwable} to it. |
| * @param level Log level of the new log entry. |
| * @param category Logging category of the new log entry. |
| * @param throwable {@link Throwable} argument of the new log entry. |
| * @return The new instance of {@link SessionLogEntry} class with all provided values set. |
| */ |
| private SessionLogEntry createLogEntry( |
| final LogCategory category, final LogLevel level, final Throwable throwable) { |
| final SessionLogEntry logEntry = initLogEntry(category, level); |
| logEntry.setException(throwable); |
| return logEntry; |
| } |
| |
| /** |
| * Create a new instance of {@link SessionLogEntry} class and set provided session, log level, logging category |
| * and {@link String} message to it. |
| * @param level Log level of the new log entry. |
| * @param category Logging category of the new log entry. |
| * @param message {@link String} message of the new log entry. |
| * @return The new instance of {@link SessionLogEntry} class with all provided values set. |
| */ |
| private SessionLogEntry createLogEntry( |
| final LogCategory category, final LogLevel level, final String message) { |
| final SessionLogEntry logEntry = initLogEntry(category, level); |
| logEntry.setMessage(message); |
| return logEntry; |
| } |
| |
| /** |
| * Create a new instance of {@link SessionLogEntry} class and set provided session, log level, logging category, |
| * {@link String} message and {@link Throwable} to it. |
| * @param level Log level of the new log entry. |
| * @param category Logging category of the new log entry. |
| * @param message {@link String} message of the new log entry. |
| * @param throwable {@link Throwable} argument of the new log entry. |
| * @return The new instance of {@link SessionLogEntry} class with all provided values set. |
| */ |
| private SessionLogEntry createLogEntry( |
| final LogCategory category, final LogLevel level, final String message, final Throwable throwable) { |
| final SessionLogEntry logEntry = initLogEntry(category, level); |
| logEntry.setMessage(message); |
| logEntry.setException(throwable); |
| return logEntry; |
| } |
| |
| /** |
| * Test {@code SLF4JLogger} default log levels for all logging categories. |
| * @param logger {@code SLF4JLogger} instance with default log levels. |
| */ |
| public void testCategoryDefaultLevels(final SLF4JLogger logger) { |
| final int configuredDefaultLevel = AbstractSessionLog.getDefaultLoggingLevel(); |
| for (LogCategory category : LogCategory.values()) { |
| final int defaultLevel = logger.getLevel(category.getName()); |
| switch(category) { |
| case ALL: |
| assertEquals("SLF4J logging level " + Integer.toString(defaultLevel) |
| + " does not match configured/default level " + Integer.toString(configuredDefaultLevel) |
| + " for category " + category.getName(), configuredDefaultLevel, defaultLevel); |
| break; |
| default: |
| assertEquals("SLF4J logging level " + Integer.toString(defaultLevel) |
| + " does not match configured/default level " + Integer.toString(configuredDefaultLevel) |
| + " for category " + category.getName(), configuredDefaultLevel, defaultLevel); |
| } |
| } |
| } |
| |
| /** Log entry check callback. */ |
| private interface Check { |
| /** |
| * Callback method implemented in individual test method. |
| * @param logEvent Logback log event. |
| */ |
| void check(final ILoggingEvent logEvent); |
| } |
| |
| /** |
| * Process log entry check for specified logger category, log level. |
| * @param category Logger logging category. |
| * @param loggerLevel Logger log level. |
| * @param messageLevel Log entry log level. |
| * @param categoryLogger Logback logger for given logging category. |
| * @param logEntry Log entry to be logged and verified. |
| * @param check Additional log entry checks callback. |
| */ |
| private void testLogEntry( |
| final LogCategory category, final LogLevel loggerLevel, final LogLevel messageLevel, |
| final Logger categoryLogger, final SessionLogEntry logEntry, final Check check) { |
| final byte loggerLevelId = loggerLevel.getId(); |
| final byte messageLevelId = messageLevel.getId(); |
| final ListAppender<ILoggingEvent> appender = new ListAppender<ILoggingEvent>(); |
| appender.setContext(loggerContext); |
| categoryLogger.addAppender(appender); |
| appender.start(); |
| logger.log(logEntry); |
| appender.stop(); |
| final int appenderSize = appender.list.size(); |
| final ILoggingEvent logEvent = appenderSize > 0 ? appender.list.get(appenderSize - 1) : null; |
| // Message must be logged. |
| if (messageLevel != LogLevel.OFF && loggerLevelId <= messageLevelId) { |
| assertNotNull("Missing log message for logger category " + category.getName() + ", level " |
| + loggerLevel.getName() + " and message level " + messageLevel.getName() , logEvent); |
| check.check(logEvent); |
| // Message shall not be logged. |
| } else { |
| assertNull("Found log message for logger category " + category.getName() + ", level " |
| + loggerLevel.getName() + " and message level " + messageLevel.getName() , logEvent); |
| } |
| } |
| |
| /** |
| * Test {@code SLF4JLogger.log(SessionLogEntry)} method with regular {@link String} message. |
| * Matrix of logger level x category settings with all log entry log levels is being checked. |
| */ |
| public void testLogMessage() { |
| // Verify loggers for logger level x category matrix. |
| for (LogCategory category : LogCategory.values()) { |
| final String nameSpace = category.getNameSpace(); |
| final Logger categoryLogger = loggerContext.getLogger(nameSpace); |
| categoryLogger.setLevel(Level.ALL); |
| for (LogLevel loggerLevel : LogLevel.values()) { |
| // Verify messages with all log levels. |
| logger.setLevel(loggerLevel.getId(), category.getName()); |
| for (LogLevel messageLevel : LogLevel.values()) { |
| final String message = "Log message"; |
| final SessionLogEntry logEntry = createLogEntry(category, messageLevel, message); |
| // Logback log event additional check. |
| final Check check = new Check() { |
| @Override public void check(final ILoggingEvent logEvent) { |
| assertEquals("Logged message \"" + message + "\" must be stored as a message.", |
| message, logEvent.getMessage()); |
| assertNull("There can't be any arguments for already rendered message.", |
| logEvent.getArgumentArray()); |
| } |
| }; |
| testLogEntry(category, loggerLevel, messageLevel, categoryLogger, logEntry, check); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Test {@code SLF4JLogger.log(SessionLogEntry)} method with {@link Throwable} and stack trace logging turned off. |
| * Matrix of logger level x category settings with all log entry log levels is being checked. |
| */ |
| public void testLogExceptionWithoutStackTrace() { |
| // Verify loggers for logger level x category matrix. |
| for (LogCategory category : LogCategory.values()) { |
| final String nameSpace = category.getNameSpace(); |
| final Logger categoryLogger = loggerContext.getLogger(nameSpace); |
| categoryLogger.setLevel(Level.ALL); |
| for (LogLevel loggerLevel : LogLevel.values()) { |
| // Verify messages with all log levels. |
| logger.setLevel(loggerLevel.getId(), category.getName()); |
| for (LogLevel messageLevel : LogLevel.values()) { |
| final Throwable exception = new RuntimeException("Exception message"); |
| final SessionLogEntry logEntry = createLogEntry(category, messageLevel, exception); |
| // Logback log event additional check. |
| final Check check = new Check() { |
| @Override public void check(final ILoggingEvent logEvent) { |
| assertEquals("Logged exception message \"" + exception.getMessage() |
| + "\" must be stored as a message.", exception.toString(), logEvent.getMessage()); |
| assertNull("There can't be any arguments for already rendered message.", |
| logEvent.getArgumentArray()); |
| } |
| }; |
| testLogEntry(category, loggerLevel, messageLevel, categoryLogger, logEntry, check); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Test {@code SLF4JLogger.log(SessionLogEntry)} method with {@link Throwable} and stack trace logging turned on. |
| * Matrix of logger level x category settings with all log entry log levels is being checked. |
| */ |
| public void testLogExceptionStackTrace() { |
| // Verify loggers for logger level x category matrix. |
| for (LogCategory category : LogCategory.values()) { |
| final String nameSpace = category.getNameSpace(); |
| final Logger categoryLogger = loggerContext.getLogger(nameSpace); |
| categoryLogger.setLevel(Level.ALL); |
| for (LogLevel loggerLevel : LogLevel.values()) { |
| // Verify messages with all log levels. |
| logger.setLevel(loggerLevel.getId(), category.getName()); |
| for (LogLevel messageLevel : LogLevel.values()) { |
| final String message = "Log message"; |
| final String exceptionMessage = "Exception message"; |
| final Throwable exception = new RuntimeException(exceptionMessage); |
| // Log entry without log message. |
| final SessionLogEntry logEntry1 = createLogEntry(category, messageLevel, exception); |
| // Log entry with log message. |
| final SessionLogEntry logEntry2 = createLogEntry(category, messageLevel, message, exception); |
| // Logback log event additional check for exception without log message. |
| final Check check1 = new Check() { |
| @Override |
| public void check(final ILoggingEvent logEvent) { |
| final String eventMessage = logEvent.getMessage(); |
| assertTrue("No message was passed so null or empty String must be stored as a message.", |
| eventMessage == null || eventMessage.isEmpty()); |
| assertEquals("Exception message must be stored in throwableProxy.", |
| exceptionMessage, logEvent.getThrowableProxy().getMessage()); |
| } |
| }; |
| // Logback log event additional check for exception with log message. |
| final Check check2 = new Check() { |
| @Override |
| public void check(final ILoggingEvent logEvent) { |
| assertEquals("Logged message \"" + message + "\" must be stored as a message.", |
| message, logEvent.getMessage()); |
| assertEquals("Exception message must be stored in throwableProxy.", |
| exceptionMessage, logEvent.getThrowableProxy().getMessage()); |
| } |
| }; |
| testLogEntry(category, loggerLevel, messageLevel, categoryLogger, logEntry1, check1); |
| testLogEntry(category, loggerLevel, messageLevel, categoryLogger, logEntry2, check2); |
| } |
| } |
| } |
| |
| } |
| |
| } |