Просмотр исходного кода

Add a JUnit 5 version of LogTester

tags/8.1.0.31237
Julien HENRY 4 лет назад
Родитель
Сommit
edb900d518

+ 1
- 0
build.gradle Просмотреть файл

@@ -212,6 +212,7 @@ subprojects {
dependency 'javax.servlet:javax.servlet-api:3.1.0'
dependency 'javax.xml.bind:jaxb-api:2.3.0'
dependency 'junit:junit:4.12'
dependency 'org.junit.jupiter:junit-jupiter-api:5.5.2'
dependency 'net.jpountz.lz4:lz4:1.3.0'
dependency 'net.lightbody.bmp:littleproxy:1.1.0-beta-bmp-17'
dependency 'org.awaitility:awaitility:4.0.1'

+ 2
- 0
sonar-plugin-api/build.gradle Просмотреть файл

@@ -25,6 +25,8 @@ dependencies {
compileOnly 'com.google.code.findbugs:jsr305'
compileOnly 'javax.servlet:javax.servlet-api'
compileOnly 'junit:junit'
// Used by LogTesterJUnit5
compileOnly 'org.junit.jupiter:junit-jupiter-api'
compileOnly 'org.slf4j:slf4j-api'

testCompile 'com.google.guava:guava'

+ 84
- 0
sonar-plugin-api/src/main/java/org/sonar/api/utils/log/AbstractLogTester.java Просмотреть файл

@@ -0,0 +1,84 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.utils.log;

import java.util.List;

class AbstractLogTester {

protected void before() {
// this shared instance breaks compatibility with parallel execution of tests
LogInterceptors.set(new ListInterceptor());
setLevel(LoggerLevel.INFO);
}

protected void after() {
LogInterceptors.set(NullInterceptor.NULL_INSTANCE);
setLevel(LoggerLevel.INFO);
}

LoggerLevel getLevel() {
return Loggers.getFactory().getLevel();
}

/**
* Enable/disable debug logs. Info, warn and error logs are always enabled.
* By default INFO logs are enabled when LogTester is started.
*/
public AbstractLogTester setLevel(LoggerLevel level) {
Loggers.getFactory().setLevel(level);
return this;
}

/**
* Logs in chronological order (item at index 0 is the oldest one)
*/
public List<String> logs() {
return ((ListInterceptor) LogInterceptors.get()).logs();
}

/**
* Logs in chronological order (item at index 0 is the oldest one) for
* a given level
*/
public List<String> logs(LoggerLevel level) {
return ((ListInterceptor) LogInterceptors.get()).logs(level);
}

/**
* Logs with arguments in chronological order (item at index 0 is the oldest one)
*/
public List<LogAndArguments> getLogs() {
return ((ListInterceptor) LogInterceptors.get()).getLogs();
}

/**
* Logs with arguments in chronological order (item at index 0 is the oldest one) for
* a given level
*/
public List<LogAndArguments> getLogs(LoggerLevel level) {
return ((ListInterceptor) LogInterceptors.get()).getLogs(level);
}

public AbstractLogTester clear() {
((ListInterceptor) LogInterceptors.get()).clear();
return this;
}
}

+ 18
- 61
sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogTester.java Просмотреть файл

@@ -19,8 +19,9 @@
*/
package org.sonar.api.utils.log;

import java.util.List;
import org.junit.rules.ExternalResource;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

/**
* <b>For tests only</b>
@@ -55,66 +56,22 @@ import org.junit.rules.ExternalResource;
*
* @since 5.1
*/
public class LogTester extends ExternalResource {

@Override
protected void before() throws Throwable {
// this shared instance breaks compatibility with parallel execution of tests
LogInterceptors.set(new ListInterceptor());
setLevel(LoggerLevel.INFO);
}

@Override
protected void after() {
LogInterceptors.set(NullInterceptor.NULL_INSTANCE);
setLevel(LoggerLevel.INFO);
}

LoggerLevel getLevel() {
return Loggers.getFactory().getLevel();
}

/**
* Enable/disable debug logs. Info, warn and error logs are always enabled.
* By default INFO logs are enabled when LogTester is started.
*/
public LogTester setLevel(LoggerLevel level) {
Loggers.getFactory().setLevel(level);
return this;
}

/**
* Logs in chronological order (item at index 0 is the oldest one)
*/
public List<String> logs() {
return ((ListInterceptor) LogInterceptors.get()).logs();
}

/**
* Logs in chronological order (item at index 0 is the oldest one) for
* a given level
*/
public List<String> logs(LoggerLevel level) {
return ((ListInterceptor) LogInterceptors.get()).logs(level);
}

/**
* Logs with arguments in chronological order (item at index 0 is the oldest one)
*/
public List<LogAndArguments> getLogs() {
return ((ListInterceptor) LogInterceptors.get()).getLogs();
}

/**
* Logs with arguments in chronological order (item at index 0 is the oldest one) for
* a given level
*/
public List<LogAndArguments> getLogs(LoggerLevel level) {
return ((ListInterceptor) LogInterceptors.get()).getLogs(level);
public class LogTester extends AbstractLogTester implements TestRule {
public Statement apply(Statement base, Description description) {
return statement(base);
}

public LogTester clear() {
((ListInterceptor) LogInterceptors.get()).clear();
return this;
private Statement statement(final Statement base) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
before();
try {
base.evaluate();
} finally {
after();
}
}
};
}
}

+ 70
- 0
sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogTesterJUnit5.java Просмотреть файл

@@ -0,0 +1,70 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.utils.log;

import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

/**
* <b>For tests only</b>
* <br>
* This JUnit 5 extension allows to configure and access logs in tests. By default
* trace level is enabled.
* <br>
* Warning - not compatible with parallel execution of tests in the same JVM fork.
* <br>
* Example:
* <pre>
* public class MyClass {
* private final Logger logger = Loggers.get("logger_name");
*
* public void doSomething() {
* logger.info("foo");
* }
* }
*
* class MyClassTests {
* &#064;org.junit.jupiter.api.extension.RegisterExtension
* LogTesterJUnit5 logTester = new LogTesterJUnit5();
*
* &#064;org.junit.jupiter.api.Test
* public void test_log() {
* new MyClass().doSomething();
*
* assertThat(logTester.logs()).containsOnly("foo");
* }
* }
* </pre>
*
* @since 8.1
*/
public class LogTesterJUnit5 extends AbstractLogTester implements BeforeTestExecutionCallback, AfterTestExecutionCallback {

@Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
before();
}

@Override
public void afterTestExecution(ExtensionContext context) throws Exception {
after();
}
}

+ 119
- 0
sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogTesterJUnit5Test.java Просмотреть файл

@@ -0,0 +1,119 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.utils.log;

import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class LogTesterJUnit5Test {

LogTesterJUnit5 underTest = new LogTesterJUnit5();

@Test
public void info_level_by_default() throws Throwable {
// when LogTester is used, then info logs are enabled by default
underTest.beforeTestExecution(null);
assertThat(underTest.getLevel()).isEqualTo(LoggerLevel.INFO);
assertThat(Loggers.getFactory().getLevel()).isEqualTo(LoggerLevel.INFO);

// change
underTest.setLevel(LoggerLevel.DEBUG);
assertThat(underTest.getLevel()).isEqualTo(LoggerLevel.DEBUG);
assertThat(Loggers.getFactory().getLevel()).isEqualTo(LoggerLevel.DEBUG);

// reset to initial level after execution of test
underTest.afterTestExecution(null);
assertThat(underTest.getLevel()).isEqualTo(LoggerLevel.INFO);
assertThat(Loggers.getFactory().getLevel()).isEqualTo(LoggerLevel.INFO);
}

@Test
public void intercept_logs() throws Throwable {
underTest.beforeTestExecution(null);
Loggers.get("logger1").info("an information");
Loggers.get("logger2").warn("warning: {}", 42);

assertThat(underTest.logs()).containsExactly("an information", "warning: 42");
assertThat(underTest.logs(LoggerLevel.ERROR)).isEmpty();
assertThat(underTest.logs(LoggerLevel.INFO)).containsOnly("an information");
assertThat(underTest.logs(LoggerLevel.WARN)).containsOnly("warning: 42");

underTest.clear();
assertThat(underTest.logs()).isEmpty();
assertThat(underTest.logs(LoggerLevel.INFO)).isEmpty();

underTest.afterTestExecution(null);
assertThat(LogInterceptors.get()).isSameAs(NullInterceptor.NULL_INSTANCE);
}

@Test
public void use_suppliers() throws Throwable {
// when LogTester is used, then info logs are enabled by default
underTest.beforeTestExecution(null);
AtomicBoolean touchedTrace = new AtomicBoolean();
AtomicBoolean touchedDebug = new AtomicBoolean();
Loggers.get("logger1").trace(() -> {
touchedTrace.set(true);
return "a trace information";
});
Loggers.get("logger1").debug(() -> {
touchedDebug.set(true);
return "a debug information";
});

assertThat(underTest.logs()).isEmpty();
assertThat(touchedTrace.get()).isFalse();
assertThat(touchedDebug.get()).isFalse();

// change level to DEBUG
underTest.setLevel(LoggerLevel.DEBUG);
Loggers.get("logger1").trace(() -> {
touchedTrace.set(true);
return "a trace information";
});
Loggers.get("logger1").debug(() -> {
touchedDebug.set(true);
return "a debug information";
});

assertThat(underTest.logs()).containsOnly("a debug information");
assertThat(touchedTrace.get()).isFalse();
assertThat(touchedDebug.get()).isTrue();
touchedDebug.set(false);
underTest.clear();

// change level to TRACE
underTest.setLevel(LoggerLevel.TRACE);
Loggers.get("logger1").trace(() -> {
touchedTrace.set(true);
return "a trace information";
});
Loggers.get("logger1").debug(() -> {
touchedDebug.set(true);
return "a debug information";
});

assertThat(underTest.logs()).containsExactly("a trace information", "a debug information");
assertThat(touchedTrace.get()).isTrue();
assertThat(touchedDebug.get()).isTrue();
}
}

Загрузка…
Отмена
Сохранить