package collector import ( "testing" ) func TestQueryBuilder(t *testing.T) { t.Run("fluent builder pattern", func(t *testing.T) { q := NewQuery(). Proto("tcp"). State("LISTEN"). WithLimit(10) if q.Filter.Proto != "tcp" { t.Errorf("expected proto tcp, got %s", q.Filter.Proto) } if q.Filter.State != "LISTEN" { t.Errorf("expected state LISTEN, got %s", q.Filter.State) } if q.Limit != 10 { t.Errorf("expected limit 10, got %d", q.Limit) } }) t.Run("convenience methods", func(t *testing.T) { q := NewQuery().Listening() if q.Filter.State != "LISTEN" { t.Errorf("Listening() should set state to LISTEN") } q = NewQuery().Established() if q.Filter.State != "ESTABLISHED" { t.Errorf("Established() should set state to ESTABLISHED") } q = NewQuery().IPv4Only() if q.Filter.IPv4 != true || q.Filter.IPv6 != false { t.Error("IPv4Only() should set IPv4=true, IPv6=false") } q = NewQuery().IPv6Only() if q.Filter.IPv4 != false || q.Filter.IPv6 != true { t.Error("IPv6Only() should set IPv4=false, IPv6=true") } }) t.Run("sort options", func(t *testing.T) { q := NewQuery().WithSortString("pid:desc") if q.Sort.Field != SortByPID { t.Errorf("expected sort by pid, got %v", q.Sort.Field) } if q.Sort.Direction != SortDesc { t.Errorf("expected sort desc, got %v", q.Sort.Direction) } }) } func TestQueryApply(t *testing.T) { conns := []Connection{ {PID: 1, Process: "nginx", Proto: "tcp", State: "LISTEN", Lport: 80}, {PID: 2, Process: "nginx", Proto: "tcp", State: "ESTABLISHED", Lport: 80}, {PID: 3, Process: "sshd", Proto: "tcp", State: "LISTEN", Lport: 22}, {PID: 4, Process: "postgres", Proto: "tcp", State: "LISTEN", Lport: 5432}, {PID: 5, Process: "dnsmasq", Proto: "udp", State: "", Lport: 53}, } t.Run("filter by state", func(t *testing.T) { q := NewQuery().Listening() result := q.Apply(conns) if len(result) != 3 { t.Errorf("expected 3 listening connections, got %d", len(result)) } }) t.Run("filter by proto", func(t *testing.T) { q := NewQuery().Proto("udp") result := q.Apply(conns) if len(result) != 1 { t.Errorf("expected 1 udp connection, got %d", len(result)) } if result[0].Process != "dnsmasq" { t.Errorf("expected dnsmasq, got %s", result[0].Process) } }) t.Run("filter and sort", func(t *testing.T) { q := NewQuery().Listening().WithSortString("lport:asc") result := q.Apply(conns) if len(result) != 3 { t.Fatalf("expected 3, got %d", len(result)) } if result[0].Lport != 22 { t.Errorf("expected port 22 first, got %d", result[0].Lport) } }) t.Run("filter sort and limit", func(t *testing.T) { q := NewQuery().Proto("tcp").WithSortString("lport:asc").WithLimit(2) result := q.Apply(conns) if len(result) != 2 { t.Errorf("expected 2 (limit), got %d", len(result)) } }) t.Run("process filter substring", func(t *testing.T) { q := NewQuery().Process("nginx") result := q.Apply(conns) if len(result) != 2 { t.Errorf("expected 2 nginx connections, got %d", len(result)) } }) t.Run("contains filter", func(t *testing.T) { q := NewQuery().Contains("post") result := q.Apply(conns) if len(result) != 1 || result[0].Process != "postgres" { t.Errorf("expected postgres, got %v", result) } }) } func TestPrebuiltQueries(t *testing.T) { t.Run("ListeningTCP", func(t *testing.T) { q := ListeningTCP() if q.Filter.Proto != "tcp" || q.Filter.State != "LISTEN" { t.Error("ListeningTCP should filter tcp + LISTEN") } }) t.Run("ListeningAll", func(t *testing.T) { q := ListeningAll() if q.Filter.State != "LISTEN" { t.Error("ListeningAll should filter LISTEN state") } }) t.Run("EstablishedTCP", func(t *testing.T) { q := EstablishedTCP() if q.Filter.Proto != "tcp" || q.Filter.State != "ESTABLISHED" { t.Error("EstablishedTCP should filter tcp + ESTABLISHED") } }) t.Run("ByProcess", func(t *testing.T) { q := ByProcess("nginx") if q.Filter.Proc != "nginx" { t.Error("ByProcess should set process filter") } }) t.Run("ByPort", func(t *testing.T) { q := ByPort(8080) if q.Filter.Lport != 8080 { t.Error("ByPort should set lport filter") } }) }