-
Notifications
You must be signed in to change notification settings - Fork 718
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #46 from ei-grad/set-context
Add Request.SetContext for go1.7 and above
- Loading branch information
Showing
8 changed files
with
358 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// +build !go1.8 | ||
|
||
package resty | ||
|
||
import "strings" | ||
|
||
func errIsContextCanceled(err error) bool { | ||
return strings.Contains(err.Error(), "request canceled") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// +build go1.8 | ||
|
||
package resty | ||
|
||
import ( | ||
"context" | ||
"net/url" | ||
) | ||
|
||
func errIsContextCanceled(err error) bool { | ||
ue, ok := err.(*url.Error) | ||
if !ok { | ||
return false | ||
} | ||
return ue.Err == context.Canceled | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
// +build go1.7 | ||
|
||
package resty | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestSetContext(t *testing.T) { | ||
ts := createGetServer(t) | ||
defer ts.Close() | ||
|
||
resp, err := R(). | ||
SetContext(context.Background()). | ||
Get(ts.URL + "/") | ||
|
||
assertError(t, err) | ||
assertEqual(t, http.StatusOK, resp.StatusCode()) | ||
assertEqual(t, "200 OK", resp.Status()) | ||
assertEqual(t, true, resp.Body() != nil) | ||
assertEqual(t, "TestGet: text response", resp.String()) | ||
|
||
logResponse(t, resp) | ||
} | ||
|
||
func TestSetContextWithError(t *testing.T) { | ||
ts := createGetServer(t) | ||
defer ts.Close() | ||
|
||
resp, err := dcr(). | ||
SetContext(context.Background()). | ||
Get(ts.URL + "/mypage") | ||
|
||
assertError(t, err) | ||
assertEqual(t, http.StatusBadRequest, resp.StatusCode()) | ||
assertEqual(t, "", resp.String()) | ||
|
||
logResponse(t, resp) | ||
} | ||
|
||
func TestSetContextCancel(t *testing.T) { | ||
ch := make(chan struct{}) | ||
ts := createTestServer(func(w http.ResponseWriter, r *http.Request) { | ||
defer func() { | ||
ch <- struct{}{} // tell test request is finished | ||
}() | ||
t.Logf("Server: %v %v", r.Method, r.URL.Path) | ||
ch <- struct{}{} | ||
<-ch // wait for client to finish request | ||
n, err := w.Write([]byte("TestSetContextCancel: response")) | ||
// FIXME? test server doesn't handle request cancellation | ||
t.Logf("Server: wrote %d bytes", n) | ||
t.Logf("Server: err is %v ", err) | ||
}) | ||
defer ts.Close() | ||
|
||
ctx, cancel := context.WithCancel(context.Background()) | ||
|
||
go func() { | ||
<-ch // wait for server to start request handling | ||
cancel() | ||
}() | ||
|
||
_, err := R(). | ||
SetContext(ctx). | ||
Get(ts.URL + "/") | ||
|
||
ch <- struct{}{} // tell server to continue request handling | ||
|
||
<-ch // wait for server to finish request handling | ||
|
||
t.Logf("Error: %v", err) | ||
if !errIsContextCanceled(err) { | ||
t.Errorf("Got unexpected error: %v", err) | ||
} | ||
} | ||
|
||
func TestSetContextCancelRetry(t *testing.T) { | ||
reqCount := 0 | ||
ch := make(chan struct{}) | ||
ts := createTestServer(func(w http.ResponseWriter, r *http.Request) { | ||
reqCount++ | ||
defer func() { | ||
ch <- struct{}{} // tell test request is finished | ||
}() | ||
t.Logf("Server: %v %v", r.Method, r.URL.Path) | ||
ch <- struct{}{} | ||
<-ch // wait for client to finish request | ||
n, err := w.Write([]byte("TestSetContextCancel: response")) | ||
// FIXME? test server doesn't handle request cancellation | ||
t.Logf("Server: wrote %d bytes", n) | ||
t.Logf("Server: err is %v ", err) | ||
}) | ||
defer ts.Close() | ||
|
||
ctx, cancel := context.WithCancel(context.Background()) | ||
|
||
go func() { | ||
<-ch // wait for server to start request handling | ||
cancel() | ||
}() | ||
|
||
c := dc() | ||
c.SetHTTPMode(). | ||
SetTimeout(time.Duration(time.Second * 3)). | ||
SetRetryCount(3) | ||
|
||
_, err := c.R(). | ||
SetContext(ctx). | ||
Get(ts.URL + "/") | ||
|
||
ch <- struct{}{} // tell server to continue request handling | ||
|
||
<-ch // wait for server to finish request handling | ||
|
||
t.Logf("Error: %v", err) | ||
if !errIsContextCanceled(err) { | ||
t.Errorf("Got unexpected error: %v", err) | ||
} | ||
|
||
if reqCount != 1 { | ||
t.Errorf("Request was retried %d times instead of 1", reqCount) | ||
} | ||
} | ||
|
||
func TestSetContextCancelWithError(t *testing.T) { | ||
ch := make(chan struct{}) | ||
ts := createTestServer(func(w http.ResponseWriter, r *http.Request) { | ||
defer func() { | ||
ch <- struct{}{} // tell test request is finished | ||
}() | ||
t.Logf("Server: %v %v", r.Method, r.URL.Path) | ||
t.Log("Server: sending StatusBadRequest response") | ||
w.WriteHeader(http.StatusBadRequest) | ||
ch <- struct{}{} | ||
<-ch // wait for client to finish request | ||
n, err := w.Write([]byte("TestSetContextCancelWithError: response")) | ||
// FIXME? test server doesn't handle request cancellation | ||
t.Logf("Server: wrote %d bytes", n) | ||
t.Logf("Server: err is %v ", err) | ||
}) | ||
defer ts.Close() | ||
|
||
ctx, cancel := context.WithCancel(context.Background()) | ||
|
||
go func() { | ||
<-ch // wait for server to start request handling | ||
cancel() | ||
}() | ||
|
||
_, err := R(). | ||
SetContext(ctx). | ||
Get(ts.URL + "/") | ||
|
||
ch <- struct{}{} // tell server to continue request handling | ||
|
||
<-ch // wait for server to finish request handling | ||
|
||
t.Logf("Error: %v", err) | ||
if !errIsContextCanceled(err) { | ||
t.Errorf("Got unexpected error: %v", err) | ||
} | ||
} | ||
|
||
func TestClientRetryWithSetContext(t *testing.T) { | ||
attempt := 0 | ||
ts := createTestServer(func(w http.ResponseWriter, r *http.Request) { | ||
t.Logf("Method: %v", r.Method) | ||
t.Logf("Path: %v", r.URL.Path) | ||
attempt++ | ||
if attempt != 3 { | ||
time.Sleep(time.Second * 2) | ||
} | ||
w.Write([]byte("TestClientRetry page")) | ||
}) | ||
defer ts.Close() | ||
|
||
c := dc() | ||
c.SetHTTPMode(). | ||
SetTimeout(time.Duration(time.Second * 1)). | ||
SetRetryCount(3) | ||
|
||
_, err := c.R(). | ||
SetContext(context.Background()). | ||
Get(ts.URL + "/") | ||
|
||
assertError(t, err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// +build !go1.7 | ||
|
||
package resty | ||
|
||
import ( | ||
"bytes" | ||
"net/http" | ||
"net/url" | ||
"time" | ||
) | ||
|
||
// Request type is used to compose and send individual request from client | ||
// go-resty is provide option override client level settings such as | ||
// Auth Token, Basic Auth credentials, Header, Query Param, Form Data, Error object | ||
// and also you can add more options for that particular request | ||
// | ||
type Request struct { | ||
URL string | ||
Method string | ||
QueryParam url.Values | ||
FormData url.Values | ||
Header http.Header | ||
UserInfo *User | ||
Token string | ||
Body interface{} | ||
Result interface{} | ||
Error interface{} | ||
Time time.Time | ||
RawRequest *http.Request | ||
|
||
client *Client | ||
bodyBuf *bytes.Buffer | ||
isMultiPart bool | ||
isFormData bool | ||
setContentLength bool | ||
isSaveResponse bool | ||
outputFile string | ||
proxyURL *url.URL | ||
multipartFiles []*File | ||
} | ||
|
||
func (r *Request) addContextIfAvailable() { | ||
// nothing to do for golang<1.7 | ||
} | ||
|
||
func (r *Request) isContextCancelledIfAvailable() bool { | ||
// just always return false golang<1.7 | ||
return false | ||
} |
Oops, something went wrong.