From 02cfe7167fc40414d3a2336a2ad7c01b41667343 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Tue, 16 Jan 2024 04:04:31 +0000 Subject: [PATCH 1/2] Google Java Format --- .../at4j/core/ratelimit/RateLimitBucket.java | 5 - .../at4j/core/ratelimit/RateLimitManager.java | 454 ++++++++++-------- .../brenoepics/at4j/AzureApiBuilderTest.java | 68 +-- .../at4j/azure/lang/LanguageTest.java | 144 +++--- .../core/ratelimit/RateLimitManagerTest.java | 252 +++++----- .../core/thread/AT4JThreadFactoryTest.java | 104 ++-- .../at4j/core/thread/ThreadPoolImplTest.java | 103 ++-- 7 files changed, 579 insertions(+), 551 deletions(-) diff --git a/src/main/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitBucket.java b/src/main/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitBucket.java index 5f5e02a..29879e4 100644 --- a/src/main/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitBucket.java +++ b/src/main/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitBucket.java @@ -1,11 +1,7 @@ package com.github.brenoepics.at4j.core.ratelimit; -import com.github.brenoepics.at4j.AzureApi; -import com.github.brenoepics.at4j.core.AzureApiImpl; import com.github.brenoepics.at4j.util.rest.RestEndpoint; import com.github.brenoepics.at4j.util.rest.RestRequest; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; /** @@ -33,7 +29,6 @@ public RateLimitBucket(RestEndpoint endpoint, String majorUrlParameter) { this.majorUrlParameter = majorUrlParameter; } - /** * Adds the given request to the bucket's queue. * diff --git a/src/main/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitManager.java b/src/main/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitManager.java index 5d56d74..276397a 100644 --- a/src/main/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitManager.java +++ b/src/main/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitManager.java @@ -18,218 +18,248 @@ import okhttp3.Response; import org.apache.logging.log4j.Logger; -/** - * This class manages rate-limits and keeps track of them. - */ +/** This class manages rate-limits and keeps track of them. */ public class RateLimitManager { - /** - * The (logger) of this class. - */ - private static final Logger logger = LoggerUtil.getLogger(RateLimitManager.class); - - /** - * The Azure API instance for this rate-limit manager. - */ - private final AzureApiImpl api; - - /** - * All buckets. - */ - private final Set> buckets = new HashSet<>(); - - /** - * Creates a new rate-limit manager. - * - * @param api The azure api instance for this rate-limit manager. - */ - public RateLimitManager(AzureApiImpl api) { - this.api = api; - } - - /** - * Queues the given request. This method is automatically called when using {@link - * RestRequest#execute(Function)}! - * - * @param request The request to queue. - */ - public void queueRequest(RestRequest request) { - Optional> searchBucket = searchBucket(request); - - if (!searchBucket.isPresent()) { - return; - } - - final RateLimitBucket bucket = searchBucket.get(); - - api.getThreadPool().getExecutorService().submit(() -> { - RestRequest currentRequest = bucket.peekRequestFromQueue(); - RestRequestResult result = null; - long responseTimestamp = System.currentTimeMillis(); - while (currentRequest != null) { - RestRequestHandler newResult = handleCurrentRequest(result, currentRequest, bucket, responseTimestamp); - result = newResult.getResult(); - currentRequest = newResult.getCurrentRequest(); - responseTimestamp = newResult.getResponseTimestamp(); - } - }); - } - - /** - * Handles the current request. - * - * @param result The result of the previous request. - * @param currentRequest The current request. - * @param bucket The bucket the request belongs to. - * @param responseTimestamp The timestamp directly after the response finished. - * @return The result of the current request. - */ - RestRequestHandler handleCurrentRequest(RestRequestResult result, RestRequest currentRequest, RateLimitBucket bucket, long responseTimestamp) { - try { - waitUntilSpaceGetsAvailable(bucket); - result = currentRequest.executeBlocking(); - responseTimestamp = System.currentTimeMillis(); - } catch (Exception e) { - responseTimestamp = System.currentTimeMillis(); - if (currentRequest.getResult().isDone()) { - logger.warn("Received exception for a request that is already done. This should not be able to" + " happen!", e); - } - - if (e instanceof AzureException) { - result = mapAzureException(e); - } - - currentRequest.getResult().completeExceptionally(e); - } finally { - try { - // Handle the response - handleResponse(currentRequest, result, bucket, responseTimestamp); - } catch (Exception e) { - logger.warn("Encountered unexpected exception.", e); - } - - // The request didn't finish, so let's try again - if (currentRequest.getResult().isDone()) { - currentRequest = retryRequest(bucket); - } - } - - return new RestRequestHandler<>(result, currentRequest, responseTimestamp); - } - - /** - * Waits until space gets available in the given bucket. - * - * @param bucket The bucket to wait for. - */ - void waitUntilSpaceGetsAvailable(RateLimitBucket bucket) { - int sleepTime = bucket.getTimeTillSpaceGetsAvailable(); - if (sleepTime > 0) { - logger.debug("Delaying requests to {} for {}ms to prevent hitting rate-limits", bucket, sleepTime); - } - - while (sleepTime > 0) { - try { - Thread.sleep(sleepTime); - } catch (InterruptedException e) { - logger.warn("We got interrupted while waiting for a rate limit!", e); - Thread.currentThread().interrupt(); // Re-interrupt the thread - } - // Update in case something changed (e.g., because we hit a global rate-limit) - sleepTime = bucket.getTimeTillSpaceGetsAvailable(); - } - } - - /** - * Retries the request of the given bucket. - * - * @param bucket The bucket to retry the request for. - * @return The request that was retried. - */ - RestRequest retryRequest(RateLimitBucket bucket) { - synchronized (buckets) { - bucket.pollRequestFromQueue(); - RestRequest request = bucket.peekRequestFromQueue(); - if (request == null) { - buckets.remove(bucket); - } - - return request; - } - } - - private RestRequestResult mapAzureException(Throwable t) { - return ((AzureException) t).getResponse().map(RestRequestResponseInformationImpl.class::cast).map(RestRequestResponseInformationImpl::getRestRequestResult).orElse(null); - } - - /** - * Searches for a bucket that fits to the given request and adds it to the queue. - * - * @param request The request. - * @return The bucket that fits to the request. - */ - Optional> searchBucket(RestRequest request) { - synchronized (buckets) { - RateLimitBucket bucket = buckets.stream().filter(b -> b.equals(request.getEndpoint(), request.getMajorUrlParameter().orElse(null))).findAny().orElseGet(() -> new RateLimitBucket<>(request.getEndpoint(), request.getMajorUrlParameter().orElse(null))); - - // Check if it is already in the queue, send not present - if (bucket.peekRequestFromQueue() != null) { - return Optional.empty(); - } - - // Add the bucket to the set of buckets (does nothing if it's already in the set) - buckets.add(bucket); - - // Add the request to the bucket's queue - bucket.addRequestToQueue(request); - return Optional.of(bucket); - } - } - - /** - * Updates the rate-limit information and sets the result if the request was successful. - * - * @param request The request. - * @param result The result of the request. - * @param bucket The bucket the request belongs to. - * @param responseTimestamp The timestamp directly after the response finished. - */ - void handleResponse(RestRequest request, RestRequestResult result, RateLimitBucket bucket, long responseTimestamp) { - if (result == null || result.getResponse() == null) { - return; - } - - Response response = result.getResponse(); - int remaining = Integer.parseInt(Objects.requireNonNull(response.header("X-RateLimit-Remaining", "1"))); - long reset = (long) (Double.parseDouble(Objects.requireNonNull(response.header("X-RateLimit-Reset", "0"))) * 1000); - - // Check if we received a 429 response - if (result.getResponse().code() != 429) { - // Check if we didn't already complete it exceptionally. - CompletableFuture> requestResult = request.getResult(); - if (!requestResult.isDone()) { - requestResult.complete(result); - } - - // Update bucket information - bucket.setRateLimitRemaining(remaining); - bucket.setRateLimitResetTimestamp(reset); - return; - } - - if (response.header("Via") == null) { - logger.warn("Hit a CloudFlare API ban! This means you were sending a very large amount of invalid" + " requests."); - int retryAfter = Integer.parseInt(Objects.requireNonNull(response.header("Retry-after"))) * 1000; - bucket.setRateLimitRemaining(retryAfter); - bucket.setRateLimitResetTimestamp(responseTimestamp + retryAfter); - return; - } - - long retryAfter = result.getJsonBody().isNull() ? 0 : (long) (result.getJsonBody().get("retry_after").asDouble() * 1000); - logger.debug("Received a 429 response from Azure! Recalculating time offset..."); - - // Update the bucket information - bucket.setRateLimitRemaining(0); - bucket.setRateLimitResetTimestamp(responseTimestamp + retryAfter); - } + /** The (logger) of this class. */ + private static final Logger logger = LoggerUtil.getLogger(RateLimitManager.class); + + /** The Azure API instance for this rate-limit manager. */ + private final AzureApiImpl api; + + /** All buckets. */ + private final Set> buckets = new HashSet<>(); + + /** + * Creates a new rate-limit manager. + * + * @param api The azure api instance for this rate-limit manager. + */ + public RateLimitManager(AzureApiImpl api) { + this.api = api; + } + + /** + * Queues the given request. This method is automatically called when using {@link + * RestRequest#execute(Function)}! + * + * @param request The request to queue. + */ + public void queueRequest(RestRequest request) { + Optional> searchBucket = searchBucket(request); + + if (!searchBucket.isPresent()) { + return; + } + + final RateLimitBucket bucket = searchBucket.get(); + + api.getThreadPool() + .getExecutorService() + .submit( + () -> { + RestRequest currentRequest = bucket.peekRequestFromQueue(); + RestRequestResult result = null; + long responseTimestamp = System.currentTimeMillis(); + while (currentRequest != null) { + RestRequestHandler newResult = + handleCurrentRequest(result, currentRequest, bucket, responseTimestamp); + result = newResult.getResult(); + currentRequest = newResult.getCurrentRequest(); + responseTimestamp = newResult.getResponseTimestamp(); + } + }); + } + + /** + * Handles the current request. + * + * @param result The result of the previous request. + * @param currentRequest The current request. + * @param bucket The bucket the request belongs to. + * @param responseTimestamp The timestamp directly after the response finished. + * @return The result of the current request. + */ + RestRequestHandler handleCurrentRequest( + RestRequestResult result, + RestRequest currentRequest, + RateLimitBucket bucket, + long responseTimestamp) { + try { + waitUntilSpaceGetsAvailable(bucket); + result = currentRequest.executeBlocking(); + responseTimestamp = System.currentTimeMillis(); + } catch (Exception e) { + responseTimestamp = System.currentTimeMillis(); + if (currentRequest.getResult().isDone()) { + logger.warn( + "Received exception for a request that is already done. This should not be able to" + + " happen!", + e); + } + + if (e instanceof AzureException) { + result = mapAzureException(e); + } + + currentRequest.getResult().completeExceptionally(e); + } finally { + try { + // Handle the response + handleResponse(currentRequest, result, bucket, responseTimestamp); + } catch (Exception e) { + logger.warn("Encountered unexpected exception.", e); + } + + // The request didn't finish, so let's try again + if (currentRequest.getResult().isDone()) { + currentRequest = retryRequest(bucket); + } + } + + return new RestRequestHandler<>(result, currentRequest, responseTimestamp); + } + + /** + * Waits until space gets available in the given bucket. + * + * @param bucket The bucket to wait for. + */ + void waitUntilSpaceGetsAvailable(RateLimitBucket bucket) { + int sleepTime = bucket.getTimeTillSpaceGetsAvailable(); + if (sleepTime > 0) { + logger.debug( + "Delaying requests to {} for {}ms to prevent hitting rate-limits", bucket, sleepTime); + } + + while (sleepTime > 0) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + logger.warn("We got interrupted while waiting for a rate limit!", e); + Thread.currentThread().interrupt(); // Re-interrupt the thread + } + // Update in case something changed (e.g., because we hit a global rate-limit) + sleepTime = bucket.getTimeTillSpaceGetsAvailable(); + } + } + + /** + * Retries the request of the given bucket. + * + * @param bucket The bucket to retry the request for. + * @return The request that was retried. + */ + RestRequest retryRequest(RateLimitBucket bucket) { + synchronized (buckets) { + bucket.pollRequestFromQueue(); + RestRequest request = bucket.peekRequestFromQueue(); + if (request == null) { + buckets.remove(bucket); + } + + return request; + } + } + + private RestRequestResult mapAzureException(Throwable t) { + return ((AzureException) t) + .getResponse() + .map(RestRequestResponseInformationImpl.class::cast) + .map(RestRequestResponseInformationImpl::getRestRequestResult) + .orElse(null); + } + + /** + * Searches for a bucket that fits to the given request and adds it to the queue. + * + * @param request The request. + * @return The bucket that fits to the request. + */ + Optional> searchBucket(RestRequest request) { + synchronized (buckets) { + RateLimitBucket bucket = + buckets.stream() + .filter( + b -> b.equals(request.getEndpoint(), request.getMajorUrlParameter().orElse(null))) + .findAny() + .orElseGet( + () -> + new RateLimitBucket<>( + request.getEndpoint(), request.getMajorUrlParameter().orElse(null))); + + // Check if it is already in the queue, send not present + if (bucket.peekRequestFromQueue() != null) { + return Optional.empty(); + } + + // Add the bucket to the set of buckets (does nothing if it's already in the set) + buckets.add(bucket); + + // Add the request to the bucket's queue + bucket.addRequestToQueue(request); + return Optional.of(bucket); + } + } + + /** + * Updates the rate-limit information and sets the result if the request was successful. + * + * @param request The request. + * @param result The result of the request. + * @param bucket The bucket the request belongs to. + * @param responseTimestamp The timestamp directly after the response finished. + */ + void handleResponse( + RestRequest request, + RestRequestResult result, + RateLimitBucket bucket, + long responseTimestamp) { + if (result == null || result.getResponse() == null) { + return; + } + + Response response = result.getResponse(); + int remaining = + Integer.parseInt(Objects.requireNonNull(response.header("X-RateLimit-Remaining", "1"))); + long reset = + (long) + (Double.parseDouble(Objects.requireNonNull(response.header("X-RateLimit-Reset", "0"))) + * 1000); + + // Check if we received a 429 response + if (result.getResponse().code() != 429) { + // Check if we didn't already complete it exceptionally. + CompletableFuture> requestResult = request.getResult(); + if (!requestResult.isDone()) { + requestResult.complete(result); + } + + // Update bucket information + bucket.setRateLimitRemaining(remaining); + bucket.setRateLimitResetTimestamp(reset); + return; + } + + if (response.header("Via") == null) { + logger.warn( + "Hit a CloudFlare API ban! This means you were sending a very large amount of invalid" + + " requests."); + int retryAfter = + Integer.parseInt(Objects.requireNonNull(response.header("Retry-after"))) * 1000; + bucket.setRateLimitRemaining(retryAfter); + bucket.setRateLimitResetTimestamp(responseTimestamp + retryAfter); + return; + } + + long retryAfter = + result.getJsonBody().isNull() + ? 0 + : (long) (result.getJsonBody().get("retry_after").asDouble() * 1000); + logger.debug("Received a 429 response from Azure! Recalculating time offset..."); + + // Update the bucket information + bucket.setRateLimitRemaining(0); + bucket.setRateLimitResetTimestamp(responseTimestamp + retryAfter); + } } diff --git a/src/test/java/com/github/brenoepics/at4j/AzureApiBuilderTest.java b/src/test/java/com/github/brenoepics/at4j/AzureApiBuilderTest.java index e3f2982..4d55ca4 100644 --- a/src/test/java/com/github/brenoepics/at4j/AzureApiBuilderTest.java +++ b/src/test/java/com/github/brenoepics/at4j/AzureApiBuilderTest.java @@ -7,37 +7,37 @@ class AzureApiBuilderTest { - @Test - void shouldSetGlobalBaseUrlByDefault() { - AzureApiBuilder builder = new AzureApiBuilder(); - AzureApi api = builder.build(); - assertEquals(BaseURL.GLOBAL, api.getBaseURL()); - } - - @Test - void shouldSetBaseUrlWhenProvided() { - AzureApiBuilder builder = new AzureApiBuilder(); - AzureApi api = builder.baseURL(BaseURL.EUROPE).build(); - assertEquals(BaseURL.EUROPE, api.getBaseURL()); - } - - @Test - void shouldThrowExceptionWhenSubscriptionKeyIsNull() { - AzureApiBuilder builder = new AzureApiBuilder(); - assertThrows(NullPointerException.class, builder::build); - } - - @Test - void shouldSetSubscriptionKeyWhenProvided() { - AzureApiBuilder builder = new AzureApiBuilder(); - AzureApi api = builder.setKey("testKey").build(); - assertEquals("testKey", api.getSubscriptionKey()); - } - - @Test - void shouldSetSubscriptionRegionWhenProvided() { - AzureApiBuilder builder = new AzureApiBuilder(); - AzureApi api = builder.region("brazilsouth").build(); - assertEquals("brazilsouth", api.getSubscriptionRegion().orElse(null)); - } -} \ No newline at end of file + @Test + void shouldSetGlobalBaseUrlByDefault() { + AzureApiBuilder builder = new AzureApiBuilder(); + AzureApi api = builder.build(); + assertEquals(BaseURL.GLOBAL, api.getBaseURL()); + } + + @Test + void shouldSetBaseUrlWhenProvided() { + AzureApiBuilder builder = new AzureApiBuilder(); + AzureApi api = builder.baseURL(BaseURL.EUROPE).build(); + assertEquals(BaseURL.EUROPE, api.getBaseURL()); + } + + @Test + void shouldThrowExceptionWhenSubscriptionKeyIsNull() { + AzureApiBuilder builder = new AzureApiBuilder(); + assertThrows(NullPointerException.class, builder::build); + } + + @Test + void shouldSetSubscriptionKeyWhenProvided() { + AzureApiBuilder builder = new AzureApiBuilder(); + AzureApi api = builder.setKey("testKey").build(); + assertEquals("testKey", api.getSubscriptionKey()); + } + + @Test + void shouldSetSubscriptionRegionWhenProvided() { + AzureApiBuilder builder = new AzureApiBuilder(); + AzureApi api = builder.region("brazilsouth").build(); + assertEquals("brazilsouth", api.getSubscriptionRegion().orElse(null)); + } +} diff --git a/src/test/java/com/github/brenoepics/at4j/azure/lang/LanguageTest.java b/src/test/java/com/github/brenoepics/at4j/azure/lang/LanguageTest.java index a56d87b..a1401ae 100644 --- a/src/test/java/com/github/brenoepics/at4j/azure/lang/LanguageTest.java +++ b/src/test/java/com/github/brenoepics/at4j/azure/lang/LanguageTest.java @@ -9,75 +9,75 @@ class LanguageTest { - private Language language; - - @BeforeEach - void setUp() { - language = new Language("en", "English", "English", LanguageDirection.LTR); - } - - @Test - void ofJSON_createsLanguageFromJson() { - ObjectNode json = JsonNodeFactory.instance.objectNode(); - json.put("name", "English"); - json.put("nativeName", "English"); - json.put("dir", "LTR"); - - Language result = Language.ofJSON("en", json); - - assertEquals("en", result.getCode()); - assertEquals("English", result.getName()); - assertEquals("English", result.getNativeName()); - assertEquals(LanguageDirection.LTR, result.getDir()); - } - - @Test - void toString_returnsCorrectFormat() { - String expected = "Language{code='en', name='English', nativeName='English', direction=LTR}"; - assertEquals(expected, language.toString()); - } - - @Test - void getCode_returnsCorrectCode() { - assertEquals("en", language.getCode()); - } - - @Test - void setCode_updatesCode() { - language.setCode("fr"); - assertEquals("fr", language.getCode()); - } - - @Test - void getName_returnsCorrectName() { - assertEquals("English", language.getName()); - } - - @Test - void setName_updatesName() { - language.setName("French"); - assertEquals("French", language.getName()); - } - - @Test - void getNativeName_returnsCorrectNativeName() { - assertEquals("English", language.getNativeName()); - } - - @Test - void setNativeName_updatesNativeName() { - language.setNativeName("Anglais"); - assertEquals("Anglais", language.getNativeName()); - } - - @Test - void getDir_returnsCorrectDirection() { - assertEquals(LanguageDirection.LTR, language.getDir()); - } - - @Test - void setDir_updatesDirection() { - language.setDir(LanguageDirection.RTL); - assertEquals(LanguageDirection.RTL, language.getDir()); - } -} \ No newline at end of file + private Language language; + + @BeforeEach + void setUp() { + language = new Language("en", "English", "English", LanguageDirection.LTR); + } + + @Test + void ofJSON_createsLanguageFromJson() { + ObjectNode json = JsonNodeFactory.instance.objectNode(); + json.put("name", "English"); + json.put("nativeName", "English"); + json.put("dir", "LTR"); + + Language result = Language.ofJSON("en", json); + + assertEquals("en", result.getCode()); + assertEquals("English", result.getName()); + assertEquals("English", result.getNativeName()); + assertEquals(LanguageDirection.LTR, result.getDir()); + } + + @Test + void toString_returnsCorrectFormat() { + String expected = "Language{code='en', name='English', nativeName='English', direction=LTR}"; + assertEquals(expected, language.toString()); + } + + @Test + void getCode_returnsCorrectCode() { + assertEquals("en", language.getCode()); + } + + @Test + void setCode_updatesCode() { + language.setCode("fr"); + assertEquals("fr", language.getCode()); + } + + @Test + void getName_returnsCorrectName() { + assertEquals("English", language.getName()); + } + + @Test + void setName_updatesName() { + language.setName("French"); + assertEquals("French", language.getName()); + } + + @Test + void getNativeName_returnsCorrectNativeName() { + assertEquals("English", language.getNativeName()); + } + + @Test + void setNativeName_updatesNativeName() { + language.setNativeName("Anglais"); + assertEquals("Anglais", language.getNativeName()); + } + + @Test + void getDir_returnsCorrectDirection() { + assertEquals(LanguageDirection.LTR, language.getDir()); + } + + @Test + void setDir_updatesDirection() { + language.setDir(LanguageDirection.RTL); + assertEquals(LanguageDirection.RTL, language.getDir()); + } +} diff --git a/src/test/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitManagerTest.java b/src/test/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitManagerTest.java index b9c853b..3837ca6 100644 --- a/src/test/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitManagerTest.java +++ b/src/test/java/com/github/brenoepics/at4j/core/ratelimit/RateLimitManagerTest.java @@ -22,129 +22,129 @@ class RateLimitManagerTest { - @Mock - private AzureApiImpl api; - @Mock - private RestRequest request; - @Mock - private RestRequestResult result; - @Mock - private Response response; - @Mock - private RateLimitBucket bucket; - - private RateLimitManager rateLimitManager; - - @Mock - private ThreadPool threadPool; - @Mock - private ExecutorService executorService; - - @BeforeEach - public void setUp() { - MockitoAnnotations.openMocks(this); - rateLimitManager = new RateLimitManager<>(api); - - when(api.getThreadPool()).thenReturn(threadPool); - when(threadPool.getExecutorService()).thenReturn(executorService); - - when(response.header("X-RateLimit-Remaining", "1")).thenReturn("10"); - when(response.header("X-RateLimit-Reset", "0")).thenReturn("1000"); - } - - @Test - void queuesRequestWhenBucketIsPresent() { - when(request.getMajorUrlParameter()).thenReturn(Optional.empty()); - when(bucket.peekRequestFromQueue()).thenReturn(null); - - rateLimitManager.queueRequest(request); - - verify(executorService, times(1)).submit(any(Runnable.class)); - } - - @Test - void retriesRequestWhenBucketIsNotEmpty() { - when(bucket.peekRequestFromQueue()).thenReturn(request); - - RestRequest retriedRequest = rateLimitManager.retryRequest(bucket); - - assertEquals(request, retriedRequest); - } - - @Test - void doesNotRetryRequestWhenBucketIsEmpty() { - when(bucket.peekRequestFromQueue()).thenReturn(null); - - RestRequest retriedRequest = rateLimitManager.retryRequest(bucket); - - assertNull(retriedRequest); - } - - @Test - void doesNotHandleResponseWhenResultIsNull() { - assertDoesNotThrow(() -> rateLimitManager.handleResponse(request, null, bucket, System.currentTimeMillis())); - } - - @Test - void queuesRequestWhenBucketIsNotPresent() { - when(request.getMajorUrlParameter()).thenReturn(Optional.empty()); - when(bucket.peekRequestFromQueue()).thenReturn(request); - - - rateLimitManager.queueRequest(request); - assertDoesNotThrow(() -> rateLimitManager.handleResponse(request, result, bucket, System.currentTimeMillis())); - } - - @Test - void handleResponseUpdatesBucketInformationWhenResponseCodeIsNot429() { - when(response.header("X-RateLimit-Remaining", "1")).thenReturn("10"); - when(response.header("X-RateLimit-Reset", "0")).thenReturn("1000"); - when(result.getResponse()).thenReturn(response); - when(response.code()).thenReturn(200); - when(request.getResult()).thenReturn(CompletableFuture.completedFuture(result)); - - rateLimitManager.handleResponse(request, result, bucket, System.currentTimeMillis()); - - verify(bucket, times(1)).setRateLimitRemaining(10); - verify(bucket, times(1)).setRateLimitResetTimestamp(anyLong()); - } - - @Test - void handleResponseDoesNotUpdateBucketInformationWhenResponseCodeIs429AndViaHeaderIsNull() { - when(result.getResponse()).thenReturn(response); - when(response.code()).thenReturn(429); - when(response.header("Via")).thenReturn(null); - when(response.header("Retry-after")).thenReturn("1000"); - when(response.header("X-RateLimit-Remaining", "1")).thenReturn("10"); - when(response.header("X-RateLimit-Reset", "0")).thenReturn("1000"); - - assertDoesNotThrow(() -> rateLimitManager.handleResponse(request, result, bucket, System.currentTimeMillis())); - } - - @Test - void handleCurrentRequestThrowsException() throws AzureException, IOException { - when(request.executeBlocking()).thenThrow(new RuntimeException()); - - assertThrows(RuntimeException.class, () -> rateLimitManager.handleCurrentRequest(result, request, bucket, System.currentTimeMillis())); - } - - - @Test - void handleResponseDoesNotUpdateBucketInformationWhenResponseCodeIsNot429AndRequestResultIsDone() { - when(result.getResponse()).thenReturn(response); - when(response.code()).thenReturn(200); - when(request.getResult()).thenReturn(CompletableFuture.completedFuture(result)); - - assertDoesNotThrow(() -> rateLimitManager.handleResponse(request, result, bucket, System.currentTimeMillis())); - } - - @Test - void searchBucketReturnsBucketWhenBucketIsPresentAndRequestQueueIsEmpty() { - when(request.getMajorUrlParameter()).thenReturn(Optional.empty()); - when(bucket.peekRequestFromQueue()).thenReturn(null); - - Optional> searchBucket = rateLimitManager.searchBucket(request); - - assertTrue(searchBucket.isPresent()); - } -} \ No newline at end of file + @Mock private AzureApiImpl api; + @Mock private RestRequest request; + @Mock private RestRequestResult result; + @Mock private Response response; + @Mock private RateLimitBucket bucket; + + private RateLimitManager rateLimitManager; + + @Mock private ThreadPool threadPool; + @Mock private ExecutorService executorService; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + rateLimitManager = new RateLimitManager<>(api); + + when(api.getThreadPool()).thenReturn(threadPool); + when(threadPool.getExecutorService()).thenReturn(executorService); + + when(response.header("X-RateLimit-Remaining", "1")).thenReturn("10"); + when(response.header("X-RateLimit-Reset", "0")).thenReturn("1000"); + } + + @Test + void queuesRequestWhenBucketIsPresent() { + when(request.getMajorUrlParameter()).thenReturn(Optional.empty()); + when(bucket.peekRequestFromQueue()).thenReturn(null); + + rateLimitManager.queueRequest(request); + + verify(executorService, times(1)).submit(any(Runnable.class)); + } + + @Test + void retriesRequestWhenBucketIsNotEmpty() { + when(bucket.peekRequestFromQueue()).thenReturn(request); + + RestRequest retriedRequest = rateLimitManager.retryRequest(bucket); + + assertEquals(request, retriedRequest); + } + + @Test + void doesNotRetryRequestWhenBucketIsEmpty() { + when(bucket.peekRequestFromQueue()).thenReturn(null); + + RestRequest retriedRequest = rateLimitManager.retryRequest(bucket); + + assertNull(retriedRequest); + } + + @Test + void doesNotHandleResponseWhenResultIsNull() { + assertDoesNotThrow( + () -> rateLimitManager.handleResponse(request, null, bucket, System.currentTimeMillis())); + } + + @Test + void queuesRequestWhenBucketIsNotPresent() { + when(request.getMajorUrlParameter()).thenReturn(Optional.empty()); + when(bucket.peekRequestFromQueue()).thenReturn(request); + + rateLimitManager.queueRequest(request); + assertDoesNotThrow( + () -> rateLimitManager.handleResponse(request, result, bucket, System.currentTimeMillis())); + } + + @Test + void handleResponseUpdatesBucketInformationWhenResponseCodeIsNot429() { + when(response.header("X-RateLimit-Remaining", "1")).thenReturn("10"); + when(response.header("X-RateLimit-Reset", "0")).thenReturn("1000"); + when(result.getResponse()).thenReturn(response); + when(response.code()).thenReturn(200); + when(request.getResult()).thenReturn(CompletableFuture.completedFuture(result)); + + rateLimitManager.handleResponse(request, result, bucket, System.currentTimeMillis()); + + verify(bucket, times(1)).setRateLimitRemaining(10); + verify(bucket, times(1)).setRateLimitResetTimestamp(anyLong()); + } + + @Test + void handleResponseDoesNotUpdateBucketInformationWhenResponseCodeIs429AndViaHeaderIsNull() { + when(result.getResponse()).thenReturn(response); + when(response.code()).thenReturn(429); + when(response.header("Via")).thenReturn(null); + when(response.header("Retry-after")).thenReturn("1000"); + when(response.header("X-RateLimit-Remaining", "1")).thenReturn("10"); + when(response.header("X-RateLimit-Reset", "0")).thenReturn("1000"); + + assertDoesNotThrow( + () -> rateLimitManager.handleResponse(request, result, bucket, System.currentTimeMillis())); + } + + @Test + void handleCurrentRequestThrowsException() throws AzureException, IOException { + when(request.executeBlocking()).thenThrow(new RuntimeException()); + + assertThrows( + RuntimeException.class, + () -> + rateLimitManager.handleCurrentRequest( + result, request, bucket, System.currentTimeMillis())); + } + + @Test + void + handleResponseDoesNotUpdateBucketInformationWhenResponseCodeIsNot429AndRequestResultIsDone() { + when(result.getResponse()).thenReturn(response); + when(response.code()).thenReturn(200); + when(request.getResult()).thenReturn(CompletableFuture.completedFuture(result)); + + assertDoesNotThrow( + () -> rateLimitManager.handleResponse(request, result, bucket, System.currentTimeMillis())); + } + + @Test + void searchBucketReturnsBucketWhenBucketIsPresentAndRequestQueueIsEmpty() { + when(request.getMajorUrlParameter()).thenReturn(Optional.empty()); + when(bucket.peekRequestFromQueue()).thenReturn(null); + + Optional> searchBucket = rateLimitManager.searchBucket(request); + + assertTrue(searchBucket.isPresent()); + } +} diff --git a/src/test/java/com/github/brenoepics/at4j/core/thread/AT4JThreadFactoryTest.java b/src/test/java/com/github/brenoepics/at4j/core/thread/AT4JThreadFactoryTest.java index 2b83ec6..9eb41ae 100644 --- a/src/test/java/com/github/brenoepics/at4j/core/thread/AT4JThreadFactoryTest.java +++ b/src/test/java/com/github/brenoepics/at4j/core/thread/AT4JThreadFactoryTest.java @@ -6,55 +6,55 @@ class AT4JThreadFactoryTest { - @Test - void shouldCreateDaemonThreadWhenDaemonIsTrue() { - // Given - AT4JThreadFactory factory = new AT4JThreadFactory("test-%d", true); - - // When - Thread thread = factory.newThread(() -> {}); - - // Then - assertTrue(thread.isDaemon()); - assertEquals("test-1", thread.getName()); - } - - @Test - void shouldCreateNonDaemonThreadWhenDaemonIsFalse() { - // Given - AT4JThreadFactory factory = new AT4JThreadFactory("test-%d", false); - - // When - Thread thread = factory.newThread(() -> {}); - - // Then - assertFalse(thread.isDaemon()); - assertEquals("test-1", thread.getName()); - } - - @Test - void shouldIncrementThreadNameCounter() { - // Given - AT4JThreadFactory factory = new AT4JThreadFactory("test-%d", true); - - // When - Thread thread1 = factory.newThread(() -> {}); - Thread thread2 = factory.newThread(() -> {}); - - // Then - assertEquals("test-1", thread1.getName()); - assertEquals("test-2", thread2.getName()); - } - - @Test - void shouldHandleNamePatternWithoutCounter() { - // Given - AT4JThreadFactory factory = new AT4JThreadFactory("test", true); - - // When - Thread thread = factory.newThread(() -> {}); - - // Then - assertEquals("test", thread.getName()); - } -} \ No newline at end of file + @Test + void shouldCreateDaemonThreadWhenDaemonIsTrue() { + // Given + AT4JThreadFactory factory = new AT4JThreadFactory("test-%d", true); + + // When + Thread thread = factory.newThread(() -> {}); + + // Then + assertTrue(thread.isDaemon()); + assertEquals("test-1", thread.getName()); + } + + @Test + void shouldCreateNonDaemonThreadWhenDaemonIsFalse() { + // Given + AT4JThreadFactory factory = new AT4JThreadFactory("test-%d", false); + + // When + Thread thread = factory.newThread(() -> {}); + + // Then + assertFalse(thread.isDaemon()); + assertEquals("test-1", thread.getName()); + } + + @Test + void shouldIncrementThreadNameCounter() { + // Given + AT4JThreadFactory factory = new AT4JThreadFactory("test-%d", true); + + // When + Thread thread1 = factory.newThread(() -> {}); + Thread thread2 = factory.newThread(() -> {}); + + // Then + assertEquals("test-1", thread1.getName()); + assertEquals("test-2", thread2.getName()); + } + + @Test + void shouldHandleNamePatternWithoutCounter() { + // Given + AT4JThreadFactory factory = new AT4JThreadFactory("test", true); + + // When + Thread thread = factory.newThread(() -> {}); + + // Then + assertEquals("test", thread.getName()); + } +} diff --git a/src/test/java/com/github/brenoepics/at4j/core/thread/ThreadPoolImplTest.java b/src/test/java/com/github/brenoepics/at4j/core/thread/ThreadPoolImplTest.java index 23aff5f..645d123 100644 --- a/src/test/java/com/github/brenoepics/at4j/core/thread/ThreadPoolImplTest.java +++ b/src/test/java/com/github/brenoepics/at4j/core/thread/ThreadPoolImplTest.java @@ -11,63 +11,66 @@ class ThreadPoolImplTest { - private ThreadPoolImpl threadPool; + private ThreadPoolImpl threadPool; - @BeforeEach - void setUp() { - threadPool = new ThreadPoolImpl(); - } + @BeforeEach + void setUp() { + threadPool = new ThreadPoolImpl(); + } - @Test - void shouldReturnExecutorService() { - ExecutorService executorService = threadPool.getExecutorService(); - assertNotNull(executorService); - } + @Test + void shouldReturnExecutorService() { + ExecutorService executorService = threadPool.getExecutorService(); + assertNotNull(executorService); + } - @Test - void shouldReturnScheduler() { - ScheduledExecutorService scheduler = threadPool.getScheduler(); - assertNotNull(scheduler); - } + @Test + void shouldReturnScheduler() { + ScheduledExecutorService scheduler = threadPool.getScheduler(); + assertNotNull(scheduler); + } - @Test - void shouldReturnDaemonScheduler() { - ScheduledExecutorService daemonScheduler = threadPool.getDaemonScheduler(); - assertNotNull(daemonScheduler); - } + @Test + void shouldReturnDaemonScheduler() { + ScheduledExecutorService daemonScheduler = threadPool.getDaemonScheduler(); + assertNotNull(daemonScheduler); + } - @Test - void shouldReturnSingleThreadExecutorService() { - ExecutorService singleThreadExecutorService = threadPool.getSingleThreadExecutorService("TestThread"); - assertNotNull(singleThreadExecutorService); - } + @Test + void shouldReturnSingleThreadExecutorService() { + ExecutorService singleThreadExecutorService = + threadPool.getSingleThreadExecutorService("TestThread"); + assertNotNull(singleThreadExecutorService); + } - @Test - void shouldReturnSingleDaemonThreadExecutorService() { - ExecutorService singleDaemonThreadExecutorService = threadPool.getSingleDaemonThreadExecutorService("TestDaemonThread"); - assertNotNull(singleDaemonThreadExecutorService); - } + @Test + void shouldReturnSingleDaemonThreadExecutorService() { + ExecutorService singleDaemonThreadExecutorService = + threadPool.getSingleDaemonThreadExecutorService("TestDaemonThread"); + assertNotNull(singleDaemonThreadExecutorService); + } - @Test - void shouldRemoveAndShutdownSingleThreadExecutorService() { - threadPool.getSingleThreadExecutorService("TestThread"); - assertTrue(threadPool.removeAndShutdownSingleThreadExecutorService("TestThread").isPresent()); - } + @Test + void shouldRemoveAndShutdownSingleThreadExecutorService() { + threadPool.getSingleThreadExecutorService("TestThread"); + assertTrue(threadPool.removeAndShutdownSingleThreadExecutorService("TestThread").isPresent()); + } - @Test - void shouldNotRemoveNonExistentSingleThreadExecutorService() { - assertFalse(threadPool.removeAndShutdownSingleThreadExecutorService("NonExistentThread").isPresent()); - } + @Test + void shouldNotRemoveNonExistentSingleThreadExecutorService() { + assertFalse( + threadPool.removeAndShutdownSingleThreadExecutorService("NonExistentThread").isPresent()); + } - @Test - void shouldRunAfterGivenDuration() { - assertDoesNotThrow(() -> threadPool.runAfter(() -> null, 1, TimeUnit.SECONDS)); - } + @Test + void shouldRunAfterGivenDuration() { + assertDoesNotThrow(() -> threadPool.runAfter(() -> null, 1, TimeUnit.SECONDS)); + } - @Test - void shouldShutdownAllServices() { - threadPool.getSingleThreadExecutorService("TestThread"); - threadPool.getSingleDaemonThreadExecutorService("TestDaemonThread"); - assertDoesNotThrow(() -> threadPool.shutdown()); - } -} \ No newline at end of file + @Test + void shouldShutdownAllServices() { + threadPool.getSingleThreadExecutorService("TestThread"); + threadPool.getSingleDaemonThreadExecutorService("TestDaemonThread"); + assertDoesNotThrow(() -> threadPool.shutdown()); + } +} From 6d25c38d4a9d3f17df4698d0cf23f936c560d29e Mon Sep 17 00:00:00 2001 From: Breno A Date: Tue, 16 Jan 2024 01:05:26 -0300 Subject: [PATCH 2/2] Delete .deepsource.toml --- .deepsource.toml | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .deepsource.toml diff --git a/.deepsource.toml b/.deepsource.toml deleted file mode 100644 index 63b9eb9..0000000 --- a/.deepsource.toml +++ /dev/null @@ -1,10 +0,0 @@ -version = 1 - -[[analyzers]] -name = "java" - - [analyzers.meta] - runtime_version = "11" - -[[transformers]] -name = "google-java-format"