package adapter import ( "context" "testing" "time" ) func TestDingTalkLimitKey(t *testing.T) { tests := []struct { name string url string want string }{ { name: "token only", url: "https://oapi.dingtalk.com/robot/send?access_token=abc123", want: "abc123", }, { name: "token with other params", url: "https://oapi.dingtalk.com/robot/send?access_token=tok&foo=1", want: "tok", }, { name: "missing token falls back to url", url: "https://oapi.dingtalk.com/robot/send?foo=1", want: "https://oapi.dingtalk.com/robot/send?foo=1", }, { name: "empty", url: "", want: "unknown", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := DingTalkLimitKey(tt.url); got != tt.want { t.Fatalf("DingTalkLimitKey(%q) = %q, want %q", tt.url, got, tt.want) } }) } } func TestDingTalkLimiterAcquireWaitsForNextWindow(t *testing.T) { now := time.Unix(1000, 0) // fixed var slept time.Duration store := newMemoryMinuteStore() lim := &DingTalkLimiter{ store: store, limit: 2, now: func() time.Time { return now }, sleep: func(d time.Duration) { slept += d now = now.Add(d) }, } ctx := context.Background() key := "tok-1" if err := lim.Acquire(ctx, key); err != nil { t.Fatal(err) } if err := lim.Acquire(ctx, key); err != nil { t.Fatal(err) } if slept != 0 { t.Fatalf("unexpected sleep before limit: %v", slept) } // third should wait until next minute boundary (60 - 1000%60 = 20s? 1000/60=16 rem 40, next at 17*60=1020, wait 20s) if err := lim.Acquire(ctx, key); err != nil { t.Fatal(err) } if slept != 20*time.Second { t.Fatalf("slept = %v, want 20s", slept) } } func TestDingTalkLimiterSameKeyShared(t *testing.T) { now := time.Unix(0, 0) store := newMemoryMinuteStore() lim := &DingTalkLimiter{ store: store, limit: 1, now: func() time.Time { return now }, sleep: func(d time.Duration) { now = now.Add(d) }, } ctx := context.Background() if err := lim.Acquire(ctx, "shared"); err != nil { t.Fatal(err) } if err := lim.Acquire(ctx, "shared"); err != nil { t.Fatal(err) } if now.Unix() != 60 { t.Fatalf("expected wait to next minute boundary, now=%v", now) } }