package deploy import ( "encoding/json" "strings" "testing" ) func TestJoinLaneForSignal(t *testing.T) { cases := []struct { name string port int want string }{ {"LanmanServer", 0, "smb"}, {"smb", 445, "smb"}, {"winrm", 5985, "winrm"}, {"sshd", 22, "linux"}, {"docker", 0, "docker"}, {"CCMEXEC", 0, "gpo"}, {"DoSvc", 0, "do_peer"}, {"Wuauserv", 0, "wsus_cache_peer"}, {"dns_txt:_aether.internal", 0, "dns_txt"}, {"webrtc_mesh", 0, "webrtc_mesh"}, {"gitlab-runner", 0, "bits_curl"}, {"jenkins", 8080, "bits_curl"}, {"unknown-svc", 9999, ""}, } for _, tc := range cases { got := JoinLaneForSignal(tc.name, tc.port) if got != tc.want { t.Fatalf("%s:%d => %q, want %q", tc.name, tc.port, got, tc.want) } } } func TestMergeServiceGraphHosts(t *testing.T) { base := map[string]ServiceGraphHost{ "10.0.0.5": { Host: "10.0.0.5", Subnet: "10.0.0", Services: []ServiceGraphEntry{ entryWithLane("smb", 445, "lan_port"), }, }, } merged := MergeServiceGraphHosts(base, ServiceGraphHost{ Host: "10.0.0.5", Subnet: "10.0.0", Services: []ServiceGraphEntry{ entryWithLane("smb", 445, "lan_port"), entryWithLane("winrm", 5985, "lan_port"), }, }, ServiceGraphHost{ Host: "10.0.0.12", Subnet: "10.0.0", Services: []ServiceGraphEntry{ entryWithLane("ssh", 22, "lan_port"), }, }) if len(merged) != 2 { t.Fatalf("hosts = %d", len(merged)) } if len(merged["10.0.0.5"].Services) != 2 { t.Fatalf("10.0.0.5 services = %v", merged["10.0.0.5"].Services) } } func TestParseWindowsDiscoverFixture(t *testing.T) { fixture := `{"services":[{"name":"CCMEXEC","status":"running"},{"name":"tcp/5985","port":5985,"status":"listening"},{"name":"LanmanServer","status":"running"}],"hints":["domain_joined","docker_pipe"]}` entries, hints := ParseWindowsDiscoverFixture(fixture) if len(entries) != 3 { t.Fatalf("entries = %v", entries) } if entries[0].JoinLaneCandidate != "gpo" { t.Fatalf("CCMEXEC lane = %q", entries[0].JoinLaneCandidate) } if entries[1].JoinLaneCandidate != "winrm" { t.Fatalf("winrm lane = %q", entries[1].JoinLaneCandidate) } if len(hints) != 2 || hints[0] != "domain_joined" { t.Fatalf("hints = %v", hints) } } func TestParseSystemctlListUnitsFixture(t *testing.T) { fixture := `UNIT LOAD ACTIVE SUB DESCRIPTION docker.service loaded active running Docker Application Container Engine ssh.service loaded active running OpenBSD Secure Shell server gitlab-runner.service loaded active running GitLab Runner` entries := ParseSystemctlListUnitsFixture(fixture) if len(entries) != 3 { t.Fatalf("entries = %v", entries) } if entries[2].JoinLaneCandidate != "bits_curl" { t.Fatalf("gitlab lane = %q", entries[2].JoinLaneCandidate) } } func TestParseServiceDiscoverJSON(t *testing.T) { raw := `noise before json {"probed_at":"2026-06-06T12:00:00Z","local":{"host":"10.1.2.3","subnet":"10.1.2","services":[{"service_name":"docker","join_lane_candidate":"docker","source":"passive_hint"}]},"lan_hosts":[{"host":"10.1.2.50","subnet":"10.1.2","services":[{"service_name":"smb","port":445,"join_lane_candidate":"smb","source":"lan_port"}]}],"passive_hints":["docker_socket"]}` result, err := ParseServiceDiscoverJSON(raw) if err != nil { t.Fatal(err) } if result.Local.Host != "10.1.2.3" || len(result.LANHosts) != 1 { t.Fatalf("result = %+v", result) } } func TestServiceDiscoverResultRoundTrip(t *testing.T) { result := ServiceDiscoverResult{ ProbedAt: "2026-06-06T12:00:00Z", Local: ServiceGraphHost{ Host: "192.168.1.10", Subnet: "192.168.1", Services: []ServiceGraphEntry{ {ServiceName: "WinRM", Port: 5985, JoinLaneCandidate: "winrm", Source: "local_service"}, }, }, } b, err := json.Marshal(result) if err != nil { t.Fatal(err) } if !strings.Contains(string(b), `"join_lane_candidate":"winrm"`) { t.Fatalf("json = %s", string(b)) } }