@ -485,6 +485,60 @@ func TestDo_rateLimit_rateLimitError(t *testing.T) {
}
}
// Ensure a network call is not made when it's known that API rate limit is still exceeded.
func TestDo_rateLimit_noNetworkCall ( t * testing . T ) {
setup ( )
defer teardown ( )
reset := time . Now ( ) . UTC ( ) . Round ( time . Second ) . Add ( time . Minute ) // Rate reset is a minute from now, with 1 second precision.
mux . HandleFunc ( "/first" , func ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Add ( headerRateLimit , "60" )
w . Header ( ) . Add ( headerRateRemaining , "0" )
w . Header ( ) . Add ( headerRateReset , fmt . Sprint ( reset . Unix ( ) ) )
w . Header ( ) . Set ( "Content-Type" , "application/json; charset=utf-8" )
w . WriteHeader ( http . StatusForbidden )
fmt . Fprintln ( w , ` {
"message" : "API rate limit exceeded for xxx.xxx.xxx.xxx. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)" ,
"documentation_url" : "https://developer.github.com/v3/#rate-limiting"
} ` )
} )
madeNetworkCall := false
mux . HandleFunc ( "/second" , func ( w http . ResponseWriter , r * http . Request ) {
madeNetworkCall = true
} )
// First request is made, and it makes the client aware of rate reset time being in the future.
req , _ := client . NewRequest ( "GET" , "/first" , nil )
client . Do ( req , nil )
// Second request should not cause a network call to be made, since client can predict a rate limit error.
req , _ = client . NewRequest ( "GET" , "/second" , nil )
_ , err := client . Do ( req , nil )
if madeNetworkCall {
t . Fatal ( "Network call was made, even though rate limit is known to still be exceeded." )
}
if err == nil {
t . Error ( "Expected error to be returned." )
}
rateLimitErr , ok := err . ( * RateLimitError )
if ! ok {
t . Fatalf ( "Expected a *RateLimitError error; got %#v." , err )
}
if got , want := rateLimitErr . Rate . Limit , 60 ; got != want {
t . Errorf ( "rateLimitErr rate limit = %v, want %v" , got , want )
}
if got , want := rateLimitErr . Rate . Remaining , 0 ; got != want {
t . Errorf ( "rateLimitErr rate remaining = %v, want %v" , got , want )
}
if rateLimitErr . Rate . Reset . UTC ( ) != reset {
t . Errorf ( "rateLimitErr rate reset = %v, want %v" , rateLimitErr . Rate . Reset . UTC ( ) , reset )
}
}
func TestDo_noContent ( t * testing . T ) {
setup ( )
defer teardown ( )
@ -635,7 +689,6 @@ func TestRateLimit(t *testing.T) {
if m := "GET" ; m != r . Method {
t . Errorf ( "Request method = %v, want %v" , r . Method , m )
}
//fmt.Fprint(w, `{"resources":{"core": {"limit":2,"remaining":1,"reset":1372700873}}}`)
fmt . Fprint ( w , ` { "resources" : {
"core" : { "limit" : 2 , "remaining" : 1 , "reset" : 1372700873 } ,
"search" : { "limit" : 3 , "remaining" : 2 , "reset" : 1372700874 }
@ -691,6 +744,13 @@ func TestRateLimits(t *testing.T) {
if ! reflect . DeepEqual ( rate , want ) {
t . Errorf ( "RateLimits returned %+v, want %+v" , rate , want )
}
if got , want := client . rateLimits [ coreCategory ] , * want . Core ; got != want {
t . Errorf ( "client.rateLimits[coreCategory] is %+v, want %+v" , got , want )
}
if got , want := client . rateLimits [ searchCategory ] , * want . Search ; got != want {
t . Errorf ( "client.rateLimits[searchCategory] is %+v, want %+v" , got , want )
}
}
func TestUnauthenticatedRateLimitedTransport ( t * testing . T ) {