|
19 | 19 | import static org.assertj.core.api.Assertions.assertThatThrownBy; |
20 | 20 |
|
21 | 21 | import java.net.URI; |
22 | | -import java.time.Clock; |
23 | | -import java.time.Instant; |
24 | | -import java.time.ZoneId; |
25 | | -import java.time.ZoneOffset; |
26 | 22 | import java.util.List; |
27 | 23 | import java.util.concurrent.CompletableFuture; |
28 | 24 | import java.util.concurrent.atomic.AtomicInteger; |
29 | | -import java.util.concurrent.atomic.AtomicReference; |
30 | | -import java.util.function.Supplier; |
31 | 25 | import org.junit.jupiter.api.Test; |
32 | 26 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; |
33 | 27 | import software.amazon.awssdk.auth.credentials.AwsCredentials; |
|
43 | 37 | import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClient; |
44 | 38 | import software.amazon.awssdk.testutils.service.http.MockSyncHttpClient; |
45 | 39 | import software.amazon.awssdk.utils.StringInputStream; |
46 | | -import software.amazon.awssdk.utils.cache.CachedSupplier; |
47 | | -import software.amazon.awssdk.utils.cache.RefreshResult; |
48 | 40 |
|
49 | 41 | /** |
50 | 42 | * Integration test verifying the end-to-end flow: |
51 | 43 | * service returns ExpiredToken → credentials invalidated → next call uses fresh credentials. |
52 | | - * |
53 | | - * Also verifies backoff interaction: when refresh backoff is active, invalidate() does not |
54 | | - * bypass it, and stale cached credentials are returned until the backoff elapses. |
55 | 44 | */ |
56 | 45 | public class AuthErrorInvalidationFunctionalTest { |
57 | 46 |
|
@@ -138,69 +127,6 @@ public void accessDenied_doesNotInvalidateCredentials() { |
138 | 127 | } |
139 | 128 | } |
140 | 129 |
|
141 | | - /** |
142 | | - * Backoff interaction: invalidation during active backoff returns stale credentials. |
143 | | - * |
144 | | - * This test verifies that when CachedSupplier has an active refresh backoff |
145 | | - * (nextAllowedRefreshTime in the future), calling invalidate() marks the cache stale |
146 | | - * but does NOT bypass the backoff. The next get() still returns cached credentials |
147 | | - * until the backoff elapses, at which point fresh credentials are obtained. |
148 | | - */ |
149 | | - @Test |
150 | | - public void invalidation_duringActiveBackoff_returnsStaleCredentials() { |
151 | | - AdjustableClock clock = new AdjustableClock(); |
152 | | - Instant now = Instant.parse("2024-01-01T00:00:00Z"); |
153 | | - clock.time = now; |
154 | | - |
155 | | - AtomicInteger fetchCount = new AtomicInteger(0); |
156 | | - AtomicReference<Supplier<RefreshResult<String>>> supplierRef = new AtomicReference<>(); |
157 | | - |
158 | | - supplierRef.set(() -> RefreshResult.builder("access-key-1") |
159 | | - .staleTime(now.plusSeconds(60)) |
160 | | - .prefetchTime(now.plusSeconds(30)) |
161 | | - .build()); |
162 | | - |
163 | | - try (CachedSupplier<String> cache = CachedSupplier.builder(() -> { |
164 | | - fetchCount.incrementAndGet(); |
165 | | - return supplierRef.get().get(); |
166 | | - }) |
167 | | - .staleValueBehavior(CachedSupplier.StaleValueBehavior.ALLOW) |
168 | | - .clock(clock) |
169 | | - .build()) { |
170 | | - |
171 | | - // Initial fetch |
172 | | - assertThat(cache.get()).isEqualTo("access-key-1"); |
173 | | - assertThat(fetchCount.get()).isEqualTo(1); |
174 | | - |
175 | | - // Advance past stale time and trigger a refresh failure to set nextAllowedRefreshTime |
176 | | - clock.time = now.plusSeconds(61); |
177 | | - supplierRef.set(() -> { |
178 | | - throw new RuntimeException("credential source unavailable"); |
179 | | - }); |
180 | | - // This get() will try to refresh, fail, set backoff, and return stale value |
181 | | - assertThat(cache.get()).isEqualTo("access-key-1"); |
182 | | - |
183 | | - // Now call invalidate — marks staleTime = now but does NOT clear backoff |
184 | | - clock.time = now.plusSeconds(62); |
185 | | - cache.invalidate(v -> v.equals("access-key-1")); |
186 | | - |
187 | | - // Set up fresh credentials in the supplier |
188 | | - supplierRef.set(() -> RefreshResult.builder("access-key-2") |
189 | | - .staleTime(now.plusSeconds(7200)) |
190 | | - .prefetchTime(now.plusSeconds(5400)) |
191 | | - .build()); |
192 | | - |
193 | | - // get() should return STALE credentials because backoff is still active |
194 | | - assertThat(cache.get()).isEqualTo("access-key-1"); |
195 | | - |
196 | | - // Advance past maximum possible backoff (61 + 600 = 661 seconds from original now) |
197 | | - clock.time = now.plusSeconds(700); |
198 | | - |
199 | | - // Now backoff has elapsed — next get() should refresh and return fresh value |
200 | | - assertThat(cache.get()).isEqualTo("access-key-2"); |
201 | | - } |
202 | | - } |
203 | | - |
204 | 130 | // --- Helper methods --- |
205 | 131 |
|
206 | 132 | private void assertRequestUsedAccessKey(SdkHttpRequest request, String expectedAccessKeyId) { |
@@ -296,26 +222,4 @@ int invalidateCallCount() { |
296 | 222 | return invalidateCount.get(); |
297 | 223 | } |
298 | 224 | } |
299 | | - |
300 | | - /** |
301 | | - * A clock whose time can be manually adjusted for testing backoff behavior. |
302 | | - */ |
303 | | - private static class AdjustableClock extends Clock { |
304 | | - volatile Instant time = Instant.now(); |
305 | | - |
306 | | - @Override |
307 | | - public ZoneId getZone() { |
308 | | - return ZoneOffset.UTC; |
309 | | - } |
310 | | - |
311 | | - @Override |
312 | | - public Clock withZone(ZoneId zone) { |
313 | | - return this; |
314 | | - } |
315 | | - |
316 | | - @Override |
317 | | - public Instant instant() { |
318 | | - return time; |
319 | | - } |
320 | | - } |
321 | 225 | } |
0 commit comments