test(updater): cover request-error retry paths
- commit
- 573527dd5bfd6aa633ba018eb2b243309621aabb
- author
- brice · · 2026-06-25 15:49 UTC
- parent
- 2bfaca9
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +67 -0
M internal/infrastructure/updater/github_test.go +67 -0
| @@ -454,6 +454,73 @@ func TestGitHubCheckerDoRequestWithRetry_RetryableStatus(t *testing.T) { | |||
| 454 | 454 | } | |
| 455 | 455 | } | |
| 456 | 456 | ||
| 457 | + | func TestGitHubCheckerDoRequestWithRetry_RetryableRequestError(t *testing.T) { | |
| 458 | + | var calls int32 | |
| 459 | + | tr := roundTripFunc(func(_ *http.Request) (*http.Response, error) { | |
| 460 | + | attempt := atomic.AddInt32(&calls, 1) | |
| 461 | + | if attempt == 1 { | |
| 462 | + | return nil, &net.OpError{Op: "read", Net: "tcp", Err: syscall.ECONNRESET} | |
| 463 | + | } | |
| 464 | + | return testResponse(http.StatusOK, `{"tag_name":"v1.2.3"}`), nil | |
| 465 | + | }) | |
| 466 | + | ||
| 467 | + | checker := NewGitHubChecker() | |
| 468 | + | checker.client = &http.Client{Transport: tr} | |
| 469 | + | checker.randInt63 = func(_ int64) int64 { return 0 } | |
| 470 | + | checker.sleep = func(context.Context, time.Duration) error { return nil } | |
| 471 | + | ||
| 472 | + | req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, githubAPIURL, http.NoBody) | |
| 473 | + | if err != nil { | |
| 474 | + | t.Fatalf("failed to create request: %v", err) | |
| 475 | + | } | |
| 476 | + | ||
| 477 | + | resp, err := checker.doRequestWithRetry(context.Background(), req) | |
| 478 | + | if err != nil { | |
| 479 | + | t.Fatalf("doRequestWithRetry() unexpected error: %v", err) | |
| 480 | + | } | |
| 481 | + | defer func() { _ = resp.Body.Close() }() | |
| 482 | + | ||
| 483 | + | if resp.StatusCode != http.StatusOK { | |
| 484 | + | t.Fatalf("status = %d, want %d", resp.StatusCode, http.StatusOK) | |
| 485 | + | } | |
| 486 | + | if atomic.LoadInt32(&calls) != 2 { | |
| 487 | + | t.Fatalf("calls = %d, want 2", calls) | |
| 488 | + | } | |
| 489 | + | } | |
| 490 | + | ||
| 491 | + | func TestGitHubCheckerDoRequestWithRetry_NoRetryOnNonRetryableRequestError(t *testing.T) { | |
| 492 | + | var calls int32 | |
| 493 | + | wantErr := errors.New("ordinary request failure") | |
| 494 | + | tr := roundTripFunc(func(_ *http.Request) (*http.Response, error) { | |
| 495 | + | atomic.AddInt32(&calls, 1) | |
| 496 | + | return nil, wantErr | |
| 497 | + | }) | |
| 498 | + | ||
| 499 | + | checker := NewGitHubChecker() | |
| 500 | + | checker.client = &http.Client{Transport: tr} | |
| 501 | + | checker.randInt63 = func(_ int64) int64 { return 0 } | |
| 502 | + | checker.sleep = func(context.Context, time.Duration) error { return nil } | |
| 503 | + | ||
| 504 | + | req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, githubAPIURL, http.NoBody) | |
| 505 | + | if err != nil { | |
| 506 | + | t.Fatalf("failed to create request: %v", err) | |
| 507 | + | } | |
| 508 | + | ||
| 509 | + | resp, err := checker.doRequestWithRetry(context.Background(), req) | |
| 510 | + | if err == nil { | |
| 511 | + | if resp != nil && resp.Body != nil { | |
| 512 | + | _ = resp.Body.Close() | |
| 513 | + | } | |
| 514 | + | t.Fatal("doRequestWithRetry() returned nil error, want request failure") | |
| 515 | + | } | |
| 516 | + | if !errors.Is(err, wantErr) { | |
| 517 | + | t.Fatalf("doRequestWithRetry() error = %v, want %v", err, wantErr) | |
| 518 | + | } | |
| 519 | + | if atomic.LoadInt32(&calls) != 1 { | |
| 520 | + | t.Fatalf("calls = %d, want 1", calls) | |
| 521 | + | } | |
| 522 | + | } | |
| 523 | + | ||
| 457 | 524 | func TestGitHubCheckerCheckForUpdate_TransientError(t *testing.T) { | |
| 458 | 525 | var calls int32 | |
| 459 | 526 | tr := roundTripFunc(func(_ *http.Request) (*http.Response, error) { | |
| @@ -454,6 +454,73 @@ func TestGitHubCheckerDoRequestWithRetry_RetryableStatus(t *testing.T) { | |||||
| 454 | } | 454 | } | ||
| 455 | } | 455 | } | ||
| 456 | 456 | ||||
| 457 | + | func TestGitHubCheckerDoRequestWithRetry_RetryableRequestError(t *testing.T) { | |||
| 458 | + | var calls int32 | |||
| 459 | + | tr := roundTripFunc(func(_ *http.Request) (*http.Response, error) { | |||
| 460 | + | attempt := atomic.AddInt32(&calls, 1) | |||
| 461 | + | if attempt == 1 { | |||
| 462 | + | return nil, &net.OpError{Op: "read", Net: "tcp", Err: syscall.ECONNRESET} | |||
| 463 | + | } | |||
| 464 | + | return testResponse(http.StatusOK, `{"tag_name":"v1.2.3"}`), nil | |||
| 465 | + | }) | |||
| 466 | + | ||||
| 467 | + | checker := NewGitHubChecker() | |||
| 468 | + | checker.client = &http.Client{Transport: tr} | |||
| 469 | + | checker.randInt63 = func(_ int64) int64 { return 0 } | |||
| 470 | + | checker.sleep = func(context.Context, time.Duration) error { return nil } | |||
| 471 | + | ||||
| 472 | + | req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, githubAPIURL, http.NoBody) | |||
| 473 | + | if err != nil { | |||
| 474 | + | t.Fatalf("failed to create request: %v", err) | |||
| 475 | + | } | |||
| 476 | + | ||||
| 477 | + | resp, err := checker.doRequestWithRetry(context.Background(), req) | |||
| 478 | + | if err != nil { | |||
| 479 | + | t.Fatalf("doRequestWithRetry() unexpected error: %v", err) | |||
| 480 | + | } | |||
| 481 | + | defer func() { _ = resp.Body.Close() }() | |||
| 482 | + | ||||
| 483 | + | if resp.StatusCode != http.StatusOK { | |||
| 484 | + | t.Fatalf("status = %d, want %d", resp.StatusCode, http.StatusOK) | |||
| 485 | + | } | |||
| 486 | + | if atomic.LoadInt32(&calls) != 2 { | |||
| 487 | + | t.Fatalf("calls = %d, want 2", calls) | |||
| 488 | + | } | |||
| 489 | + | } | |||
| 490 | + | ||||
| 491 | + | func TestGitHubCheckerDoRequestWithRetry_NoRetryOnNonRetryableRequestError(t *testing.T) { | |||
| 492 | + | var calls int32 | |||
| 493 | + | wantErr := errors.New("ordinary request failure") | |||
| 494 | + | tr := roundTripFunc(func(_ *http.Request) (*http.Response, error) { | |||
| 495 | + | atomic.AddInt32(&calls, 1) | |||
| 496 | + | return nil, wantErr | |||
| 497 | + | }) | |||
| 498 | + | ||||
| 499 | + | checker := NewGitHubChecker() | |||
| 500 | + | checker.client = &http.Client{Transport: tr} | |||
| 501 | + | checker.randInt63 = func(_ int64) int64 { return 0 } | |||
| 502 | + | checker.sleep = func(context.Context, time.Duration) error { return nil } | |||
| 503 | + | ||||
| 504 | + | req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, githubAPIURL, http.NoBody) | |||
| 505 | + | if err != nil { | |||
| 506 | + | t.Fatalf("failed to create request: %v", err) | |||
| 507 | + | } | |||
| 508 | + | ||||
| 509 | + | resp, err := checker.doRequestWithRetry(context.Background(), req) | |||
| 510 | + | if err == nil { | |||
| 511 | + | if resp != nil && resp.Body != nil { | |||
| 512 | + | _ = resp.Body.Close() | |||
| 513 | + | } | |||
| 514 | + | t.Fatal("doRequestWithRetry() returned nil error, want request failure") | |||
| 515 | + | } | |||
| 516 | + | if !errors.Is(err, wantErr) { | |||
| 517 | + | t.Fatalf("doRequestWithRetry() error = %v, want %v", err, wantErr) | |||
| 518 | + | } | |||
| 519 | + | if atomic.LoadInt32(&calls) != 1 { | |||
| 520 | + | t.Fatalf("calls = %d, want 1", calls) | |||
| 521 | + | } | |||
| 522 | + | } | |||
| 523 | + | ||||
| 457 | func TestGitHubCheckerCheckForUpdate_TransientError(t *testing.T) { | 524 | func TestGitHubCheckerCheckForUpdate_TransientError(t *testing.T) { | ||
| 458 | var calls int32 | 525 | var calls int32 | ||
| 459 | tr := roundTripFunc(func(_ *http.Request) (*http.Response, error) { | 526 | tr := roundTripFunc(func(_ *http.Request) (*http.Response, error) { | ||