Skip to content

Commit 63207aa

Browse files
Validating Client Request ID and Testing (#246)
* Validating client request id and testing * Fixed a bug that was causing failing errors * Resolved comments from PR & made additional fixes * Fixed bug throwing nil pointer errors Co-authored-by: Mohit Sharma <65536214+mohsha-msft@users.noreply.github.com>
1 parent 559b75b commit 63207aa

File tree

3 files changed

+122
-4
lines changed

3 files changed

+122
-4
lines changed

azblob/zc_policy_unique_request_id.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package azblob
22

33
import (
44
"context"
5-
5+
"errors"
66
"github.com/Azure/azure-pipeline-go/pipeline"
77
)
88

@@ -14,9 +14,22 @@ func NewUniqueRequestIDPolicyFactory() pipeline.Factory {
1414
return func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
1515
id := request.Header.Get(xMsClientRequestID)
1616
if id == "" { // Add a unique request ID if the caller didn't specify one already
17-
request.Header.Set(xMsClientRequestID, newUUID().String())
17+
id = newUUID().String()
18+
request.Header.Set(xMsClientRequestID, id)
1819
}
19-
return next.Do(ctx, request)
20+
21+
resp, err := next.Do(ctx, request)
22+
23+
if err == nil && resp != nil {
24+
val := resp.Response().Header.Values(xMsClientRequestID)
25+
if len(val) > 0 {
26+
if val[0] != id {
27+
err = errors.New("client Request ID from request and response does not match")
28+
}
29+
}
30+
}
31+
32+
return resp, err
2033
}
2134
})
2235
}

azblob/zt_policy_request_id_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package azblob
2+
3+
import (
4+
"context"
5+
"errors"
6+
"github.com/Azure/azure-pipeline-go/pipeline"
7+
chk "gopkg.in/check.v1"
8+
"net/http"
9+
"net/url"
10+
)
11+
12+
type requestIDTestScenario int
13+
14+
const (
15+
// Testing scenarios for echoing Client Request ID
16+
clientRequestIDMissing requestIDTestScenario = 1
17+
errorFromNextPolicy requestIDTestScenario = 2
18+
clientRequestIDMatch requestIDTestScenario = 3
19+
clientRequestIDNoMatch requestIDTestScenario = 4
20+
errorMessageClientRequestIDNoMatch = "client Request ID from request and response does not match"
21+
errorMessageFromNextPolicy = "error is not nil"
22+
)
23+
24+
type clientRequestIDPolicy struct {
25+
matchID string
26+
scenario requestIDTestScenario
27+
}
28+
29+
func (p clientRequestIDPolicy) Do(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
30+
var header http.Header = make(map[string][]string)
31+
var err error
32+
33+
// Set headers and errors according to each scenario
34+
switch p.scenario {
35+
case clientRequestIDMissing:
36+
case errorFromNextPolicy:
37+
err = errors.New(errorMessageFromNextPolicy)
38+
case clientRequestIDMatch:
39+
header.Add(xMsClientRequestID, request.Header.Get(xMsClientRequestID))
40+
case clientRequestIDNoMatch:
41+
header.Add(xMsClientRequestID, "fake-client-request-id")
42+
default:
43+
header.Add(xMsClientRequestID, newUUID().String())
44+
}
45+
46+
response := http.Response{Header: header}
47+
48+
return pipeline.NewHTTPResponse(&response), err
49+
}
50+
51+
func (s *aztestsSuite) TestEchoClientRequestIDMissing(c *chk.C) {
52+
factory := NewUniqueRequestIDPolicyFactory()
53+
54+
// Scenario 1: Client Request ID is missing
55+
policy := factory.New(clientRequestIDPolicy{scenario: clientRequestIDMissing}, nil)
56+
request, _ := pipeline.NewRequest("GET", url.URL{}, nil)
57+
resp, err := policy.Do(context.Background(), request)
58+
59+
c.Assert(err, chk.IsNil)
60+
c.Assert(resp, chk.NotNil)
61+
c.Assert(resp.Response().Header.Values(xMsClientRequestID), chk.IsNil)
62+
}
63+
64+
func (s *aztestsSuite) TestEchoClientRequestIDErrorFromNextPolicy(c *chk.C) {
65+
factory := NewUniqueRequestIDPolicyFactory()
66+
67+
// Scenario 2: Do method returns an error
68+
policy := factory.New(clientRequestIDPolicy{scenario: errorFromNextPolicy}, nil)
69+
request, _ := pipeline.NewRequest("GET", url.URL{}, nil)
70+
resp, err := policy.Do(context.Background(), request)
71+
72+
c.Assert(err, chk.NotNil)
73+
c.Assert(err.Error(), chk.Equals, errorMessageFromNextPolicy)
74+
c.Assert(resp, chk.NotNil)
75+
}
76+
77+
func (s *aztestsSuite) TestEchoClientRequestIDMatch(c *chk.C) {
78+
factory := NewUniqueRequestIDPolicyFactory()
79+
80+
// Scenario 3: Client Request ID matches
81+
matchRequestID := newUUID().String()
82+
policy := factory.New(clientRequestIDPolicy{matchID: matchRequestID, scenario: clientRequestIDMatch}, nil)
83+
request, _ := pipeline.NewRequest("GET", url.URL{}, nil)
84+
request.Header.Set(xMsClientRequestID, matchRequestID)
85+
resp, err := policy.Do(context.Background(), request)
86+
87+
c.Assert(err, chk.IsNil)
88+
c.Assert(resp, chk.NotNil)
89+
c.Assert(resp.Response().Header.Get(xMsClientRequestID), chk.Equals, request.Header.Get(xMsClientRequestID))
90+
}
91+
92+
func (s *aztestsSuite) TestEchoClientRequestIDNoMatch(c *chk.C) {
93+
factory := NewUniqueRequestIDPolicyFactory()
94+
95+
// Scenario 4: Client Request ID does not match
96+
matchRequestID := newUUID().String()
97+
policy := factory.New(clientRequestIDPolicy{matchID: matchRequestID, scenario: clientRequestIDNoMatch}, nil)
98+
request, _ := pipeline.NewRequest("GET", url.URL{}, nil)
99+
request.Header.Set(xMsClientRequestID, matchRequestID)
100+
resp, err := policy.Do(context.Background(), request)
101+
102+
c.Assert(err, chk.NotNil)
103+
c.Assert(err.Error(), chk.Equals, errorMessageClientRequestIDNoMatch)
104+
c.Assert(resp, chk.NotNil)
105+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ require (
77
github.com/Azure/go-autorest/autorest/adal v0.9.2
88
github.com/google/uuid v1.1.1
99
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
10-
golang.org/x/sys v0.0.0-20200828194041-157a740278f4
10+
golang.org/x/sys v0.0.0-20200828194041-157a740278f4 // indirect
1111
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f
1212
)

0 commit comments

Comments
 (0)