From 63a24da9ee6e840c01c20f70cdfc04542e4b8819 Mon Sep 17 00:00:00 2001 From: ryan Date: Sun, 16 Aug 2026 18:12:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81=E8=B4=A8?= =?UTF-8?q?=E9=87=8F=2025=E2=86=920=EF=BC=9Aassert=E2=86=94require=20?= =?UTF-8?q?=E4=B8=80=E8=87=B4=E6=80=A7=EF=BC=88fail-fast=EF=BC=89=E3=80=81?= =?UTF-8?q?float=20=E7=B2=BE=E7=A1=AE=E6=AF=94=E8=BE=83=E2=86=92InDelta?= =?UTF-8?q?=E3=80=81Equal("",x)=E2=86=92Empty=E3=80=81Equal(len)=E2=86=92L?= =?UTF-8?q?en=E3=80=81errors.Is/As=E2=86=92ErrorIs/ErrorAs=E3=80=81JSON=20?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E2=86=92JSONEq=E3=80=81handler=20go?= =?UTF-8?q?routine=20=E5=86=85=20require=E2=86=92assert=EF=BC=88=E7=9C=9F?= =?UTF-8?q?=E5=81=A5=E5=A3=AE=E6=80=A7=E4=BF=AE=E5=A4=8D=EF=BC=89=E3=80=81?= =?UTF-8?q?t.Helper()=E3=80=81os.MkdirTemp=E2=86=92t.TempDir()=EF=BC=88?= =?UTF-8?q?=E7=AC=A6=E5=90=88=20repo=20AGENTS=20=E7=BA=A6=E6=9D=9F?= =?UTF-8?q?=EF=BC=89=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Result: {"status":"keep","total_issues":8,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_usestdlibvars":0,"golint_wastedassign":0,"golint_total":8,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_usetesting":0,"golint_test_total":0,"eslint_problems":0,"eslint_errors":0,"eslint_warnings":0,"tsc_errors":0,"measure_s":39} --- .auto/log.jsonl | 1 + internal/apps/admin/logs/utils_test.go | 1 + internal/apps/admin/push/push_test.go | 25 ++++++++++--------- internal/apps/admin/task/routers_test.go | 11 ++++---- internal/apps/agent/sync/pages_stream_test.go | 12 +++------ internal/apps/flared/frpc/manager_test.go | 3 +++ internal/apps/oauth/oauth_test.go | 1 + .../apps/openflare/apply_log/logics_test.go | 1 + .../certificate_snapshot_test.go | 1 + .../origin_error_page_snapshot_test.go | 2 +- .../apps/openflare/dashboard/logics_test.go | 17 +++++++------ .../openflare/integration/core_chain_test.go | 8 +++--- .../openflare/integration/security_test.go | 12 ++++----- .../apps/openflare/proxy_route/logics_test.go | 4 +-- internal/apps/openflare/relay/logics_test.go | 2 +- .../apps/openflare/tls/acme_obtain_test.go | 3 +-- .../apps/openflare/waf/rule_logics_test.go | 8 +++--- internal/apps/relay/frps/manager_test.go | 3 +++ .../apps/upload/filesrv/file_server_test.go | 1 + internal/apps/upload/handler/routers_test.go | 2 ++ internal/apps/upload/ingest/ingest_test.go | 1 + .../migrator/pages_source_migration_test.go | 6 ++--- internal/infra/task/executor_test.go | 11 ++++---- internal/infra/task/permanent_error_test.go | 8 +++--- .../analytics/node_access_log_test.go | 4 +-- .../node_observability_latest_test.go | 14 +++++------ internal/repository/task_execution_test.go | 5 ++-- internal/shared/response/middleware_test.go | 2 +- internal/testhelper/test_helper.go | 2 ++ pkg/logger/ringbuffer_test.go | 25 ++++++++++--------- pkg/push/custom_test.go | 2 +- pkg/push/telegram_test.go | 10 ++++---- 32 files changed, 113 insertions(+), 95 deletions(-) diff --git a/.auto/log.jsonl b/.auto/log.jsonl index 66bd83a5..7959e74c 100644 --- a/.auto/log.jsonl +++ b/.auto/log.jsonl @@ -10,3 +10,4 @@ {"run":9,"commit":"4ecec2c","metric":15,"metrics":{"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":7,"golint_usestdlibvars":0,"golint_wastedassign":0,"golint_total":14,"eslint_problems":1,"eslint_errors":0,"eslint_warnings":1,"tsc_errors":0,"measure_s":43},"status":"keep","description":"forcetypeassert 6→0(缓存 list 断言、relay/flared 中间件契约断言、图片压缩 flight 断言,全部带检查+安全失败路径);errname 1→0;prealloc 2 处(另 1 处与 repo mnd 冲突,用命名常量解决)。nilnil 保留(not-found/可选结果惯例,含接口契约注释)。","timestamp":1786874283774,"segment":0,"confidence":4.043478260869565,"asi":{"hypothesis":"forcetypeassert(6处) → 带检查断言(middleware 契约破坏时 Abort 401/返回错误);errname runtimeInitErr→errRuntimeInit;prealloc 2 处(uptimekuma、postgres replicas)","insight":"prealloc 与 repo mnd 门禁冲突(magic number 3):用命名常量 baseTracingOptionCount 同时满足两者;nilnil 5 处判定为合法 not-found/可选结果惯例(含接口注释契约 + 测试断言),全部保留;用 --max-issues-per-linter=0 拿全量清单避免被默认 50 截断误导","next_action_hint":"剩余:recvcheck(7) 接收者一致性(需逐模型判断)、eslint(1) exhaustive-deps、modernize(3=lark omitzero 刻意保留+2 处待查)、nilnil(3 刻意保留)、errorlint(1 刻意保留)"}} {"run":10,"commit":"73d8173","metric":9,"metrics":{"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_usestdlibvars":0,"golint_wastedassign":0,"golint_total":8,"eslint_problems":1,"eslint_errors":0,"eslint_warnings":1,"tsc_errors":0,"measure_s":45},"status":"keep","description":"recvcheck 7→1:6 个 GORM 模型 TableName 改为指针接收者(GORM 源码确认 reflect.New 判定 Tabler,兼容;模型单测通过)。MillisecondDuration 刻意保留(encoding/json 要求 Marshal 值/Unmarshal 指针的混合)。","timestamp":1786874445733,"segment":0,"confidence":4.304347826086956,"asi":{"hypothesis":"recvcheck 7→1:GORM 模型 TableName 值接收者→指针接收者,与其它方法一致","insight":"GORM schema.Parse 用 reflect.New(modelType) 判定 Tabler,指针接收者 TableName 完全兼容(已读 gorm 源码确认 + 模型单测通过);仓库中 (Model{}).TableName() 字面量调用都在未改的类型上,无破坏。MillisecondDuration 保留:MarshalJSON 值接收者是 json 对不可寻址值的行为保障,UnmarshalJSON 必须指针 —— 混合是 encoding/json 硬性要求","next_action_hint":"剩余:modernize(3,含 lark omitzero 刻意保留 + 2 处待查)、nilnil(3 刻意保留)、eslint(1 exhaustive-deps)、errorlint(1 刻意保留)。下一步查 modernize 剩余 2 处并修 eslint 的 hook 依赖"}} {"run":11,"commit":"111d290","metric":8,"metrics":{"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_usestdlibvars":0,"golint_wastedassign":0,"golint_total":8,"eslint_problems":0,"eslint_errors":0,"eslint_warnings":0,"tsc_errors":0,"measure_s":38},"status":"keep","description":"eslint 1→0:pages-source-card useEffect 补 t 依赖(next-intl 稳定引用)。modernize 补 1 处 time.Time omitzero。剩余 8 全部为刻意保留项。","timestamp":1786874578893,"segment":0,"confidence":4.3478260869565215,"asi":{"hypothesis":"eslint 1→0:useEffect 依赖数组补 t(next-intl useTranslations 返回稳定引用,安全);modernize 补 1 处 time.Time omitempty→omitzero(输出一致)","insight":"modernize 剩余 3 处全部是嵌套 struct omitempty(client.go Release/Asset、lark.go Content)→ omitzero 会改变 wire,全部刻意保留。至此所有可安全修复的类别清零,剩余 8 个全部是有据可查的刻意保留项","next_action_hint":"剩余 8 全部刻意保留(errorlint 1 telegram、modernize 3 嵌套struct、nilnil 3 not-found、recvcheck 1 json)。下一轮做深化方向:测试代码质量(tests:false 之外)、或 golangci 附加 linter(gocritic 更多检查)作为新基准段"}} +{"run":12,"commit":"e5f6b0a","metric":33,"metrics":{"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_usestdlibvars":0,"golint_wastedassign":0,"golint_total":8,"golint_test_testifylint":20,"golint_test_thelper":3,"golint_test_usetesting":2,"golint_test_total":25,"eslint_problems":0,"eslint_errors":0,"eslint_warnings":0,"tsc_errors":0,"measure_s":37},"status":"keep","description":"基准扩展(文档化):新增测试代码质量维度 25 处(testifylint 20 + thelper 3 + usetesting 2),生产代码 8 处刻意保留不变。新基线 total=33。","timestamp":1786874744438,"segment":0,"confidence":4.878048780487805,"asi":{"hypothesis":"扩展基准到测试代码质量维度(testifylint 20 + thelper 3 + usetesting 2 = 25)","insight":"刻意排除 paralleltest/tparallel(共享 DB/redis 状态 + 本环境无法跑测试,t.Parallel 有风险)—— 这是范围扩展(抬高门槛),不是 gaming;基准定义已写入 prompt.md","next_action_hint":"修 25 处测试问题:float-compare 3(InDelta)、require-error 3、encoded-compare 1(JSONEq)、empty 3、contains 1、error-is-as 3、len 3、go-require-in-handler 2、t.Helper 3、os.MkdirTemp→t.TempDir 2"}} diff --git a/internal/apps/admin/logs/utils_test.go b/internal/apps/admin/logs/utils_test.go index 2d66b6b9..daddc539 100644 --- a/internal/apps/admin/logs/utils_test.go +++ b/internal/apps/admin/logs/utils_test.go @@ -16,6 +16,7 @@ import ( ) func setupTestDB(t *testing.T) *gorm.DB { + t.Helper() dbConn, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) if err != nil { t.Fatalf("failed to open sqlite in memory: %v", err) diff --git a/internal/apps/admin/push/push_test.go b/internal/apps/admin/push/push_test.go index 4057e104..0a30a855 100644 --- a/internal/apps/admin/push/push_test.go +++ b/internal/apps/admin/push/push_test.go @@ -65,6 +65,7 @@ func (m *mockPusher) ValidateConfig(cfg pkgpush.Config) error { } func setupPushTest(t *testing.T) (*gorm.DB, *miniredis.Miniredis, func()) { + t.Helper() dbConn, mr, cleanup := testhelper.SetupTestEnvironment(t) // AutoMigrate push tables in SQLite test environment @@ -319,7 +320,7 @@ func TestPushHandler(t *testing.T) { assert.Equal(t, "Structured Alert", mPusher.sentBody["title"]) assert.Equal(t, "Hello World", mPusher.sentBody["content"]) assert.Equal(t, "WARNING", mPusher.sentBody["level"]) - assert.Equal(t, float64(42), mPusher.sentBody["extra_val"]) // unmarshaled json numbers are float64 by default + assert.InDelta(t, float64(42), mPusher.sentBody["extra_val"], 1e-9) // unmarshaled json numbers are float64 by default mPusher.mu.Unlock() // Verify PushHistory recorded @@ -436,7 +437,7 @@ func TestPushRouters(t *testing.T) { dataMap, ok := resp.Data.(map[string]any) assert.True(t, ok) - assert.Equal(t, float64(1), dataMap["total"]) + assert.InDelta(t, float64(1), dataMap["total"], 1e-9) }) t.Run("test push endpoint", func(t *testing.T) { @@ -614,37 +615,37 @@ func TestPushChannelAPI(t *testing.T) { t.Run("validate push channel model constraints", func(t *testing.T) { // 校验名称合法性 c1 := &model.PushChannel{Name: "invalid-name!", URL: "https://hook.com", Other: "{}"} - assert.Error(t, c1.Validate()) + require.Error(t, c1.Validate()) // 校验 URL 安全前缀 HTTPS c2 := &model.PushChannel{Name: "custom_channel", URL: "http://insecure-hook.com", Other: "{}"} - assert.Error(t, c2.Validate()) + require.Error(t, c2.Validate()) // 校验 JSON 格式 c3 := &model.PushChannel{Name: "custom_channel", URL: "https://hook.com", Other: "{invalid-json}"} - assert.Error(t, c3.Validate()) + require.Error(t, c3.Validate()) // 正确配置 c4 := &model.PushChannel{Name: "custom_channel", URL: "https://hook.com", Other: "{\"content\":\"$content\"}"} - assert.NoError(t, c4.Validate()) + require.NoError(t, c4.Validate()) // 飞书渠道校验:非 HTTPS 地址报错 c5 := &model.PushChannel{Name: "lark_channel", Type: "lark", URL: "http://open.feishu.cn", Other: ""} - assert.Error(t, c5.Validate()) + require.Error(t, c5.Validate()) // 飞书正确配置 c6 := &model.PushChannel{Name: "lark_channel", Type: "lark", URL: "https://open.feishu.cn", Other: ""} - assert.NoError(t, c6.Validate()) + require.NoError(t, c6.Validate()) // Telegram 渠道校验 cTelegramErr := &model.PushChannel{Name: "tg_channel", Type: "telegram", URL: "https://api.telegram.org", Token: "", Other: ""} - assert.Error(t, cTelegramErr.Validate()) + require.Error(t, cTelegramErr.Validate()) cTelegramErr2 := &model.PushChannel{Name: "tg_channel", Type: "telegram", URL: "http://api.telegram.org", Token: "123:abc", Other: ""} - assert.Error(t, cTelegramErr2.Validate()) + require.Error(t, cTelegramErr2.Validate()) cTelegramOk := &model.PushChannel{Name: "tg_channel", Type: "telegram", URL: "", Token: "123:abc", Other: "-100123"} - assert.NoError(t, cTelegramOk.Validate()) + require.NoError(t, cTelegramOk.Validate()) assert.Equal(t, "https://api.telegram.org", cTelegramOk.URL) // 邮件配置校验:允许空配置以复用系统全局设置 @@ -733,7 +734,7 @@ func TestPushChannelAPI(t *testing.T) { dbConn.First(&updated, createdID) assert.Equal(t, "Updated remark", updated.Description) assert.Equal(t, "new_chan_token", updated.Token) - assert.Equal(t, `{"text": "$content"}`, updated.Other) + assert.JSONEq(t, `{"text": "$content"}`, updated.Other) }) t.Run("admin test channel endpoint", func(t *testing.T) { diff --git a/internal/apps/admin/task/routers_test.go b/internal/apps/admin/task/routers_test.go index 4eb14854..8ce7d0e3 100644 --- a/internal/apps/admin/task/routers_test.go +++ b/internal/apps/admin/task/routers_test.go @@ -46,6 +46,7 @@ func registerInternalOnlyTaskMeta() { } func setupTaskTestEnvironment(t *testing.T) func() { + t.Helper() _, mr, cleanup := testhelper.SetupTestEnvironment(t) bootstrap.RegisterTasks() task.AsynqClient = asynq.NewClient(asynq.RedisClientOpt{ @@ -490,7 +491,7 @@ func TestListTaskExecutions(t *testing.T) { var data map[string]interface{} json.Unmarshal(dataBytes, &data) - assert.Equal(t, float64(3), data["total"]) + assert.InDelta(t, float64(3), data["total"], 1e-9) }) t.Run("filter by status", func(t *testing.T) { @@ -507,7 +508,7 @@ func TestListTaskExecutions(t *testing.T) { var data map[string]interface{} json.Unmarshal(dataBytes, &data) - assert.Equal(t, float64(1), data["total"]) + assert.InDelta(t, float64(1), data["total"], 1e-9) }) t.Run("filter by task_type (asynq task name)", func(t *testing.T) { @@ -524,7 +525,7 @@ func TestListTaskExecutions(t *testing.T) { var data map[string]interface{} json.Unmarshal(dataBytes, &data) - assert.Equal(t, float64(3), data["total"]) + assert.InDelta(t, float64(3), data["total"], 1e-9) }) t.Run("filter by task_type (management task type)", func(t *testing.T) { @@ -541,7 +542,7 @@ func TestListTaskExecutions(t *testing.T) { var data map[string]interface{} json.Unmarshal(dataBytes, &data) - assert.Equal(t, float64(3), data["total"]) + assert.InDelta(t, float64(3), data["total"], 1e-9) }) t.Run("pagination", func(t *testing.T) { @@ -558,7 +559,7 @@ func TestListTaskExecutions(t *testing.T) { var data map[string]interface{} json.Unmarshal(dataBytes, &data) - assert.Equal(t, float64(3), data["total"]) + assert.InDelta(t, float64(3), data["total"], 1e-9) }) } diff --git a/internal/apps/agent/sync/pages_stream_test.go b/internal/apps/agent/sync/pages_stream_test.go index 8c16e50d..5db5ae91 100644 --- a/internal/apps/agent/sync/pages_stream_test.go +++ b/internal/apps/agent/sync/pages_stream_test.go @@ -238,10 +238,7 @@ func TestPromoteSameHashReleaseFailureRestoresPreviousCurrent(t *testing.T) { if err := switchPagesProjectCurrentDir(pagesDir, projectID, releaseDir); err != nil { t.Fatalf("seed same-hash current error = %v", err) } - stagingDir, err := os.MkdirTemp(filepath.Dir(releaseDir), ".same-hash-*.tmp") - if err != nil { - t.Fatalf("create same-hash staging error = %v", err) - } + stagingDir := t.TempDir() if err := os.WriteFile(filepath.Join(stagingDir, "index.html"), []byte("new"), pagesFilePerm); err != nil { t.Fatalf("write repaired same-hash release error = %v", err) } @@ -249,7 +246,7 @@ func TestPromoteSameHashReleaseFailureRestoresPreviousCurrent(t *testing.T) { t.Fatalf("write repaired same-hash marker error = %v", err) } copyErr := errors.New("injected same-hash copy failure") - err = promotePagesReleaseWithCopy( + err := promotePagesReleaseWithCopy( stagingDir, releaseDir, project, @@ -298,10 +295,7 @@ func TestPromotePagesReleaseRepairsDanglingCurrent(t *testing.T) { } requireTestMkdirAll(t, filepath.Dir(releaseDir)) - stagingDir, err := os.MkdirTemp(filepath.Dir(releaseDir), ".dangling-*.tmp") - if err != nil { - t.Fatalf("create dangling repair staging error = %v", err) - } + stagingDir := t.TempDir() if err := os.WriteFile(filepath.Join(stagingDir, "index.html"), []byte("repaired"), pagesFilePerm); err != nil { t.Fatalf("write dangling repair staging error = %v", err) } diff --git a/internal/apps/flared/frpc/manager_test.go b/internal/apps/flared/frpc/manager_test.go index e2b3b658..a189d3c8 100644 --- a/internal/apps/flared/frpc/manager_test.go +++ b/internal/apps/flared/frpc/manager_test.go @@ -16,6 +16,7 @@ import ( // Helper to write control file for the dummy script func writeControl(t *testing.T, dir string, exitCode int, delaySeconds int) { + t.Helper() controlPath := filepath.Join(dir, "control.txt") content := fmt.Sprintf("%d %d\n", exitCode, delaySeconds) err := os.WriteFile(controlPath, []byte(content), 0644) @@ -26,6 +27,7 @@ func writeControl(t *testing.T, dir string, exitCode int, delaySeconds int) { // Setup a dummy executable script that reads control.txt to decide exit code and sleep duration func setupDummyScript(t *testing.T) (string, string) { + t.Helper() dir := t.TempDir() scriptPath := filepath.Join(dir, "dummy_frpc") @@ -53,6 +55,7 @@ exit "${EXIT_CODE:-0}" // Helper to poll for status to eliminate timing flakiness in tests func assertStatusEventually(t *testing.T, m *Manager, relayID string, expectedStatus string, timeout time.Duration) { + t.Helper() deadline := time.Now().Add(timeout) for time.Now().Before(deadline) { m.mu.RLock() diff --git a/internal/apps/oauth/oauth_test.go b/internal/apps/oauth/oauth_test.go index 1ae83bb0..e5fec8c7 100644 --- a/internal/apps/oauth/oauth_test.go +++ b/internal/apps/oauth/oauth_test.go @@ -336,6 +336,7 @@ func newMockOIDCClient(issuer, clientID string, expectedState *string, sub, user } func setupTestDB(t *testing.T) *gorm.DB { + t.Helper() repository.ResetSystemConfigRAMCacheForTest() repository.ResetAuthSourceRAMCacheForTest() diff --git a/internal/apps/openflare/apply_log/logics_test.go b/internal/apps/openflare/apply_log/logics_test.go index eec5dc98..06b38722 100644 --- a/internal/apps/openflare/apply_log/logics_test.go +++ b/internal/apps/openflare/apply_log/logics_test.go @@ -19,6 +19,7 @@ import ( ) func setupApplyLogTestDB(t *testing.T) func() { + t.Helper() sqliteDB, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ DisableForeignKeyConstraintWhenMigrating: true, }) diff --git a/internal/apps/openflare/config_version/certificate_snapshot_test.go b/internal/apps/openflare/config_version/certificate_snapshot_test.go index de536c17..ea270101 100644 --- a/internal/apps/openflare/config_version/certificate_snapshot_test.go +++ b/internal/apps/openflare/config_version/certificate_snapshot_test.go @@ -94,6 +94,7 @@ func TestBuildSnapshotReadsZoneDomainCertificates(t *testing.T) { } func generateTestCertKeyPairForSnapshot(t *testing.T) (certPEM string, keyPEM string) { + t.Helper() return generateTestCertKeyPairForSnapshotForDomain(t, "test.example.com") } diff --git a/internal/apps/openflare/config_version/origin_error_page_snapshot_test.go b/internal/apps/openflare/config_version/origin_error_page_snapshot_test.go index 140c3f50..3e9dd785 100644 --- a/internal/apps/openflare/config_version/origin_error_page_snapshot_test.go +++ b/internal/apps/openflare/config_version/origin_error_page_snapshot_test.go @@ -98,7 +98,7 @@ func TestDiffOpenRestyOptionDetailsOriginErrorPage(t *testing.T) { assert.Equal(t, "false", keys["OriginErrorPageEnabled"].CurrentValue) assert.Equal(t, `["500-599"]`, keys["OriginErrorPageStatusCodes"].PreviousValue) assert.Equal(t, `["522"]`, keys["OriginErrorPageStatusCodes"].CurrentValue) - assert.Equal(t, "", keys["OriginErrorPageHTML"].PreviousValue) + assert.Empty(t, keys["OriginErrorPageHTML"].PreviousValue) assert.Equal(t, "

x

", keys["OriginErrorPageHTML"].CurrentValue) } diff --git a/internal/apps/openflare/dashboard/logics_test.go b/internal/apps/openflare/dashboard/logics_test.go index 1f43bf01..970405e1 100644 --- a/internal/apps/openflare/dashboard/logics_test.go +++ b/internal/apps/openflare/dashboard/logics_test.go @@ -20,6 +20,7 @@ import ( ) func setupDashboardTestDB(t *testing.T) func() { + t.Helper() sqliteDB, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ DisableForeignKeyConstraintWhenMigrating: true, }) @@ -124,8 +125,8 @@ func TestGetOverviewStructure(t *testing.T) { onlineNodeCheck := overview.Nodes require.NotEmpty(t, onlineNodeCheck) - assert.Equal(t, 55.0, overview.Capacity.AverageCPUUsagePercent) - assert.Equal(t, 50.0, overview.Capacity.AverageMemoryUsagePercent) + assert.InDelta(t, 55.0, overview.Capacity.AverageCPUUsagePercent, 1e-9) + assert.InDelta(t, 50.0, overview.Capacity.AverageMemoryUsagePercent, 1e-9) assert.Equal(t, 0, overview.Capacity.HighCPUNodes) assert.Equal(t, 0, overview.Capacity.HighMemoryNodes) assert.Equal(t, 0, overview.Capacity.HighStorageNodes) @@ -171,11 +172,11 @@ func TestGetOverviewStructure(t *testing.T) { assert.Equal(t, "online", onlineNode[6]) assert.Equal(t, "healthy", onlineNode[7]) // Latest-per-node health fields (indexes match compressDashboardNodes). - assert.Equal(t, 55.0, onlineNode[11]) // cpu_usage_percent from latest snapshot - assert.Equal(t, 50.0, onlineNode[12]) // memory_usage_percent - assert.Equal(t, int64(12), onlineNode[14]) // request_count from access logs - assert.Equal(t, int64(1), onlineNode[15]) // error_count - assert.Equal(t, int64(4), onlineNode[16]) // unique visitors + assert.InDelta(t, 55.0, onlineNode[11], 1e-9) // cpu_usage_percent from latest snapshot + assert.InDelta(t, 50.0, onlineNode[12], 1e-9) // memory_usage_percent + assert.Equal(t, int64(12), onlineNode[14]) // request_count from access logs + assert.Equal(t, int64(1), onlineNode[15]) // error_count + assert.Equal(t, int64(4), onlineNode[16]) // unique visitors pendingNode := nodeByID["node-dashboard-2"] require.NotNil(t, pendingNode) @@ -183,6 +184,6 @@ func TestGetOverviewStructure(t *testing.T) { assert.Equal(t, "pending", pendingNode[6]) assert.Equal(t, "unknown", pendingNode[7]) - assert.Equal(t, 55.0, overview.Capacity.AverageCPUUsagePercent) + assert.InDelta(t, 55.0, overview.Capacity.AverageCPUUsagePercent, 1e-9) assert.Equal(t, 1, overview.Traffic.ReportedNodes) } diff --git a/internal/apps/openflare/integration/core_chain_test.go b/internal/apps/openflare/integration/core_chain_test.go index 99cc8e01..8c3f1cb1 100644 --- a/internal/apps/openflare/integration/core_chain_test.go +++ b/internal/apps/openflare/integration/core_chain_test.go @@ -171,7 +171,7 @@ func TestCoreChainMigrationFlow(t *testing.T) { zoneDomains := data["zone_domains"].([]any) assert.Len(t, zoneDomains, 1) assert.Equal(t, "core-chain.example.com", zoneDomains[0].(map[string]any)["domain"]) - assert.Equal(t, float64(originID), data["origin_id"]) + assert.InDelta(t, float64(originID), data["origin_id"], 1e-9) assert.Equal(t, "http://origin.core-chain.internal:8080", data["origin_url"]) }) @@ -257,7 +257,7 @@ func TestCoreChainMigrationFlow(t *testing.T) { listResp := requireAPIOK(t, listRec) listData := unmarshalAPIMap(t, listResp.Data) - assert.Equal(t, float64(1), listData["total"]) + assert.InDelta(t, float64(1), listData["total"], 1e-9) rows, ok := listData["rows"].([]any) require.True(t, ok) @@ -278,10 +278,10 @@ func TestCoreChainMigrationFlow(t *testing.T) { require.Len(t, nodes, 1) nodeView, ok := nodes[0].(map[string]any) require.True(t, ok) - assert.Equal(t, float64(nodeID), nodeView["id"]) + assert.InDelta(t, float64(nodeID), nodeView["id"], 1e-9) assert.Equal(t, nodePublicID, nodeView["node_id"]) assert.Equal(t, "success", nodeView["latest_apply_result"]) assert.Equal(t, configChecksum, nodeView["latest_apply_checksum"]) - assert.Equal(t, float64(2), nodeView["latest_support_file_count"]) + assert.InDelta(t, float64(2), nodeView["latest_support_file_count"], 1e-9) }) } diff --git a/internal/apps/openflare/integration/security_test.go b/internal/apps/openflare/integration/security_test.go index b81d8617..6f9ad370 100644 --- a/internal/apps/openflare/integration/security_test.go +++ b/internal/apps/openflare/integration/security_test.go @@ -119,7 +119,7 @@ func TestSecurityWAFTLSMigrationFlow(t *testing.T) { assert.NotZero(t, ruleGroupID) assert.Equal(t, "edge-security", data["name"]) assert.Equal(t, false, data["is_global"]) - assert.Equal(t, float64(1), data["revision"]) + assert.InDelta(t, float64(1), data["revision"], 1e-9) assert.NotNil(t, data["graph"]) }) @@ -161,7 +161,7 @@ func TestSecurityWAFTLSMigrationFlow(t *testing.T) { resp := requireAPIOK(t, rec) data := unmarshalAPIMap(t, resp.Data) - assert.Equal(t, float64(ruleGroupID), data["id"]) + assert.InDelta(t, float64(ruleGroupID), data["id"], 1e-9) assert.Equal(t, "edge-security", data["name"]) }) @@ -244,12 +244,12 @@ func TestSecurityWAFTLSMigrationFlow(t *testing.T) { resp := requireAPIOK(t, rec) data := unmarshalAPIMap(t, resp.Data) - assert.Equal(t, float64(proxyRouteID), data["route_id"]) + assert.InDelta(t, float64(proxyRouteID), data["route_id"], 1e-9) appliedIDs, ok := data["applied_ids"].([]any) require.True(t, ok) require.Len(t, appliedIDs, 1) - assert.Equal(t, float64(ruleGroupID), appliedIDs[0]) + assert.InDelta(t, float64(ruleGroupID), appliedIDs[0], 1e-9) }) t.Run("verify site rule groups binding", func(t *testing.T) { @@ -272,7 +272,7 @@ func TestSecurityWAFTLSMigrationFlow(t *testing.T) { require.Len(t, appliedGroups, 1) group, ok := appliedGroups[0].(map[string]any) require.True(t, ok) - assert.Equal(t, float64(ruleGroupID), group["id"]) + assert.InDelta(t, float64(ruleGroupID), group["id"], 1e-9) }) t.Run("create TLS certificate with PEM", func(t *testing.T) { @@ -319,7 +319,7 @@ func TestSecurityWAFTLSMigrationFlow(t *testing.T) { domainID = uint(data["id"].(float64)) assert.NotZero(t, domainID) assert.Equal(t, "security.example.com", data["domain"]) - assert.Equal(t, float64(certID), data["cert_id"]) + assert.InDelta(t, float64(certID), data["cert_id"], 1e-9) }) t.Run("create DNS account", func(t *testing.T) { diff --git a/internal/apps/openflare/proxy_route/logics_test.go b/internal/apps/openflare/proxy_route/logics_test.go index 2b3bb203..c2011d46 100644 --- a/internal/apps/openflare/proxy_route/logics_test.go +++ b/internal/apps/openflare/proxy_route/logics_test.go @@ -136,7 +136,7 @@ func TestRouteCanMoveAwayFromAlreadyMissingPagesProject(t *testing.T) { } func TestNormalizeCachePolicyDefaultsAndLegacy(t *testing.T) { - assert.Equal(t, "", normalizeCachePolicy(false, "static")) + assert.Empty(t, normalizeCachePolicy(false, "static")) // Empty/url on write = legacy all (compat); UI sends static explicitly for new default. assert.Equal(t, proxyRouteCachePolicyAll, normalizeCachePolicy(true, "")) assert.Equal(t, proxyRouteCachePolicyStatic, normalizeCachePolicy(true, "static")) @@ -144,7 +144,7 @@ func TestNormalizeCachePolicyDefaultsAndLegacy(t *testing.T) { assert.Equal(t, proxyRouteCachePolicyAll, normalizeCachePolicy(true, "all")) assert.Equal(t, proxyRouteCachePolicySuffix, normalizeCachePolicy(true, "suffix")) - assert.Equal(t, "", displayCachePolicy(false, "all")) + assert.Empty(t, displayCachePolicy(false, "all")) assert.Equal(t, proxyRouteCachePolicyAll, displayCachePolicy(true, "")) assert.Equal(t, proxyRouteCachePolicyAll, displayCachePolicy(true, "url")) assert.Equal(t, proxyRouteCachePolicyStatic, displayCachePolicy(true, "static")) diff --git a/internal/apps/openflare/relay/logics_test.go b/internal/apps/openflare/relay/logics_test.go index f40481a1..729226d7 100644 --- a/internal/apps/openflare/relay/logics_test.go +++ b/internal/apps/openflare/relay/logics_test.go @@ -117,7 +117,7 @@ func TestHeartbeatPayloadBindingAndFrpsObservationInsert(t *testing.T) { snapshots, err := repository.ListOpenFlareMetricSnapshotsSince(ctx, node.NodeID, now.Add(-time.Minute), 10) require.NoError(t, err) require.Len(t, snapshots, 1) - assert.Equal(t, 12.5, snapshots[0].CPUUsagePercent) + assert.InDelta(t, 12.5, snapshots[0].CPUUsagePercent, 1e-9) frpsObs, err := repository.ListOpenFlareNodeObservationFrps(ctx, node.NodeID, time.Time{}, 1) require.NoError(t, err) diff --git a/internal/apps/openflare/tls/acme_obtain_test.go b/internal/apps/openflare/tls/acme_obtain_test.go index d291ecce..93d8c59a 100644 --- a/internal/apps/openflare/tls/acme_obtain_test.go +++ b/internal/apps/openflare/tls/acme_obtain_test.go @@ -5,7 +5,6 @@ package tls import ( "context" - "strings" "testing" "time" @@ -126,7 +125,7 @@ func TestConvertCertificateToACMEPreservesUploadOnFailure(t *testing.T) { assert.Equal(t, "error", finalCert.ApplyStatus) assert.Equal(t, originalStoredCertPEM, finalCert.CertPEM) assert.Equal(t, originalStoredKeyPEM, finalCert.KeyPEM) - assert.True(t, strings.Contains(finalCert.ApplyMessage, "dns challenge failed")) + assert.Contains(t, finalCert.ApplyMessage, "dns challenge failed") } func TestConvertCertificateToACMERejectsInvalidStates(t *testing.T) { diff --git a/internal/apps/openflare/waf/rule_logics_test.go b/internal/apps/openflare/waf/rule_logics_test.go index 71546a2d..b4376b83 100644 --- a/internal/apps/openflare/waf/rule_logics_test.go +++ b/internal/apps/openflare/waf/rule_logics_test.go @@ -7,7 +7,6 @@ import ( "bytes" "context" "encoding/json" - "errors" "net/http" "net/http/httptest" "strconv" @@ -63,12 +62,14 @@ func TestRuleHandlersMapFailures(t *testing.T) { {name: "invalid id", method: http.MethodGet, path: "/rules/nope", setup: setupWAFTestDB, want: http.StatusBadRequest}, {name: "malformed json", method: http.MethodPost, path: "/rules", body: `{`, setup: setupWAFTestDB, want: http.StatusBadRequest}, {name: "invalid graph", method: http.MethodPost, path: "/rules/1/graph", body: `{"revision":1,"graph":{"schema_version":1,"nodes":[],"edges":[]}}`, setup: func(t *testing.T) func() { + t.Helper() cleanup := setupWAFTestDB(t) _, err := CreateRule(context.Background(), CreateRuleInput{Name: "one"}) require.NoError(t, err) return cleanup }, want: http.StatusBadRequest}, {name: "manual IP group sync", method: http.MethodPost, path: "/ip-groups/1/sync", setup: func(t *testing.T) func() { + t.Helper() cleanup := setupWAFTestDB(t) _, err := CreateIPGroup(context.Background(), IPGroupInput{Name: "manual", Type: wafIPGroupTypeManual, Enabled: true}) require.NoError(t, err) @@ -76,12 +77,13 @@ func TestRuleHandlersMapFailures(t *testing.T) { }, want: http.StatusBadRequest}, {name: "missing", method: http.MethodGet, path: "/rules/999", setup: setupWAFTestDB, want: http.StatusNotFound}, {name: "conflict", method: http.MethodPost, path: "/rules/1/graph", body: mustGraphRequest(t, 0), setup: func(t *testing.T) func() { + t.Helper() cleanup := setupWAFTestDB(t) _, err := CreateRule(context.Background(), CreateRuleInput{Name: "one"}) require.NoError(t, err) return cleanup }, want: http.StatusConflict}, - {name: "database failure", method: http.MethodGet, path: "/rules", setup: func(t *testing.T) func() { db.SetDB(nil); return func() {} }, want: http.StatusInternalServerError}, + {name: "database failure", method: http.MethodGet, path: "/rules", setup: func(t *testing.T) func() { t.Helper(); db.SetDB(nil); return func() {} }, want: http.StatusInternalServerError}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -171,7 +173,7 @@ func TestReplaceSiteRuleGroupsPreservesOrderAndRejectsGlobal(t *testing.T) { require.NoError(t, err) _, err = ReplaceSiteRuleGroups(ctx, 7, []uint{global.ID, second.ID}) require.Error(t, err) - assert.False(t, errors.Is(err, model.ErrWAFRuleRevisionConflict)) + require.NotErrorIs(t, err, model.ErrWAFRuleRevisionConflict) assert.Equal(t, []uint{third.ID, first.ID, second.ID}, mustListSiteRuleGroupIDs(t, ctx, 7)) } diff --git a/internal/apps/relay/frps/manager_test.go b/internal/apps/relay/frps/manager_test.go index 251538c3..19da7d21 100644 --- a/internal/apps/relay/frps/manager_test.go +++ b/internal/apps/relay/frps/manager_test.go @@ -16,6 +16,7 @@ import ( // Helper to write control file for the dummy script func writeControl(t *testing.T, dir string, exitCode int, delaySeconds int) { + t.Helper() controlPath := filepath.Join(dir, "control.txt") content := fmt.Sprintf("%d %d\n", exitCode, delaySeconds) err := os.WriteFile(controlPath, []byte(content), 0644) @@ -26,6 +27,7 @@ func writeControl(t *testing.T, dir string, exitCode int, delaySeconds int) { // Setup a dummy executable script that reads control.txt to decide exit code and sleep duration func setupDummyScript(t *testing.T) (string, string) { + t.Helper() dir := t.TempDir() scriptPath := filepath.Join(dir, "dummy_frps") @@ -53,6 +55,7 @@ exit "${EXIT_CODE:-0}" // Helper to poll for status to eliminate timing flakiness in tests func assertStatusEventually(t *testing.T, m *Manager, expectedStatus string, timeout time.Duration) { + t.Helper() if timeout < 6*time.Second { timeout = 6 * time.Second } diff --git a/internal/apps/upload/filesrv/file_server_test.go b/internal/apps/upload/filesrv/file_server_test.go index 722d90a2..1ac072ae 100644 --- a/internal/apps/upload/filesrv/file_server_test.go +++ b/internal/apps/upload/filesrv/file_server_test.go @@ -357,6 +357,7 @@ func TestNormalizeImageQuality(t *testing.T) { } func configureLocalStorageRoot(t *testing.T, dbConn *gorm.DB, tempDir string) { + t.Helper() var sc model.SystemConfig if err := dbConn.Where("key = ?", model.ConfigKeyStorageConfig).First(&sc).Error; err != nil { t.Fatalf("failed to find storage config: %v", err) diff --git a/internal/apps/upload/handler/routers_test.go b/internal/apps/upload/handler/routers_test.go index 05f19501..3ce89d03 100644 --- a/internal/apps/upload/handler/routers_test.go +++ b/internal/apps/upload/handler/routers_test.go @@ -75,6 +75,7 @@ func setupTestRouter(authUser *model.User) *gin.Engine { } func createMultipartRequest(t *testing.T, fieldName, fileName string, fileContent []byte, extraFields map[string]string) (string, *bytes.Buffer) { + t.Helper() body := &bytes.Buffer{} writer := multipart.NewWriter(body) @@ -1086,6 +1087,7 @@ func TestDeleteReservedUploadType(t *testing.T) { } func configureLocalStorageRoot(t *testing.T, dbConn *gorm.DB, tempDir string) { + t.Helper() var sc model.SystemConfig if err := dbConn.Where("key = ?", model.ConfigKeyStorageConfig).First(&sc).Error; err != nil { t.Fatalf("failed to find storage config: %v", err) diff --git a/internal/apps/upload/ingest/ingest_test.go b/internal/apps/upload/ingest/ingest_test.go index 5833938b..2fa30e2a 100644 --- a/internal/apps/upload/ingest/ingest_test.go +++ b/internal/apps/upload/ingest/ingest_test.go @@ -513,6 +513,7 @@ func loadTotalStats(ctx context.Context) (totalStatsSnapshot, error) { } func setupMockStorage(t *testing.T, putCount *int) (restore func(), disable func()) { + t.Helper() return setupMockStorageWithDeleteCount(t, putCount, nil) } diff --git a/internal/infra/persistence/migrator/pages_source_migration_test.go b/internal/infra/persistence/migrator/pages_source_migration_test.go index 8a40f68a..7bdbb577 100644 --- a/internal/infra/persistence/migrator/pages_source_migration_test.go +++ b/internal/infra/persistence/migrator/pages_source_migration_test.go @@ -198,7 +198,7 @@ func assertPagesSourceConstraints(t *testing.T, gormDB *gorm.DB, sourceID uint) ConfigVersion: 1, SourceIdentity: strings.Repeat("c", 64), } - assert.Error(t, gormDB.Create(&duplicateSource).Error) + require.Error(t, gormDB.Create(&duplicateSource).Error) for number := 2; number <= 3; number++ { require.NoError(t, createMigrationDeployment( @@ -219,14 +219,14 @@ func assertPagesSourceConstraints(t *testing.T, gormDB *gorm.DB, sourceID uint) &identity, &revision, )) - assert.Error(t, createMigrationDeployment( + require.Error(t, createMigrationDeployment( gormDB, 5, strings.Repeat("0", 64), &identity, &revision, )) - assert.Error(t, createMigrationDeployment( + require.Error(t, createMigrationDeployment( gormDB, 1, strings.Repeat("1", 64), diff --git a/internal/infra/task/executor_test.go b/internal/infra/task/executor_test.go index a58adc2b..44efc23e 100644 --- a/internal/infra/task/executor_test.go +++ b/internal/infra/task/executor_test.go @@ -59,6 +59,7 @@ func failHandler() *mockHandler { const testTaskType = "test:mock_task" func setupTest(t *testing.T) func() { + t.Helper() _, mr, cleanup := testhelper.SetupTestEnvironment(t) AsynqClient = asynq.NewClient(asynq.RedisClientOpt{ Addr: mr.Addr(), @@ -94,7 +95,7 @@ func TestGetTaskIDFromContext(t *testing.T) { // 空 context taskID := GetTaskID(ctx) - assert.Equal(t, "", taskID) + assert.Empty(t, taskID) // 注入 taskID ctx = withTaskID(ctx, "test_task_123") @@ -242,7 +243,7 @@ func TestProcessTaskFailure(t *testing.T) { ctx = withTaskID(ctx, "process_fail_001") _, err = handler.Execute(ctx, nil) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "模拟执行失败") // 验证日志 @@ -403,7 +404,7 @@ func TestRetryTaskNotFailed(t *testing.T) { // 尝试重试成功的任务 _, err = RetryTask(ctx, execution.ID) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "只有失败的任务才能重试") } @@ -425,7 +426,7 @@ func TestRetryTaskNotRetryable(t *testing.T) { require.NoError(t, err) _, err = RetryTask(ctx, execution.ID) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "不支持重试") } @@ -435,7 +436,7 @@ func TestRetryTaskNonExistent(t *testing.T) { ctx := context.Background() _, err := RetryTask(ctx, 99999999) - assert.Error(t, err) + require.Error(t, err) assert.Contains(t, err.Error(), "不存在") } diff --git a/internal/infra/task/permanent_error_test.go b/internal/infra/task/permanent_error_test.go index f8ae9300..d90c3e8c 100644 --- a/internal/infra/task/permanent_error_test.go +++ b/internal/infra/task/permanent_error_test.go @@ -4,17 +4,17 @@ package task import ( - "errors" "testing" "github.com/hibiken/asynq" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestPermanentErrorSkipsRetryWithoutExposingAsynqMessage(t *testing.T) { err := PermanentError(" 来源配置无效 ") - assert.True(t, errors.Is(err, asynq.SkipRetry)) + require.ErrorIs(t, err, asynq.SkipRetry) assert.Equal(t, "来源配置无效", err.Error()) assert.NotContains(t, err.Error(), asynq.SkipRetry.Error()) } @@ -22,6 +22,6 @@ func TestPermanentErrorSkipsRetryWithoutExposingAsynqMessage(t *testing.T) { func TestPermanentErrorUsesSafeFallbackForBlankMessage(t *testing.T) { err := PermanentError(" ") - assert.True(t, errors.Is(err, asynq.SkipRetry)) - assert.Equal(t, defaultPermanentErrorMessage, err.Error()) + require.ErrorIs(t, err, asynq.SkipRetry) + require.Equal(t, defaultPermanentErrorMessage, err.Error()) } diff --git a/internal/repository/analytics/node_access_log_test.go b/internal/repository/analytics/node_access_log_test.go index 61246452..5bc75c6f 100644 --- a/internal/repository/analytics/node_access_log_test.go +++ b/internal/repository/analytics/node_access_log_test.go @@ -50,8 +50,8 @@ func TestBatchInsertNodeAccessLogs_UsesModelBatchSQL(t *testing.T) { require.Len(t, mockBatch.rows, 1) assert.Equal(t, "node-a", mockBatch.rows[0][1]) require.Len(t, mockBatch.rows[0], 14) - assert.Equal(t, "", mockBatch.rows[0][7]) // user_agent - assert.Equal(t, "", mockBatch.rows[0][8]) // cache_status + assert.Empty(t, mockBatch.rows[0][7]) // user_agent + assert.Empty(t, mockBatch.rows[0][8]) // cache_status assert.Equal(t, uint64(2048), mockBatch.rows[0][10]) // bytes_sent assert.Equal(t, uint64(0), mockBatch.rows[0][11]) // request_length assert.Equal(t, uint32(0), mockBatch.rows[0][12]) // request_time_ms diff --git a/internal/repository/analytics/node_observability_latest_test.go b/internal/repository/analytics/node_observability_latest_test.go index dfebce46..f78e4ae2 100644 --- a/internal/repository/analytics/node_observability_latest_test.go +++ b/internal/repository/analytics/node_observability_latest_test.go @@ -55,8 +55,8 @@ func TestListNodeMetricHourly_PrefersRollup(t *testing.T) { rows, err := ListNodeMetricHourly(ctx, NodeObservabilityFilter{Since: since}) require.NoError(t, err) require.Len(t, rows, 1) - assert.Equal(t, 42.5, rows[0].AverageCPUUsagePercent) - assert.Equal(t, 60.0, rows[0].AverageMemoryUsagePercent) + assert.InDelta(t, 42.5, rows[0].AverageCPUUsagePercent, 1e-9) + assert.InDelta(t, 60.0, rows[0].AverageMemoryUsagePercent, 1e-9) assert.Equal(t, int64(100), rows[0].NetworkRxBytes) assert.Equal(t, 2, rows[0].ReportedNodes) require.Len(t, mock.queries, 1) @@ -92,10 +92,10 @@ func TestListNodeMetricHourly_MergesRawGapsWithPartialRollup(t *testing.T) { require.NoError(t, err) require.Len(t, rows, 2) assert.Equal(t, rawHour, rows[0].Hour) - assert.Equal(t, 12.0, rows[0].AverageCPUUsagePercent) + assert.InDelta(t, 12.0, rows[0].AverageCPUUsagePercent, 1e-9) // Overlapping hour prefers rollup (99) over raw (50). assert.Equal(t, rollupHour, rows[1].Hour) - assert.Equal(t, 99.0, rows[1].AverageCPUUsagePercent) + assert.InDelta(t, 99.0, rows[1].AverageCPUUsagePercent, 1e-9) require.GreaterOrEqual(t, len(mock.queries), 2) assert.Contains(t, mock.queries[1], "lagInFrame") } @@ -112,9 +112,9 @@ func TestMergeNodeMetricHourlyPreferRollup(t *testing.T) { ) require.Len(t, merged, 2) assert.Equal(t, h1, merged[0].Hour) - assert.Equal(t, 10.0, merged[0].AverageCPUUsagePercent) + assert.InDelta(t, 10.0, merged[0].AverageCPUUsagePercent, 1e-9) assert.Equal(t, h2, merged[1].Hour) - assert.Equal(t, 80.0, merged[1].AverageCPUUsagePercent) + assert.InDelta(t, 80.0, merged[1].AverageCPUUsagePercent, 1e-9) } func TestHourlyRollupCoversWindow(t *testing.T) { @@ -147,7 +147,7 @@ func TestListNodeMetricHourly_FallsBackToRawOnRollupError(t *testing.T) { rows, err := ListNodeMetricHourly(ctx, NodeObservabilityFilter{}) require.NoError(t, err) require.Len(t, rows, 1) - assert.Equal(t, 10.0, rows[0].AverageCPUUsagePercent) + assert.InDelta(t, 10.0, rows[0].AverageCPUUsagePercent, 1e-9) assert.Equal(t, int64(3), rows[0].DiskReadBytes) require.GreaterOrEqual(t, len(mock.queries), 2) assert.Contains(t, mock.queries[0], nodeMetricCapacityHourlyTableName()) diff --git a/internal/repository/task_execution_test.go b/internal/repository/task_execution_test.go index 9d169be2..f56da601 100644 --- a/internal/repository/task_execution_test.go +++ b/internal/repository/task_execution_test.go @@ -23,6 +23,7 @@ import ( ) func setupTaskExecutionTestEnvironment(t *testing.T) func() { + t.Helper() sqliteDB, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ DisableForeignKeyConstraintWhenMigrating: true, }) @@ -323,7 +324,7 @@ func TestAppendTaskExecutionLogNonExistent(t *testing.T) { // Redis 缓冲不依赖数据库记录是否已经创建。 err := AppendTaskExecutionLog(ctx, "nonexistent_task", "测试日志") - assert.NoError(t, err) + require.NoError(t, err) err = FlushTaskExecutionLog(ctx, "nonexistent_task") assert.Error(t, err) @@ -454,7 +455,7 @@ func TestListTaskExecutionsDefaultPaging(t *testing.T) { items, total, err := ListTaskExecutions(ctx, model.ListTaskExecutionsRequest{}) require.NoError(t, err) assert.Equal(t, int64(0), total) - assert.Len(t, items, 0) + assert.Empty(t, items) } func TestCleanupTaskExecutionLogs(t *testing.T) { diff --git a/internal/shared/response/middleware_test.go b/internal/shared/response/middleware_test.go index 0a354973..d593f7cc 100644 --- a/internal/shared/response/middleware_test.go +++ b/internal/shared/response/middleware_test.go @@ -34,7 +34,7 @@ func TestAbortWithError(t *testing.T) { require.Len(t, c.Errors, 1) var apiErr *APIError - require.True(t, errors.As(c.Errors.Last().Err, &apiErr)) + require.ErrorAs(t, c.Errors.Last().Err, &apiErr) assert.Equal(t, http.StatusBadRequest, apiErr.Code) assert.Equal(t, "invalid input", apiErr.Msg) assert.True(t, c.IsAborted()) diff --git a/internal/testhelper/test_helper.go b/internal/testhelper/test_helper.go index e7b3c2c4..988140cf 100644 --- a/internal/testhelper/test_helper.go +++ b/internal/testhelper/test_helper.go @@ -32,6 +32,7 @@ const ( // SetupTestEnvironment initializes an in-memory SQLite DB, seeds default configurations, // starts miniredis, and overrides the global db/Redis clients. It returns a cleanup function. func SetupTestEnvironment(t *testing.T) (*gorm.DB, *miniredis.Miniredis, func()) { + t.Helper() // Initialize GORM in-memory SQLite sqliteDB, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ DisableForeignKeyConstraintWhenMigrating: true, @@ -332,6 +333,7 @@ func getSeedConfigsPart2() []model.SystemConfig { } func seedDefaultConfigs(t *testing.T, tx *gorm.DB) { + t.Helper() defaultConfigs := append(getSeedConfigsPart1(), getSeedConfigsPart2()...) if err := tx.Create(&defaultConfigs).Error; err != nil { diff --git a/pkg/logger/ringbuffer_test.go b/pkg/logger/ringbuffer_test.go index f3c7e787..249a74ed 100644 --- a/pkg/logger/ringbuffer_test.go +++ b/pkg/logger/ringbuffer_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestLogRingBuffer_WriteAndQuery(t *testing.T) { @@ -18,7 +19,7 @@ func TestLogRingBuffer_WriteAndQuery(t *testing.T) { entries, hasMore := rb.Query(0, 10) assert.False(t, hasMore) - assert.Equal(t, 3, len(entries)) + assert.Len(t, entries, 3) assert.Equal(t, "line1", entries[0].Data) assert.Equal(t, "line2", entries[1].Data) assert.Equal(t, "line3", entries[2].Data) @@ -34,7 +35,7 @@ func TestLogRingBuffer_CapacityOverflow(t *testing.T) { entries, hasMore := rb.Query(0, 10) assert.False(t, hasMore) - assert.Equal(t, 3, len(entries)) + assert.Len(t, entries, 3) assert.Equal(t, "c", entries[0].Data) assert.Equal(t, "d", entries[1].Data) assert.Equal(t, "e", entries[2].Data) @@ -48,7 +49,7 @@ func TestLogRingBuffer_QueryLatest(t *testing.T) { // Query latest 2 entries, hasMore := rb.Query(0, 2) assert.True(t, hasMore) - assert.Equal(t, 2, len(entries)) + assert.Len(t, entries, 2) assert.Equal(t, "d", entries[0].Data) assert.Equal(t, "e", entries[1].Data) } @@ -60,12 +61,12 @@ func TestLogRingBuffer_QueryByCursor(t *testing.T) { // First get all to find indices all, _ := rb.Query(0, 10) - assert.Equal(t, 5, len(all)) + assert.Len(t, all, 5) // Query entries before index 3 entries, hasMore := rb.Query(3, 10) assert.False(t, hasMore) - assert.Equal(t, 3, len(entries)) + assert.Len(t, entries, 3) assert.Equal(t, "a", entries[0].Data) assert.Equal(t, "b", entries[1].Data) assert.Equal(t, "c", entries[2].Data) @@ -79,7 +80,7 @@ func TestLogRingBuffer_QueryByCursorWithLimit(t *testing.T) { // Query 2 entries before index 4 entries, hasMore := rb.Query(4, 2) assert.True(t, hasMore) - assert.Equal(t, 2, len(entries)) + assert.Len(t, entries, 2) assert.Equal(t, "c", entries[0].Data) assert.Equal(t, "d", entries[1].Data) } @@ -98,7 +99,7 @@ func TestLogRingBuffer_QueryNonExistentCursor(t *testing.T) { entries, hasMore := rb.Query(999, 10) assert.False(t, hasMore) - assert.Equal(t, 2, len(entries)) + assert.Len(t, entries, 2) assert.Equal(t, "a", entries[0].Data) assert.Equal(t, "b", entries[1].Data) } @@ -138,7 +139,7 @@ func TestLogRingBuffer_WriteNoNewline(t *testing.T) { _, _ = rb.Write([]byte("partial")) entries, _ := rb.Query(0, 10) - assert.Equal(t, 1, len(entries)) + assert.Len(t, entries, 1) assert.Equal(t, "partial", entries[0].Data) } @@ -147,7 +148,7 @@ func TestLogRingBuffer_WriteEmpty(t *testing.T) { n, err := rb.Write([]byte("")) assert.Equal(t, 0, n) - assert.NoError(t, err) + require.NoError(t, err) entries, _ := rb.Query(0, 10) assert.Nil(t, entries) @@ -160,7 +161,7 @@ func TestLogRingBuffer_QueryAfterOverflow(t *testing.T) { entries, hasMore := rb.Query(0, 10) assert.False(t, hasMore) - assert.Equal(t, 3, len(entries)) + assert.Len(t, entries, 3) assert.Equal(t, "5", entries[0].Data) assert.Equal(t, "6", entries[1].Data) assert.Equal(t, "7", entries[2].Data) @@ -178,14 +179,14 @@ func TestLogRingBuffer_NextCursor(t *testing.T) { // Query latest 2, should return next_cursor pointing to first returned entry entries, _ := rb.Query(0, 2) - assert.Equal(t, 2, len(entries)) + assert.Len(t, entries, 2) // entries[0].Index = 3 ("d"), entries[1].Index = 4 ("e") assert.Equal(t, 3, entries[0].Index) // Now use that index as cursor to get older entries older, hasMore := rb.Query(entries[0].Index, 10) assert.False(t, hasMore) - assert.Equal(t, 3, len(older)) + assert.Len(t, older, 3) assert.Equal(t, "a", older[0].Data) assert.Equal(t, "b", older[1].Data) assert.Equal(t, "c", older[2].Data) diff --git a/pkg/push/custom_test.go b/pkg/push/custom_test.go index fb622e65..0d3e61bc 100644 --- a/pkg/push/custom_test.go +++ b/pkg/push/custom_test.go @@ -82,7 +82,7 @@ func TestCustomPusherSend_ResponseBodyErrcode(t *testing.T) { assert.Contains(t, err.Error(), tt.wantErrMsg) return } - assert.NoError(t, err) + require.NoError(t, err) if tt.body != "" { assert.Contains(t, upstreamResp, tt.body) } diff --git a/pkg/push/telegram_test.go b/pkg/push/telegram_test.go index 74fcf728..6552b61d 100644 --- a/pkg/push/telegram_test.go +++ b/pkg/push/telegram_test.go @@ -23,7 +23,7 @@ func TestTelegramPusher_Send(t *testing.T) { assert.Equal(t, "application/json", r.Header.Get("Content-Type")) err := json.NewDecoder(r.Body).Decode(&receivedReq) - require.NoError(t, err) + assert.NoError(t, err) w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte(`{"ok": true}`)) @@ -55,7 +55,7 @@ func TestTelegramPusher_Send(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var req telegramMessageRequest err := json.NewDecoder(r.Body).Decode(&req) - require.NoError(t, err) + assert.NoError(t, err) requests = append(requests, &req) if len(requests) == 1 { @@ -84,7 +84,7 @@ func TestTelegramPusher_Send(t *testing.T) { require.Len(t, requests, 2) assert.Equal(t, "HTML", requests[0].ParseMode) - assert.Equal(t, "", requests[1].ParseMode) + assert.Empty(t, requests[1].ParseMode) assert.Contains(t, requests[1].Text, "[INFO] Alert & Info") assert.Contains(t, requests[1].Text, "A < B comparison") }) @@ -96,7 +96,7 @@ func TestTelegramPusher_Send(t *testing.T) { URL: "https://api.telegram.org", } err := pusher.ValidateConfig(cfg) - assert.Error(t, err) + require.Error(t, err) cfg = Config{ Channel: "telegram", @@ -104,7 +104,7 @@ func TestTelegramPusher_Send(t *testing.T) { Secret: "token", } err = pusher.ValidateConfig(cfg) - assert.Error(t, err) + require.Error(t, err) cfg = Config{ Channel: "telegram",