初版功能完成
ci / Go checks (ubuntu-latest) (push) Has been cancelled
ci / Go checks (windows-latest) (push) Has been cancelled

This commit is contained in:
qsc
2026-08-29 13:12:17 +08:00
commit 142e5dc7d6
217 changed files with 21313 additions and 0 deletions
+132
View File
@@ -0,0 +1,132 @@
package config
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestLoadServerUsesDefaultsAndStrictFields(t *testing.T) {
t.Parallel()
path := writeConfig(t, "data:\n directory: ./custom-data\n")
config, err := LoadServer(path)
if err != nil {
t.Fatalf("LoadServer() error = %v", err)
}
if config.Data.Directory != "./custom-data" {
t.Fatalf("Data.Directory = %q, want ./custom-data", config.Data.Directory)
}
if config.Network.OverlayCIDR != DefaultOverlayCIDR {
t.Fatalf("OverlayCIDR = %q, want %q", config.Network.OverlayCIDR, DefaultOverlayCIDR)
}
unknown := writeConfig(t, "node_token: must-not-be-in-yaml\n")
if _, err := LoadServer(unknown); err == nil || !strings.Contains(err.Error(), "field node_token not found") {
t.Fatalf("LoadServer() unknown-field error = %v", err)
}
}
func TestServerConfigValidation(t *testing.T) {
t.Parallel()
config := DefaultServerConfig()
config.Server.ControlListen = "10.88.0.2:7001"
if err := config.Validate(); err == nil || !strings.Contains(err.Error(), "must bind") {
t.Fatalf("Validate() error = %v, want Control listen mismatch", err)
}
config = DefaultServerConfig()
config.Network.OverlayCIDR = "10.88.0.1/16"
if err := config.Validate(); err == nil || !strings.Contains(err.Error(), "network address") {
t.Fatalf("Validate() error = %v, want unmasked CIDR error", err)
}
config = DefaultServerConfig()
config.Network.OverlayCIDR = "0.0.0.0/0"
config.Network.ServerOverlayIP = "10.88.0.1"
config.Server.ControlListen = "10.88.0.1:7001"
if err := config.Validate(); err == nil || !strings.Contains(err.Error(), "Exit Node") {
t.Fatalf("Validate() /0 error = %v", err)
}
}
func TestLoadEngineerAndSite(t *testing.T) {
t.Parallel()
valid := writeConfig(t, "server: http://127.0.0.1:8080\nnode_name: test-node\njoin_token: ' yaml-token '\n")
engineer, err := LoadEngineer(valid)
if err != nil {
t.Fatalf("LoadEngineer() error = %v", err)
}
if engineer.NodeName != "test-node" || engineer.JoinToken != "yaml-token" {
t.Fatalf("Engineer config = %+v", engineer)
}
site, err := LoadSite(valid)
if err != nil {
t.Fatalf("LoadSite() error = %v", err)
}
if site.JoinToken != "yaml-token" || site.Netstack.TCPFlowLimit != 2048 || site.Netstack.UDPFlowLimit != 4096 || site.Netstack.UDPIdleSeconds != 60 {
t.Fatalf("Site netstack defaults = %+v", site.Netstack)
}
customSite := writeConfig(t, "server: http://127.0.0.1:8080\nnode_name: site\nnetstack:\n tcp_flow_limit: 32\n udp_flow_limit: 64\n udp_idle_seconds: 15\n")
site, err = LoadSite(customSite)
if err != nil || site.Netstack.TCPFlowLimit != 32 || site.Netstack.UDPFlowLimit != 64 || site.Netstack.UDPIdleSeconds != 15 {
t.Fatalf("custom Site netstack = %+v, %v", site.Netstack, err)
}
invalidSite := writeConfig(t, "server: http://127.0.0.1:8080\nnode_name: site\nnetstack:\n udp_idle_seconds: 0\n")
if _, err := LoadSite(invalidSite); err == nil {
t.Fatal("LoadSite accepted zero UDP idle timeout")
}
sensitive := writeConfig(t, "server: http://127.0.0.1:8080\nnode_name: test-node\nwg_private_key: secret\n")
if _, err := LoadEngineer(sensitive); err == nil || !strings.Contains(err.Error(), "field wg_private_key not found") {
t.Fatalf("LoadEngineer() sensitive-field error = %v", err)
}
}
func TestResolveJoinTokenPrecedence(t *testing.T) {
t.Parallel()
if got := ResolveJoinToken(" cli-or-env ", "yaml"); got != "cli-or-env" {
t.Fatalf("ResolveJoinToken override = %q", got)
}
if got := ResolveJoinToken("", " yaml "); got != "yaml" {
t.Fatalf("ResolveJoinToken YAML fallback = %q", got)
}
if got := ResolveJoinToken(" ", " "); got != "" {
t.Fatalf("ResolveJoinToken empty = %q", got)
}
}
func TestValidateServerURLRejectsAmbiguousAuthority(t *testing.T) {
t.Parallel()
invalid := []string{
"ftp://example.test", "http://user:secret@example.test", "http://example.test/api",
"http://example.test?", "http://example.test?x=1", "http://example.test#fragment", "not-a-url",
}
for _, raw := range invalid {
if err := ValidateServerURL(raw); err == nil {
t.Errorf("ValidateServerURL(%q) accepted an unsafe or ambiguous URL", raw)
}
}
for _, raw := range []string{"http://127.0.0.1:8080", "https://example.test/"} {
if err := ValidateServerURL(raw); err != nil {
t.Errorf("ValidateServerURL(%q) error = %v", raw, err)
}
}
}
func TestConfigRejectsMultipleDocuments(t *testing.T) {
t.Parallel()
path := writeConfig(t, "server: http://127.0.0.1:8080\nnode_name: one\n---\nserver: http://127.0.0.1:8080\nnode_name: two\n")
if _, err := LoadSite(path); err == nil || !strings.Contains(err.Error(), "exactly one") {
t.Fatalf("LoadSite() error = %v, want multiple-document error", err)
}
}
func writeConfig(t *testing.T, content string) string {
t.Helper()
path := filepath.Join(t.TempDir(), "config.yaml")
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
t.Fatalf("write config: %v", err)
}
return path
}