@@ -17,6 +17,7 @@ import (
1717 "os"
1818 "path"
1919 "reflect"
20+ "strconv"
2021 "strings"
2122 "testing"
2223 "time"
@@ -1475,14 +1476,14 @@ func TestDo_rateLimit_abuseRateLimitErrorEnterprise(t *testing.T) {
14751476 }
14761477}
14771478
1478- // Ensure *AbuseRateLimitError.RetryAfter is parsed correctly.
1479+ // Ensure *AbuseRateLimitError.RetryAfter is parsed correctly for the Retry-After header .
14791480func TestDo_rateLimit_abuseRateLimitError_retryAfter (t * testing.T ) {
14801481 client , mux , _ , teardown := setup ()
14811482 defer teardown ()
14821483
14831484 mux .HandleFunc ("/" , func (w http.ResponseWriter , r * http.Request ) {
14841485 w .Header ().Set ("Content-Type" , "application/json; charset=utf-8" )
1485- w .Header ().Set ("Retry-After" , "123" ) // Retry after value of 123 seconds.
1486+ w .Header ().Set (headerRetryAfter , "123" ) // Retry after value of 123 seconds.
14861487 w .WriteHeader (http .StatusForbidden )
14871488 fmt .Fprintln (w , `{
14881489 "message": "You have triggered an abuse detection mechanism ...",
@@ -1528,6 +1529,64 @@ func TestDo_rateLimit_abuseRateLimitError_retryAfter(t *testing.T) {
15281529 }
15291530}
15301531
1532+ // Ensure *AbuseRateLimitError.RetryAfter is parsed correctly for the x-ratelimit-reset header.
1533+ func TestDo_rateLimit_abuseRateLimitError_xRateLimitReset (t * testing.T ) {
1534+ client , mux , _ , teardown := setup ()
1535+ defer teardown ()
1536+
1537+ // x-ratelimit-reset value of 123 seconds into the future.
1538+ blockUntil := time .Now ().Add (time .Duration (123 ) * time .Second ).Unix ()
1539+
1540+ mux .HandleFunc ("/" , func (w http.ResponseWriter , r * http.Request ) {
1541+ w .Header ().Set ("Content-Type" , "application/json; charset=utf-8" )
1542+ w .Header ().Set (headerRateReset , strconv .Itoa (int (blockUntil )))
1543+ w .Header ().Set (headerRateRemaining , "1" ) // set remaining to a value > 0 to distinct from a primary rate limit
1544+ w .WriteHeader (http .StatusForbidden )
1545+ fmt .Fprintln (w , `{
1546+ "message": "You have triggered an abuse detection mechanism ...",
1547+ "documentation_url": "https://docs.github.com/en/rest/overview/resources-in-the-rest-api#abuse-rate-limits"
1548+ }` )
1549+ })
1550+
1551+ req , _ := client .NewRequest ("GET" , "." , nil )
1552+ ctx := context .Background ()
1553+ _ , err := client .Do (ctx , req , nil )
1554+
1555+ if err == nil {
1556+ t .Error ("Expected error to be returned." )
1557+ }
1558+ abuseRateLimitErr , ok := err .(* AbuseRateLimitError )
1559+ if ! ok {
1560+ t .Fatalf ("Expected a *AbuseRateLimitError error; got %#v." , err )
1561+ }
1562+ if abuseRateLimitErr .RetryAfter == nil {
1563+ t .Fatalf ("abuseRateLimitErr RetryAfter is nil, expected not-nil" )
1564+ }
1565+ // the retry after value might be a bit smaller than the original duration because the duration is calculated from the expected end-of-cooldown time
1566+ if got , want := * abuseRateLimitErr .RetryAfter , 123 * time .Second ; want - got > 1 * time .Second {
1567+ t .Errorf ("abuseRateLimitErr RetryAfter = %v, want %v" , got , want )
1568+ }
1569+
1570+ // expect prevention of a following request
1571+ if _ , err = client .Do (ctx , req , nil ); err == nil {
1572+ t .Error ("Expected error to be returned." )
1573+ }
1574+ abuseRateLimitErr , ok = err .(* AbuseRateLimitError )
1575+ if ! ok {
1576+ t .Fatalf ("Expected a *AbuseRateLimitError error; got %#v." , err )
1577+ }
1578+ if abuseRateLimitErr .RetryAfter == nil {
1579+ t .Fatalf ("abuseRateLimitErr RetryAfter is nil, expected not-nil" )
1580+ }
1581+ // the saved duration might be a bit smaller than Retry-After because the duration is calculated from the expected end-of-cooldown time
1582+ if got , want := * abuseRateLimitErr .RetryAfter , 123 * time .Second ; want - got > 1 * time .Second {
1583+ t .Errorf ("abuseRateLimitErr RetryAfter = %v, want %v" , got , want )
1584+ }
1585+ if got , wantSuffix := abuseRateLimitErr .Message , "not making remote request." ; ! strings .HasSuffix (got , wantSuffix ) {
1586+ t .Errorf ("Expected request to be prevented because of secondary rate limit, got: %v." , got )
1587+ }
1588+ }
1589+
15311590func TestDo_noContent (t * testing.T ) {
15321591 client , mux , _ , teardown := setup ()
15331592 defer teardown ()
0 commit comments