View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2013-2025 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.jcabi.github.wire;
6   
7   import com.jcabi.github.RandomPort;
8   import com.jcabi.http.mock.MkAnswer;
9   import com.jcabi.http.mock.MkContainer;
10  import com.jcabi.http.mock.MkGrizzlyContainer;
11  import com.jcabi.http.request.FakeRequest;
12  import com.jcabi.http.request.JdkRequest;
13  import com.jcabi.http.response.RestResponse;
14  import java.io.IOException;
15  import java.net.HttpURLConnection;
16  import java.util.concurrent.TimeUnit;
17  import org.hamcrest.MatcherAssert;
18  import org.hamcrest.Matchers;
19  import org.junit.jupiter.api.Test;
20  import org.junit.jupiter.api.extension.ExtendWith;
21  
22  /**
23   * Test case for {@link RetryCarefulWire}.
24   * Just combines the RetryWire and CarefulWire test cases.
25   * @since 0.1
26   */
27  @ExtendWith(RandomPort.class)
28  final class RetryCarefulWireTest {
29      /**
30       * HTTP 200 status reason.
31       */
32      private static final String OK = "OK";
33  
34      /**
35       * Name of GitHub's number-of-requests-remaining rate limit header.
36       */
37      private static final String REMAINING_HEADER = "X-RateLimit-Remaining";
38  
39      /**
40       * The rule for skipping test if there's BindException.
41       * @checkstyle VisibilityModifierCheck (3 lines)
42       */
43      @Test
44      void makesMultipleRequestsAndWaitUntilReset() throws IOException {
45          final int threshold = 10;
46          // @checkstyle MagicNumber (2 lines)
47          final long reset = TimeUnit.MILLISECONDS
48              .toSeconds(System.currentTimeMillis()) + 5L;
49          final MkContainer container = new MkGrizzlyContainer()
50              .next(new MkAnswer.Simple(HttpURLConnection.HTTP_INTERNAL_ERROR))
51              .next(new MkAnswer.Simple(HttpURLConnection.HTTP_INTERNAL_ERROR))
52              .next(new MkAnswer.Simple(HttpURLConnection.HTTP_OK)
53                  .withHeader(RetryCarefulWireTest.REMAINING_HEADER, "9")
54                  .withHeader("X-RateLimit-Reset", String.valueOf(reset))
55              )
56              .start(RandomPort.port());
57          new JdkRequest(container.home())
58              .through(RetryCarefulWire.class, threshold)
59              .fetch()
60              .as(RestResponse.class)
61              .assertStatus(HttpURLConnection.HTTP_OK);
62          final long now = TimeUnit.MILLISECONDS
63              .toSeconds(System.currentTimeMillis());
64          MatcherAssert.assertThat(
65              "Value is not greater than expected",
66              now,
67              Matchers.greaterThanOrEqualTo(reset)
68          );
69          container.stop();
70      }
71  
72      /**
73       * RetryCarefulWire can tolerate the lack the X-RateLimit-Remaining header.
74       * @throws IOException If some problem inside
75       */
76      @Test
77      void tolerateMissingRateLimitRemainingHeader() throws IOException {
78          final int threshold = 11;
79          // @checkstyle MagicNumber (1 lines)
80          new FakeRequest()
81              .withStatus(HttpURLConnection.HTTP_OK)
82              .withReason(RetryCarefulWireTest.OK)
83              .through(RetryCarefulWire.class, threshold)
84              .fetch();
85          MatcherAssert.assertThat(
86              "Did not crash when X-RateLimit-Remaining header was absent",
87              true,
88              Matchers.is(true)
89          );
90      }
91  
92      /**
93       * RetryCarefulWire can tolerate the lack the X-RateLimit-Reset header.
94       * @throws IOException If some problem inside
95       */
96      @Test
97      void tolerateMissingRateLimitResetHeader() throws IOException {
98          final int threshold = 8;
99          // @checkstyle MagicNumber (1 lines)
100         new FakeRequest()
101             .withStatus(HttpURLConnection.HTTP_OK)
102             .withReason(RetryCarefulWireTest.OK)
103             .withHeader(RetryCarefulWireTest.REMAINING_HEADER, "7")
104             .through(RetryCarefulWire.class, threshold)
105             .fetch();
106         MatcherAssert.assertThat(
107             "Did not crash when X-RateLimit-Reset header was absent",
108             true,
109             Matchers.is(true)
110         );
111     }
112 }