Compare commits

..

No commits in common. "main" and "1.0.6" have entirely different histories.
main ... 1.0.6

34 changed files with 247 additions and 559 deletions

View file

@ -1,5 +1,5 @@
name: Quarkus Commons name: Quarkus Commons
release: release:
current-version: "1.0.8" current-version: "1.0.6"
next-version: "1.0.9-SNAPSHOT" next-version: "1.0.7-SNAPSHOT"

View file

@ -63,8 +63,14 @@ jobs:
servers: | servers: |
[{ [{
"id": "phoenix-oss", "id": "phoenix-oss",
"username": "${{ vars.ORG_PACKAGE_WRITER_USERNAME }}", "configuration": {
"password": "${{ secrets.ORG_PACKAGE_WRITER_TOKEN }}" "httpHeaders": {
"property": {
"name": "Authorization",
"value": "token ${{ secrets.ORG_PACKAGE_WRITER_TOKEN }}"
}
}
}
}] }]
- name: Make maven wrapper executable - name: Make maven wrapper executable

View file

@ -2,12 +2,12 @@ Quarkus Commons
=============== ===============
[![Java version](https://img.shields.io/badge/Java%20version-21-brightgreen)](https://openjdk.org/projects/jdk/21/) [![Java version](https://img.shields.io/badge/Java%20version-21-brightgreen)](https://openjdk.org/projects/jdk/21/)
[![Coverage](https://sonarqube.pub.basel.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=coverage&token=sqb_b56d9ea175c7f51f522ce63acd7fe7807643ac9e)](https://sonarqube.pub.basel.kvant.cloud/dashboard?id=quarkus-commons) [![Coverage](https://sonarqube.pub.production.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=coverage&token=sqb_b39e0a05145228a10eb07d8771fd073297800645)](https://sonarqube.pub.production.kvant.cloud/dashboard?id=quarkus-commons)
[![Duplicated Lines (%)](https://sonarqube.pub.basel.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=duplicated_lines_density&token=sqb_b56d9ea175c7f51f522ce63acd7fe7807643ac9e)](https://sonarqube.pub.basel.kvant.cloud/dashboard?id=quarkus-commons) [![Duplicated Lines (%)](https://sonarqube.pub.production.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=duplicated_lines_density&token=sqb_b39e0a05145228a10eb07d8771fd073297800645)](https://sonarqube.pub.production.kvant.cloud/dashboard?id=quarkus-commons)
[![Quality Gate Status](https://sonarqube.pub.basel.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=alert_status&token=sqb_b56d9ea175c7f51f522ce63acd7fe7807643ac9e)](https://sonarqube.pub.basel.kvant.cloud/dashboard?id=quarkus-commons) [![Quality Gate Status](https://sonarqube.pub.production.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=alert_status&token=sqb_b39e0a05145228a10eb07d8771fd073297800645)](https://sonarqube.pub.production.kvant.cloud/dashboard?id=quarkus-commons)
[![Security Rating](https://sonarqube.pub.basel.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=security_rating&token=sqb_b56d9ea175c7f51f522ce63acd7fe7807643ac9e)](https://sonarqube.pub.basel.kvant.cloud/dashboard?id=quarkus-commons) [![Security Rating](https://sonarqube.pub.production.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=security_rating&token=sqb_b39e0a05145228a10eb07d8771fd073297800645)](https://sonarqube.pub.production.kvant.cloud/dashboard?id=quarkus-commons)
[![Reliability Rating](https://sonarqube.pub.basel.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=reliability_rating&token=sqb_b56d9ea175c7f51f522ce63acd7fe7807643ac9e)](https://sonarqube.pub.basel.kvant.cloud/dashboard?id=quarkus-commons) [![Reliability Rating](https://sonarqube.pub.production.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=reliability_rating&token=sqb_b39e0a05145228a10eb07d8771fd073297800645)](https://sonarqube.pub.production.kvant.cloud/dashboard?id=quarkus-commons)
[![Maintainability Rating](https://sonarqube.pub.basel.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=sqale_rating&token=sqb_b56d9ea175c7f51f522ce63acd7fe7807643ac9e)](https://sonarqube.pub.basel.kvant.cloud/dashboard?id=quarkus-commons) [![Maintainability Rating](https://sonarqube.pub.production.kvant.cloud/api/project_badges/measure?project=quarkus-commons&metric=sqale_rating&token=sqb_b39e0a05145228a10eb07d8771fd073297800645)](https://sonarqube.pub.production.kvant.cloud/dashboard?id=quarkus-commons)
# Introduction # Introduction

14
pom.xml
View file

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>ch.phoenix.oss</groupId> <groupId>ch.phoenix.oss</groupId>
<artifactId>quarkus-commons</artifactId> <artifactId>quarkus-commons</artifactId>
<version>1.0.9-SNAPSHOT</version> <version>1.0.6</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
@ -21,15 +21,15 @@
<!-- Quarkus properties --> <!-- Quarkus properties -->
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id> <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id> <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.25.0</quarkus.platform.version> <quarkus.platform.version>3.24.4</quarkus.platform.version>
<!-- Plugin versions --> <!-- Plugin versions -->
<compiler-plugin.version>3.14.0</compiler-plugin.version> <compiler-plugin.version>3.14.0</compiler-plugin.version>
<surefire-plugin.version>3.5.3</surefire-plugin.version> <surefire-plugin.version>3.5.3</surefire-plugin.version>
<spotless-plugin.version>2.46.1</spotless-plugin.version> <spotless-plugin.version>2.45.0</spotless-plugin.version>
<palantir-java-format.version>2.72.0</palantir-java-format.version> <palantir-java-format.version>2.70.0</palantir-java-format.version>
<jacoco-plugin.version>0.8.13</jacoco-plugin.version> <!-- Match with version from Quarkus BOM --> <jacoco-plugin.version>0.8.13</jacoco-plugin.version> <!-- Match with version from Quarkus BOM -->
<jandex-plugin.version>3.4.0</jandex-plugin.version> <jandex-plugin.version>3.3.1</jandex-plugin.version>
<release-plugin.version>3.1.1</release-plugin.version> <release-plugin.version>3.1.1</release-plugin.version>
<source-plugin.version>3.3.1</source-plugin.version> <source-plugin.version>3.3.1</source-plugin.version>
@ -73,7 +73,7 @@
<connection>scm:git:ssh://git@git-ssh.kvant.cloud:2222/phoenix-oss/quarkus-commons.git</connection> <connection>scm:git:ssh://git@git-ssh.kvant.cloud:2222/phoenix-oss/quarkus-commons.git</connection>
<developerConnection>scm:git:ssh://git@git-ssh.kvant.cloud:2222/phoenix-oss/quarkus-commons.git</developerConnection> <developerConnection>scm:git:ssh://git@git-ssh.kvant.cloud:2222/phoenix-oss/quarkus-commons.git</developerConnection>
<url>https://git.kvant.cloud/phoenix-oss/quarkus-commons.git</url> <url>https://git.kvant.cloud/phoenix-oss/quarkus-commons.git</url>
<tag>HEAD</tag> <tag>1.0.6</tag>
</scm> </scm>
<dependencies> <dependencies>
@ -196,7 +196,7 @@
<tagNameFormat>@{project.version}</tagNameFormat> <tagNameFormat>@{project.version}</tagNameFormat>
<checkModificationExcludes>mvnw</checkModificationExcludes> <checkModificationExcludes>mvnw</checkModificationExcludes>
<scmReleaseCommitComment>chore: release @{releaseLabel}</scmReleaseCommitComment> <scmReleaseCommitComment>chore: release @{releaseLabel}</scmReleaseCommitComment>
<scmDevelopmentCommitComment>chore: prepare for next development iteration</scmDevelopmentCommitComment> <scmDevelopmentCommitComment>chore: prepare for next development iteration [skip ci]</scmDevelopmentCommitComment>
<autoVersionSubmodules>true</autoVersionSubmodules> <autoVersionSubmodules>true</autoVersionSubmodules>
</configuration> </configuration>
</plugin> </plugin>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ch.phoenix.oss</groupId> <groupId>ch.phoenix.oss</groupId>
<artifactId>quarkus-commons</artifactId> <artifactId>quarkus-commons</artifactId>
<version>1.0.9-SNAPSHOT</version> <version>1.0.6</version>
</parent> </parent>
<artifactId>quarkus-audit-tools</artifactId> <artifactId>quarkus-audit-tools</artifactId>
@ -51,38 +51,38 @@
</dependency> </dependency>
</dependencies> </dependencies>
<build> <!-- <build>-->
<plugins> <!-- <plugins>-->
<plugin> <!-- <plugin>-->
<groupId>org.jacoco</groupId> <!-- <groupId>org.jacoco</groupId>-->
<artifactId>jacoco-maven-plugin</artifactId> <!-- <artifactId>jacoco-maven-plugin</artifactId>-->
<version>${jacoco-plugin.version}</version> <!-- <version>${jacoco-plugin.version}</version>-->
<executions> <!-- <executions>-->
<execution> <!-- <execution>-->
<id>jacoco-check</id> <!-- <id>jacoco-check</id>-->
<goals> <!-- <goals>-->
<goal>check</goal> <!-- <goal>check</goal>-->
</goals> <!-- </goals>-->
<phase>test</phase> <!-- <phase>test</phase>-->
<configuration> <!-- <configuration>-->
<dataFile>${project.build.directory}/jacoco-quarkus.exec</dataFile> <!-- <dataFile>${project.build.directory}/jacoco-quarkus.exec</dataFile>-->
<rules> <!-- <rules>-->
<rule> <!-- <rule>-->
<element>BUNDLE</element> <!-- <element>BUNDLE</element>-->
<limits> <!-- <limits>-->
<limit> <!-- <limit>-->
<counter>INSTRUCTION</counter> <!-- <counter>INSTRUCTION</counter>-->
<value>COVEREDRATIO</value> <!-- <value>COVEREDRATIO</value>-->
<minimum>1</minimum> <!-- <minimum>1</minimum>-->
</limit> <!-- </limit>-->
</limits> <!-- </limits>-->
</rule> <!-- </rule>-->
</rules> <!-- </rules>-->
</configuration> <!-- </configuration>-->
</execution> <!-- </execution>-->
</executions> <!-- </executions>-->
</plugin> <!-- </plugin>-->
</plugins> <!-- </plugins>-->
</build> <!-- </build>-->
</project> </project>

View file

@ -1,6 +1,7 @@
package ch.phoenix.oss.quarkus.commons.audit; package ch.phoenix.oss.quarkus.commons.audit;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.mockStatic;
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.QuarkusTest;

View file

@ -1,6 +1,7 @@
package ch.phoenix.oss.quarkus.commons.audit; package ch.phoenix.oss.quarkus.commons.audit;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -16,36 +17,12 @@ class RevisionTest {
var r2 = new Revision(); var r2 = new Revision();
r2.rev = 1; r2.rev = 1;
var r3 = new Revision(); assertThat(r1).as("Revisions should be equal").isEqualTo(r2);
r3.rev = 2;
assertThat(r1)
.as("Revisions equality should should match expected value")
.isEqualTo(r1)
.isEqualTo(r2)
.isNotEqualTo(r3)
.isNotEqualTo(new Object());
} }
@Test @Test
void testHashCode() { void testHashCode() {}
var r1 = new Revision();
r1.rev = 123;
var r2 = new Revision();
r2.rev = 123;
var r3 = new Revision();
r3.rev = 2;
assertThat(r1.hashCode()).isEqualTo(123).isEqualTo(r2.hashCode()).isNotEqualTo(r3.hashCode());
}
@Test @Test
void testToString() { void testToString() {}
var rev = new Revision();
rev.rev = 1;
assertThat(rev).as("Revision's toString should match expected value").hasToString("Revision{rev=1}");
}
} }

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ch.phoenix.oss</groupId> <groupId>ch.phoenix.oss</groupId>
<artifactId>quarkus-commons</artifactId> <artifactId>quarkus-commons</artifactId>
<version>1.0.9-SNAPSHOT</version> <version>1.0.6</version>
</parent> </parent>
<artifactId>quarkus-client-logger</artifactId> <artifactId>quarkus-client-logger</artifactId>
@ -16,16 +16,6 @@
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client</artifactId> <artifactId>quarkus-rest-client</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-config-yaml</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-jackson</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -50,7 +40,7 @@
<limit> <limit>
<counter>INSTRUCTION</counter> <counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value> <value>COVEREDRATIO</value>
<minimum>0.92</minimum> <minimum>1</minimum>
</limit> </limit>
</limits> </limits>
</rule> </rule>

View file

@ -1,10 +0,0 @@
package ch.phoenix.oss.quarkus.commons.client.logger;
import org.eclipse.microprofile.config.spi.Converter;
public class LowerCaseStringConverter implements Converter<String> {
@Override
public String convert(String value) throws IllegalArgumentException, NullPointerException {
return value.toLowerCase();
}
}

View file

@ -6,36 +6,23 @@ import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse; import io.vertx.core.http.HttpClientResponse;
import jakarta.enterprise.context.Dependent; import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject; import jakarta.ws.rs.core.HttpHeaders;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.client.api.ClientLogger; import org.jboss.resteasy.reactive.client.api.ClientLogger;
/** /**
* This is based on org.jboss.resteasy.reactive.client.logging.DefaultClientLogger, * This is based on org.jboss.resteasy.reactive.client.logging.DefaultClientLogger,
* with the only change being that headers are redacted based on the Set provided * with the only change being that the value of "Authorization" header, when present,
* by the configuration. * is redacted.
*/ */
@Dependent @Dependent
public class RedactingClientLogger implements ClientLogger { public class RedactingClientLogger implements ClientLogger {
private static final Logger log = Logger.getLogger(RedactingClientLogger.class); private static final Logger log = Logger.getLogger(RedactingClientLogger.class);
private static final String REDACTED_VALUE = "*****";
private final Set<String> redactedHeaders;
private int bodySize; private int bodySize;
@Inject
public RedactingClientLogger(RedactingClientLoggerConfiguration configuration) {
this.redactedHeaders = configuration
.headers()
.redact()
.orElse(RedactingClientLoggerConfiguration.Headers.DEFAULT_REDACTED_HEADERS);
}
@Override @Override
public void setBodySize(int bodySize) { public void setBodySize(int bodySize) {
this.bodySize = bodySize; this.bodySize = bodySize;
@ -110,7 +97,7 @@ public class RedactingClientLogger implements ClientLogger {
} }
var key = entry.getKey(); var key = entry.getKey();
var value = redactedHeaders.contains(key.toLowerCase()) ? REDACTED_VALUE : entry.getValue(); var value = HttpHeaders.AUTHORIZATION.equalsIgnoreCase(key) ? "*****" : entry.getValue();
sb.append(key).append('=').append(value); sb.append(key).append('=').append(value);
} }

View file

@ -1,20 +0,0 @@
package ch.phoenix.oss.quarkus.commons.client.logger;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithConverter;
import jakarta.ws.rs.core.HttpHeaders;
import java.util.Optional;
import java.util.Set;
@ConfigMapping(prefix = "phoenix.client-logger")
public interface RedactingClientLoggerConfiguration {
Headers headers();
interface Headers {
Set<String> DEFAULT_REDACTED_HEADERS = Set.of(HttpHeaders.AUTHORIZATION.toLowerCase());
Optional<Set<@WithConverter(LowerCaseStringConverter.class) String>> redact();
}
}

View file

@ -1,12 +0,0 @@
package ch.phoenix.oss.quarkus.commons.client.logger;
import io.quarkus.test.junit.QuarkusTestProfile;
import java.util.Map;
public class InfoLevelProfile implements QuarkusTestProfile {
@Override
public Map<String, String> getConfigOverrides() {
return Map.of("quarkus.log.category.\"ch.phoenix.oss.quarkus.commons.client.logger\".level", "INFO");
}
}

View file

@ -1,44 +0,0 @@
package ch.phoenix.oss.quarkus.commons.client.logger;
import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.TestProfile;
import jakarta.inject.Inject;
import java.net.URI;
import java.util.Optional;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.Test;
@QuarkusTest
@TestProfile(InfoLevelProfile.class)
class InfoLevelTest {
@Inject
@RestClient
TestClient injectedClient;
TestClient builtClient = QuarkusRestClientBuilder.newBuilder()
.clientLogger(new RedactingClientLogger(() -> Optional::empty))
.baseUri(URI.create("http://localhost:8087"))
.build(TestClient.class);
@Test
void getWithInjectedClient() {
injectedClient.get("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "also redacted");
}
@Test
void getWithBuiltClientAndEmptyConfig() {
builtClient.get("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "not redacted");
}
@Test
void postWithInjectedClient() {
injectedClient.post("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "also redacted", "body");
}
@Test
void postWithBuiltClientAndEmptyConfig() {
builtClient.post("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "not redacted", "");
}
}

View file

@ -1,47 +0,0 @@
package ch.phoenix.oss.quarkus.commons.client.logger;
import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import java.net.URI;
import java.util.Optional;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.Test;
@QuarkusTest
class RedactingClientLoggerTest {
@Inject
@RestClient
TestClient injectedClient;
TestClient builtClient = QuarkusRestClientBuilder.newBuilder()
.clientLogger(new RedactingClientLogger(() -> Optional::empty))
.baseUri(URI.create("http://localhost:8087"))
.build(TestClient.class);
@Test
void getWithInjectedClient() {
injectedClient.get("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "also redacted");
}
@Test
void getWithBuiltClientAndEmptyConfig() {
builtClient.get("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "not redacted");
}
@Test
void postWithInjectedClient() {
injectedClient.post("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "also redacted", "body");
}
@Test
void postWithInjectedClientAndNullBody() {
injectedClient.post("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "also redacted", null);
}
@Test
void postWithBuiltClientAndEmptyConfig() {
builtClient.post("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "not redacted", "");
}
}

View file

@ -1,12 +0,0 @@
package ch.phoenix.oss.quarkus.commons.client.logger;
import io.quarkus.test.junit.QuarkusTestProfile;
import java.util.Map;
public class ScopeNoneProfile implements QuarkusTestProfile {
@Override
public Map<String, String> getConfigOverrides() {
return Map.of("quarkus.rest-client.logging.scope", "none");
}
}

View file

@ -1,44 +0,0 @@
package ch.phoenix.oss.quarkus.commons.client.logger;
import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.TestProfile;
import jakarta.inject.Inject;
import java.net.URI;
import java.util.Optional;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.Test;
@QuarkusTest
@TestProfile(ScopeNoneProfile.class)
class ScopeNoneTest {
@Inject
@RestClient
TestClient injectedClient;
TestClient builtClient = QuarkusRestClientBuilder.newBuilder()
.clientLogger(new RedactingClientLogger(() -> Optional::empty))
.baseUri(URI.create("http://localhost:8087"))
.build(TestClient.class);
@Test
void getWithInjectedClient() {
injectedClient.get("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "also redacted");
}
@Test
void getWithBuiltClientAndEmptyConfig() {
builtClient.get("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "not redacted");
}
@Test
void postWithInjectedClient() {
injectedClient.post("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "also redacted", "body");
}
@Test
void postWithBuiltClientAndEmptyConfig() {
builtClient.post("this will be redacted", "5c0d8e45-e402-4b71-8f84-24cc0cfd7eec", "not redacted", "");
}
}

View file

@ -1,28 +0,0 @@
package ch.phoenix.oss.quarkus.commons.client.logger;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@SuppressWarnings("UastIncorrectHttpHeaderInspection")
@RegisterRestClient(configKey = "test")
public interface TestClient {
@GET
@Path("/")
@Produces(MediaType.TEXT_PLAIN)
String get(
@HeaderParam("Authorization") String authorization,
@HeaderParam("X-Request-ID") String requestId,
@HeaderParam("X-Something-Else") String somethingElse);
@POST
@Path("/")
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.TEXT_PLAIN)
String post(
@HeaderParam("Authorization") String authorization,
@HeaderParam("X-Request-ID") String requestId,
@HeaderParam("X-Something-Else") String somethingElse,
String body);
}

View file

@ -1,21 +0,0 @@
package ch.phoenix.oss.quarkus.commons.client.logger;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
@Path("/")
public class TestResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String get() {
return "get";
}
@POST
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.TEXT_PLAIN)
public String post(String body) {
return body;
}
}

View file

@ -1,20 +0,0 @@
quarkus:
http:
test-port: 8087
rest-client:
logging:
scope: request-response
body-limit: 10000
test:
url: http://localhost:${quarkus.http.test-port}
log:
category:
"ch.phoenix.oss.quarkus.commons.client.logger":
level: DEBUG
phoenix:
client-logger:
headers:
redact:
- AUTHORIZATION
- X-SOMETHING-ELSE

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ch.phoenix.oss</groupId> <groupId>ch.phoenix.oss</groupId>
<artifactId>quarkus-commons</artifactId> <artifactId>quarkus-commons</artifactId>
<version>1.0.9-SNAPSHOT</version> <version>1.0.6</version>
</parent> </parent>
<artifactId>quarkus-clock-service</artifactId> <artifactId>quarkus-clock-service</artifactId>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ch.phoenix.oss</groupId> <groupId>ch.phoenix.oss</groupId>
<artifactId>quarkus-commons</artifactId> <artifactId>quarkus-commons</artifactId>
<version>1.0.9-SNAPSHOT</version> <version>1.0.6</version>
</parent> </parent>
<artifactId>quarkus-json-service</artifactId> <artifactId>quarkus-json-service</artifactId>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ch.phoenix.oss</groupId> <groupId>ch.phoenix.oss</groupId>
<artifactId>quarkus-commons</artifactId> <artifactId>quarkus-commons</artifactId>
<version>1.0.9-SNAPSHOT</version> <version>1.0.6</version>
</parent> </parent>
<artifactId>quarkus-message-digest-service</artifactId> <artifactId>quarkus-message-digest-service</artifactId>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ch.phoenix.oss</groupId> <groupId>ch.phoenix.oss</groupId>
<artifactId>quarkus-commons</artifactId> <artifactId>quarkus-commons</artifactId>
<version>1.0.9-SNAPSHOT</version> <version>1.0.6</version>
</parent> </parent>
<artifactId>quarkus-random-number-generator</artifactId> <artifactId>quarkus-random-number-generator</artifactId>

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ch.phoenix.oss</groupId> <groupId>ch.phoenix.oss</groupId>
<artifactId>quarkus-commons</artifactId> <artifactId>quarkus-commons</artifactId>
<version>1.0.9-SNAPSHOT</version> <version>1.0.6</version>
</parent> </parent>
<artifactId>quarkus-tracing-service</artifactId> <artifactId>quarkus-tracing-service</artifactId>
@ -41,38 +41,4 @@
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-plugin.version}</version>
<executions>
<execution>
<id>jacoco-check</id>
<goals>
<goal>check</goal>
</goals>
<phase>test</phase>
<configuration>
<dataFile>${project.build.directory}/jacoco-quarkus.exec</dataFile>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value>
<minimum>0.95</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project> </project>

View file

@ -8,7 +8,7 @@ public interface TracingService {
String getActor(); String getActor();
String getRequestPathRaw(); String getRequestPath();
String getRequestMethod(); String getRequestMethod();

View file

@ -33,7 +33,7 @@ class TracingServiceImpl implements TracingService {
} }
@Override @Override
public String getRequestPathRaw() { public String getRequestPath() {
return (String) MDC.get(TracingConstants.REQUEST_PATH_RAW); return (String) MDC.get(TracingConstants.REQUEST_PATH_RAW);
} }

View file

@ -12,7 +12,7 @@ import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@QuarkusTest @QuarkusTest
class ActorTest { public class ActorTest {
@InjectSpy @InjectSpy
TracingService tracingService; TracingService tracingService;

View file

@ -12,7 +12,7 @@ import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@QuarkusTest @QuarkusTest
class QueryParamTest { public class QueryParamTest {
@InjectSpy @InjectSpy
TracingService tracingService; TracingService tracingService;

View file

@ -14,7 +14,7 @@ import org.junit.jupiter.api.Test;
@QuarkusTest @QuarkusTest
@TestProfile(Test2Profile.class) @TestProfile(Test2Profile.class)
class RawPathTest { public class RawPathTest {
@InjectSpy @InjectSpy
TracingService tracingService; TracingService tracingService;

View file

@ -14,7 +14,7 @@ import org.junit.jupiter.api.Test;
@QuarkusTest @QuarkusTest
@TestProfile(Test2Profile.class) @TestProfile(Test2Profile.class)
class RedactedTest { public class RedactedTest {
@InjectSpy @InjectSpy
TracingService tracingService; TracingService tracingService;

View file

@ -1,6 +1,5 @@
package ch.phoenix.oss.quarkus.commons.tracing; package ch.phoenix.oss.quarkus.commons.tracing;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.startsWith; import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -11,11 +10,7 @@ import io.quarkus.test.junit.mockito.InjectSpy;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@QuarkusTest @QuarkusTest
class RoutePatternTest { class RoutePatternTest {
@ -23,46 +18,12 @@ class RoutePatternTest {
@InjectSpy @InjectSpy
TracingService tracingService; TracingService tracingService;
static Stream<Arguments> get() { @Test
return Stream.of( void getBlankResource() {
arguments("/", Map.of()), var route = "/";
arguments("/leading-and-no-trailing", Map.of()), RestAssured.given().accept(ContentType.TEXT).when().get(route).then().statusCode(200);
arguments("/leading/{param}/{param2}", Map.of("param", "1", "param2", "2")),
arguments("/{param}/{param2}/trailing", Map.of("param", "1", "param2", "2")),
arguments("/leading-and-no-trailing/{param}", Map.of("param", "1")),
arguments("/leading-and-no-trailing/{param}/{param2}", Map.of("param", "1", "param2", "2")),
arguments("/leading-and-trailing", Map.of()),
arguments("/leading-and-trailing/{param}", Map.of("param", "1")),
arguments("/leading-and-trailing/{param}/{param2}", Map.of("param", "1", "param2", "2")),
arguments("/no-leading-and-no-trailing", Map.of()),
arguments("/no-leading-and-no-trailing/{param}", Map.of("param", "1")),
arguments("/no-leading-and-no-trailing/{param}/{param2}", Map.of("param", "1", "param2", "2")),
arguments("/no-leading-and-trailing", Map.of()),
arguments("/no-leading-and-trailing/{param}", Map.of("param", "1")),
arguments("/no-leading-and-trailing/{param}/{param2}", Map.of("param", "1", "param2", "2")));
}
@MethodSource verifyGetTracing(route, Map.of());
@ParameterizedTest
void get(String route, Map<String, String> pathParams) {
RestAssured.given()
.accept(ContentType.TEXT)
.when()
.get(route, pathParams)
.then()
.statusCode(200);
verify(tracingService).trace("actor", "anonymous");
verify(tracingService).trace("request.method", "GET");
verify(tracingService).trace("request.route", route);
pathParams.forEach((key, value) -> verify(tracingService).trace("request.path.params." + key, value));
verify(tracingService).trace("request.headers.accept", "text/plain");
verify(tracingService).trace("request.headers.accept-encoding", "gzip,deflate");
verify(tracingService).trace("request.headers.connection", "Keep-Alive");
verify(tracingService).trace(eq("request.headers.host"), startsWith("localhost:"));
verify(tracingService).trace(eq("request.headers.user-agent"), startsWith("Apache-HttpClient"));
verify(tracingService).trace("request.client.ip", "127.0.0.1");
verifyNoMoreInteractions(tracingService);
} }
@Test @Test
@ -84,4 +45,160 @@ class RoutePatternTest {
verify(tracingService).trace("request.client.ip", "127.0.0.1"); verify(tracingService).trace("request.client.ip", "127.0.0.1");
verifyNoMoreInteractions(tracingService); verifyNoMoreInteractions(tracingService);
} }
@Test
void getLeadingResource() {
var route = "/leading/{id}/{anotherId}";
RestAssured.given()
.accept(ContentType.TEXT)
.when()
.get(route, 1, 2)
.then()
.statusCode(200);
verifyGetTracing(route, Map.of("id", "1", "anotherId", "2"));
}
@Test
void getTrailingResource() {
var route = "/{id}/{anotherId}/trailing";
RestAssured.given()
.accept(ContentType.TEXT)
.when()
.get(route, 1, 2)
.then()
.statusCode(200);
verifyGetTracing(route, Map.of("id", "1", "anotherId", "2"));
}
@Test
void getLeadingAndNoTrailingResource() {
var route = "/leading-and-no-trailing";
RestAssured.given().accept(ContentType.TEXT).when().get(route).then().statusCode(200);
verifyGetTracing(route, Map.of());
}
@Test
void getLeadingAndNoTrailingWithSingleParamResource() {
var route = "/leading-and-no-trailing/{param}";
RestAssured.given().accept(ContentType.TEXT).when().get(route, 1).then().statusCode(200);
verifyGetTracing(route, Map.of("param", "1"));
}
@Test
void getLeadingAndNoTrailingWithMultiParamResource() {
var route = "/leading-and-no-trailing/{param}/{param2}";
RestAssured.given()
.accept(ContentType.TEXT)
.when()
.get(route, 1, 2)
.then()
.statusCode(200);
verifyGetTracing(route, Map.of("param", "1", "param2", "2"));
}
@Test
void getLeadingAndTrailingResource() {
var route = "/leading-and-trailing";
RestAssured.given().accept(ContentType.TEXT).when().get(route).then().statusCode(200);
verifyGetTracing(route, Map.of());
}
@Test
void getLeadingAndTrailingWithSingleParamResource() {
var route = "/leading-and-trailing/{param}";
RestAssured.given().accept(ContentType.TEXT).when().get(route, 1).then().statusCode(200);
verifyGetTracing(route, Map.of("param", "1"));
}
@Test
void getLeadingAndTrailingWithMultiParamResource() {
var route = "/leading-and-trailing/{param}/{param2}";
RestAssured.given()
.accept(ContentType.TEXT)
.when()
.get(route, 1, 2)
.then()
.statusCode(200);
verifyGetTracing(route, Map.of("param", "1", "param2", "2"));
}
@Test
void getNoLeadingAndNoTrailingResource() {
var route = "/no-leading-and-no-trailing";
RestAssured.given().accept(ContentType.TEXT).when().get(route).then().statusCode(200);
verifyGetTracing(route, Map.of());
}
@Test
void geNoLeadingAndNoTrailingWithSingleParamResource() {
var route = "/no-leading-and-no-trailing/{param}";
RestAssured.given().accept(ContentType.TEXT).when().get(route, 1).then().statusCode(200);
verifyGetTracing(route, Map.of("param", "1"));
}
@Test
void getNoLeadingAndNoTrailingWithMultiParamResource() {
var route = "/no-leading-and-no-trailing/{param}/{param2}";
RestAssured.given()
.accept(ContentType.TEXT)
.when()
.get(route, 1, 2)
.then()
.statusCode(200);
verifyGetTracing(route, Map.of("param", "1", "param2", "2"));
}
@Test
void getNoLeadingAndTrailingResource() {
var route = "/no-leading-and-trailing";
RestAssured.given().accept(ContentType.TEXT).when().get(route).then().statusCode(200);
verifyGetTracing(route, Map.of());
}
@Test
void getNoLeadingAndTrailingWithSingleParamResource() {
var route = "/no-leading-and-trailing/{param}";
RestAssured.given().accept(ContentType.TEXT).when().get(route, 1).then().statusCode(200);
verifyGetTracing(route, Map.of("param", "1"));
}
@Test
void getNoLeadingAndTrailingWithMultiParamResource() {
var route = "/no-leading-and-trailing/{param}/{param2}";
RestAssured.given()
.accept(ContentType.TEXT)
.when()
.get(route, 1, 2)
.then()
.statusCode(200);
verifyGetTracing(route, Map.of("param", "1", "param2", "2"));
}
private void verifyGetTracing(String route, Map<String, String> pathParams) {
verify(tracingService).trace("actor", "anonymous");
verify(tracingService).trace("request.method", "GET");
verify(tracingService).trace("request.route", route);
pathParams.forEach((key, value) -> verify(tracingService).trace("request.path.params." + key, value));
verify(tracingService).trace("request.headers.accept", "text/plain");
verify(tracingService).trace("request.headers.accept-encoding", "gzip,deflate");
verify(tracingService).trace("request.headers.connection", "Keep-Alive");
verify(tracingService).trace(eq("request.headers.host"), startsWith("localhost:"));
verify(tracingService).trace(eq("request.headers.user-agent"), startsWith("Apache-HttpClient"));
verify(tracingService).trace("request.client.ip", "127.0.0.1");
verifyNoMoreInteractions(tracingService);
}
} }

View file

@ -1,98 +0,0 @@
package ch.phoenix.oss.quarkus.commons.tracing;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.instrumentation.annotations.WithSpan;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.jboss.logging.MDC;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@QuarkusTest
class TracingServiceImplTest {
@Inject
TracingService tracingService;
@Inject
Span span;
@BeforeEach
void setUp() {
MDC.clear();
}
@Test
void getActor() {
tracingService.trace("actor", "abc");
assertThat(tracingService.getActor())
.as("Actor should match expected value")
.isEqualTo("abc");
}
@Test
void getRequestPathRaw() {
tracingService.trace("request.path.raw", "/foo/bar");
assertThat(tracingService.getRequestPathRaw())
.as("Request Path Raw should match expected value")
.isEqualTo("/foo/bar");
}
@Test
void getRequestMethod() {
tracingService.trace("request.method", "GET");
assertThat(tracingService.getRequestMethod())
.as("Request Method should match expected value")
.isEqualTo("GET");
}
@Test
void getRequestId() {
tracingService.trace("request.headers.x-request-id", "ba458367-bfeb-46ba-87da-50b9343be8f9");
assertThat(tracingService.getRequestId())
.as("Request Id should match expected value")
.isEqualTo("ba458367-bfeb-46ba-87da-50b9343be8f9");
}
@Test
@WithSpan
void getTraceId() {
assertThat(tracingService.getTraceId())
.as("Request Trace Id should match expected value")
.isEqualTo(span.getSpanContext().getTraceId());
}
@Test
@WithSpan
void getSpanId() {
assertThat(tracingService.getSpanId())
.as("Request Span Id should match expected value")
.isEqualTo(span.getSpanContext().getSpanId());
}
@Test
void getClientIp() {
tracingService.trace("request.client.ip", "127.0.0.1");
assertThat(tracingService.getClientIp())
.as("Request Client Iü should match expected value")
.isEqualTo("127.0.0.1");
}
@Test
void getSchedulerJob() {
tracingService.trace("scheduler.job.name", "scheduler/abc");
assertThat(tracingService.getSchedulerJob())
.as("Scheduler Job Name should match expected value")
.isEqualTo("scheduler/abc");
}
@Test
void clearAll() {
tracingService.trace("aaa", "bbb");
assertThat(MDC.get("aaa")).isEqualTo("bbb");
tracingService.clearAll();
assertThat(MDC.get("aaa")).isNull();
}
}

View file

@ -10,14 +10,14 @@ import jakarta.ws.rs.core.MediaType;
public class SlashResource { public class SlashResource {
@GET @GET
@Path("/leading/{param}/{param2}") @Path("/leading/{id}/{anotherId}")
public String doubleLeading(int param, int param2) { public String doubleLeading(int id, int anotherId) {
return "leading/" + param + "/" + param2; return "leading/" + id + "/" + anotherId;
} }
@GET @GET
@Path("{param}/{param2}/trailing/") @Path("{id}/{anotherId}/trailing/")
public String doubleTrailing(int param, int param2) { public String doubleTrailing(int id, int anotherId) {
return param + "/" + param2 + "/trailing"; return id + "/" + anotherId + "/trailing";
} }
} }

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ch.phoenix.oss</groupId> <groupId>ch.phoenix.oss</groupId>
<artifactId>quarkus-commons</artifactId> <artifactId>quarkus-commons</artifactId>
<version>1.0.9-SNAPSHOT</version> <version>1.0.6</version>
</parent> </parent>
<artifactId>quarkus-uuid-generator</artifactId> <artifactId>quarkus-uuid-generator</artifactId>