From 7a2ed9c4a707090902de30f214cde415010c1237 Mon Sep 17 00:00:00 2001 From: Joel Hendrix Date: Fri, 14 Feb 2020 09:38:56 -0800 Subject: [PATCH 1/2] Enable specifying SendDecorators on a client Added field SendDecorators to autorest.Client; this value will be preferred over the default SendDecorators. Added method Client.Send() which includes logic for using custom SendDecorator chains. --- CHANGELOG.md | 7 ++++ autorest/client.go | 23 +++++++++++ autorest/client_test.go | 89 +++++++++++++++++++++++++++++++++++++++++ autorest/version.go | 2 +- 4 files changed, 120 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aca6c6d6f..e7ae6a949 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## v13.4.0 + +## New Features + +- Added field `SendDecorators` to the `Client` type. This can be used to specify a custom chain of SendDecorators per client. +- Added method `Client.Send()` which includes logic for selecting the preferred chain of SendDecorators. + ## v13.3.3 ### Bug Fixes diff --git a/autorest/client.go b/autorest/client.go index 1c6a0617a..e04f9fd4e 100644 --- a/autorest/client.go +++ b/autorest/client.go @@ -179,6 +179,11 @@ type Client struct { // Set to true to skip attempted registration of resource providers (false by default). SkipResourceProviderRegistration bool + + // SendDecorators can be used to override the default chain of SendDecorators. + // This can be used to specify things like a custom retry SendDecorator. + // Set this to an empty slice to use no SendDecorators. + SendDecorators []SendDecorator } // NewClientWithUserAgent returns an instance of a Client with the UserAgent set to the passed @@ -298,3 +303,21 @@ func (c Client) ByInspecting() RespondDecorator { } return c.ResponseInspector } + +// Send sends the provided http.Request using the client's Sender or the default sender. +// It returns the http.Response and possible error. It also accepts a, possibly empty, +// default set of SendDecorators used when sending the request. +// SendDecorators have the following precedence: +// 1. In a request's context via WithSendDecorators() +// 2. Specified on the client in SendDecorators +// 3. The default values specified in this method +func (c Client) Send(req *http.Request, decorators ...SendDecorator) (*http.Response, error) { + if c.SendDecorators != nil { + decorators = c.SendDecorators + } + inCtx := req.Context().Value(ctxSendDecorators{}) + if sd, ok := inCtx.([]SendDecorator); ok { + decorators = sd + } + return SendWithSender(c, req, decorators...) +} diff --git a/autorest/client_test.go b/autorest/client_test.go index 6cf885cd2..4f1f84453 100644 --- a/autorest/client_test.go +++ b/autorest/client_test.go @@ -16,6 +16,7 @@ package autorest import ( "bytes" + "context" "crypto/tls" "fmt" "io/ioutil" @@ -461,3 +462,91 @@ func randomString(n int) string { } return string(s) } + +func TestClientSendMethod(t *testing.T) { + sender := mocks.NewSender() + sender.AppendResponse(newAcceptedResponse()) + client := Client{ + Sender: sender, + } + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, mocks.TestURL, nil) + if err != nil { + t.Fatal(err) + } + // no SendDecorators + resp, err := client.Send(req) + if err != nil { + t.Fatal(err) + } + if resp.StatusCode != http.StatusAccepted { + t.Fatalf("expected status code %d, got %d", http.StatusAccepted, resp.StatusCode) + } + // default SendDecorators + sender.AppendResponse(newAcceptedResponse()) + resp, err = client.Send(req, DefaultSendDecorator()) + if err != nil { + t.Fatal(err) + } + if v := resp.Header.Get("default-decorator"); v != "true" { + t.Fatal("didn't find default-decorator header in response") + } + // using client SendDecorators + sender.AppendResponse(newAcceptedResponse()) + client.SendDecorators = []SendDecorator{ClientSendDecorator()} + resp, err = client.Send(req, DefaultSendDecorator()) + if err != nil { + t.Fatal(err) + } + if v := resp.Header.Get("client-decorator"); v != "true" { + t.Fatal("didn't find client-decorator header in response") + } + if v := resp.Header.Get("default-decorator"); v == "true" { + t.Fatal("unexpected default-decorator header in response") + } + // using context SendDecorators + sender.AppendResponse(newAcceptedResponse()) + req = req.WithContext(WithSendDecorators(req.Context(), []SendDecorator{ContextSendDecorator()})) + resp, err = client.Send(req, DefaultSendDecorator()) + if err != nil { + t.Fatal(err) + } + if v := resp.Header.Get("context-decorator"); v != "true" { + t.Fatal("didn't find context-decorator header in response") + } + if v := resp.Header.Get("client-decorator"); v == "true" { + t.Fatal("unexpected client-decorator header in response") + } + if v := resp.Header.Get("default-decorator"); v == "true" { + t.Fatal("unexpected default-decorator header in response") + } +} + +func DefaultSendDecorator() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + resp, err := s.Do(r) + resp.Header.Set("default-decorator", "true") + return resp, err + }) + } +} + +func ClientSendDecorator() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + resp, err := s.Do(r) + resp.Header.Set("client-decorator", "true") + return resp, err + }) + } +} + +func ContextSendDecorator() SendDecorator { + return func(s Sender) Sender { + return SenderFunc(func(r *http.Request) (*http.Response, error) { + resp, err := s.Do(r) + resp.Header.Set("context-decorator", "true") + return resp, err + }) + } +} diff --git a/autorest/version.go b/autorest/version.go index bdaff1d08..a42f705d3 100644 --- a/autorest/version.go +++ b/autorest/version.go @@ -19,7 +19,7 @@ import ( "runtime" ) -const number = "v13.3.3" +const number = "v13.4.0" var ( userAgent = fmt.Sprintf("Go/%s (%s-%s) go-autorest/%s", From 266495b72b3e33bf8e8131c323505b80ce823d35 Mon Sep 17 00:00:00 2001 From: Joel Hendrix Date: Fri, 14 Feb 2020 10:17:39 -0800 Subject: [PATCH 2/2] fix test to work with older versions of Go --- autorest/client_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autorest/client_test.go b/autorest/client_test.go index 4f1f84453..bdd65a594 100644 --- a/autorest/client_test.go +++ b/autorest/client_test.go @@ -469,7 +469,8 @@ func TestClientSendMethod(t *testing.T) { client := Client{ Sender: sender, } - req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, mocks.TestURL, nil) + req, err := http.NewRequest(http.MethodGet, mocks.TestURL, nil) + req = req.WithContext(context.Background()) if err != nil { t.Fatal(err) }