eb1bd11439
ci-pangolin / Lint — shellcheck (pull_request) Failing after 9s
ci-pangolin / OpenAPI Sync Check (pull_request) Successful in 18s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (pull_request) Successful in 6s
ci-pangolin / Flutter — analyze + test (pull_request) Successful in 39s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (pull_request) Successful in 5s
ci-pangolin / Codegen Drift — token 生成物未漂移 (pull_request) Successful in 4s
ci-pangolin / Go — build + test (pull_request) Successful in 2m2s
ci-pangolin / E2E Smoke — L4 进程级端到端 (pull_request) Failing after 2m14s
ci-pangolin / Golden — 视觉回归 (components + auth) (pull_request) Successful in 31s
CI 暴露:我的契约测试引用了未提交的 stats-overhaul 文件,本地能过(文件在工作区)、 CI checkout 已提交代码就崩: - api_contract_test.dart import device_usage.dart(?? 未提交)→ flutter analyze 报 'Target of URI doesn't exist' - usage/contract_test.go 引用 DeviceUsagePoint/deviceUsageResponse(HEAD service.go/ handler.go 均无)→ go-server 编译失败 摘掉 /v1/usage/devices(DeviceUsage)契约,保留 /v1/me + /v1/usage(已提交)。 待 stats-overhaul 合并后再补 DeviceUsage 契约。 验证:flutter analyze test/contract 'No issues';go vet usage 无错。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
package usage
|
|
|
|
// contract_test.go — HTTP 契约快照(支柱 2:契约单源)。
|
|
//
|
|
// 冻结 /v1/usage(UsagePoint)与 /v1/usage/devices(deviceUsageResponse + DeviceUsagePoint)
|
|
// 的字段面。改字段会让本测试失败,逼同步客户端 model + 文档。
|
|
//
|
|
// ⚠️ 与客户端冻结集对账:client/test/contract/api_contract_test.dart 的
|
|
// _frozenUsagePointKeys / _frozenDeviceUsageKeys。两端必须一致。
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func jsonTagSet(v any) map[string]struct{} {
|
|
t := reflect.TypeOf(v)
|
|
if t.Kind() == reflect.Ptr {
|
|
t = t.Elem()
|
|
}
|
|
set := map[string]struct{}{}
|
|
for i := 0; i < t.NumField(); i++ {
|
|
tag := t.Field(i).Tag.Get("json")
|
|
if tag == "" || tag == "-" {
|
|
continue
|
|
}
|
|
name := strings.SplitN(tag, ",", 2)[0]
|
|
if name != "" {
|
|
set[name] = struct{}{}
|
|
}
|
|
}
|
|
return set
|
|
}
|
|
|
|
func assertFrozenKeys(t *testing.T, name string, got map[string]struct{}, want ...string) {
|
|
t.Helper()
|
|
wantSet := make(map[string]struct{}, len(want))
|
|
for _, k := range want {
|
|
wantSet[k] = struct{}{}
|
|
}
|
|
for k := range got {
|
|
if _, ok := wantSet[k]; !ok {
|
|
t.Errorf("%s: 出现未冻结字段 %q —— 改契约需同步另一端(客户端 model)+ 文档", name, k)
|
|
}
|
|
}
|
|
for _, k := range want {
|
|
if _, ok := got[k]; !ok {
|
|
t.Errorf("%s: 缺失冻结字段 %q", name, k)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestContractUsagePoint(t *testing.T) {
|
|
assertFrozenKeys(t, "/v1/usage UsagePoint", jsonTagSet(UsagePoint{}),
|
|
"date", "bytes_up", "bytes_down", "minutes_used",
|
|
)
|
|
}
|
|
|
|
// 注:/v1/usage/devices(DeviceUsagePoint + deviceUsageResponse)契约待 stats-overhaul
|
|
// 合并后补——这两个 struct 当前是未提交 WIP,引用它们会让 CI 编译失败。
|