package api import ( "net/http" "net/http/httptest" "testing" "github.com/uopi/uopi/internal/access" "github.com/uopi/uopi/internal/datasource" "github.com/uopi/uopi/internal/datasource/synthetic" "github.com/uopi/uopi/internal/panelacl" ) // TestExtractLogicBlock covers the three branches of the extractor. func TestExtractLogicBlock(t *testing.T) { if got := extractLogicBlock([]byte(``)); got != "" { t.Errorf("extract = %q", got) } if got := extractLogicBlock([]byte(``)); got != "" { t.Errorf("no logic: want empty, got %q", got) } if got := extractLogicBlock([]byte(`unterminated`)); got != "" { t.Errorf("unterminated: want empty, got %q", got) } } // TestDataTypeName covers every DataType→token mapping plus the default. func TestDataTypeName(t *testing.T) { cases := map[datasource.DataType]string{ datasource.TypeFloat64: "float64", datasource.TypeFloat64Array: "float64[]", datasource.TypeString: "string", datasource.TypeInt64: "int64", datasource.TypeBool: "bool", datasource.TypeEnum: "enum", datasource.DataType(255): "unknown", } for typ, want := range cases { if got := dataTypeName(typ); got != want { t.Errorf("dataTypeName(%v) = %q, want %q", typ, got, want) } } } // TestSynVisible covers each visibility branch of synVisible. func TestSynVisible(t *testing.T) { cases := []struct { name string def synthetic.SignalDef user string panel string groups []string want bool }{ {"user own", synthetic.SignalDef{Visibility: "user", Owner: "alice"}, "alice", "", nil, true}, {"user other", synthetic.SignalDef{Visibility: "user", Owner: "alice"}, "bob", "", nil, false}, {"panel match", synthetic.SignalDef{Visibility: "panel", Panel: "p1"}, "bob", "p1", nil, true}, {"panel mismatch", synthetic.SignalDef{Visibility: "panel", Panel: "p1"}, "bob", "p2", nil, false}, {"global", synthetic.SignalDef{Visibility: "global"}, "", "", nil, true}, {"legacy empty", synthetic.SignalDef{}, "", "", nil, true}, {"group member", synthetic.SignalDef{Visibility: "group", Owner: "alice", Groups: []string{"ops"}}, "bob", "", []string{"ops"}, true}, {"group outsider", synthetic.SignalDef{Visibility: "group", Owner: "alice", Groups: []string{"ops"}}, "bob", "", []string{"hr"}, false}, } for _, tc := range cases { if got := synVisible(tc.def, tc.user, tc.panel, tc.groups); got != tc.want { t.Errorf("%s: synVisible = %v, want %v", tc.name, got, tc.want) } } } // TestPanelScope covers the nil/public→global, group, and private branches. func TestPanelScope(t *testing.T) { if sc, _ := panelScope(nil); sc != access.ScopeGlobal { t.Errorf("nil acl: scope = %q, want global", sc) } if sc, _ := panelScope(&panelacl.PanelACL{Public: "read"}); sc != access.ScopeGlobal { t.Errorf("public acl: scope = %q, want global", sc) } sc, groups := panelScope(&panelacl.PanelACL{ Grants: []panelacl.Grant{{Kind: "group", Name: "ops"}, {Kind: "user", Name: "x"}}, }) if sc != access.ScopeGroup || len(groups) != 1 || groups[0] != "ops" { t.Errorf("group acl: scope=%q groups=%v", sc, groups) } if sc, _ := panelScope(&panelacl.PanelACL{Owner: "alice"}); sc != access.ScopePrivate { t.Errorf("private acl: scope = %q, want private", sc) } } // TestClientIP covers the XFF, X-Real-IP, host:port, and bare-RemoteAddr cases. func TestClientIP(t *testing.T) { mk := func(set func(*http.Request)) *http.Request { r := httptest.NewRequest(http.MethodGet, "/", nil) set(r) return r } if got := clientIP(mk(func(r *http.Request) { r.Header.Set("X-Forwarded-For", "1.2.3.4, 5.6.7.8") })); got != "1.2.3.4" { t.Errorf("XFF list: got %q", got) } if got := clientIP(mk(func(r *http.Request) { r.Header.Set("X-Forwarded-For", "9.9.9.9") })); got != "9.9.9.9" { t.Errorf("XFF single: got %q", got) } if got := clientIP(mk(func(r *http.Request) { r.Header.Set("X-Real-IP", "8.8.8.8") })); got != "8.8.8.8" { t.Errorf("X-Real-IP: got %q", got) } if got := clientIP(mk(func(r *http.Request) { r.RemoteAddr = "10.0.0.1:5555" })); got != "10.0.0.1" { t.Errorf("host:port: got %q", got) } if got := clientIP(mk(func(r *http.Request) { r.RemoteAddr = "bare-addr" })); got != "bare-addr" { t.Errorf("bare addr: got %q", got) } }