Files
team-api/internal/logic/monitor/request_tracker_test.go
T

89 lines
3.2 KiB
Go

package monitor
import (
"sync"
"testing"
"time"
)
func TestSnapshotBandwidthConcurrent(t *testing.T) {
tracker := &requestTracker{}
tracker.bytesIn.Store(1024)
tracker.bytesOut.Store(2048)
base := time.Now()
var workers sync.WaitGroup
for i := range 100 {
workers.Add(1)
go func(offset int) {
defer workers.Done()
tracker.snapshotBandwidth(base.Add(time.Duration(offset) * time.Millisecond))
}(i)
}
workers.Wait()
tracker.bytesIn.Add(100)
tracker.bytesOut.Add(200)
snapshot := tracker.snapshotBandwidth(base.Add(time.Second))
if snapshot.BytesInPerSec < 0 || snapshot.BytesOutPerSec < 0 {
t.Fatalf("bandwidth rates must not be negative: %+v", snapshot)
}
}
// 读接口不得推进采样:历史点只能来自后台采样器,
// 否则页面关闭期间不采样、旧曲线不过期,再打开时会把上次会话的并发/带宽当成"刚刚"画出来。
func TestGetRealtimeDataDoesNotSample(t *testing.T) {
InitRequestTracker()
defer StopRequestTracker()
for range 3 {
if data := GetRealtimeData(); len(data.History) != 0 || len(data.BandwidthHistory) != 0 {
t.Fatalf("读接口不应写入历史点: conc=%d bw=%d", len(data.History), len(data.BandwidthHistory))
}
}
tracker.sample(time.Now())
data := GetRealtimeData()
if len(data.History) != 1 || len(data.BandwidthHistory) != 1 {
t.Fatalf("采样器应产出 1 个点: conc=%d bw=%d", len(data.History), len(data.BandwidthHistory))
}
}
// 超时未反注册的悬挂条目必须被清扫,且计数以 map 为准重算(修正漏减漂移)。
func TestSweepStaleDropsHangingRequests(t *testing.T) {
tr := &requestTracker{activeRequests: make(map[string]*TrackedRequest)}
now := time.Now()
tr.activeRequests["fresh"] = &TrackedRequest{RequestID: "fresh", StartTime: now.Add(-time.Minute), IsStream: true}
tr.activeRequests["hung-req"] = &TrackedRequest{RequestID: "hung-req", StartTime: now.Add(-staleRequestTTL - time.Minute)}
tr.activeRequests["hung-task"] = &TrackedRequest{RequestID: "hung-task", StartTime: now.Add(-staleTaskTTL - time.Minute), IsAsyncTask: true}
// 未到异步任务 TTL 的长任务应保留
tr.activeRequests["live-task"] = &TrackedRequest{RequestID: "live-task", StartTime: now.Add(-staleRequestTTL - time.Minute), IsAsyncTask: true}
// 计数故意置成漂移值,验证重算能自愈
tr.totalActive.Store(99)
total, streaming := tr.sweepStale(now)
if total != 2 || streaming != 1 {
t.Fatalf("清扫后应剩 2 条(1 条流式),实际 total=%d streaming=%d", total, streaming)
}
if got := tr.totalActive.Load(); got != 2 {
t.Fatalf("计数应按 map 重算为 2,实际 %d", got)
}
if _, ok := tr.activeRequests["live-task"]; !ok {
t.Fatal("未超时的异步任务被误清扫")
}
}
func TestFilterRecentDropsStalePoints(t *testing.T) {
now := time.Now()
items := []ConcurrencySnapshot{
{Timestamp: now.Add(-2 * historyWindow), TotalActive: 7}, // 上次会话遗留
{Timestamp: now.Add(-time.Minute), TotalActive: 1},
{Timestamp: now, TotalActive: 2},
}
got := filterRecent(items, now.Add(-historyWindow), func(s ConcurrencySnapshot) time.Time { return s.Timestamp })
if len(got) != 2 || got[0].TotalActive != 1 {
t.Fatalf("应只保留窗口内的 2 个点,实际 %+v", got)
}
}