feat(zarinhub): automate access token refresh
This commit is contained in:
@@ -97,7 +97,7 @@ func TestClientConvertSuccess(t *testing.T) {
|
||||
Timeout: time.Second,
|
||||
},
|
||||
server.URL,
|
||||
token,
|
||||
&fakeTokenProvider{tokens: []string{token}},
|
||||
)
|
||||
|
||||
result, err := client.Convert(
|
||||
@@ -171,7 +171,7 @@ func TestClientReturnsRejectedForApplicationFailure(
|
||||
Timeout: time.Second,
|
||||
},
|
||||
server.URL,
|
||||
"test-token",
|
||||
&fakeTokenProvider{tokens: []string{"test-token"}},
|
||||
)
|
||||
|
||||
result, err := client.Convert(
|
||||
@@ -263,7 +263,7 @@ func TestClientMapsHTTPStatusErrors(t *testing.T) {
|
||||
Timeout: time.Second,
|
||||
},
|
||||
server.URL,
|
||||
"test-token",
|
||||
&fakeTokenProvider{tokens: []string{"test-token"}},
|
||||
)
|
||||
|
||||
result, err := client.Convert(
|
||||
@@ -321,7 +321,7 @@ func TestClientReturnsInvalidResponseForMalformedJSON(
|
||||
Timeout: time.Second,
|
||||
},
|
||||
server.URL,
|
||||
"test-token",
|
||||
&fakeTokenProvider{tokens: []string{"test-token"}},
|
||||
)
|
||||
|
||||
result, err := client.Convert(
|
||||
@@ -366,7 +366,7 @@ func TestClientReturnsTimeout(t *testing.T) {
|
||||
Timeout: 50 * time.Millisecond,
|
||||
},
|
||||
server.URL,
|
||||
"test-token",
|
||||
&fakeTokenProvider{tokens: []string{"test-token"}},
|
||||
)
|
||||
|
||||
_, err := client.Convert(
|
||||
@@ -402,7 +402,7 @@ func TestClientRejectsOversizedResponse(t *testing.T) {
|
||||
client := NewClient(
|
||||
&http.Client{Timeout: time.Second},
|
||||
server.URL,
|
||||
"test-token",
|
||||
&fakeTokenProvider{tokens: []string{"test-token"}},
|
||||
)
|
||||
|
||||
_, err := client.Convert(
|
||||
@@ -414,3 +414,67 @@ func TestClientRejectsOversizedResponse(t *testing.T) {
|
||||
t.Fatalf("error = %v, want ErrInvalidResponse", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientRefreshesAndRetriesUnauthorizedRequest(t *testing.T) {
|
||||
const expectedIBAN = "IR820540102680020817909002"
|
||||
requestCount := 0
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
requestCount++
|
||||
authorization := r.Header.Get("Authorization")
|
||||
|
||||
if requestCount == 1 {
|
||||
if authorization != "Bearer expired-token" {
|
||||
t.Errorf("first authorization = %q", authorization)
|
||||
}
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if authorization != "Bearer fresh-token" {
|
||||
t.Errorf("second authorization = %q", authorization)
|
||||
}
|
||||
fmt.Fprintf(w, `{
|
||||
"data":{"iban":%q},
|
||||
"meta":{"isSuccess":true,"errors":[]}
|
||||
}`, expectedIBAN)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
tokens := &fakeTokenProvider{tokens: []string{"expired-token", "fresh-token"}}
|
||||
client := NewClient(server.Client(), server.URL, tokens)
|
||||
|
||||
result, err := client.Convert(context.Background(), "6037997512345678")
|
||||
if err != nil {
|
||||
t.Fatalf("Convert() error = %v", err)
|
||||
}
|
||||
if result.IBAN != expectedIBAN {
|
||||
t.Errorf("IBAN = %q, want %q", result.IBAN, expectedIBAN)
|
||||
}
|
||||
if requestCount != 2 {
|
||||
t.Errorf("request count = %d, want 2", requestCount)
|
||||
}
|
||||
if len(tokens.invalidated) != 1 || tokens.invalidated[0] != "expired-token" {
|
||||
t.Errorf("invalidated tokens = %v", tokens.invalidated)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeTokenProvider struct {
|
||||
tokens []string
|
||||
calls int
|
||||
invalidated []string
|
||||
}
|
||||
|
||||
func (p *fakeTokenProvider) AccessToken(context.Context) (string, error) {
|
||||
index := p.calls
|
||||
if index >= len(p.tokens) {
|
||||
index = len(p.tokens) - 1
|
||||
}
|
||||
p.calls++
|
||||
|
||||
return p.tokens[index], nil
|
||||
}
|
||||
|
||||
func (p *fakeTokenProvider) Invalidate(token string) {
|
||||
p.invalidated = append(p.invalidated, token)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user