1616
1717import static org .hamcrest .CoreMatchers .*;
1818import static org .hamcrest .CoreMatchers .notNullValue ;
19+ import static org .hamcrest .Matchers .greaterThan ;
1920import static org .hamcrest .core .IsInstanceOf .instanceOf ;
2021
2122// TODO: Auto-generated Javadoc
@@ -98,22 +99,14 @@ public void onError(IOException e, HttpURLConnection uc) throws IOException {
9899 // getting an input stream in an error case should throw
99100 IOException ioEx = Assert .assertThrows (IOException .class , () -> uc .getInputStream ());
100101
101- try (InputStream errorStream = uc .getErrorStream ()) {
102- assertThat (errorStream , notNullValue ());
103- String errorString = IOUtils .toString (errorStream , StandardCharsets .UTF_8 );
104- assertThat (errorString , containsString ("Must have push access to repository" ));
105- }
102+ checkErrorMessageMatches (uc , "Must have push access to repository" );
106103
107104 // calling again should still error
108105 ioEx = Assert .assertThrows (IOException .class , () -> uc .getInputStream ());
109106
110107 // calling again on a GitHubConnectorResponse should yield the same value
111108 if (uc .toString ().contains ("GitHubConnectorResponseHttpUrlConnectionAdapter" )) {
112- try (InputStream errorStream = uc .getErrorStream ()) {
113- assertThat (errorStream , notNullValue ());
114- String errorString = IOUtils .toString (errorStream , StandardCharsets .UTF_8 );
115- assertThat (errorString , containsString ("Must have push access to repository" ));
116- }
109+ checkErrorMessageMatches (uc , "Must have push access to repository" );
117110 } else {
118111 try (InputStream errorStream = uc .getErrorStream ()) {
119112 assertThat (errorStream , notNullValue ());
@@ -126,7 +119,7 @@ public void onError(IOException e, HttpURLConnection uc) throws IOException {
126119 }
127120
128121 assertThat (uc .getHeaderFields (), instanceOf (Map .class ));
129- assertThat (uc .getHeaderFields ().size (), Matchers . greaterThan (25 ));
122+ assertThat (uc .getHeaderFields ().size (), greaterThan (25 ));
130123 assertThat (uc .getHeaderField ("Status" ), equalTo ("403 Forbidden" ));
131124
132125 String key = uc .getHeaderFieldKey (1 );
@@ -349,16 +342,203 @@ public void onError(IOException e, HttpURLConnection uc) throws IOException {
349342 assertThat (uc .getContentType (), equalTo ("application/json; charset=utf-8" ));
350343 assertThat (uc .getContentLength (), equalTo (-1 ));
351344 assertThat (uc .getHeaderFields (), instanceOf (Map .class ));
352- assertThat (uc .getHeaderFields ().size (), Matchers . greaterThan (25 ));
345+ assertThat (uc .getHeaderFields ().size (), greaterThan (25 ));
353346 assertThat (uc .getHeaderField ("Status" ), equalTo ("403 Forbidden" ));
354347
355- try (InputStream errorStream = uc .getErrorStream ()) {
356- assertThat (errorStream , notNullValue ());
357- String errorString = IOUtils .toString (errorStream , StandardCharsets .UTF_8 );
358- assertThat (errorString ,
359- containsString (
360- "You have exceeded a secondary rate limit. Please wait a few minutes before you try again" ));
361- }
348+ checkErrorMessageMatches (uc ,
349+ "You have exceeded a secondary rate limit. Please wait a few minutes before you try again" );
350+ AbuseLimitHandler .FAIL .onError (e , uc );
351+ }
352+ })
353+ .build ();
354+
355+ gitHub .getMyself ();
356+ assertThat (mockGitHub .getRequestCount (), equalTo (1 ));
357+ try {
358+ getTempRepository ();
359+ fail ();
360+ } catch (Exception e ) {
361+ assertThat (e , instanceOf (HttpException .class ));
362+ assertThat (e .getMessage (), equalTo ("Abuse limit reached" ));
363+ }
364+ assertThat (mockGitHub .getRequestCount (), equalTo (2 ));
365+ }
366+
367+ /**
368+ * This is making an assertion about the behaviour of the mock, so it's useful for making sure we're on the right
369+ * mock, but should not be used to validate assumptions about the behaviour of the actual GitHub API.
370+ */
371+ private static void checkErrorMessageMatches (HttpURLConnection uc , String substring ) throws IOException {
372+ try (InputStream errorStream = uc .getErrorStream ()) {
373+ assertThat (errorStream , notNullValue ());
374+ String errorString = IOUtils .toString (errorStream , StandardCharsets .UTF_8 );
375+ assertThat (errorString , containsString (substring ));
376+ }
377+ }
378+
379+ /**
380+ * Tests the behavior of the GitHub API client when the abuse limit handler is set to WAIT then the handler waits
381+ * appropriately when secondary rate limits are encountered.
382+ *
383+ * @throws Exception
384+ * if any error occurs during the test execution.
385+ */
386+ @ Test
387+ public void testHandler_Wait_Secondary_Limits_Too_Many_Requests () throws Exception {
388+ // Customized response that templates the date to keep things working
389+ snapshotNotAllowed ();
390+ final HttpURLConnection [] savedConnection = new HttpURLConnection [1 ];
391+ gitHub = getGitHubBuilder ().withEndpoint (mockGitHub .apiServer ().baseUrl ())
392+ .withAbuseLimitHandler (new AbuseLimitHandler () {
393+ /**
394+ * Overriding method because the actual method will wait for one minute causing slowness in unit
395+ * tests
396+ */
397+ @ Override
398+ public void onError (IOException e , HttpURLConnection uc ) throws IOException {
399+ savedConnection [0 ] = uc ;
400+ // Verify the test data is what we expected it to be for this test case
401+ assertThat (uc .getDate (), Matchers .greaterThanOrEqualTo (new Date ().getTime () - 10000 ));
402+ assertThat (uc .getExpiration (), equalTo (0L ));
403+ assertThat (uc .getIfModifiedSince (), equalTo (0L ));
404+ assertThat (uc .getLastModified (), equalTo (1581014017000L ));
405+ assertThat (uc .getRequestMethod (), equalTo ("GET" ));
406+ assertThat (uc .getResponseCode (), equalTo (429 ));
407+ assertThat (uc .getResponseMessage (), containsString ("Many" ));
408+ assertThat (uc .getURL ().toString (),
409+ endsWith (
410+ "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests" ));
411+ assertThat (uc .getContentLength (), equalTo (-1 ));
412+ assertThat (uc .getHeaderFields (), instanceOf (Map .class ));
413+ assertThat (uc .getHeaderField ("Status" ), equalTo ("429 Too Many Requests" ));
414+ assertThat (uc .getHeaderField ("Retry-After" ), equalTo ("42" ));
415+
416+ checkErrorMessageMatches (uc ,
417+ "You have exceeded a secondary rate limit. Please wait a few minutes before you try again" );
418+ // Because we've overridden onError to bypass the wait, we don't cover the wait calculation
419+ // logic
420+ // Manually invoke it to make sure it's what we intended
421+ long waitTime = parseWaitTime (uc );
422+ assertThat (waitTime , equalTo (42 * 1000l ));
423+
424+ AbuseLimitHandler .FAIL .onError (e , uc );
425+ }
426+ })
427+ .build ();
428+
429+ gitHub .getMyself ();
430+ assertThat (mockGitHub .getRequestCount (), equalTo (1 ));
431+ try {
432+ getTempRepository ();
433+ fail ();
434+ } catch (Exception e ) {
435+ assertThat (e , instanceOf (HttpException .class ));
436+ assertThat (e .getMessage (), equalTo ("Abuse limit reached" ));
437+ }
438+ assertThat (mockGitHub .getRequestCount (), equalTo (2 ));
439+ }
440+
441+ /**
442+ * Tests the behavior of the GitHub API client when the abuse limit handler with a date retry.
443+ *
444+ * @throws Exception
445+ * if any error occurs during the test execution.
446+ */
447+ @ Test
448+ public void testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After () throws Exception {
449+ // Customized response that templates the date to keep things working
450+ snapshotNotAllowed ();
451+ final HttpURLConnection [] savedConnection = new HttpURLConnection [1 ];
452+ gitHub = getGitHubBuilder ().withEndpoint (mockGitHub .apiServer ().baseUrl ())
453+ .withAbuseLimitHandler (new AbuseLimitHandler () {
454+ /**
455+ * Overriding method because the actual method will wait for one minute causing slowness in unit
456+ * tests
457+ */
458+ @ Override
459+ public void onError (IOException e , HttpURLConnection uc ) throws IOException {
460+ savedConnection [0 ] = uc ;
461+ // Verify the test data is what we expected it to be for this test case
462+ assertThat (uc .getRequestMethod (), equalTo ("GET" ));
463+ assertThat (uc .getResponseCode (), equalTo (429 ));
464+ assertThat (uc .getResponseMessage (), containsString ("Many" ));
465+ assertThat (uc .getURL ().toString (),
466+ endsWith (
467+ "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After" ));
468+ assertThat (uc .getContentLength (), equalTo (-1 ));
469+ assertThat (uc .getHeaderField ("Status" ), equalTo ("429 Too Many Requests" ));
470+ assertThat (uc .getHeaderField ("Retry-After" ), startsWith ("Mon" ));
471+
472+ checkErrorMessageMatches (uc ,
473+ "You have exceeded a secondary rate limit. Please wait a few minutes before you try again" );
474+
475+ // Because we've overridden onError to bypass the wait, we don't cover the wait calculation
476+ // logic
477+ // Manually invoke it to make sure it's what we intended
478+ long waitTime = parseWaitTime (uc );
479+ // The exact value here will depend on when the test is run, but it should be positive, and huge
480+ assertThat (waitTime , greaterThan (1000 * 1000l ));
481+
482+ AbuseLimitHandler .FAIL .onError (e , uc );
483+ }
484+ })
485+ .build ();
486+
487+ gitHub .getMyself ();
488+ assertThat (mockGitHub .getRequestCount (), equalTo (1 ));
489+ try {
490+ getTempRepository ();
491+ fail ();
492+ } catch (Exception e ) {
493+ assertThat (e , instanceOf (HttpException .class ));
494+ assertThat (e .getMessage (), equalTo ("Abuse limit reached" ));
495+ }
496+ assertThat (mockGitHub .getRequestCount (), equalTo (2 ));
497+ }
498+
499+ /**
500+ * Tests the behavior of the GitHub API client when the abuse limit handler with a no retry after header.
501+ *
502+ * @throws Exception
503+ * if any error occurs during the test execution.
504+ */
505+ @ Test
506+ public void testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After () throws Exception {
507+ // Customized response that templates the date to keep things working
508+ snapshotNotAllowed ();
509+ final HttpURLConnection [] savedConnection = new HttpURLConnection [1 ];
510+ gitHub = getGitHubBuilder ().withEndpoint (mockGitHub .apiServer ().baseUrl ())
511+ .withAbuseLimitHandler (new AbuseLimitHandler () {
512+ /**
513+ * Overriding method because the actual method will wait for one minute causing slowness in unit
514+ * tests
515+ */
516+ @ Override
517+ public void onError (IOException e , HttpURLConnection uc ) throws IOException {
518+ savedConnection [0 ] = uc ;
519+ // Verify the test data is what we expected it to be for this test case
520+ assertThat (uc .getRequestMethod (), equalTo ("GET" ));
521+ assertThat (uc .getResponseCode (), equalTo (429 ));
522+ assertThat (uc .getResponseMessage (), containsString ("Many" ));
523+ assertThat (uc .getURL ().toString (),
524+ endsWith (
525+ "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After" ));
526+ assertThat (uc .getContentEncoding (), nullValue ());
527+ assertThat (uc .getContentType (), equalTo ("application/json; charset=utf-8" ));
528+ assertThat (uc .getContentLength (), equalTo (-1 ));
529+ assertThat (uc .getHeaderFields (), instanceOf (Map .class ));
530+ assertThat (uc .getHeaderField ("Status" ), equalTo ("429 Too Many Requests" ));
531+ assertThat (uc .getHeaderField ("Retry-After" ), nullValue ());
532+
533+ checkErrorMessageMatches (uc ,
534+ "You have exceeded a secondary rate limit. Please wait a few minutes before you try again" );
535+
536+ // Because we've overridden onError to bypass the wait, we don't cover the wait calculation
537+ // logic
538+ // Manually invoke it to make sure it's what we intended
539+ long waitTime = parseWaitTime (uc );
540+ assertThat (waitTime , greaterThan (60000l ));
541+
362542 AbuseLimitHandler .FAIL .onError (e , uc );
363543 }
364544 })
0 commit comments