测试代码质量 25→0:assert↔require 一致性(fail-fast)、float 精确比较→InDelta、Equal("",x)→Empty、Equal(len)→Len、errors.Is/As→ErrorIs/ErrorAs、JSON 字符串→JSONEq、handler goroutine 内 require→assert(真健壮性修复)、t.Helper()、os.MkdirTemp→t.TempDir()(符合 repo AGENTS 约束)。

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}
This commit is contained in:
ryan
2026-08-16 18:12:58 +08:00
parent e5f6b0ad90
commit 63a24da9ee
32 changed files with 113 additions and 95 deletions
+1
View File
@@ -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)
+13 -12
View File
@@ -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) {
+6 -5
View File
@@ -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)
})
}
@@ -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)
}
@@ -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()
+1
View File
@@ -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()
@@ -19,6 +19,7 @@ import (
)
func setupApplyLogTestDB(t *testing.T) func() {
t.Helper()
sqliteDB, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true,
})
@@ -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")
}
@@ -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, "<p>x</p>", keys["OriginErrorPageHTML"].CurrentValue)
}
@@ -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)
}
@@ -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)
})
}
@@ -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) {
@@ -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"))
+1 -1
View File
@@ -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)
@@ -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) {
@@ -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))
}
+3
View File
@@ -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
}
@@ -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)
@@ -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)
@@ -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)
}
@@ -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),
+6 -5
View File
@@ -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(), "不存在")
}
+4 -4
View File
@@ -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())
}
@@ -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
@@ -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())
+3 -2
View File
@@ -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) {
+1 -1
View File
@@ -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())
+2
View File
@@ -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 {