From bb438a7e7e6b3f8af0e582ee8ad0f8c90d3d5302 Mon Sep 17 00:00:00 2001 From: Rain Ramm Date: Fri, 24 May 2024 17:55:54 +0300 Subject: [PATCH 1/7] Replace MDCTaskDecorator with spring-security agnostic and basic version --- .github/dependabot.yml | 10 +++- .github/workflows/build.yml | 8 ++- .github/workflows/publish-packages.yml | 6 +-- build.gradle | 2 +- .../core/trace/thread/MDCTaskDecorator.java | 4 ++ .../decorator/BasicMDCTaskDecorator.java | 30 +++++++++++ .../SecurityAwareMDCTaskDecorator.java | 34 ++++++++++++ .../decorator/BasicMDCTaskDecoratorTest.java | 52 +++++++++++++++++++ .../SecurityAwareMDCTaskDecoratorTest.java | 52 +++++++++++++++++++ 9 files changed, 192 insertions(+), 6 deletions(-) create mode 100644 src/main/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecorator.java create mode 100644 src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java create mode 100644 src/test/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecoratorTest.java create mode 100644 src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java diff --git a/.github/dependabot.yml b/.github/dependabot.yml index db7ac60..a87b871 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,4 +14,12 @@ updates: - "*" update-types: - "minor" - - "patch" \ No newline at end of file + - "patch" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + reviewers: + - "Jorich" + - "pr11t" + - "rammrain" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 63dba0b..1df56df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,6 +9,10 @@ on: jobs: test: runs-on: ubuntu-latest + strategy: + matrix: + java: [ '17', '21' ] + name: Test with Java ${{ matrix.Java }} steps: - name: Checkout code uses: actions/checkout@v4 @@ -19,10 +23,12 @@ jobs: uses: actions/setup-java@v4 with: distribution: temurin - java-version: 17 + java-version: ${{ matrix.java }} - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 + with: + gradle-version: 8.6 - name: Run tests and generate reports run: ./gradlew testAndReport diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml index b87355b..676461f 100644 --- a/.github/workflows/publish-packages.yml +++ b/.github/workflows/publish-packages.yml @@ -9,14 +9,14 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin java-version: 17 - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@v3 with: - gradle-version: 8.5 + gradle-version: 8.6 - name: Publish packages env: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} diff --git a/build.gradle b/build.gradle index 832eb04..a3f0bdb 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ plugins { } group 'ee.bitweb' -version '3.2.0' +version '3.3.0' java { sourceCompatibility = '17' } diff --git a/src/main/java/ee/bitweb/core/trace/thread/MDCTaskDecorator.java b/src/main/java/ee/bitweb/core/trace/thread/MDCTaskDecorator.java index 5ecea2b..4bfa913 100644 --- a/src/main/java/ee/bitweb/core/trace/thread/MDCTaskDecorator.java +++ b/src/main/java/ee/bitweb/core/trace/thread/MDCTaskDecorator.java @@ -7,6 +7,10 @@ import java.util.Map; +/** + * @deprecated use BasicMDCTaskDecorator or SecurityAwareMDCTaskDecorator + */ +@Deprecated(since = "3.3.0", forRemoval = true) @RequiredArgsConstructor public class MDCTaskDecorator implements TaskDecorator { diff --git a/src/main/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecorator.java b/src/main/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecorator.java new file mode 100644 index 0000000..0a1be70 --- /dev/null +++ b/src/main/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecorator.java @@ -0,0 +1,30 @@ +package ee.bitweb.core.trace.thread.decorator; + +import ee.bitweb.core.trace.thread.ThreadTraceIdResolver; +import lombok.RequiredArgsConstructor; +import org.slf4j.MDC; +import org.springframework.core.task.TaskDecorator; + +import java.util.Map; + +@RequiredArgsConstructor +public class BasicMDCTaskDecorator implements TaskDecorator { + + private final ThreadTraceIdResolver resolver; + + @Override + public Runnable decorate(Runnable runnable) { + Map contextMap = MDC.getCopyOfContextMap(); + + return () -> { + try { + MDC.setContextMap(contextMap); + resolver.resolve(); + + runnable.run(); + } finally { + MDC.clear(); + } + }; + } +} diff --git a/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java b/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java new file mode 100644 index 0000000..8c8ae98 --- /dev/null +++ b/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java @@ -0,0 +1,34 @@ +package ee.bitweb.core.trace.thread.decorator; + +import ee.bitweb.core.trace.thread.ThreadTraceIdResolver; +import lombok.RequiredArgsConstructor; +import org.slf4j.MDC; +import org.springframework.core.task.TaskDecorator; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.Map; + +@RequiredArgsConstructor +public class SecurityAwareMDCTaskDecorator implements TaskDecorator { + + private final ThreadTraceIdResolver resolver; + + @Override + public Runnable decorate(Runnable runnable) { + Map contextMap = MDC.getCopyOfContextMap(); + var securityContext = SecurityContextHolder.getContext(); + + return () -> { + try { + MDC.setContextMap(contextMap); + SecurityContextHolder.setContext(securityContext); + resolver.resolve(); + + runnable.run(); + } finally { + MDC.clear(); + SecurityContextHolder.clearContext(); + } + }; + } +} diff --git a/src/test/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecoratorTest.java b/src/test/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecoratorTest.java new file mode 100644 index 0000000..033ed92 --- /dev/null +++ b/src/test/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecoratorTest.java @@ -0,0 +1,52 @@ +package ee.bitweb.core.trace.thread.decorator; + +import ee.bitweb.core.trace.thread.ThreadTraceIdResolver; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.MDC; + +import static org.junit.jupiter.api.Assertions.*; + +@Tag("unit") +@ExtendWith(MockitoExtension.class) +class BasicMDCTaskDecoratorTest { + + @Mock + private ThreadTraceIdResolver resolver; + + @Test + void testMDCIsPopulatedAndCleared() { + Mockito.when(resolver.resolve()).thenReturn(null); + MDC.put("custom-key", "custom-value"); + + new BasicMDCTaskDecorator(resolver).decorate(() -> { + assertEquals("custom-value", MDC.get("custom-key")); + }).run(); + + assertNull(MDC.get("custom-key")); + + Mockito.verifyNoMoreInteractions(resolver); + } + + @Test + void testMDCIsPopulatedAndClearedWhenExceptionIsThrown() { + Mockito.when(resolver.resolve()).thenReturn(null); + MDC.put("custom-key", "custom-value"); + + try { + new BasicMDCTaskDecorator(resolver).decorate(() -> { + assertEquals("custom-value", MDC.get("custom-key")); + + throw new RuntimeException(); + }).run(); + } catch (RuntimeException ignored) { + assertNull(MDC.get("custom-key")); + } + + Mockito.verifyNoMoreInteractions(resolver); + } +} diff --git a/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java b/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java new file mode 100644 index 0000000..12edf19 --- /dev/null +++ b/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java @@ -0,0 +1,52 @@ +package ee.bitweb.core.trace.thread.decorator; + +import ee.bitweb.core.trace.thread.ThreadTraceIdResolver; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.MDC; + +import static org.junit.jupiter.api.Assertions.*; + +@Tag("unit") +@ExtendWith(MockitoExtension.class) +class SecurityAwareMDCTaskDecoratorTest { + + @Mock + private ThreadTraceIdResolver resolver; + + @Test + void testMDCIsPopulatedAndCleared() { + Mockito.when(resolver.resolve()).thenReturn(null); + MDC.put("custom-key", "custom-value"); + + new BasicMDCTaskDecorator(resolver).decorate(() -> { + assertEquals("custom-value", MDC.get("custom-key")); + }).run(); + + assertNull(MDC.get("custom-key")); + + Mockito.verifyNoMoreInteractions(resolver); + } + + @Test + void testMDCIsPopulatedAndClearedWhenExceptionIsThrown() { + Mockito.when(resolver.resolve()).thenReturn(null); + MDC.put("custom-key", "custom-value"); + + try { + new BasicMDCTaskDecorator(resolver).decorate(() -> { + assertEquals("custom-value", MDC.get("custom-key")); + + throw new RuntimeException(); + }).run(); + } catch (RuntimeException ignored) { + assertNull(MDC.get("custom-key")); + } + + Mockito.verifyNoMoreInteractions(resolver); + } +} From d2ab7d00f4ff0a77b338d54030e60950cac1e571 Mon Sep 17 00:00:00 2001 From: Rain Ramm Date: Fri, 24 May 2024 18:17:25 +0300 Subject: [PATCH 2/7] Replace MDCTaskDecorator with spring-security agnostic and basic version --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1df56df..20a3cfe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,6 +41,7 @@ jobs: - name: Upload Artifact uses: actions/upload-artifact@v4 + if: matrix.Java == '17' with: name: report path: build/reports/** From df85d812917c046fd3b1014ef1da9ebb8cdc587c Mon Sep 17 00:00:00 2001 From: Rain Ramm Date: Fri, 24 May 2024 18:18:21 +0300 Subject: [PATCH 3/7] Replace MDCTaskDecorator with spring-security agnostic and basic version --- .github/workflows/build.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 20a3cfe..73b3047 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,9 +41,8 @@ jobs: - name: Upload Artifact uses: actions/upload-artifact@v4 - if: matrix.Java == '17' with: - name: report + name: report-java-${{ matrix.Java }} path: build/reports/** retention-days: 5 From c15320c4b6e3d6dd802b72a7c5b197b9bbc934c0 Mon Sep 17 00:00:00 2001 From: Rain Ramm Date: Fri, 24 May 2024 18:24:49 +0300 Subject: [PATCH 4/7] Replace MDCTaskDecorator with spring-security agnostic and basic version --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73b3047..0186f80 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,6 +34,7 @@ jobs: run: ./gradlew testAndReport - name: Run Sonar analysis + id: matrix.Java == '17' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 499ce9998b318000b9a061617f8bbac5c89df337 Mon Sep 17 00:00:00 2001 From: Rain Ramm Date: Fri, 24 May 2024 18:28:38 +0300 Subject: [PATCH 5/7] Replace MDCTaskDecorator with spring-security agnostic and basic version --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0186f80..f624059 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,7 +34,7 @@ jobs: run: ./gradlew testAndReport - name: Run Sonar analysis - id: matrix.Java == '17' + if: matrix.Java == '17' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 7dac71bfb5d354f4b92875f21e429c6587227cc0 Mon Sep 17 00:00:00 2001 From: Rain Ramm Date: Sun, 26 May 2024 14:34:09 +0300 Subject: [PATCH 6/7] Replace MDCTaskDecorator with spring-security agnostic and basic version --- .github/dependabot.yml | 3 ++ .../core/trace/thread/MDCTaskDecorator.java | 31 +++---------------- .../SecurityAwareMDCTaskDecorator.java | 3 +- .../SecurityAwareMDCTaskDecoratorTest.java | 4 +-- 4 files changed, 11 insertions(+), 30 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a87b871..68f5d43 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,5 +1,7 @@ version: 2 + updates: + - package-ecosystem: "gradle" directory: "/" schedule: @@ -15,6 +17,7 @@ updates: update-types: - "minor" - "patch" + - package-ecosystem: "github-actions" directory: "/" schedule: diff --git a/src/main/java/ee/bitweb/core/trace/thread/MDCTaskDecorator.java b/src/main/java/ee/bitweb/core/trace/thread/MDCTaskDecorator.java index 4bfa913..9910deb 100644 --- a/src/main/java/ee/bitweb/core/trace/thread/MDCTaskDecorator.java +++ b/src/main/java/ee/bitweb/core/trace/thread/MDCTaskDecorator.java @@ -1,37 +1,14 @@ package ee.bitweb.core.trace.thread; -import lombok.RequiredArgsConstructor; -import org.slf4j.MDC; -import org.springframework.core.task.TaskDecorator; -import org.springframework.security.core.context.SecurityContextHolder; - -import java.util.Map; +import ee.bitweb.core.trace.thread.decorator.SecurityAwareMDCTaskDecorator; /** * @deprecated use BasicMDCTaskDecorator or SecurityAwareMDCTaskDecorator */ @Deprecated(since = "3.3.0", forRemoval = true) -@RequiredArgsConstructor -public class MDCTaskDecorator implements TaskDecorator { - - private final ThreadTraceIdResolver resolver; - - @Override - public Runnable decorate(Runnable runnable) { - Map contextMap = MDC.getCopyOfContextMap(); - var securityContext = SecurityContextHolder.getContext(); - - return () -> { - try { - MDC.setContextMap(contextMap); - SecurityContextHolder.setContext(securityContext); - resolver.resolve(); +public class MDCTaskDecorator extends SecurityAwareMDCTaskDecorator { - runnable.run(); - } finally { - MDC.clear(); - SecurityContextHolder.clearContext(); - } - }; + public MDCTaskDecorator(ThreadTraceIdResolver resolver) { + super(resolver); } } diff --git a/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java b/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java index 8c8ae98..5fc435d 100644 --- a/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java +++ b/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java @@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor; import org.slf4j.MDC; import org.springframework.core.task.TaskDecorator; +import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import java.util.Map; @@ -16,7 +17,7 @@ public class SecurityAwareMDCTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { Map contextMap = MDC.getCopyOfContextMap(); - var securityContext = SecurityContextHolder.getContext(); + SecurityContext securityContext = SecurityContextHolder.getContext(); return () -> { try { diff --git a/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java b/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java index 12edf19..9fd5cd4 100644 --- a/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java +++ b/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java @@ -23,7 +23,7 @@ void testMDCIsPopulatedAndCleared() { Mockito.when(resolver.resolve()).thenReturn(null); MDC.put("custom-key", "custom-value"); - new BasicMDCTaskDecorator(resolver).decorate(() -> { + new SecurityAwareMDCTaskDecorator(resolver).decorate(() -> { assertEquals("custom-value", MDC.get("custom-key")); }).run(); @@ -38,7 +38,7 @@ void testMDCIsPopulatedAndClearedWhenExceptionIsThrown() { MDC.put("custom-key", "custom-value"); try { - new BasicMDCTaskDecorator(resolver).decorate(() -> { + new SecurityAwareMDCTaskDecorator(resolver).decorate(() -> { assertEquals("custom-value", MDC.get("custom-key")); throw new RuntimeException(); From 764123354b0cad92ef5f4a23b3f3aa36aabc462b Mon Sep 17 00:00:00 2001 From: Rain Ramm Date: Mon, 27 May 2024 13:53:51 +0300 Subject: [PATCH 7/7] Replace MDCTaskDecorator with spring-security agnostic and basic version --- .../decorator/BasicMDCTaskDecorator.java | 5 +-- .../SecurityAwareMDCTaskDecorator.java | 9 ++--- .../decorator/BasicMDCTaskDecoratorTest.java | 14 ++++++++ .../SecurityAwareMDCTaskDecoratorTest.java | 34 +++++++++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/main/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecorator.java b/src/main/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecorator.java index 0a1be70..e48ded4 100644 --- a/src/main/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecorator.java +++ b/src/main/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecorator.java @@ -5,6 +5,7 @@ import org.slf4j.MDC; import org.springframework.core.task.TaskDecorator; +import java.util.HashMap; import java.util.Map; @RequiredArgsConstructor @@ -14,11 +15,11 @@ public class BasicMDCTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { - Map contextMap = MDC.getCopyOfContextMap(); + final Map contextMap = MDC.getCopyOfContextMap(); return () -> { try { - MDC.setContextMap(contextMap); + MDC.setContextMap(contextMap == null ? new HashMap<>() : contextMap); resolver.resolve(); runnable.run(); diff --git a/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java b/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java index 5fc435d..f0aff57 100644 --- a/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java +++ b/src/main/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecorator.java @@ -7,6 +7,7 @@ import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import java.util.HashMap; import java.util.Map; @RequiredArgsConstructor @@ -16,13 +17,13 @@ public class SecurityAwareMDCTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { - Map contextMap = MDC.getCopyOfContextMap(); - SecurityContext securityContext = SecurityContextHolder.getContext(); + final Map contextMap = MDC.getCopyOfContextMap(); + final SecurityContext securityContext = SecurityContextHolder.getContext(); return () -> { try { - MDC.setContextMap(contextMap); - SecurityContextHolder.setContext(securityContext); + MDC.setContextMap(contextMap == null ? new HashMap<>() : contextMap); + SecurityContextHolder.setContext(securityContext == null ? SecurityContextHolder.createEmptyContext() : securityContext); resolver.resolve(); runnable.run(); diff --git a/src/test/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecoratorTest.java b/src/test/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecoratorTest.java index 033ed92..7d42f61 100644 --- a/src/test/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecoratorTest.java +++ b/src/test/java/ee/bitweb/core/trace/thread/decorator/BasicMDCTaskDecoratorTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.MockSettings; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.slf4j.MDC; @@ -49,4 +51,16 @@ void testMDCIsPopulatedAndClearedWhenExceptionIsThrown() { Mockito.verifyNoMoreInteractions(resolver); } + + @Test + void testMDCIsPopulatedGivenMDCContextMapIsNull() { + Mockito.when(resolver.resolve()).thenReturn(null); + assertNull(MDC.getCopyOfContextMap()); + + new BasicMDCTaskDecorator(resolver).decorate(() -> { + assertNotNull(MDC.getCopyOfContextMap()); + }).run(); + + Mockito.verifyNoMoreInteractions(resolver); + } } diff --git a/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java b/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java index 9fd5cd4..22120d6 100644 --- a/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java +++ b/src/test/java/ee/bitweb/core/trace/thread/decorator/SecurityAwareMDCTaskDecoratorTest.java @@ -5,9 +5,12 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.slf4j.MDC; +import org.springframework.boot.actuate.endpoint.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; import static org.junit.jupiter.api.Assertions.*; @@ -49,4 +52,35 @@ void testMDCIsPopulatedAndClearedWhenExceptionIsThrown() { Mockito.verifyNoMoreInteractions(resolver); } + + @Test + void testMDCIsPopulatedGivenMDCContextMapIsNull() { + Mockito.when(resolver.resolve()).thenReturn(null); + assertNull(MDC.getCopyOfContextMap()); + + new SecurityAwareMDCTaskDecorator(resolver).decorate(() -> { + assertNotNull(MDC.getCopyOfContextMap()); + }).run(); + + Mockito.verifyNoMoreInteractions(resolver); + } + + @Test + void testDecorateCanHandleNullSecurityContext() { + Mockito.when(resolver.resolve()).thenReturn(null); + + Runnable task; + + try (MockedStatic holder = Mockito.mockStatic(SecurityContextHolder.class)) { + holder.when(SecurityContextHolder::getContext).thenReturn(null); + + task = new SecurityAwareMDCTaskDecorator(resolver).decorate(() -> { + assertNotNull(SecurityContextHolder.getContext()); + }); + } + + task.run(); + + Mockito.verifyNoMoreInteractions(resolver); + } }