diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index 6fa9108..755fc4a 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -28,6 +28,8 @@ jobs: run: | mvn -s settings.xml -Dgpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} --batch-mode deploy -P publish env: + AZURE_KEY: ${{ secrets.AZURE_KEY }} + AZURE_REGION: ${{ secrets.AZURE_REGION }} MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 084086c..1bc75a3 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -29,9 +29,6 @@ jobs: cache: maven - name: Build with Maven run: mvn -B package --file pom.xml - env: - AZURE_KEY: ${{ secrets.AZURE_KEY }} - AZURE_REGION: ${{ secrets.AZURE_REGION }} formatting: runs-on: ubuntu-latest diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 6d3872e..5551eeb 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -36,7 +36,9 @@ jobs: key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - name: Build and analyze - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: mvn -B clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=brenoepics_at4j -P coverage + env: + AZURE_KEY: ${{ secrets.AZURE_KEY }} + AZURE_REGION: ${{ secrets.AZURE_REGION }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} \ No newline at end of file diff --git a/src/main/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitBucket.java b/src/main/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitBucket.java index 27aea50..10974fc 100644 --- a/src/main/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitBucket.java +++ b/src/main/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitBucket.java @@ -81,6 +81,14 @@ public int getTimeTillSpaceGetsAvailable() { return (int) (Math.max(rateLimitResetTimestamp, globalRLResetTimestamp) - timestamp); } + /** + * Gets the remaining RateLimit + * @return int the remaining RateLimit + */ + public int getRateLimitRemaining() { + return rateLimitRemaining; + } + /** * Checks if a bucket created with the given parameters would equal this bucket. * diff --git a/src/main/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitManager.java b/src/main/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitManager.java index 55f8ea9..e29dde9 100644 --- a/src/main/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitManager.java +++ b/src/main/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitManager.java @@ -237,11 +237,11 @@ private RateLimitBucket getMatchingBucket(RestRequest request) { * @param bucket The bucket the request belongs to. * @param responseTimestamp The timestamp directly after the response finished. */ - private void handleResponse( - RestRequest request, - RestRequestResult result, - RateLimitBucket bucket, - long responseTimestamp) { + void handleResponse( + RestRequest request, + RestRequestResult result, + RateLimitBucket bucket, + long responseTimestamp) { try { HttpResponse response = result.getResponse(); diff --git a/src/test/java/io/github/brenoepics/at4j/AzureApiTest.java b/src/test/java/io/github/brenoepics/at4j/AzureApiTest.java index 72c2887..811e842 100644 --- a/src/test/java/io/github/brenoepics/at4j/AzureApiTest.java +++ b/src/test/java/io/github/brenoepics/at4j/AzureApiTest.java @@ -99,14 +99,14 @@ void translateEmptySourceLanguage() { @Test void translateHelloWorld() { - String subscriptionKey = System.getenv("AZURE_KEY"); - String subscriptionRegion = System.getenv("AZURE_REGION"); + String azureKey = System.getenv("AZURE_KEY"); + String region = System.getenv("AZURE_REGION"); Assumptions.assumeTrue( - subscriptionKey != null && subscriptionRegion != null, - "Azure Credentials are null, skipping the test"); + azureKey != null && region != null, "Azure Credentials are null, skipping the test"); + Assumptions.assumeTrue( + !azureKey.isEmpty() && !region.isEmpty(), "Azure Credentials are empty, skipping the test"); - AzureApiBuilder builder = - new AzureApiBuilder().setKey(subscriptionKey).region(subscriptionRegion); + AzureApiBuilder builder = new AzureApiBuilder().setKey(azureKey).region(region); AzureApi api = builder.build(); TranslateParams params = new TranslateParams("Hello World!", List.of("pt", "es")); @@ -117,13 +117,14 @@ void translateHelloWorld() { @Test void detectHelloWorldLanguage() { - String subscriptionKey = System.getenv("AZURE_KEY"); - String subscriptionRegion = System.getenv("AZURE_REGION"); + String azureKey = System.getenv("AZURE_KEY"); + String region = System.getenv("AZURE_REGION"); + Assumptions.assumeTrue( + azureKey != null && region != null, "Azure Credentials are null, skipping the test"); Assumptions.assumeTrue( - subscriptionKey != null && subscriptionRegion != null, - "Azure Credentials are null, skipping the test"); - AzureApiBuilder builder = - new AzureApiBuilder().setKey(subscriptionKey).region(subscriptionRegion); + !azureKey.isEmpty() && !region.isEmpty(), "Azure Credentials are empty, skipping the test"); + + AzureApiBuilder builder = new AzureApiBuilder().setKey(azureKey).region(region); AzureApi api = builder.build(); Optional detect = diff --git a/src/test/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitManagerTest.java b/src/test/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitManagerTest.java new file mode 100644 index 0000000..328f372 --- /dev/null +++ b/src/test/java/io/github/brenoepics/at4j/core/ratelimit/RateLimitManagerTest.java @@ -0,0 +1,85 @@ +package io.github.brenoepics.at4j.core.ratelimit; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import io.github.brenoepics.at4j.core.AzureApiImpl; +import io.github.brenoepics.at4j.util.rest.RestEndpoint; +import io.github.brenoepics.at4j.util.rest.RestRequest; + +import java.net.http.HttpHeaders; +import java.net.http.HttpResponse; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import io.github.brenoepics.at4j.util.rest.RestRequestResult; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class RateLimitManagerTest { + private AzureApiImpl api; + private RestRequest request; + private RateLimitManager rateLimitManager; + + @BeforeEach + public void setUp() { + api = mock(AzureApiImpl.class, RETURNS_DEEP_STUBS); + request = mock(RestRequest.class); + rateLimitManager = new RateLimitManager<>(api); + } + + @Test + void testQueueRequest() { + when(request.getEndpoint()).thenReturn(RestEndpoint.LANGUAGES); + rateLimitManager.queueRequest(request); + verify(api.getThreadPool().getExecutorService()).submit(any(Runnable.class)); + } + + @Test + void testSearchBucket() { + when(request.getEndpoint()).thenReturn(RestEndpoint.LANGUAGES); + Optional> bucket = rateLimitManager.searchBucket(request); + assertTrue(bucket.isPresent()); + } + + @Test + void testWaitUntilSpaceGetsAvailable() { + RateLimitBucket bucket = new RateLimitBucket<>(RestEndpoint.LANGUAGES); + bucket.setRateLimitRemaining(1000); + bucket.setRateLimitResetTimestamp(System.currentTimeMillis() + 1000); + assertDoesNotThrow(() -> rateLimitManager.waitUntilSpaceGetsAvailable(bucket)); + } + + @Test + void testRetryRequest() { + when(request.getEndpoint()).thenReturn(RestEndpoint.LANGUAGES); + rateLimitManager.searchBucket(request); + RestRequest retriedRequest = rateLimitManager.retryRequest(new RateLimitBucket<>(RestEndpoint.LANGUAGES )); + assertNull(retriedRequest); + } + + @Test + void retryRequestWhenBucketIsEmpty() { + when(request.getEndpoint()).thenReturn(RestEndpoint.LANGUAGES); + rateLimitManager.searchBucket(request); + RestRequest retriedRequest = rateLimitManager.retryRequest(new RateLimitBucket<>(RestEndpoint.LANGUAGES)); + assertNull(retriedRequest); + } + + @Test + void handleResponseWhenStatusCodeIsNot429() { + HttpHeaders headers = mock(HttpHeaders.class); + when(headers.firstValue(RateLimitManager.RATE_LIMITED_HEADER)).thenReturn(Optional.of("1")); + when(headers.firstValue(RateLimitManager.RATE_LIMIT_RESET_HEADER)).thenReturn(Optional.of("0")); + RateLimitBucket bucket = new RateLimitBucket<>(RestEndpoint.LANGUAGES); + RestRequestResult result = mock(RestRequestResult.class); + when(result.getResponse()).thenReturn(mock(HttpResponse.class)); + when(result.getResponse().statusCode()).thenReturn(200); + when(result.getResponse().headers()).thenReturn(headers); + CompletableFuture> future = new CompletableFuture<>(); + future.complete(result); + when(request.getResult()).thenReturn(future); + rateLimitManager.handleResponse(request, result, bucket, System.currentTimeMillis()); + assertEquals(1, bucket.getRateLimitRemaining()); + } +} \ No newline at end of file