From 4a9cffbaa5e131cc427c2255818fc98c884f6579 Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer Date: Thu, 4 Jan 2024 07:33:03 +0100 Subject: feat #17: initial support for request retry --- .../dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt | 8 ++++++-- .../kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src/test/kotlin/dev') diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt index 3ec9757..9945538 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt @@ -1,7 +1,7 @@ /* * This file is part of ETL-Processor * - * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors + * Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -35,6 +35,8 @@ import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.* import org.springframework.kafka.core.KafkaTemplate import org.springframework.kafka.support.SendResult +import org.springframework.retry.policy.SimpleRetryPolicy +import org.springframework.retry.support.RetryTemplateBuilder import java.util.concurrent.CompletableFuture.completedFuture import java.util.concurrent.ExecutionException @@ -52,10 +54,12 @@ class KafkaMtbFileSenderTest { @Mock kafkaTemplate: KafkaTemplate ) { val kafkaTargetProperties = KafkaTargetProperties("testtopic") + val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(1)).build() + this.objectMapper = ObjectMapper() this.kafkaTemplate = kafkaTemplate - this.kafkaMtbFileSender = KafkaMtbFileSender(kafkaTemplate, kafkaTargetProperties, objectMapper) + this.kafkaMtbFileSender = KafkaMtbFileSender(kafkaTemplate, kafkaTargetProperties, retryTemplate, objectMapper) } @ParameterizedTest diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt index 0cad285..e39c61b 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt @@ -1,7 +1,7 @@ /* * This file is part of ETL-Processor * - * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors + * Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -28,6 +28,8 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus +import org.springframework.retry.policy.SimpleRetryPolicy +import org.springframework.retry.support.RetryTemplateBuilder import org.springframework.test.web.client.MockRestServiceServer import org.springframework.test.web.client.match.MockRestRequestMatchers.method import org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo @@ -44,10 +46,11 @@ class RestMtbFileSenderTest { fun setup() { val restTemplate = RestTemplate() val restTargetProperties = RestTargetProperties("http://localhost:9000/mtbfile") + val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(1)).build() this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) - this.restMtbFileSender = RestMtbFileSender(restTemplate, restTargetProperties) + this.restMtbFileSender = RestMtbFileSender(restTemplate, restTargetProperties, retryTemplate) } @ParameterizedTest -- cgit v1.2.3 From c892ff24613bbe600458aa8a0abfb2b96d1092e1 Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer Date: Thu, 4 Jan 2024 11:50:39 +0100 Subject: test #17: add tests for retry --- .../etl/processor/output/KafkaMtbFileSenderTest.kt | 52 +++++++++++++++++++ .../etl/processor/output/RestMtbFileSenderTest.kt | 59 ++++++++++++++++++++++ 2 files changed, 111 insertions(+) (limited to 'src/test/kotlin/dev') diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt index 9945538..d0f7c30 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/KafkaMtbFileSenderTest.kt @@ -122,6 +122,58 @@ class KafkaMtbFileSenderTest { assertThat(captor.secondValue).isEqualTo(objectMapper.writeValueAsString(kafkaRecordData("TestID", Consent.Status.REJECTED))) } + @ParameterizedTest + @MethodSource("requestWithResponseSource") + fun shouldRetryOnMtbFileKafkaSendError(testData: TestData) { + val kafkaTargetProperties = KafkaTargetProperties("testtopic") + val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(3)).build() + this.kafkaMtbFileSender = KafkaMtbFileSender(this.kafkaTemplate, kafkaTargetProperties, retryTemplate, this.objectMapper) + + doAnswer { + if (null != testData.exception) { + throw testData.exception + } + completedFuture(SendResult(null, null)) + }.whenever(kafkaTemplate).send(anyString(), anyString(), anyString()) + + kafkaMtbFileSender.send(MtbFileSender.MtbFileRequest("TestID", mtbFile(Consent.Status.ACTIVE))) + + val expectedCount = when (testData.exception) { + // OK - No Retry + null -> times(1) + // Request failed - Retry max 3 times + else -> times(3) + } + + verify(kafkaTemplate, expectedCount).send(anyString(), anyString(), anyString()) + } + + @ParameterizedTest + @MethodSource("requestWithResponseSource") + fun shouldRetryOnDeleteKafkaSendError(testData: TestData) { + val kafkaTargetProperties = KafkaTargetProperties("testtopic") + val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(3)).build() + this.kafkaMtbFileSender = KafkaMtbFileSender(this.kafkaTemplate, kafkaTargetProperties, retryTemplate, this.objectMapper) + + doAnswer { + if (null != testData.exception) { + throw testData.exception + } + completedFuture(SendResult(null, null)) + }.whenever(kafkaTemplate).send(anyString(), anyString(), anyString()) + + kafkaMtbFileSender.send(MtbFileSender.DeleteRequest("TestID", "PID")) + + val expectedCount = when (testData.exception) { + // OK - No Retry + null -> times(1) + // Request failed - Retry max 3 times + else -> times(3) + } + + verify(kafkaTemplate, expectedCount).send(anyString(), anyString(), anyString()) + } + companion object { fun mtbFile(consentStatus: Consent.Status): MtbFile { return if (consentStatus == Consent.Status.ACTIVE) { diff --git a/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt index e39c61b..df19ddb 100644 --- a/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt +++ b/src/test/kotlin/dev/dnpm/etl/processor/output/RestMtbFileSenderTest.kt @@ -30,6 +30,7 @@ import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus import org.springframework.retry.policy.SimpleRetryPolicy import org.springframework.retry.support.RetryTemplateBuilder +import org.springframework.test.web.client.ExpectedCount import org.springframework.test.web.client.MockRestServiceServer import org.springframework.test.web.client.match.MockRestRequestMatchers.method import org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo @@ -83,6 +84,64 @@ class RestMtbFileSenderTest { assertThat(response.body).isEqualTo(requestWithResponse.response.body) } + @ParameterizedTest + @MethodSource("mtbFileRequestWithResponseSource") + fun shouldRetryOnMtbFileHttpRequestError(requestWithResponse: RequestWithResponse) { + val restTemplate = RestTemplate() + val restTargetProperties = RestTargetProperties("http://localhost:9000/mtbfile") + val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(3)).build() + + this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) + this.restMtbFileSender = RestMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + + val expectedCount = when (requestWithResponse.httpStatus) { + // OK - No Retry + HttpStatus.OK, HttpStatus.CREATED -> ExpectedCount.max(1) + // Request failed - Retry max 3 times + else -> ExpectedCount.max(3) + } + + this.mockRestServiceServer.expect(expectedCount) { + method(HttpMethod.POST) + requestTo("/mtbfile") + }.andRespond { + withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) + } + + val response = restMtbFileSender.send(MtbFileSender.MtbFileRequest("TestID", mtbFile)) + assertThat(response.status).isEqualTo(requestWithResponse.response.status) + assertThat(response.body).isEqualTo(requestWithResponse.response.body) + } + + @ParameterizedTest + @MethodSource("deleteRequestWithResponseSource") + fun shouldRetryOnDeleteHttpRequestError(requestWithResponse: RequestWithResponse) { + val restTemplate = RestTemplate() + val restTargetProperties = RestTargetProperties("http://localhost:9000/mtbfile") + val retryTemplate = RetryTemplateBuilder().customPolicy(SimpleRetryPolicy(3)).build() + + this.mockRestServiceServer = MockRestServiceServer.createServer(restTemplate) + this.restMtbFileSender = RestMtbFileSender(restTemplate, restTargetProperties, retryTemplate) + + val expectedCount = when (requestWithResponse.httpStatus) { + // OK - No Retry + HttpStatus.OK, HttpStatus.CREATED -> ExpectedCount.max(1) + // Request failed - Retry max 3 times + else -> ExpectedCount.max(3) + } + + this.mockRestServiceServer.expect(expectedCount) { + method(HttpMethod.DELETE) + requestTo("/mtbfile") + }.andRespond { + withStatus(requestWithResponse.httpStatus).body(requestWithResponse.body).createResponse(it) + } + + val response = restMtbFileSender.send(MtbFileSender.DeleteRequest("TestID", "PID")) + assertThat(response.status).isEqualTo(requestWithResponse.response.status) + assertThat(response.body).isEqualTo(requestWithResponse.response.body) + } + companion object { data class RequestWithResponse( val httpStatus: HttpStatus, -- cgit v1.2.3