Download internal/upstream/idle_test.go from a3216/gcli2api: direct link, hf CLI and curl.
- Browser
- Download file 3.38 kB
-
https://huggingface.co/spaces/a3216/gcli2api/resolve/main/internal/upstream/idle_test.go
- Command line
-
hf download hf://spaces/a3216/gcli2api/internal/upstream/idle_test.go
-
curl -L -o idle_test.go https://huggingface.co/spaces/a3216/gcli2api/resolve/main/internal/upstream/idle_test.go
3.38 kB
| package upstream | |
| import ( | |
| "context" | |
| "io" | |
| "testing" | |
| "time" | |
| ) | |
| // TestMonitorBodyIdleCutoff 静默超过 idle(配小值)→ Read 返回错误(context canceled)。 | |
| func TestMonitorBodyIdleCutoff(t *testing.T) { | |
| ctx, cancel := context.WithCancel(context.Background()) | |
| defer cancel() | |
| // 模拟真实 resp.Body:阻塞直到请求 context 被 cancel 才返回 error。 | |
| body := monitorBody(&ctxBoundReader{ctx: ctx}, 50*time.Millisecond, cancel) | |
| defer body.Close() | |
| if _, err := body.Read(make([]byte, 16)); err == nil { | |
| t.Fatal("expect read error after idle cutoff") | |
| } | |
| } | |
| // TestMonitorBodyRenewsOnActivity 持续活跃(周期吐数据,总时长 > idle)→ 流不被掐。 | |
| func TestMonitorBodyRenewsOnActivity(t *testing.T) { | |
| _, cancel := context.WithCancel(context.Background()) | |
| defer cancel() | |
| // 每 30ms 吐 1 字节;idle=80ms。总读 10 字节耗时 300ms > idle: | |
| // 若空闲续命失效(绝对 deadline 语义)早在 80ms 就被掐断。 | |
| body := monitorBody(nopCloserBody{Reader: periodicReader{period: 30 * time.Millisecond}}, 80*time.Millisecond, cancel) | |
| defer body.Close() | |
| buf := make([]byte, 1) | |
| for i := 0; i < 10; i++ { | |
| if _, err := io.ReadFull(body, buf); err != nil { | |
| t.Fatalf("read %d: %v (active stream must not be cut)", i, err) | |
| } | |
| } | |
| } | |
| // TestMonitorBodyDisabledWhenIdleZero idle<=0 直接返回原底流。 | |
| func TestMonitorBodyDisabledWhenIdleZero(t *testing.T) { | |
| _, cancel := context.WithCancel(context.Background()) | |
| defer cancel() | |
| rc := nopCloserBody{Reader: &oneByteReader{}} | |
| out := monitorBody(rc, 0, cancel) | |
| if _, ok := out.(nopCloserBody); !ok { | |
| t.Fatalf("idle<=0 should return underlying body verbatim, got %T", out) | |
| } | |
| buf := make([]byte, 1) | |
| if _, err := out.Read(buf); err != nil || buf[0] != 'a' { | |
| t.Fatalf("read=%q err=%v", buf, err) | |
| } | |
| } | |
| // TestMonitorBodyCloseStopsGoroutine Close 停掉 goroutine,无泄漏(等效监控循环 + 短周期)。 | |
| func TestMonitorBodyCloseStopsGoroutine(t *testing.T) { | |
| m := &idleMonitoringBody{ | |
| rc: &ctxBoundReader{ctx: context.Background()}, | |
| lastRead: time.Now(), | |
| stopCh: make(chan struct{}), | |
| cancel: func() {}, | |
| } | |
| stopped := make(chan struct{}) | |
| go func() { | |
| tk := time.NewTicker(idleTick(40 * time.Millisecond)) | |
| defer tk.Stop() | |
| for { | |
| select { | |
| case <-m.stopCh: | |
| close(stopped) | |
| return | |
| case <-tk.C: | |
| } | |
| } | |
| }() | |
| m.Close() | |
| select { | |
| case <-stopped: | |
| case <-time.After(time.Second): | |
| t.Fatal("goroutine not stopped after Close") | |
| } | |
| } | |
| // —— helpers —— | |
| // ctxBoundReader 模拟 net/http resp.Body:Read 阻塞在 ctx.Done() 上,ctx cancel 后返回错误。 | |
| type ctxBoundReader struct{ ctx context.Context } | |
| func (r *ctxBoundReader) Read([]byte) (int, error) { | |
| <-r.ctx.Done() | |
| return 0, r.ctx.Err() | |
| } | |
| func (r *ctxBoundReader) Close() error { return nil } | |
| type periodicReader struct{ period time.Duration } | |
| func (r periodicReader) Read(p []byte) (int, error) { | |
| time.Sleep(r.period) | |
| p[0] = 'x' | |
| return 1, nil | |
| } | |
| type oneByteReader struct{ done bool } | |
| func (r *oneByteReader) Read(p []byte) (int, error) { | |
| if r.done { | |
| return 0, io.EOF | |
| } | |
| r.done = true | |
| p[0] = 'a' | |
| return 1, nil | |
| } | |
| type nopCloserBody struct{ io.Reader } | |
| func (nopCloserBody) Close() error { return nil } | |