From 6e49df6a419f8b25501e074d06fb7e3dd50381f4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 13 Aug 2026 06:22:12 +0900 Subject: [PATCH] test(etl): reproduce invalid amount coercion --- .../EtlServiceAmountIntegrityTest.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 etl-service/src/test/java/com/xtrmetl/etl/service/EtlServiceAmountIntegrityTest.java diff --git a/etl-service/src/test/java/com/xtrmetl/etl/service/EtlServiceAmountIntegrityTest.java b/etl-service/src/test/java/com/xtrmetl/etl/service/EtlServiceAmountIntegrityTest.java new file mode 100644 index 00000000..d905af5d --- /dev/null +++ b/etl-service/src/test/java/com/xtrmetl/etl/service/EtlServiceAmountIntegrityTest.java @@ -0,0 +1,71 @@ +package com.xtrmetl.etl.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.jdbc.core.JdbcTemplate; + +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; + +/** + * Proves that invalid monetary input is rejected rather than converted into a legitimate zero. + */ +class EtlServiceAmountIntegrityTest { + + private JdbcTemplate jdbcTemplate; + private EtlService etlService; + + @BeforeEach + void setUp() { + jdbcTemplate = mock(JdbcTemplate.class); + EtlBatchProperties properties = new EtlBatchProperties(); + properties.setMaxPayloadBytes(65_536); + properties.setMaxBatchRecords(100); + etlService = new EtlService(jdbcTemplate, new ObjectMapper(), properties); + } + + @ParameterizedTest + @ValueSource(strings = { + "", + "not-a-number", + "123456789012345678901234567890123456789", + "0.0000000000000000001", + "1E+19" + }) + void rejectsInvalidOrUnsupportedAmountsBeforeJdbc(String amount) { + EtlRequestException exception = assertThrows( + EtlRequestException.class, + () -> etlService.processData(jsonRecord("record_alpha", amount)) + ); + + assertSame(EtlRequestError.INVALID_RECORD, exception.error()); + verifyNoInteractions(jdbcTemplate); + } + + @Test + void invalidAmountMakesTheWholeBatchFailBeforeAnyJdbcWrite() { + String payload = """ + [ + {"id":"record_alpha","amount":"10.00"}, + {"id":"record_beta","amount":"not-a-number"} + ] + """; + + EtlRequestException exception = assertThrows( + EtlRequestException.class, + () -> etlService.processData(payload) + ); + + assertSame(EtlRequestError.INVALID_RECORD, exception.error()); + verifyNoInteractions(jdbcTemplate); + } + + private static String jsonRecord(String id, String amount) { + return "[{\"id\":\"" + id + "\",\"amount\":\"" + amount + "\"}]"; + } +}