Files
pangolin/server/internal/usage/handler_test.go
T
wangjia 636a3bbf2f feat(server/stats): stats-overhaul Phase2 — 每设备归因 + GB 综合配额
服务端记账从「账户」细到「每设备」(每设备独立 dp_uuid),配额单位分钟→GB
按账户综合卡控。000015_per_device_usage 迁移(mysql+sqlite 双份):devices.dp_uuid
+ usage_device_daily 表 + plans.daily_mb。handler_grpc 按 dp_uuid 回映射
(user_id,device_id) 双写账户+每设备;usage 服务/handler 暴露 /v1/usage(/devices)。
含 sqlite_per_device / usage handler 测试。

注:此迁移 prod 已 migrate up 运行、部署二进制已内嵌;本次补提交使 git 与线上一致。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 18:12:00 +08:00

47 lines
1.5 KiB
Go

package usage
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/wangjia/pangolin/server/internal/codes"
)
// authedRequest builds a request whose context carries an authenticated user id,
// mirroring what auth.RequireAuth installs upstream.
func authedRequest(method, target string, userID int64) *http.Request {
r := httptest.NewRequest(method, target, nil)
if userID != 0 {
r = r.WithContext(context.WithValue(r.Context(), codes.CtxKeyUserID, userID))
}
return r
}
// The DeviceUsageHandler gates on auth, method and the days query param before
// ever touching the service/DB — these branches are verified DB-free.
func TestDeviceUsageHandler_Guards(t *testing.T) {
h := NewDeviceUsageHandler(NewService(nil, nil, nil, 0))
cases := []struct {
name string
req *http.Request
status int
}{
{"no auth → 401", authedRequest(http.MethodGet, "/v1/usage/devices", 0), http.StatusUnauthorized},
{"wrong method → 405", authedRequest(http.MethodPost, "/v1/usage/devices", 7), http.StatusMethodNotAllowed},
{"days out of range → 400", authedRequest(http.MethodGet, "/v1/usage/devices?days=999", 7), http.StatusBadRequest},
{"days non-numeric → 400", authedRequest(http.MethodGet, "/v1/usage/devices?days=abc", 7), http.StatusBadRequest},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
w := httptest.NewRecorder()
h.ServeHTTP(w, c.req)
if w.Code != c.status {
t.Errorf("status=%d, want %d (body=%s)", w.Code, c.status, w.Body.String())
}
})
}
}