From d0d75253c65a392ad020ef995920af26444bdff4 Mon Sep 17 00:00:00 2001 From: Kaido Hallik Date: Thu, 12 Mar 2026 15:32:32 +0200 Subject: [PATCH 1/4] Fix AuthenticationResponseMapperImpl.validateSignatureAlgorithmParameters error messages and test logged messages --- .../AuthenticationResponseMapperImpl.java | 8 +-- .../AuthenticationResponseMapperImplTest.java | 54 ++++++++++++++++++- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/main/java/ee/sk/smartid/AuthenticationResponseMapperImpl.java b/src/main/java/ee/sk/smartid/AuthenticationResponseMapperImpl.java index 75639014..b036e61e 100644 --- a/src/main/java/ee/sk/smartid/AuthenticationResponseMapperImpl.java +++ b/src/main/java/ee/sk/smartid/AuthenticationResponseMapperImpl.java @@ -4,7 +4,7 @@ * #%L * Smart ID sample Java client * %% - * Copyright (C) 2018 - 2025 SK ID Solutions AS + * Copyright (C) 2018 - 2026 SK ID Solutions AS * %% * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -220,14 +220,14 @@ private static void validateSignatureAlgorithmParameters(SessionSignature sessio } Optional maskGenHashAlgorithm = HashAlgorithm.fromString(maskGenAlgorithm.getParameters().getHashAlgorithm()); if (maskGenHashAlgorithm.isEmpty()) { - logger.error("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.hashAlgorithm' has invalid value: {}", maskGenAlgorithm.getParameters().getHashAlgorithm()); + logger.error("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' has invalid value: {}", maskGenAlgorithm.getParameters().getHashAlgorithm()); throw new UnprocessableSmartIdResponseException("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' has unsupported value"); } if (hashAlgorithm.get() != maskGenHashAlgorithm.get()) { - logger.error("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.hashAlgorithm' and 'signature.signatureAlgorithmParameters.hashAlgorithm' do not match. Expected: {}, actual: {}", + logger.error("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' and 'signature.signatureAlgorithmParameters.hashAlgorithm' do not match. Expected: {}, actual: {}", hashAlgorithm.get().getAlgorithmName(), maskGenHashAlgorithm.get().getAlgorithmName()); - throw new UnprocessableSmartIdResponseException("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.hashAlgorithm' value does not match 'signature.signatureAlgorithmParameters.hashAlgorithm' value"); + throw new UnprocessableSmartIdResponseException("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' value does not match 'signature.signatureAlgorithmParameters.hashAlgorithm' value"); } if (signatureAlgorithmParameters.getSaltLength() == null) { diff --git a/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java b/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java index a671136a..64ce5f8c 100644 --- a/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java +++ b/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java @@ -4,7 +4,7 @@ * #%L * Smart ID sample Java client * %% - * Copyright (C) 2018 - 2025 SK ID Solutions AS + * Copyright (C) 2018 - 2026 SK ID Solutions AS * %% * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -39,6 +39,11 @@ import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; +import org.slf4j.LoggerFactory; + import ee.sk.smartid.exception.UnprocessableSmartIdResponseException; import ee.sk.smartid.exception.permanent.SmartIdClientException; import ee.sk.smartid.rest.dao.SessionCertificate; @@ -54,6 +59,8 @@ class AuthenticationResponseMapperImplTest { private static final String AUTH_CERT = FileUtil.readFileToString("test-certs/auth-cert-40504040001.pem.crt"); + private static final Logger authenticationResponseMapperImplLogger = (Logger) LoggerFactory.getLogger(AuthenticationResponseMapperImpl.class); + private AuthenticationResponseMapper authenticationResponseMapper; @BeforeEach @@ -438,7 +445,12 @@ void from_hashAlgorithmIsInvalid_throwException(String invalidHashAlgorithm) { var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); + ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); + var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); + + assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.hashAlgorithm' has invalid value: " + invalidHashAlgorithm); + assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.hashAlgorithm' has unsupported value", exception.getMessage()); } @@ -486,7 +498,12 @@ void from_algorithmValueInMaskGenAlgorithmIsInvalid_throwException() { var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); + ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); + var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); + + assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm' has invalid value: " + maskGenAlgorithm.getAlgorithm()); + assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm' has unsupported value", exception.getMessage()); } @@ -548,7 +565,12 @@ void from_hashAlgorithmInMaskGenAlgorithmParametersInvalid_throwException(String var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); + ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); + var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); + + assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' has invalid value: " + maskGenAlgorithmParameters.getHashAlgorithm()); + assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' has unsupported value", exception.getMessage()); } @@ -569,8 +591,13 @@ void from_hashAlgorithmInMaskGenAlgorithmDoesNotMatchSignaturesHashAlgorithm_thr var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); + ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); + var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); - assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.hashAlgorithm' value does not match 'signature.signatureAlgorithmParameters.hashAlgorithm' value", exception.getMessage()); + + assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' and 'signature.signatureAlgorithmParameters.hashAlgorithm' do not match. Expected: SHA3-512, actual: SHA-512"); + + assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' value does not match 'signature.signatureAlgorithmParameters.hashAlgorithm' value", exception.getMessage()); } @Test @@ -607,7 +634,12 @@ void from_saltLengthDoesNotMatchHashAlgorithmOctetLength_throwException() { var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); + ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); + var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); + + assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.saltLength' has invalid value. Expected: 64, actual: 20"); + assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.saltLength' has invalid value", exception.getMessage()); } @@ -648,7 +680,12 @@ void from_trailerFieldValueIsInvalid_throwException() { var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); + ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); + var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); + + assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.trailerField' has invalid value: invalid"); + assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.trailerField' has unsupported value", exception.getMessage()); } @@ -834,4 +871,17 @@ private static SessionStatus toSessionStatus(SessionResult sessionResult, Sessio sessionStatus.setDeviceIpAddress("0.0.0.0"); return sessionStatus; } + + private static ListAppender getAuthenticationResponseMapperImplLoggerListAppender() { + ListAppender listAppender = new ListAppender<>(); + listAppender.start(); + authenticationResponseMapperImplLogger.addAppender(listAppender); + return listAppender; + } + + private void assertSingleLogAndDetachLoggerAppender(ListAppender listAppender, String message) { + assertEquals(1, listAppender.list.size()); + assertEquals(message, listAppender.list.get(0).getFormattedMessage()); + authenticationResponseMapperImplLogger.detachAppender(listAppender); + } } From 388ef4393a0fec00f470b72cb14cb77577a7b315 Mon Sep 17 00:00:00 2001 From: Kaido Hallik Date: Thu, 12 Mar 2026 21:58:00 +0200 Subject: [PATCH 2/4] Add and use general log spy classes --- .../AuthenticationResponseMapperImplTest.java | 51 ++++---------- .../java/ee/sk/smartid/util/log/Logs.java | 13 ++++ .../java/ee/sk/smartid/util/log/LogsSpy.java | 68 +++++++++++++++++++ .../sk/smartid/util/log/LogsSpyExtension.java | 68 +++++++++++++++++++ 4 files changed, 163 insertions(+), 37 deletions(-) create mode 100644 src/test/java/ee/sk/smartid/util/log/Logs.java create mode 100644 src/test/java/ee/sk/smartid/util/log/LogsSpy.java create mode 100644 src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java diff --git a/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java b/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java index 64ce5f8c..937fd8b6 100644 --- a/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java +++ b/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java @@ -30,20 +30,17 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import ch.qos.logback.classic.Level; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.read.ListAppender; -import org.slf4j.LoggerFactory; - import ee.sk.smartid.exception.UnprocessableSmartIdResponseException; import ee.sk.smartid.exception.permanent.SmartIdClientException; import ee.sk.smartid.rest.dao.SessionCertificate; @@ -54,12 +51,17 @@ import ee.sk.smartid.rest.dao.SessionSignature; import ee.sk.smartid.rest.dao.SessionSignatureAlgorithmParameters; import ee.sk.smartid.rest.dao.SessionStatus; +import ee.sk.smartid.util.log.Logs; +import ee.sk.smartid.util.log.LogsSpy; +import ee.sk.smartid.util.log.LogsSpyExtension; +@ExtendWith(LogsSpyExtension.class) class AuthenticationResponseMapperImplTest { private static final String AUTH_CERT = FileUtil.readFileToString("test-certs/auth-cert-40504040001.pem.crt"); - private static final Logger authenticationResponseMapperImplLogger = (Logger) LoggerFactory.getLogger(AuthenticationResponseMapperImpl.class); + @Logs + private LogsSpy logs; private AuthenticationResponseMapper authenticationResponseMapper; @@ -445,11 +447,9 @@ void from_hashAlgorithmIsInvalid_throwException(String invalidHashAlgorithm) { var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); - ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); - var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); - assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.hashAlgorithm' has invalid value: " + invalidHashAlgorithm); + logs.shouldHave(Level.ERROR, "Authentication session status field 'signature.signatureAlgorithmParameters.hashAlgorithm' has invalid value: " + invalidHashAlgorithm); assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.hashAlgorithm' has unsupported value", exception.getMessage()); } @@ -498,11 +498,9 @@ void from_algorithmValueInMaskGenAlgorithmIsInvalid_throwException() { var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); - ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); - var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); - assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm' has invalid value: " + maskGenAlgorithm.getAlgorithm()); + logs.shouldHave(Level.ERROR, "Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm' has invalid value: " + maskGenAlgorithm.getAlgorithm()); assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm' has unsupported value", exception.getMessage()); } @@ -565,11 +563,9 @@ void from_hashAlgorithmInMaskGenAlgorithmParametersInvalid_throwException(String var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); - ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); - var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); - assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' has invalid value: " + maskGenAlgorithmParameters.getHashAlgorithm()); + logs.shouldHave(Level.ERROR, "Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' has invalid value: " + maskGenAlgorithmParameters.getHashAlgorithm()); assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' has unsupported value", exception.getMessage()); } @@ -591,11 +587,9 @@ void from_hashAlgorithmInMaskGenAlgorithmDoesNotMatchSignaturesHashAlgorithm_thr var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); - ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); - var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); - assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' and 'signature.signatureAlgorithmParameters.hashAlgorithm' do not match. Expected: SHA3-512, actual: SHA-512"); + logs.shouldHave(Level.ERROR, "Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' and 'signature.signatureAlgorithmParameters.hashAlgorithm' do not match. Expected: SHA3-512, actual: SHA-512"); assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.maskGenAlgorithm.parameters.hashAlgorithm' value does not match 'signature.signatureAlgorithmParameters.hashAlgorithm' value", exception.getMessage()); } @@ -634,11 +628,9 @@ void from_saltLengthDoesNotMatchHashAlgorithmOctetLength_throwException() { var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); - ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); - var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); - assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.saltLength' has invalid value. Expected: 64, actual: 20"); + logs.shouldHave(Level.ERROR, "Authentication session status field 'signature.signatureAlgorithmParameters.saltLength' has invalid value. Expected: 64, actual: 20"); assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.saltLength' has invalid value", exception.getMessage()); } @@ -680,11 +672,9 @@ void from_trailerFieldValueIsInvalid_throwException() { var sessionSignature = toSessionSignature(signatureAlgorithmParameters); var sessionStatus = toSessionStatus(sessionResult, sessionSignature); - ListAppender listAppender = getAuthenticationResponseMapperImplLoggerListAppender(); - var exception = assertThrows(UnprocessableSmartIdResponseException.class, () -> authenticationResponseMapper.from(sessionStatus)); - assertSingleLogAndDetachLoggerAppender(listAppender, "Authentication session status field 'signature.signatureAlgorithmParameters.trailerField' has invalid value: invalid"); + logs.shouldHave(Level.ERROR, "Authentication session status field 'signature.signatureAlgorithmParameters.trailerField' has invalid value: invalid"); assertEquals("Authentication session status field 'signature.signatureAlgorithmParameters.trailerField' has unsupported value", exception.getMessage()); } @@ -871,17 +861,4 @@ private static SessionStatus toSessionStatus(SessionResult sessionResult, Sessio sessionStatus.setDeviceIpAddress("0.0.0.0"); return sessionStatus; } - - private static ListAppender getAuthenticationResponseMapperImplLoggerListAppender() { - ListAppender listAppender = new ListAppender<>(); - listAppender.start(); - authenticationResponseMapperImplLogger.addAppender(listAppender); - return listAppender; - } - - private void assertSingleLogAndDetachLoggerAppender(ListAppender listAppender, String message) { - assertEquals(1, listAppender.list.size()); - assertEquals(message, listAppender.list.get(0).getFormattedMessage()); - authenticationResponseMapperImplLogger.detachAppender(listAppender); - } } diff --git a/src/test/java/ee/sk/smartid/util/log/Logs.java b/src/test/java/ee/sk/smartid/util/log/Logs.java new file mode 100644 index 00000000..50f11a52 --- /dev/null +++ b/src/test/java/ee/sk/smartid/util/log/Logs.java @@ -0,0 +1,13 @@ +package ee.sk.smartid.util.log; + +import org.junit.jupiter.api.extension.ExtendWith; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.FIELD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(LogsSpyExtension.class) +public @interface Logs {} diff --git a/src/test/java/ee/sk/smartid/util/log/LogsSpy.java b/src/test/java/ee/sk/smartid/util/log/LogsSpy.java new file mode 100644 index 00000000..dbb8154e --- /dev/null +++ b/src/test/java/ee/sk/smartid/util/log/LogsSpy.java @@ -0,0 +1,68 @@ +package ee.sk.smartid.util.log; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.function.Predicate; + +public final class LogsSpy { + + private Logger logger; + private ListAppender appender; + private Level initialLevel; + + void prepare() { + appender = new ListAppender<>(); + logger = (Logger) LoggerFactory.getLogger("ee.sk.smartid"); + logger.addAppender(appender); + initialLevel = logger.getLevel(); + logger.setLevel(Level.TRACE); + appender.start(); + } + + void reset() { + logger.setLevel(initialLevel); + logger.detachAppender(appender); + } + + public LogsSpy shouldHave(Level level, String content) { + boolean found = logEvents().stream().anyMatch(withLog(level, content)); + assertTrue(found, "Expected at least one log entry with level " + level + " and content: " + content); + + return this; + } + + public LogsSpy shouldHave(Level level, String content, int count) { + long actualCount = logEvents().stream() + .filter(withLog(level, content)) + .count(); + + assertEquals(count, actualCount, "Expected " + count + " log entries with level " + level + " and content: " + content); + + return this; + } + + public LogsSpy shouldNotHave(Level level, String content) { + boolean found = logEvents().stream().anyMatch(withLog(level, content)); + assertFalse(found, "Expected no log entries with level " + level + " and content: " + content); + + return this; + } + + private List logEvents() { + // Copy the list to avoid concurrent modification exceptions + return List.copyOf(appender.list); + } + + private Predicate withLog(Level level, String content) { + return event -> level.equals(event.getLevel()) && event.toString().contains(content); + } +} diff --git a/src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java b/src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java new file mode 100644 index 00000000..820411f3 --- /dev/null +++ b/src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java @@ -0,0 +1,68 @@ +package ee.sk.smartid.util.log; + +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.junit.jupiter.api.extension.TestInstancePostProcessor; +import org.junit.platform.commons.support.ModifierSupport; + +import java.lang.reflect.Field; +import java.util.function.Predicate; + +import static org.junit.platform.commons.util.AnnotationUtils.findAnnotatedFields; + +public final class LogsSpyExtension + implements BeforeAllCallback, BeforeEachCallback, AfterEachCallback, ParameterResolver, TestInstancePostProcessor { + + private final LogsSpy logsSpy = new LogsSpy(); + + @Override + public void beforeEach(ExtensionContext context) { + logsSpy.prepare(); + } + + @Override + public void afterEach(ExtensionContext context) { + logsSpy.reset(); + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return parameterContext.getParameter().getType().equals(LogsSpy.class); + } + + @Override + public LogsSpy resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return logsSpy; + } + + @Override + public void beforeAll(ExtensionContext context) { + Class testClass = context.getRequiredTestClass(); + injectFields(testClass, null, ModifierSupport::isStatic); + } + + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext context) { + Class testClass = context.getRequiredTestClass(); + injectFields(testClass, testInstance, ModifierSupport::isNotStatic); + } + + private void injectFields(Class testClass, Object testInstance, Predicate predicate) { + predicate = predicate.and(field -> LogsSpy.class.isAssignableFrom(field.getType())); + findAnnotatedFields(testClass, Logs.class, predicate).forEach(field -> { + try { + field.setAccessible(true); + field.set(testInstance, logsSpy); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + }); + } +} From 4b5fcc339aca57cf8441b2e3ca3bf4124fa5a4ca Mon Sep 17 00:00:00 2001 From: Kaido Hallik Date: Thu, 12 Mar 2026 22:20:34 +0200 Subject: [PATCH 3/4] Add license headers --- .../java/ee/sk/smartid/util/log/Logs.java | 26 +++++++++++++++++++ .../java/ee/sk/smartid/util/log/LogsSpy.java | 26 +++++++++++++++++++ .../sk/smartid/util/log/LogsSpyExtension.java | 26 +++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/src/test/java/ee/sk/smartid/util/log/Logs.java b/src/test/java/ee/sk/smartid/util/log/Logs.java index 50f11a52..27533fa9 100644 --- a/src/test/java/ee/sk/smartid/util/log/Logs.java +++ b/src/test/java/ee/sk/smartid/util/log/Logs.java @@ -1,5 +1,31 @@ package ee.sk.smartid.util.log; +/*- + * #%L + * Smart ID sample Java client + * %% + * Copyright (C) 2018 - 2026 SK ID Solutions AS + * %% + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * #L% + */ + import org.junit.jupiter.api.extension.ExtendWith; import java.lang.annotation.ElementType; diff --git a/src/test/java/ee/sk/smartid/util/log/LogsSpy.java b/src/test/java/ee/sk/smartid/util/log/LogsSpy.java index dbb8154e..90876bb0 100644 --- a/src/test/java/ee/sk/smartid/util/log/LogsSpy.java +++ b/src/test/java/ee/sk/smartid/util/log/LogsSpy.java @@ -1,5 +1,31 @@ package ee.sk.smartid.util.log; +/*- + * #%L + * Smart ID sample Java client + * %% + * Copyright (C) 2018 - 2026 SK ID Solutions AS + * %% + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * #L% + */ + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java b/src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java index 820411f3..c4fcfce5 100644 --- a/src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java +++ b/src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java @@ -1,5 +1,31 @@ package ee.sk.smartid.util.log; +/*- + * #%L + * Smart ID sample Java client + * %% + * Copyright (C) 2018 - 2026 SK ID Solutions AS + * %% + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * #L% + */ + import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; From 2728e9993a45f745c3b9ea9dcaceaffcfed9a09e Mon Sep 17 00:00:00 2001 From: Kaido Hallik Date: Fri, 13 Mar 2026 09:28:57 +0200 Subject: [PATCH 4/4] Move LogSpy classes into testhelper.log package --- .../ee/sk/smartid/AuthenticationResponseMapperImplTest.java | 6 +++--- .../java/ee/sk/smartid/{util => testhelper}/log/Logs.java | 2 +- .../ee/sk/smartid/{util => testhelper}/log/LogsSpy.java | 2 +- .../smartid/{util => testhelper}/log/LogsSpyExtension.java | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/test/java/ee/sk/smartid/{util => testhelper}/log/Logs.java (97%) rename src/test/java/ee/sk/smartid/{util => testhelper}/log/LogsSpy.java (98%) rename src/test/java/ee/sk/smartid/{util => testhelper}/log/LogsSpyExtension.java (98%) diff --git a/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java b/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java index 937fd8b6..a2b5bb2a 100644 --- a/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java +++ b/src/test/java/ee/sk/smartid/AuthenticationResponseMapperImplTest.java @@ -51,9 +51,9 @@ import ee.sk.smartid.rest.dao.SessionSignature; import ee.sk.smartid.rest.dao.SessionSignatureAlgorithmParameters; import ee.sk.smartid.rest.dao.SessionStatus; -import ee.sk.smartid.util.log.Logs; -import ee.sk.smartid.util.log.LogsSpy; -import ee.sk.smartid.util.log.LogsSpyExtension; +import ee.sk.smartid.testhelper.log.Logs; +import ee.sk.smartid.testhelper.log.LogsSpy; +import ee.sk.smartid.testhelper.log.LogsSpyExtension; @ExtendWith(LogsSpyExtension.class) class AuthenticationResponseMapperImplTest { diff --git a/src/test/java/ee/sk/smartid/util/log/Logs.java b/src/test/java/ee/sk/smartid/testhelper/log/Logs.java similarity index 97% rename from src/test/java/ee/sk/smartid/util/log/Logs.java rename to src/test/java/ee/sk/smartid/testhelper/log/Logs.java index 27533fa9..89d5c5d4 100644 --- a/src/test/java/ee/sk/smartid/util/log/Logs.java +++ b/src/test/java/ee/sk/smartid/testhelper/log/Logs.java @@ -1,4 +1,4 @@ -package ee.sk.smartid.util.log; +package ee.sk.smartid.testhelper.log; /*- * #%L diff --git a/src/test/java/ee/sk/smartid/util/log/LogsSpy.java b/src/test/java/ee/sk/smartid/testhelper/log/LogsSpy.java similarity index 98% rename from src/test/java/ee/sk/smartid/util/log/LogsSpy.java rename to src/test/java/ee/sk/smartid/testhelper/log/LogsSpy.java index 90876bb0..19808efa 100644 --- a/src/test/java/ee/sk/smartid/util/log/LogsSpy.java +++ b/src/test/java/ee/sk/smartid/testhelper/log/LogsSpy.java @@ -1,4 +1,4 @@ -package ee.sk.smartid.util.log; +package ee.sk.smartid.testhelper.log; /*- * #%L diff --git a/src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java b/src/test/java/ee/sk/smartid/testhelper/log/LogsSpyExtension.java similarity index 98% rename from src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java rename to src/test/java/ee/sk/smartid/testhelper/log/LogsSpyExtension.java index c4fcfce5..2fa41c38 100644 --- a/src/test/java/ee/sk/smartid/util/log/LogsSpyExtension.java +++ b/src/test/java/ee/sk/smartid/testhelper/log/LogsSpyExtension.java @@ -1,4 +1,4 @@ -package ee.sk.smartid.util.log; +package ee.sk.smartid.testhelper.log; /*- * #%L