package tests import ( "log/slog" "strings" "testing" "git.cloudinit.dev/coreci/orca/internal/emitter" "git.cloudinit.dev/coreci/orca/internal/jobspec" "git.cloudinit.dev/coreci/orca/internal/proxmox" "git.cloudinit.dev/coreci/orca/internal/traefik" ) // TestNftEmitter_PostroutingAndDNATTarget (REQ-173) verifies the nft // emitter renders the postrouting masquerade chain and supports // DNATTarget substitution. func TestNftEmitter_PostroutingAndDNATTarget(t *testing.T) { files, err := emitter.NftEmitter{}.RenderNftConfig(emitter.NftClusterConfig{ DNATTarget: "10.99.0.10", EnableSNAT: true, }) if err != nil { t.Fatalf("RenderNftConfig: %v", err) } c := files[0].Content if !strings.Contains(c, "chain postrouting") { t.Errorf("missing postrouting chain:\n%s", c) } if !strings.Contains(c, "masquerade") { t.Errorf("missing masquerade rule:\n%s", c) } if !strings.Contains(c, "dnat to 10.99.0.10:8443") { t.Errorf("missing custom DNAT target:\n%s", c) } } // TestNftEmitter_PriorityMinus10 (research Topic 2) verifies the input // and forward chains use priority -10 for pve-firewall coexistence. func TestNftEmitter_PriorityMinus10(t *testing.T) { files, _ := emitter.NftEmitter{}.RenderNftConfig(emitter.NftClusterConfig{}) c := files[0].Content if !strings.Contains(c, "hook input priority -10;") { t.Errorf("input chain should use priority -10:\n%s", c) } if !strings.Contains(c, "hook forward priority -10;") { t.Errorf("forward chain should use priority -10:\n%s", c) } } // TestTraefikEmitter_TLSModel (REQ-172) verifies the dynamic config // emits tls: {} and does NOT contain certResolver (dropped in v0.14). func TestTraefikEmitter_TLSModel(t *testing.T) { spec := &jobspec.WorkloadSpec{ Name: "test-svc", Kind: "Service", Ports: []jobspec.PortSpec{{Name: "http"}}, } node := &emitter.Node{ Hostname: "test-node", } files, err := emitter.TraefikEmitter{}.Render(spec, node) if err != nil { t.Fatalf("Render: %v", err) } c := files[0].Content if !strings.Contains(c, "tls: {}") { t.Errorf("missing tls: {} (v0.14 model):\n%s", c) } if strings.Contains(c, "certResolver: orca") { t.Errorf("certResolver: orca should be removed (v0.14):\n%s", c) } } // TestTraefikImageRef verifies the image reference resolution for the // orca-traefik podman container. func TestTraefikImageRef(t *testing.T) { ref := traefik.ImageRef("v0.13.7") want := "git.cloudinit.dev/coreci/orca-traefik:v0.13.7" if ref != want { t.Errorf("ImageRef(v0.13.7) = %q, want %q", ref, want) } // Dev build falls back to latest. ref = traefik.ImageRef("dev") if ref != "git.cloudinit.dev/coreci/orca-traefik:latest" { t.Errorf("ImageRef(dev) = %q, want latest", ref) } } // TestProxmox_FloatingIP_LXC_ProvisioningCommands (REQ-176) verifies // the ProvisionIngressLXC function sends the correct pct create // command with the right net0 parameters. func TestProxmox_FloatingIP_LXC_ProvisioningCommands(t *testing.T) { var cmds []string execFn := func(cmd string) ([]byte, error) { cmds = append(cmds, cmd) // Simulate: pct status returns "absent" on first call, then OK. if strings.Contains(cmd, "pct status 201") { return []byte("absent\n"), nil } if strings.Contains(cmd, "pct create") { return []byte(""), nil } if strings.Contains(cmd, "pct start 201") { return []byte(""), nil } if strings.Contains(cmd, "hostname -I") { return []byte("203.0.113.10\n"), nil } return []byte(""), nil } err := proxmox.ProvisionIngressLXC(nil, execFn, proxmox.FloatingIPOptions{ FloatingIP: "203.0.113.10", Gateway: "203.0.113.1", MAC: "02:01:02:03:04:05", NetPrefix: 24, LXCTemplate: "ubuntu-24.04", }, slog.Default()) if err != nil { t.Fatalf("ProvisionIngressLXC: %v", err) } // Verify pct create has the right net0 params. foundCreate := false for _, c := range cmds { if strings.Contains(c, "pct create") { foundCreate = true if !strings.Contains(c, "hostname ingress") { t.Errorf("pct create missing hostname ingress: %s", c) } if !strings.Contains(c, "hwaddr=02:01:02:03:04:05") { t.Errorf("pct create missing hwaddr: %s", c) } if !strings.Contains(c, "ip=203.0.113.10/24") { t.Errorf("pct create missing ip: %s", c) } if !strings.Contains(c, "gw=203.0.113.1") { t.Errorf("pct create missing gw: %s", c) } if !strings.Contains(c, "nesting=1,keyctl=1,fuse=1") { t.Errorf("pct create missing features (research Topic 3): %s", c) } } } if !foundCreate { t.Errorf("pct create command not sent\ncommands: %v", cmds) } } // TestProxmox_GenerateRandomMAC (D-261) verifies MAC generation produces // a valid locally-administered MAC. func TestProxmox_GenerateRandomMAC(t *testing.T) { mac, err := proxmox.GenerateRandomMAC() if err != nil { t.Fatalf("GenerateRandomMAC: %v", err) } if !strings.HasPrefix(mac, "02:") { t.Errorf("MAC should start with 02: (locally administered): %s", mac) } // Verify it's 6 octets. parts := strings.Split(mac, ":") if len(parts) != 6 { t.Errorf("MAC should have 6 octets: %s", mac) } }