| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache license, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the license for the specific language governing permissions and |
| * limitations under the license. |
| */ |
| package org.apache.logging.log4j.kotlin |
| |
| import com.nhaarman.mockitokotlin2.* |
| import org.apache.logging.log4j.Level |
| import org.apache.logging.log4j.MarkerManager |
| import org.apache.logging.log4j.junit.LoggerContextRule |
| import org.apache.logging.log4j.message.DefaultFlowMessageFactory |
| import org.apache.logging.log4j.message.MessageFactory2 |
| import org.apache.logging.log4j.message.ParameterizedMessage |
| import org.apache.logging.log4j.message.ParameterizedMessageFactory |
| import org.apache.logging.log4j.spi.ExtendedLogger |
| import org.junit.Rule |
| import org.junit.Test |
| import org.mockito.ArgumentMatchers.anyString |
| import kotlin.test.assertFailsWith |
| import kotlin.test.assertTrue |
| |
| data class Custom(val i: Int) |
| |
| interface Manager { |
| fun fetchValue(): Int |
| } |
| |
| typealias LoggerStubbingFn = KStubbing<ExtendedLogger>.() -> Unit |
| |
| class LoggerTest { |
| companion object { |
| val msg = ParameterizedMessage("msg {}", 17) |
| val entryMsg = DefaultFlowMessageFactory().newEntryMessage(msg) |
| val cseqMsg: CharSequence = StringBuilder().append("cseq msg") |
| val objectMsg = Custom(17) |
| val cause = RuntimeException("cause") |
| val marker = MarkerManager.getMarker("marker") |
| val result = "foo" |
| val managerValue: Int = 4711 |
| } |
| |
| @Rule @JvmField var init = LoggerContextRule("InfoLogger.xml") |
| |
| class Fixture(stubbing: LoggerStubbingFn? = null) { |
| val mockLogger = mock<ExtendedLogger> { |
| on { getMessageFactory<MessageFactory2>() } doReturn ParameterizedMessageFactory() |
| if(stubbing != null) stubbing() |
| } |
| |
| val manager = mock<Manager> { |
| on { fetchValue() } doReturn managerValue |
| } |
| } |
| |
| fun withFixture(stubbing: LoggerStubbingFn?, level: Level, returning: Boolean, block: Fixture.(KotlinLogger) -> Unit): Fixture { |
| val f = Fixture(stubbing) |
| whenever(f.mockLogger.isEnabled(level)).thenReturn(returning) |
| val logger = KotlinLogger(f.mockLogger) |
| block(f, logger) |
| return f |
| } |
| |
| fun withLevelFixture(level: Level, returning: Boolean, block: Fixture.(KotlinLogger) -> Unit): Fixture { |
| return withFixture({ |
| on { isEnabled(level) } doReturn returning |
| }, level, returning, block) |
| } |
| |
| @Test |
| fun `Logging works!`() { |
| val f = withLevelFixture(Level.ERROR, true) { |
| it.error(result) |
| } |
| verify(f.mockLogger).logIfEnabled(anyString(), eq(Level.ERROR), isNull(), eq<CharSequence>(result), isNull()) |
| } |
| |
| @Test |
| fun `Level fatal enabled with String message`() { |
| val f = withLevelFixture(Level.FATAL, true) { |
| it.fatal("string msg with value: ${manager.fetchValue()}") |
| } |
| verify(f.mockLogger).logIfEnabled(anyString(), eq(Level.FATAL), isNull(), eq<CharSequence>("string msg with value: $managerValue"), isNull()) |
| verify(f.manager).fetchValue() |
| } |
| |
| |
| @Test |
| fun `Level fatal disabled with String message`() { |
| val f = withLevelFixture(Level.FATAL, false) { |
| it.fatal("string msg with value: ${manager.fetchValue()}") |
| } |
| |
| verify(f.mockLogger).logIfEnabled(anyString(), eq(Level.FATAL), isNull(), eq<CharSequence>("string msg with value: $managerValue"), isNull()) |
| // one might expect times(0), but we just delegate so times(1), we don't have any extra macro-based logic like the Scala api |
| // use the lambda approach to not evaluate the message if the level is not enabled |
| verify(f.manager, times(1)).fetchValue() |
| } |
| |
| @Test |
| fun `Lambda functions are evaluated if the level is high enough`() { |
| var count = 0 |
| fun lamdaFun(): String { |
| count++ |
| return result |
| } |
| val log = logger() |
| log.info { lamdaFun() } |
| assertTrue { count == 1 } |
| } |
| |
| @Test |
| fun `Lambda functions are not evaluated if the level is low enough`() { |
| var count = 0 |
| fun lamdaFun(): String { |
| count++ |
| return result |
| } |
| val log = logger() |
| log.debug { lamdaFun() } |
| assertTrue { count == 0 } |
| } |
| |
| @Test |
| fun `CharSequence messages are logged`() { |
| val f = withLevelFixture(Level.INFO, true) { |
| it.info(cseqMsg) |
| } |
| verify(f.mockLogger).logIfEnabled(anyString(), eq(Level.INFO), isNull(), eq(cseqMsg), isNull()) |
| } |
| |
| @Test |
| fun `Object messages are logged`() { |
| val f = withLevelFixture(Level.INFO, true) { |
| it.info(objectMsg) |
| } |
| verify(f.mockLogger).logIfEnabled(anyString(), eq(Level.INFO), isNull(), eq(objectMsg), isNull()) |
| } |
| |
| @Test |
| fun `Markers are logged`() { |
| val f = withLevelFixture(Level.INFO, true) { |
| it.info(marker, result) |
| } |
| verify(f.mockLogger).logIfEnabled(anyString(), eq(Level.INFO), eq(marker), eq<CharSequence>(result), isNull()) |
| } |
| |
| @Test |
| fun `Run in trace with no result`() { |
| var count = 0 |
| val f = withLevelFixture(Level.INFO, true) { |
| it.runInTrace(entryMsg) { |
| ++count |
| Unit |
| } |
| } |
| assertTrue { count == 1 } |
| verify(f.mockLogger).traceExit(eq(entryMsg)) |
| } |
| |
| @Test |
| fun `Run in trace with result`() { |
| var count = 0 |
| val f = withLevelFixture(Level.INFO, true) { |
| it.runInTrace(entryMsg) { |
| ++count |
| } |
| } |
| assertTrue { count == 1 } |
| verify(f.mockLogger).traceExit(eq(entryMsg), eq(1)) |
| } |
| |
| @Test |
| fun `Run in trace with Exception`() { |
| var count = 0 |
| val f = withLevelFixture(Level.INFO, true) { |
| assertFailsWith<RuntimeException> { |
| it.runInTrace(entryMsg) { |
| ++count |
| throw cause |
| } |
| } |
| } |
| assertTrue { count == 1 } |
| verify(f.mockLogger, times(0)).traceExit(any()) |
| verify(f.mockLogger).catching(argThat { message == "cause" }) |
| } |
| } |