package infra import ( "os" "path/filepath" "strings" "testing" ) const wgTestSubnet = "10.42.0.0/24" // baseConfig es un [Interface] mínimo para simular wg0.conf vacío de peers. const wgBaseConfig = `[Interface] Address = 10.42.0.1/24 PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= ListenPort = 51820 ` func wgTempConfig(t *testing.T, content string) string { t.Helper() dir := t.TempDir() p := filepath.Join(dir, "wg0.conf") if err := os.WriteFile(p, []byte(content), 0600); err != nil { t.Fatalf("wgTempConfig: %v", err) } return p } func init() { // asegura que syncconf no se ejecuta en tests os.Setenv("WG_SKIP_SYNCCONF", "1") } func TestWGPeerAdd(t *testing.T) { t.Run("peer nuevo con AllowedIPs vacio asigna 10.42.0.2", func(t *testing.T) { cfg := wgTempConfig(t, wgBaseConfig) spec := WGPeerSpec{ DeviceID: "pc-aurgi", PublicKey: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=", } res, err := WGPeerAdd(spec, cfg, wgTestSubnet) if err != nil { t.Fatalf("unexpected error: %v", err) } if res.AssignedIP != "10.42.0.2" { t.Errorf("AssignedIP = %q, want 10.42.0.2", res.AssignedIP) } if res.Status != "added" { t.Errorf("Status = %q, want added", res.Status) } if res.DeviceID != "pc-aurgi" { t.Errorf("DeviceID = %q, want pc-aurgi", res.DeviceID) } // verificar que el bloque está en el archivo raw, _ := os.ReadFile(cfg) content := string(raw) if !strings.Contains(content, "# DeviceID: pc-aurgi") { t.Errorf("config missing DeviceID comment, got:\n%s", content) } if !strings.Contains(content, "AllowedIPs = 10.42.0.2/32") { t.Errorf("config missing AllowedIPs, got:\n%s", content) } }) t.Run("agregar segundo peer asigna 10.42.0.3", func(t *testing.T) { cfg := wgTempConfig(t, wgBaseConfig) spec1 := WGPeerSpec{ DeviceID: "pc-aurgi", PublicKey: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=", } if _, err := WGPeerAdd(spec1, cfg, wgTestSubnet); err != nil { t.Fatalf("add peer1: %v", err) } spec2 := WGPeerSpec{ DeviceID: "home-wsl", PublicKey: "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=", } res, err := WGPeerAdd(spec2, cfg, wgTestSubnet) if err != nil { t.Fatalf("add peer2: %v", err) } if res.AssignedIP != "10.42.0.3" { t.Errorf("AssignedIP = %q, want 10.42.0.3", res.AssignedIP) } if res.Status != "added" { t.Errorf("Status = %q, want added", res.Status) } raw, _ := os.ReadFile(cfg) content := string(raw) if !strings.Contains(content, "# DeviceID: home-wsl") { t.Errorf("config missing second DeviceID comment, got:\n%s", content) } }) t.Run("agregar mismo PublicKey otra vez retorna already-present", func(t *testing.T) { cfg := wgTempConfig(t, wgBaseConfig) spec := WGPeerSpec{ DeviceID: "pc-aurgi", PublicKey: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=", } if _, err := WGPeerAdd(spec, cfg, wgTestSubnet); err != nil { t.Fatalf("first add: %v", err) } res, err := WGPeerAdd(spec, cfg, wgTestSubnet) if err != nil { t.Fatalf("second add: %v", err) } if res.Status != "already-present" { t.Errorf("Status = %q, want already-present", res.Status) } if res.AssignedIP != "10.42.0.2" { t.Errorf("AssignedIP = %q, want 10.42.0.2", res.AssignedIP) } }) t.Run("agregar DeviceID existente con clave distinta retorna reconfigured", func(t *testing.T) { cfg := wgTempConfig(t, wgBaseConfig) spec1 := WGPeerSpec{ DeviceID: "pc-aurgi", PublicKey: "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=", } if _, err := WGPeerAdd(spec1, cfg, wgTestSubnet); err != nil { t.Fatalf("first add: %v", err) } // misma DeviceID, PublicKey diferente spec2 := WGPeerSpec{ DeviceID: "pc-aurgi", PublicKey: "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD=", AllowedIPs: "10.42.0.2/32", } res, err := WGPeerAdd(spec2, cfg, wgTestSubnet) if err != nil { t.Fatalf("reconfigure: %v", err) } if res.Status != "reconfigured" { t.Errorf("Status = %q, want reconfigured", res.Status) } // la clave vieja no debe estar, la nueva sí raw, _ := os.ReadFile(cfg) content := string(raw) if strings.Contains(content, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=") { t.Errorf("old PublicKey still present after reconfigure:\n%s", content) } if !strings.Contains(content, "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD=") { t.Errorf("new PublicKey not found after reconfigure:\n%s", content) } // solo debe haber un bloque [Peer] count := strings.Count(content, "[Peer]") if count != 1 { t.Errorf("[Peer] count = %d, want 1:\n%s", count, content) } }) }