Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation for JDK Platform Logging #3

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/codacy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: "Codacy"

on:
push:
branches: [ "**" ]
tags-ignore:
- v*
pull_request:
# The branches below must be a subset of the branches above
branches: [ "**" ]

permissions: read-all

jobs:
build:
name: Maven build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java JDK
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: 11
- name: Build with Maven
run: ./mvnw --batch-mode
- name: Temporarily save target and test requests
uses: actions/upload-artifact@master
with:
name: targets
path: |
jdk-platform-logging/targets
junit-extension/target
keeper/target
retention-days: 1
codacy-security-scan:
name: Codacy Security Scan
needs: build
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@09916000460adeeedc96b9704f86deba53e2ad5d
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
output: results.sarif
format: sarif
gh-code-scanning-compat: true
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
codacy-coverage-reporter:
name: Codacy Coverage Reporter
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Retrieve saved test requests and target
uses: actions/download-artifact@master
with:
name: targets
path: .
- name: Run codacy-coverage-reporter
uses: codacy/codacy-coverage-reporter-action@a38818475bb21847788496e9f0fddaa4e84955ba
with:
coverage-reports: jdk-platform-logging/target/site/jacoco/jacoco.xml,junit-extension/target/site/jacoco/jacoco.xml,keeper/target/site/jacoco/jacoco.xml
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
85 changes: 85 additions & 0 deletions jdk-platform-logging/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2024 Vitalij Berdinskih

Licensed 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.
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<artifactId>mock-loggers-jdk-platform-logging</artifactId>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId>
</plugin>
<plugin>
<artifactId>jacoco-maven-plugin</artifactId>
<groupId>org.jacoco</groupId>
</plugin>
</plugins>
</build>
<dependencies>
<!-- main -->
<dependency>
<artifactId>annotations</artifactId>
<groupId>org.jetbrains</groupId>
<scope>provided</scope>
</dependency>
<dependency>
<artifactId>mock-loggers-keeper</artifactId>
<groupId>io.github.vitalijr2.logging</groupId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<artifactId>mockito-core</artifactId>
<groupId>org.mockito</groupId>
<scope>provided</scope>
</dependency>
<!-- test -->
<dependency>
<artifactId>hamcrest</artifactId>
<groupId>org.hamcrest</groupId>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>junit-jupiter-engine</artifactId>
<groupId>org.junit.jupiter</groupId>
<scope>provided</scope>
</dependency>
<dependency>
<artifactId>junit-jupiter-params</artifactId>
<groupId>org.junit.jupiter</groupId>
<scope>provided</scope>
</dependency>
<dependency>
<artifactId>mockito-junit-jupiter</artifactId>
<groupId>org.mockito</groupId>
<scope>provided</scope>
</dependency>
</dependencies>
<description>Mock loggers for JDK Platform Logging backed by Mockito.</description>
<name>Mock loggers for JDK Platform Logging</name>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>mock-loggers</artifactId>
<groupId>io.github.vitalijr2.logging</groupId>
<relativePath>../pom.xml</relativePath>
<version>1.0.0-SNAPSHOT</version>
</parent>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright 2024 Vitalij Berdinskih
*
* Licensed 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 io.github.vitalijr2.logging.platform;

import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;

import io.github.vitalijr2.logging.keeper.MockLoggerCleaner;
import java.lang.System.Logger;
import java.lang.System.LoggerFinder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.VisibleForTesting;

/**
* Uses {@link org.mockito.Mockito#mock(Class, String)} to get a mock that is adapted for {@link Logger}.
* <p>
* Example:
* <pre><code class="language-java">
* {@literal @}Test
* void helloWorld() {
* var helloService = new HelloService();
*
* assertDoesNotThrow(helloService::sayHelloWorld);
*
* verify(System.getLogger("HelloService")).log(Level.INFO, "Hello World!");
* }
* </code></pre>
*
* @since 1.0.0
*/
public class MockLoggerFinder extends LoggerFinder implements MockLoggerCleaner {

private final Map<String, Logger> loggers;

/**
* Create a map-based logger finder. The finder uses a concurrent map: a logger name is a key.
*/
public MockLoggerFinder() {
this(new ConcurrentHashMap<>());
}

@VisibleForTesting
MockLoggerFinder(Map<String, Logger> loggers) {
this.loggers = loggers;
}

@Override
public List<String> cleanAndReset() {
var processedLoggers = new ArrayList<String>();

loggers.forEach((loggerName, logger) -> {
clearInvocations(logger);
reset(logger);
processedLoggers.add(loggerName);
});

return processedLoggers;
}

/**
* Returns an instance of Logger for the given name, module is ignored.
*
* @param name logging name
* @param module logging module
* @return mock logger
*/
@Override
public Logger getLogger(String name, Module module) {
return loggers.computeIfAbsent(name, key -> mock(Logger.class, "Mock for logger " + key));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Mock loggers for JDK Platform Logging backed by <a href="https://site.mockito.org/">Mockito</a>.
*
* @since 1.0.0
*/
package io.github.vitalijr2.logging.platform;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.github.vitalijr2.logging.platform.MockLoggerFinder
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package io.github.vitalijr2.logging.platform;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import static org.hamcrest.core.Is.isA;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.StringStartsWith.startsWith;
import static org.hamcrest.object.HasToString.hasToString;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.mockito.Mockito.mock;

import java.lang.System.Logger;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@Tag("fast")
class MockLoggerFinderFastTest {

@DisplayName("Create and add logger")
@Test
void createLogger() {
// given
var loggers = new HashMap<String, Logger>();
var loggerFinder = new MockLoggerFinder(loggers);

// when
loggerFinder.getLogger("test", getClass().getModule());

// then
assertAll("Logger was created", () -> assertThat("size", loggers, aMapWithSize(1)),
() -> assertThat("entry", loggers, hasEntry(equalTo("test"), isA(Logger.class))),
() -> assertThat(loggers.values().iterator().next(), hasToString("Mock for logger test")));
}

@DisplayName("Reuse existing logger")
@Test
void reuseExistingLogger() {
// given
var loggers = new HashMap<>(Map.of("test", mock(Logger.class)));
var loggerFinder = new MockLoggerFinder(loggers);

// when
loggerFinder.getLogger("test", getClass().getModule());

// then
assertAll("Logger was reused", () -> assertThat("size", loggers, aMapWithSize(1)),
() -> assertThat("entry", loggers, hasEntry(equalTo("test"), isA(Logger.class))),
() -> assertThat(loggers.values().iterator().next(), hasToString(startsWith("Mock for Logger, hashCode:"))));
}

@DisplayName("Clean and reset loggers")
@Test
void cleanAndResetLoggers() {
// given
var loggers = new HashMap<>(Map.of("a", mock(Logger.class), "b", mock(Logger.class), "c", mock(Logger.class)));
var loggerFinder = new MockLoggerFinder(loggers);

// when
var loggerNames = loggerFinder.cleanAndReset();

// then
assertThat(loggerNames, contains("a", "b", "c"));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.github.vitalijr2.logging.platform;

import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;

import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

@Tag("slow")
class MockLoggerFinderSlowTest {

private static Logger logger;

@BeforeAll
static void setUpClass() {
logger = System.getLogger("test");
}

@AfterEach
void tearDown() {
clearInvocations(logger);
}

@DisplayName("Test")
@ParameterizedTest
@ValueSource(strings = {"TRACE", "DEBUG", "INFO", "WARNING", "ERROR"})
void test(Level level) {
// given
verifyNoInteractions(logger);

// when
System.getLogger("test").log(level, "test message");

// then
verify(logger).log(level, "test message");
}

}
15 changes: 15 additions & 0 deletions junit-extension/pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2024 Vitalij Berdinskih

Licensed 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.
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
Expand Down
Loading