113 lines
4.3 KiB
Go
113 lines
4.3 KiB
Go
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 <logic> extractor.
|
|
func TestExtractLogicBlock(t *testing.T) {
|
|
if got := extractLogicBlock([]byte(`<i><logic><n/></logic></i>`)); got != "<logic><n/></logic>" {
|
|
t.Errorf("extract = %q", got)
|
|
}
|
|
if got := extractLogicBlock([]byte(`<i></i>`)); got != "" {
|
|
t.Errorf("no logic: want empty, got %q", got)
|
|
}
|
|
if got := extractLogicBlock([]byte(`<i><logic>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)
|
|
}
|
|
}
|