//go:build linux // +build linux // 本文件仅用于在 Linux 上 smoke test frpc-client-win 的核心逻辑。 // 编译: GOOS=linux GOARCH=amd64 go build -tags linux -o /tmp/frpc-client-test . // 不参与正式 Windows 构建。 package main import ( "embed" "errors" "fmt" "io/fs" "os" "path/filepath" "frpc-client-win/internal/config" "frpc-client-win/internal/logger" ) //go:embed assets/frpc.exe var smokeFS embed.FS func main() { tmpDir, err := os.MkdirTemp("", "frpc-test-*") if err != nil { fmt.Println("mkdir:", err) os.Exit(1) } defer os.RemoveAll(tmpDir) log, err := logger.New(filepath.Join(tmpDir, "logs")) if err != nil { fmt.Println("logger:", err) os.Exit(1) } defer log.Close() cfg := config.New(tmpDir, "frpc.exe", smokeFS, log) // 测试 EnsureFrpcBinary:应该从 embed 释放 frpc.exe if err := cfg.EnsureFrpcBinary(); err != nil { fmt.Println("EnsureFrpcBinary failed:", err) os.Exit(1) } stat, err := os.Stat(cfg.FrpcPath) if err != nil { fmt.Println("frpc.exe not released:", err) os.Exit(1) } fmt.Printf("✔ frpc.exe released: %s (%d bytes)\n", cfg.FrpcPath, stat.Size()) // 验证确实是 PE 文件 if _, err := fs.Stat(smokeFS, "assets/frpc.exe"); err != nil { fmt.Println("embed missing:", err) os.Exit(1) } fmt.Println("✔ embed.FS contains assets/frpc.exe") // 测试 EnsureIni:应该失败,因为没有配置文件 if err := cfg.EnsureIni(); err == nil { fmt.Println("expected EnsureIni to fail, got nil") os.Exit(1) } else { fmt.Printf("✔ EnsureIni correctly returned: %v\n", err) } // 创建一个假的 ini 并测试 iniPath := filepath.Join(tmpDir, "frpc.ini") if err := os.WriteFile(iniPath, []byte("[common]\nserver_addr = 127.0.0.1\nserver_port = 7000\n"), 0o644); err != nil { fmt.Println("write ini:", err) os.Exit(1) } if err := cfg.EnsureIni(); err != nil { fmt.Println("EnsureIni should now succeed:", err) os.Exit(1) } fmt.Printf("✔ EnsureIni OK; effective config: %s\n", cfg.EffectiveConfigPath()) // 测试 EffectiveConfigPath 优先级:新建一个 toml,EffectiveConfigPath 仍然应返回 ini tomlPath := filepath.Join(tmpDir, "frpc.toml") os.WriteFile(tomlPath, []byte("# toml"), 0o644) if cfg.EffectiveConfigPath() != iniPath { fmt.Printf("expected ini preferred, got: %s\n", cfg.EffectiveConfigPath()) os.Exit(1) } os.Remove(tomlPath) fmt.Println("✔ .ini takes precedence over .toml") // === 新场景:任意 *.ini 文件名(frpc-mike.ini 这类) === // 先清掉标准名 ini,只留一个非标准名的 os.Remove(iniPath) mikeIni := filepath.Join(tmpDir, "frpc-mike.ini") if err := os.WriteFile(mikeIni, []byte("[common]\nserver_addr = 10.0.0.1\n"), 0o644); err != nil { fmt.Println("write mike ini:", err) os.Exit(1) } if err := cfg.EnsureIni(); err != nil { fmt.Println("EnsureIni should pick frpc-mike.ini via scan:", err) os.Exit(1) } if cfg.EffectiveConfigPath() != mikeIni { fmt.Printf("expected scan to find frpc-mike.ini, got: %s\n", cfg.EffectiveConfigPath()) os.Exit(1) } if cfg.ConfigSource() != "scan" { fmt.Printf("expected source=scan, got: %s\n", cfg.ConfigSource()) os.Exit(1) } fmt.Println("✔ arbitrary-name ini (frpc-mike.ini) auto-detected via scan") // === 多个候选应报错 === os.WriteFile(filepath.Join(tmpDir, "frpc-other.ini"), []byte("[common]\n"), 0o644) if err := cfg.EnsureIni(); err == nil { fmt.Println("expected ambiguous error, got nil") os.Exit(1) } else if !errors.Is(err, config.ErrIniAmbiguous) { fmt.Printf("expected ErrIniAmbiguous, got: %v\n", err) os.Exit(1) } fmt.Println("✔ multiple candidates correctly reported ambiguous") fmt.Println("\n✔ ALL SMOKE TESTS PASSED") }