feat(zarinhub): implement card to iban client
This commit is contained in:
383
backend/internal/zarinhub/client_test.go
Normal file
383
backend/internal/zarinhub/client_test.go
Normal file
@@ -0,0 +1,383 @@
|
||||
package zarinhub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestClientConvertSuccess(t *testing.T) {
|
||||
const cardNumber = "6037997512345678"
|
||||
const expectedIBAN = "IR820540102680020817909002"
|
||||
const token = "test-token"
|
||||
|
||||
server := httptest.NewServer(
|
||||
http.HandlerFunc(func(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
) {
|
||||
if r.Method != http.MethodPost {
|
||||
t.Errorf(
|
||||
"method = %s, want POST",
|
||||
r.Method,
|
||||
)
|
||||
}
|
||||
|
||||
if got := r.Header.Get("Authorization"); got != "Bearer "+token {
|
||||
t.Errorf(
|
||||
"Authorization = %q, want %q",
|
||||
got,
|
||||
"Bearer "+token,
|
||||
)
|
||||
}
|
||||
|
||||
if got := r.Header.Get("Content-Type"); got != "application/json" {
|
||||
t.Errorf(
|
||||
"Content-Type = %q, want application/json",
|
||||
got,
|
||||
)
|
||||
}
|
||||
|
||||
var req convertRequest
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
t.Fatalf(
|
||||
"decode request: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
if req.Card != cardNumber {
|
||||
t.Errorf(
|
||||
"card = %q, want %q",
|
||||
req.Card,
|
||||
cardNumber,
|
||||
)
|
||||
}
|
||||
|
||||
w.Header().Set(
|
||||
"Content-Type",
|
||||
"application/json",
|
||||
)
|
||||
|
||||
fmt.Fprint(w, `{
|
||||
"data": {
|
||||
"bankName": "bankName_value",
|
||||
"card": "6037997512345678",
|
||||
"deposit": "0101234567001",
|
||||
"depositDescription": "depositDescription_value",
|
||||
"depositOwners": "depositOwners_value",
|
||||
"depositStatus": "depositStatus_value",
|
||||
"englishBankName": "englishBankName_value",
|
||||
"iban": "IR820540102680020817909002"
|
||||
},
|
||||
"meta": {
|
||||
"code": 0,
|
||||
"errorMessage": null,
|
||||
"errorType": null,
|
||||
"errors": [],
|
||||
"isSuccess": true,
|
||||
"message": "success",
|
||||
"status": "success",
|
||||
"trackId": "test-track-id"
|
||||
}
|
||||
}`)
|
||||
}),
|
||||
)
|
||||
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(
|
||||
&http.Client{
|
||||
Timeout: time.Second,
|
||||
},
|
||||
server.URL,
|
||||
token,
|
||||
)
|
||||
|
||||
result, err := client.Convert(
|
||||
context.Background(),
|
||||
cardNumber,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(
|
||||
"Convert() unexpected error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
if result.IBAN != expectedIBAN {
|
||||
t.Errorf(
|
||||
"IBAN = %q, want %q",
|
||||
result.IBAN,
|
||||
expectedIBAN,
|
||||
)
|
||||
}
|
||||
|
||||
if result.UpstreamHTTPStatus != http.StatusOK {
|
||||
t.Errorf(
|
||||
"status = %d, want %d",
|
||||
result.UpstreamHTTPStatus,
|
||||
http.StatusOK,
|
||||
)
|
||||
}
|
||||
|
||||
if len(result.RawResponse) == 0 {
|
||||
t.Error(
|
||||
"expected raw response to be preserved",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientReturnsRejectedForApplicationFailure(
|
||||
t *testing.T,
|
||||
) {
|
||||
server := httptest.NewServer(
|
||||
http.HandlerFunc(func(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
) {
|
||||
w.Header().Set(
|
||||
"Content-Type",
|
||||
"application/json",
|
||||
)
|
||||
|
||||
fmt.Fprint(w, `{
|
||||
"data": {},
|
||||
"meta": {
|
||||
"trackId": null,
|
||||
"status": "error",
|
||||
"isSuccess": false,
|
||||
"code": -1,
|
||||
"message": "request failed",
|
||||
"errorMessage": "invalid parameters",
|
||||
"errorType": "validation_error",
|
||||
"errors": []
|
||||
}
|
||||
}`)
|
||||
}),
|
||||
)
|
||||
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(
|
||||
&http.Client{
|
||||
Timeout: time.Second,
|
||||
},
|
||||
server.URL,
|
||||
"test-token",
|
||||
)
|
||||
|
||||
result, err := client.Convert(
|
||||
context.Background(),
|
||||
"6037997512345678",
|
||||
)
|
||||
|
||||
if !errors.Is(err, ErrRejected) {
|
||||
t.Fatalf(
|
||||
"error = %v, want ErrRejected",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
if result.UpstreamHTTPStatus != http.StatusOK {
|
||||
t.Errorf(
|
||||
"status = %d, want 200",
|
||||
result.UpstreamHTTPStatus,
|
||||
)
|
||||
}
|
||||
|
||||
if len(result.RawResponse) == 0 {
|
||||
t.Error(
|
||||
"expected raw response to be preserved",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientMapsHTTPStatusErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
status int
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "unauthorized",
|
||||
status: http.StatusUnauthorized,
|
||||
wantErr: ErrAuthentication,
|
||||
},
|
||||
{
|
||||
name: "forbidden",
|
||||
status: http.StatusForbidden,
|
||||
wantErr: ErrAuthentication,
|
||||
},
|
||||
{
|
||||
name: "request timeout",
|
||||
status: http.StatusRequestTimeout,
|
||||
wantErr: ErrTimeout,
|
||||
},
|
||||
{
|
||||
name: "rate limited",
|
||||
status: http.StatusTooManyRequests,
|
||||
wantErr: ErrUnavailable,
|
||||
},
|
||||
{
|
||||
name: "server error",
|
||||
status: http.StatusInternalServerError,
|
||||
wantErr: ErrUnavailable,
|
||||
},
|
||||
{
|
||||
name: "bad request",
|
||||
status: http.StatusBadRequest,
|
||||
wantErr: ErrRejected,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(
|
||||
tt.name,
|
||||
func(t *testing.T) {
|
||||
server := httptest.NewServer(
|
||||
http.HandlerFunc(func(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
) {
|
||||
w.WriteHeader(tt.status)
|
||||
|
||||
fmt.Fprint(
|
||||
w,
|
||||
`{"error":"test"}`,
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(
|
||||
&http.Client{
|
||||
Timeout: time.Second,
|
||||
},
|
||||
server.URL,
|
||||
"test-token",
|
||||
)
|
||||
|
||||
result, err := client.Convert(
|
||||
context.Background(),
|
||||
"6037997512345678",
|
||||
)
|
||||
|
||||
if !errors.Is(err, tt.wantErr) {
|
||||
t.Fatalf(
|
||||
"error = %v, want %v",
|
||||
err,
|
||||
tt.wantErr,
|
||||
)
|
||||
}
|
||||
|
||||
if result.UpstreamHTTPStatus != tt.status {
|
||||
t.Errorf(
|
||||
"status = %d, want %d",
|
||||
result.UpstreamHTTPStatus,
|
||||
tt.status,
|
||||
)
|
||||
}
|
||||
|
||||
if len(result.RawResponse) == 0 {
|
||||
t.Error(
|
||||
"expected raw response to be preserved",
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientReturnsInvalidResponseForMalformedJSON(
|
||||
t *testing.T,
|
||||
) {
|
||||
server := httptest.NewServer(
|
||||
http.HandlerFunc(func(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
fmt.Fprint(
|
||||
w,
|
||||
`{not-json}`,
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(
|
||||
&http.Client{
|
||||
Timeout: time.Second,
|
||||
},
|
||||
server.URL,
|
||||
"test-token",
|
||||
)
|
||||
|
||||
result, err := client.Convert(
|
||||
context.Background(),
|
||||
"6037997512345678",
|
||||
)
|
||||
|
||||
if !errors.Is(err, ErrInvalidResponse) {
|
||||
t.Fatalf(
|
||||
"error = %v, want ErrInvalidResponse",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
if result.UpstreamHTTPStatus != http.StatusOK {
|
||||
t.Errorf(
|
||||
"status = %d, want 200",
|
||||
result.UpstreamHTTPStatus,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientReturnsTimeout(t *testing.T) {
|
||||
server := httptest.NewServer(
|
||||
http.HandlerFunc(func(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
) {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
fmt.Fprint(
|
||||
w,
|
||||
`{}`,
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
defer server.Close()
|
||||
|
||||
client := NewClient(
|
||||
&http.Client{
|
||||
Timeout: 50 * time.Millisecond,
|
||||
},
|
||||
server.URL,
|
||||
"test-token",
|
||||
)
|
||||
|
||||
_, err := client.Convert(
|
||||
context.Background(),
|
||||
"6037997512345678",
|
||||
)
|
||||
|
||||
if !errors.Is(err, ErrTimeout) {
|
||||
t.Fatalf(
|
||||
"error = %v, want ErrTimeout",
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user