From 2f01aae5b9b7b85d361c48a92446580b9d231cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20Rodr=C3=ADguez?= <127134616+armando-rodriguez-cko@users.noreply.github.com> Date: Tue, 12 May 2026 12:57:32 +0200 Subject: [PATCH] fix(sessions): add exemption values to ChallengeIndicator enum Restores the five exemption values defined by the POST /sessions challenge_indicator schema (low_value, trusted_listing, trusted_listing_prompt, transaction_risk_assessment, data_share) to com.checkout.common.ChallengeIndicator. They were dropped in a prior refactor that moved them to a separate Exemption enum, which broke merchant code such as: SessionRequest.builder() .challengeIndicator(ChallengeIndicator.TRANSACTION_RISK_ASSESSMENT) The five values carry a JavaDoc note indicating they are only valid for POST /sessions (3DS Standalone Authentication); the inline challenge_indicator on POST /payments three_ds and on session responses still only accepts the original four values, which the remote API enforces at runtime. Adds ChallengeIndicatorTest covering serialization, deserialization and round-trip for all nine values via the Gson serializer. --- .../checkout/common/ChallengeIndicator.java | 39 ++++++++++++++ .../common/ChallengeIndicatorTest.java | 52 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/test/java/com/checkout/common/ChallengeIndicatorTest.java diff --git a/src/main/java/com/checkout/common/ChallengeIndicator.java b/src/main/java/com/checkout/common/ChallengeIndicator.java index 1c8f995a..a9f531d6 100644 --- a/src/main/java/com/checkout/common/ChallengeIndicator.java +++ b/src/main/java/com/checkout/common/ChallengeIndicator.java @@ -2,6 +2,19 @@ import com.google.gson.annotations.SerializedName; +/** + * Indicates whether a challenge is requested for an authentication. + *

+ * The first four values are valid for all endpoints that accept a challenge indicator + * (e.g. {@code POST /payments} {@code three_ds.challenge_indicator}, {@code POST /sessions}, + * and their responses). + *

+ * The remaining values ({@link #LOW_VALUE}, {@link #TRUSTED_LISTING}, + * {@link #TRUSTED_LISTING_PROMPT}, {@link #TRANSACTION_RISK_ASSESSMENT}, {@link #DATA_SHARE}) + * represent requests for exemption and are only valid for {@code POST /sessions} + * (3DS Standalone Authentication). If an exemption cannot be applied, the value + * {@link #NO_CHALLENGE_REQUESTED} will be used instead. + */ public enum ChallengeIndicator { @SerializedName("challenge_requested") @@ -12,5 +25,31 @@ public enum ChallengeIndicator { NO_CHALLENGE_REQUESTED, @SerializedName("no_preference") NO_PREFERENCE, + /** + * Request a low-value exemption. Only valid for {@code POST /sessions}. + */ + @SerializedName("low_value") + LOW_VALUE, + /** + * Request a trusted listing exemption. Only valid for {@code POST /sessions}. + */ + @SerializedName("trusted_listing") + TRUSTED_LISTING, + /** + * Request a trusted listing prompt to add the merchant to the cardholder's trusted list. + * Only valid for {@code POST /sessions}. + */ + @SerializedName("trusted_listing_prompt") + TRUSTED_LISTING_PROMPT, + /** + * Request a transaction risk analysis (TRA) exemption. Only valid for {@code POST /sessions}. + */ + @SerializedName("transaction_risk_assessment") + TRANSACTION_RISK_ASSESSMENT, + /** + * Indicates a data-share authentication request. Only valid for {@code POST /sessions}. + */ + @SerializedName("data_share") + DATA_SHARE, } diff --git a/src/test/java/com/checkout/common/ChallengeIndicatorTest.java b/src/test/java/com/checkout/common/ChallengeIndicatorTest.java new file mode 100644 index 00000000..0d01df94 --- /dev/null +++ b/src/test/java/com/checkout/common/ChallengeIndicatorTest.java @@ -0,0 +1,52 @@ +package com.checkout.common; + +import com.checkout.GsonSerializer; +import com.checkout.Serializer; +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; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ChallengeIndicatorTest { + + private final Serializer serializer = new GsonSerializer(); + + private static Stream challengeIndicators() { + return Stream.of( + Arguments.of(ChallengeIndicator.NO_PREFERENCE, "\"no_preference\""), + Arguments.of(ChallengeIndicator.NO_CHALLENGE_REQUESTED, "\"no_challenge_requested\""), + Arguments.of(ChallengeIndicator.CHALLENGE_REQUESTED, "\"challenge_requested\""), + Arguments.of(ChallengeIndicator.CHALLENGE_REQUESTED_MANDATE, "\"challenge_requested_mandate\""), + Arguments.of(ChallengeIndicator.LOW_VALUE, "\"low_value\""), + Arguments.of(ChallengeIndicator.TRUSTED_LISTING, "\"trusted_listing\""), + Arguments.of(ChallengeIndicator.TRUSTED_LISTING_PROMPT, "\"trusted_listing_prompt\""), + Arguments.of(ChallengeIndicator.TRANSACTION_RISK_ASSESSMENT, "\"transaction_risk_assessment\""), + Arguments.of(ChallengeIndicator.DATA_SHARE, "\"data_share\"") + ); + } + + @ParameterizedTest + @MethodSource("challengeIndicators") + void shouldSerializeChallengeIndicatorToSnakeCase(final ChallengeIndicator value, final String expectedJson) { + assertEquals(expectedJson, serializer.toJson(value)); + } + + @ParameterizedTest + @MethodSource("challengeIndicators") + void shouldDeserializeChallengeIndicatorFromSnakeCase(final ChallengeIndicator expected, final String json) { + assertEquals(expected, serializer.fromJson(json, ChallengeIndicator.class)); + } + + @Test + void shouldRoundTripAllValues() { + for (final ChallengeIndicator value : ChallengeIndicator.values()) { + final String json = serializer.toJson(value); + assertEquals(value, serializer.fromJson(json, ChallengeIndicator.class)); + } + } + +}