fix(logger): add logging for request retries

This commit is contained in:
2026-09-21 22:19:00 +03:30
parent c6e2ce7fd5
commit 8bea266f03
3 changed files with 147 additions and 0 deletions

View File

@@ -1,12 +1,15 @@
package zarinhub
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
@@ -667,3 +670,97 @@ func TestClientStopsRetryOnContextCancellation(t *testing.T) {
t.Errorf("request count = %d, want 1", requestCount)
}
}
func TestClientRetryLogging(t *testing.T) {
const expectedIBAN = "IR820540102680020817909002"
requestCount := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestCount++
if requestCount == 1 {
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprint(w, `{"error":"temporary outage"}`)
return
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{
"data":{"iban":%q},
"meta":{"isSuccess":true,"errors":[]}
}`, expectedIBAN)
}))
defer server.Close()
var logBuf bytes.Buffer
logger := slog.New(slog.NewJSONHandler(&logBuf, nil))
client := NewClient(
&http.Client{Timeout: time.Second},
server.URL,
&fakeTokenProvider{tokens: []string{"test-token"}},
2,
logger,
)
client.retryWait = func(ctx context.Context, delay time.Duration) bool {
return true
}
result, err := client.Convert(context.Background(), "6037997512345678")
if err != nil {
t.Fatalf("Convert() unexpected error = %v", err)
}
if result.IBAN != expectedIBAN {
t.Errorf("IBAN = %q, want %q", result.IBAN, expectedIBAN)
}
logs := logBuf.String()
if !strings.Contains(logs, "[INITIAL] zarinhub request") {
t.Errorf("expected logs to contain '[INITIAL] zarinhub request', got:\n%s", logs)
}
if !strings.Contains(logs, `"is_retry":false`) {
t.Errorf("expected logs to contain '\"is_retry\":false', got:\n%s", logs)
}
if !strings.Contains(logs, "[RETRY] zarinhub request attempt 1") {
t.Errorf("expected logs to contain '[RETRY] zarinhub request attempt 1', got:\n%s", logs)
}
if !strings.Contains(logs, "[RETRY] zarinhub request failed, retrying in") {
t.Errorf("expected logs to contain '[RETRY] zarinhub request failed, retrying in', got:\n%s", logs)
}
if !strings.Contains(logs, `"is_retry":true`) {
t.Errorf("expected logs to contain '\"is_retry\":true', got:\n%s", logs)
}
}
func TestClientRetryLoggingExhausted(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprint(w, `{"error":"down"}`)
}))
defer server.Close()
var logBuf bytes.Buffer
logger := slog.New(slog.NewJSONHandler(&logBuf, nil))
client := NewClient(
&http.Client{Timeout: time.Second},
server.URL,
&fakeTokenProvider{tokens: []string{"test-token"}},
1,
logger,
)
client.retryWait = func(ctx context.Context, delay time.Duration) bool {
return true
}
_, err := client.Convert(context.Background(), "6037997512345678")
if !errors.Is(err, ErrUnavailable) {
t.Fatalf("error = %v, want ErrUnavailable", err)
}
logs := logBuf.String()
if !strings.Contains(logs, "[RETRY] zarinhub request failed: all retries exhausted") {
t.Errorf("expected logs to contain exhausted retries message, got:\n%s", logs)
}
}