Files
picoclaw/pkg/channels/errors_test.go
T
Hoshina a32d98534c refactor(channels): add per-channel rate limiting and send retry with error classification
Define sentinel error types (ErrNotRunning, ErrRateLimit, ErrTemporary,
ErrSendFailed) so the Manager can classify Send failures and choose the
right retry strategy: permanent errors bail immediately, rate-limit
errors use a fixed 1s delay, and temporary/unknown errors use exponential
backoff (500ms→1s→2s, capped at 8s, up to 3 retries). A per-channel
token-bucket rate limiter (golang.org/x/time/rate) throttles outbound
sends before they hit the platform API.
2026-02-24 12:10:45 +08:00

57 lines
1.3 KiB
Go

package channels
import (
"errors"
"fmt"
"testing"
)
func TestErrorsIs(t *testing.T) {
wrapped := fmt.Errorf("telegram API: %w", ErrRateLimit)
if !errors.Is(wrapped, ErrRateLimit) {
t.Error("wrapped ErrRateLimit should match")
}
if errors.Is(wrapped, ErrTemporary) {
t.Error("wrapped ErrRateLimit should not match ErrTemporary")
}
}
func TestErrorsIsAllTypes(t *testing.T) {
sentinels := []error{ErrNotRunning, ErrRateLimit, ErrTemporary, ErrSendFailed}
for _, sentinel := range sentinels {
wrapped := fmt.Errorf("context: %w", sentinel)
if !errors.Is(wrapped, sentinel) {
t.Errorf("wrapped %v should match itself", sentinel)
}
// Verify it doesn't match other sentinel errors
for _, other := range sentinels {
if other == sentinel {
continue
}
if errors.Is(wrapped, other) {
t.Errorf("wrapped %v should not match %v", sentinel, other)
}
}
}
}
func TestErrorMessages(t *testing.T) {
tests := []struct {
err error
want string
}{
{ErrNotRunning, "channel not running"},
{ErrRateLimit, "rate limited"},
{ErrTemporary, "temporary failure"},
{ErrSendFailed, "send failed"},
}
for _, tt := range tests {
if got := tt.err.Error(); got != tt.want {
t.Errorf("error message = %q, want %q", got, tt.want)
}
}
}