package main import ( "errors" "strings" "testing" ) func TestStartupErrorContainsPhaseAndCause(t *testing.T) { cause := errors.New("底层失败") err := newStartupError(phaseDatabase, "数据库初始化失败", cause) if err.Phase() != "database" { t.Fatalf("phase = %q, want database", err.Phase()) } if !errors.Is(err, cause) { t.Fatal("startupError 应保留底层 cause") } if !strings.Contains(err.Error(), "database") { t.Fatalf("错误字符串应包含 phase,实际: %s", err.Error()) } } func TestStartupErrorRedactsSensitiveUserMessage(t *testing.T) { message := "数据库初始化失败: nex:secret@tcp(localhost:3306)/nex password=secret api_key=sk-test" err := newStartupError(phaseDatabase, message, errors.New("cause password=secret api_key=sk-test")) userMessage := err.UserMessage() for _, secret := range []string{"secret", "sk-test"} { if strings.Contains(userMessage, secret) { t.Fatalf("用户提示不应包含敏感信息 %q,实际: %s", secret, userMessage) } if strings.Contains(err.Error(), secret) { t.Fatalf("日志错误字符串不应包含敏感信息 %q,实际: %s", secret, err.Error()) } } if !strings.Contains(userMessage, "") { t.Fatalf("用户提示应包含脱敏占位符,实际: %s", userMessage) } }