Release Please / Release Please (push) Skipped
Release / GoReleaser (push) Skipped
Tests / Secret scan (gitleaks) (push) Skipped
Tests / Test (Go 1.25) (push) Skipped
Tests / Test (Go stable) (push) Skipped
Tests / Secret scan (gitleaks) (pull_request) Successful in 4s
Tests / Test (Go 1.25) (pull_request) Successful in 21s
Tests / Test (Go stable) (pull_request) Successful in 21s
- Route HTTP helpers (getJSON/formRequest/deleteReq/postJSON/putJSON/ multipart upload), Query and AuthenticateContext/ensureToken through the deterministic 429/502/503/504 retry (retryRaw), so the integration suite no longer fails on the shared openresty rate limit under parallel runs. - Fix stale cmd/office/fetch integration test: loader.TaskFields was replaced by loader.DetailForm (broke go vet -tags=integration). - Add unit tests for Transient/DoRetry.
89 lines
2.3 KiB
Go
89 lines
2.3 KiB
Go
package onlyoffice
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTransient(t *testing.T) {
|
|
cases := []struct {
|
|
err error
|
|
want bool
|
|
}{
|
|
{nil, false},
|
|
{errors.New("boom"), false},
|
|
{errors.New("GET /api/2.0/files/1.json: 429 Too Many Requests"), true},
|
|
{errors.New("auth: 502 bad gateway"), true},
|
|
{errors.New("POST /x: 503 service unavailable"), true},
|
|
{errors.New("PUT /x: 504 gateway timeout"), true},
|
|
{errors.New("GET /x: 404 not found"), false},
|
|
{errors.New("GET /x: 4290 not a code"), false},
|
|
}
|
|
for _, c := range cases {
|
|
if got := Transient(c.err); got != c.want {
|
|
t.Errorf("Transient(%v) = %v, want %v", c.err, got, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDoRetryRetriesTransientThenSucceeds(t *testing.T) {
|
|
p := RetryPolicy{Attempts: 5, Base: time.Millisecond, Max: 5 * time.Millisecond}
|
|
attempts := 0
|
|
err := DoRetry(context.Background(), p, func() error {
|
|
attempts++
|
|
if attempts < 3 {
|
|
return errors.New("GET /x: 429 Too Many Requests")
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("DoRetry: %v", err)
|
|
}
|
|
if attempts != 3 {
|
|
t.Fatalf("attempts = %d, want 3", attempts)
|
|
}
|
|
}
|
|
|
|
func TestDoRetryStopsOnPermanentError(t *testing.T) {
|
|
p := RetryPolicy{Attempts: 5, Base: time.Millisecond, Max: time.Millisecond}
|
|
attempts := 0
|
|
err := DoRetry(context.Background(), p, func() error {
|
|
attempts++
|
|
return errors.New("GET /x: 404 not found")
|
|
})
|
|
if err == nil {
|
|
t.Fatal("want error")
|
|
}
|
|
if attempts != 1 {
|
|
t.Fatalf("attempts = %d, want 1", attempts)
|
|
}
|
|
}
|
|
|
|
func TestDoRetryExhaustsAttemptsOnPersistentTransient(t *testing.T) {
|
|
p := RetryPolicy{Attempts: 3, Base: time.Millisecond, Max: time.Millisecond}
|
|
attempts := 0
|
|
err := DoRetry(context.Background(), p, func() error {
|
|
attempts++
|
|
return errors.New("GET /x: 429 Too Many Requests")
|
|
})
|
|
if !Transient(err) {
|
|
t.Fatalf("want transient error, got %v", err)
|
|
}
|
|
if attempts != 3 {
|
|
t.Fatalf("attempts = %d, want 3", attempts)
|
|
}
|
|
}
|
|
|
|
func TestDoRetryHonoursContextCancellation(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
err := DoRetry(ctx, RetryPolicy{Attempts: 3, Base: time.Millisecond, Max: time.Millisecond}, func() error {
|
|
return errors.New("GET /x: 429 Too Many Requests")
|
|
})
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("want context.Canceled, got %v", err)
|
|
}
|
|
}
|