Skip to content

Commit fe336b1

Browse files
author
Shikhar Tanwar
committed
Add unit tests
1 parent 79e6014 commit fe336b1

3 files changed

Lines changed: 315 additions & 0 deletions

File tree

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2017 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
package com.adobe.aio.exception.feign;
13+
14+
import static com.adobe.aio.util.feign.FeignTestUtils.DEFAULT_RETRY_AFTER_SECONDS_STR;
15+
import static com.adobe.aio.util.feign.FeignTestUtils.create429Response;
16+
import static com.adobe.aio.util.feign.FeignTestUtils.createResponseWithEmptyHeaders;
17+
import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
import static org.junit.jupiter.api.Assertions.assertTrue;
20+
21+
import feign.FeignException;
22+
import feign.Response;
23+
import java.time.ZonedDateTime;
24+
import org.junit.jupiter.api.Test;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
27+
28+
class RetryAfterErrorTest {
29+
30+
private static final String TEST_REQUEST_ID = "test-request-id";
31+
private static final String TEST_METHOD = "testMethod";
32+
private static final Logger logger = LoggerFactory.getLogger(RetryAfterErrorTest.class);
33+
34+
@Test
35+
void testRetryAfterErrorCreation() {
36+
Response response = create429Response(DEFAULT_RETRY_AFTER_SECONDS_STR);
37+
RetryAfterError retryAfterError = createRetryAfterError(response, DEFAULT_RETRY_AFTER_SECONDS_STR);
38+
39+
// Test basic properties
40+
assertBasicProperties(retryAfterError);
41+
42+
// Test retry-after functionality (delay-seconds format)
43+
assertEquals(60L, retryAfterError.getRetryAfterInSeconds());
44+
45+
// Test request ID
46+
assertRequestIdProperties(retryAfterError);
47+
}
48+
49+
@Test
50+
void testRetryAfterErrorWithoutRetryAfter() {
51+
Response response = createResponseWithEmptyHeaders(429, "Too Many Requests");
52+
RetryAfterError retryAfterError = createRetryAfterError(response, null);
53+
54+
// Test retry-after functionality when not available
55+
assertEquals(0L, retryAfterError.getRetryAfterInSeconds());
56+
}
57+
58+
@Test
59+
void testRetryAfterErrorWithInvalidRetryAfter() {
60+
Response response = createResponseWithEmptyHeaders(429, "Too Many Requests");
61+
RetryAfterError retryAfterError = createRetryAfterError(response, "invalid");
62+
63+
// Test retry-after functionality with invalid value
64+
assertEquals(0L, retryAfterError.getRetryAfterInSeconds()); // Should return 0 for invalid values
65+
}
66+
67+
@Test
68+
void testRetryAfterErrorWithHttpDate() {
69+
Response response = createResponseWithEmptyHeaders(429, "Too Many Requests");
70+
String httpDate = "Fri, 31 Dec 1999 23:59:59 GMT";
71+
RetryAfterError retryAfterError = createRetryAfterError(response, httpDate);
72+
73+
// Test with HTTP-date format (past date)
74+
assertEquals(0L, retryAfterError.getRetryAfterInSeconds()); // Past date should return 0
75+
}
76+
77+
@Test
78+
void testRetryAfterErrorWithFutureHttpDate() {
79+
Response response = createResponseWithEmptyHeaders(429, "Too Many Requests");
80+
// Add a day to get a future date
81+
ZonedDateTime futureDate = ZonedDateTime.now().plusDays(1);
82+
83+
// Format using RFC 1123 formatter
84+
String formattedFutureDate = futureDate.format(RFC_1123_DATE_TIME);
85+
logger.info("Future date: {}", formattedFutureDate);
86+
87+
RetryAfterError retryAfterError = createRetryAfterError(response, formattedFutureDate);
88+
89+
// Should return a positive number of seconds until the future date
90+
long retrySeconds = retryAfterError.getRetryAfterInSeconds();
91+
assertTrue(retrySeconds > 0, "Should return positive seconds for future date");
92+
assertEquals(24 * 60 * 60, retrySeconds);
93+
}
94+
95+
// Helper methods for creating test objects and assertions
96+
97+
private RetryAfterError createRetryAfterError(Response response, String retryAfter) {
98+
FeignException originalException = FeignException.errorStatus(TEST_METHOD, response);
99+
return new RetryAfterError(response, originalException, TEST_REQUEST_ID, retryAfter);
100+
}
101+
102+
private void assertBasicProperties(RetryAfterError retryAfterError) {
103+
assertEquals(429, retryAfterError.status());
104+
assertTrue(retryAfterError.getMessage().contains("Rate limit exceeded"));
105+
assertTrue(retryAfterError.getMessage().contains(TEST_REQUEST_ID));
106+
assertTrue(retryAfterError.getMessage().contains(DEFAULT_RETRY_AFTER_SECONDS_STR));
107+
}
108+
109+
private void assertRequestIdProperties(RetryAfterError retryAfterError) {
110+
assertTrue(retryAfterError.getUpStreamRequestId().isPresent());
111+
assertEquals(RetryAfterErrorTest.TEST_REQUEST_ID, retryAfterError.getUpStreamRequestId().get());
112+
}
113+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2017 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
package com.adobe.aio.util.feign;
13+
14+
import feign.Request;
15+
import feign.Response;
16+
import java.util.Collections;
17+
import java.util.HashMap;
18+
import java.util.Map;
19+
20+
/**
21+
* Utility class for creating test objects in Feign-related tests
22+
*/
23+
public class FeignTestUtils {
24+
25+
private static final String DEFAULT_URL = "http://test.com";
26+
public static final String DEFAULT_REQUEST_ID = "test-request-id";
27+
public static final String DEFAULT_RETRY_AFTER_SECONDS_STR = "60";
28+
29+
private FeignTestUtils() {
30+
// Utility class - prevent instantiation
31+
throw new IllegalStateException("Utility class must not be instantiated");
32+
}
33+
34+
/**
35+
* Creates a basic HTTP request for testing
36+
*/
37+
public static Request createBasicRequest() {
38+
return Request.create(Request.HttpMethod.GET, DEFAULT_URL, new HashMap<>(), null, null, null);
39+
}
40+
41+
/**
42+
* Creates a response builder with common defaults
43+
*/
44+
public static Response.Builder createResponseBuilder(int status, String reason) {
45+
return Response.builder().status(status).reason(reason).request(createBasicRequest());
46+
}
47+
48+
/**
49+
* Creates a response with retry-after and request-id headers
50+
*/
51+
public static Response createResponseWithHeaders(int status, String reason, String retryAfter,
52+
String requestId) {
53+
Map<String, java.util.Collection<String>> headers = new HashMap<>();
54+
if (retryAfter != null) {
55+
headers.put("retry-after", Collections.singletonList(retryAfter));
56+
}
57+
if (requestId != null) {
58+
headers.put("x-request-id", Collections.singletonList(requestId));
59+
}
60+
61+
return createResponseBuilder(status, reason).headers(headers).build();
62+
}
63+
64+
/**
65+
* Creates a 429 response with retry-after header
66+
*/
67+
public static Response create429Response(String retryAfter) {
68+
return createResponseWithHeaders(429, "Too Many Requests", retryAfter, DEFAULT_REQUEST_ID);
69+
}
70+
71+
/**
72+
* Creates a 429 response without retry-after header
73+
*/
74+
public static Response create429ResponseWithoutRetryAfter() {
75+
return createResponseWithHeaders(429, "Too Many Requests", null, DEFAULT_REQUEST_ID);
76+
}
77+
78+
/**
79+
* Creates a 500 response with request-id header
80+
*/
81+
public static Response create500Response() {
82+
return createResponseWithHeaders(500, "Internal Server Error", null, DEFAULT_REQUEST_ID);
83+
}
84+
85+
/**
86+
* Creates a 400 response without special headers
87+
*/
88+
public static Response create400Response() {
89+
return createResponseBuilder(400, "Bad Request").headers(new HashMap<>()).build();
90+
}
91+
92+
/**
93+
* Creates a response with empty headers
94+
*/
95+
public static Response createResponseWithEmptyHeaders(int status, String reason) {
96+
return createResponseBuilder(status, reason).headers(new HashMap<>()).build();
97+
}
98+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2017 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
package com.adobe.aio.util.feign;
13+
14+
import static com.adobe.aio.util.feign.FeignTestUtils.DEFAULT_REQUEST_ID;
15+
import static com.adobe.aio.util.feign.FeignTestUtils.DEFAULT_RETRY_AFTER_SECONDS_STR;
16+
import static com.adobe.aio.util.feign.FeignTestUtils.create429Response;
17+
import static com.adobe.aio.util.feign.FeignTestUtils.create429ResponseWithoutRetryAfter;
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
import static org.junit.jupiter.api.Assertions.assertFalse;
20+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
21+
import static org.junit.jupiter.api.Assertions.assertTrue;
22+
23+
import com.adobe.aio.exception.feign.IOUpstreamError;
24+
import com.adobe.aio.exception.feign.RetryAfterError;
25+
import feign.FeignException;
26+
import feign.Response;
27+
import org.junit.jupiter.api.Test;
28+
29+
class IOErrorDecoderTest {
30+
31+
private static final String TEST_METHOD = "testMethod";
32+
private final IOErrorDecoder decoder = new IOErrorDecoder();
33+
34+
@Test
35+
void testDecode429ResponseWithRetryAfter() {
36+
Response response = create429Response(DEFAULT_RETRY_AFTER_SECONDS_STR);
37+
Exception exception = decoder.decode(TEST_METHOD, response);
38+
39+
// Should return a RetryAfterError
40+
assertInstanceOf(RetryAfterError.class, exception);
41+
RetryAfterError retryAfterError = (RetryAfterError) exception;
42+
43+
assertRetryAfterErrorProperties(retryAfterError, 60L);
44+
}
45+
46+
@Test
47+
void testDecode429ResponseWithoutRetryAfter() {
48+
Response response = create429ResponseWithoutRetryAfter();
49+
Exception exception = decoder.decode(TEST_METHOD, response);
50+
51+
// Should still return a RetryAfterError
52+
assertInstanceOf(RetryAfterError.class, exception);
53+
RetryAfterError retryAfterError = (RetryAfterError) exception;
54+
55+
assertEquals(429, retryAfterError.status());
56+
assertEquals(0L, retryAfterError.getRetryAfterInSeconds());
57+
assertRequestIdPresent(retryAfterError);
58+
}
59+
60+
@Test
61+
void testDecode500Response() {
62+
Response response = FeignTestUtils.create500Response();
63+
Exception exception = decoder.decode(TEST_METHOD, response);
64+
65+
// Should return an IOUpstreamError for 5xx responses
66+
assertInstanceOf(IOUpstreamError.class, exception);
67+
IOUpstreamError upstreamError = (IOUpstreamError) exception;
68+
69+
assertEquals(500, upstreamError.status());
70+
assertRequestIdPresent(upstreamError);
71+
}
72+
73+
@Test
74+
void testDecode400Response() {
75+
Response response = FeignTestUtils.create400Response();
76+
Exception exception = decoder.decode(TEST_METHOD, response);
77+
78+
// Should return a regular FeignException for 4xx responses (except 429)
79+
assertInstanceOf(FeignException.class, exception);
80+
assertFalse(exception instanceof RetryAfterError);
81+
assertFalse(exception instanceof IOUpstreamError);
82+
83+
assertEquals(400, ((FeignException) exception).status());
84+
}
85+
86+
// Helper methods for assertions
87+
88+
private void assertRetryAfterErrorProperties(RetryAfterError retryAfterError,
89+
long expectedSeconds) {
90+
assertEquals(429, retryAfterError.status());
91+
assertEquals(expectedSeconds, retryAfterError.getRetryAfterInSeconds());
92+
assertRequestIdPresent(retryAfterError);
93+
}
94+
95+
private void assertRequestIdPresent(RetryAfterError retryAfterError) {
96+
assertTrue(retryAfterError.getUpStreamRequestId().isPresent());
97+
assertEquals(DEFAULT_REQUEST_ID, retryAfterError.getUpStreamRequestId().get());
98+
}
99+
100+
private void assertRequestIdPresent(IOUpstreamError upstreamError) {
101+
assertTrue(upstreamError.getUpStreamRequestId().isPresent());
102+
assertEquals(DEFAULT_REQUEST_ID, upstreamError.getUpStreamRequestId().get());
103+
}
104+
}

0 commit comments

Comments
 (0)