package api import ( "encoding/json" "net/http" "net/http/httptest" "testing" "git.golem15.com/golem15/summercms/modules/bouncer" ) // mcpRequest is a request as pier dispatches it in-process: the api_token // marker with a principal on its context. func mcpRequest(method, target string) *http.Request { r := httptest.NewRequest(method, target, nil) return r.WithContext(bouncer.WithDispatch(r.Context(), &bouncer.Dispatch{ Guards: []string{"api_token"}, Principal: &bouncer.Principal{ID: 7}, })) } // keysOf marshals v and returns its top-level JSON object. func keysOf(t *testing.T, v any) map[string]any { t.Helper() raw, err := json.Marshal(v) if err != nil { t.Fatal(err) } var out map[string]any if err := json.Unmarshal(raw, &out); err != nil { t.Fatal(err) } return out } func TestViaMCP(t *testing.T) { plain := httptest.NewRequest(http.MethodGet, "/", nil) if viaMCP(plain) { t.Error("a plain request is an MCP call") } if !viaMCP(mcpRequest(http.MethodGet, "/")) { t.Error("a dispatched api_token request is not an MCP call") } backend := httptest.NewRequest(http.MethodGet, "/", nil) backend = backend.WithContext(bouncer.WithDispatch(backend.Context(), &bouncer.Dispatch{ Guards: []string{"backend"}, Principal: &bouncer.Principal{ID: 7}, })) if viaMCP(backend) { t.Error("a backend dispatch is an MCP call of jz.bm") } for target, want := range map[string]bool{ "/": false, "/?include_body=false": false, "/?include_body=0": false, "/?include_body=true": true, "/?include_body=1": true, } { if got := includeBody(httptest.NewRequest(http.MethodGet, target, nil)); got != want { t.Errorf("includeBody(%s) = %v, want %v", target, got, want) } } } func TestMCPMaterialView(t *testing.T) { body := "transcript text" url := "https://x.test/a" detail := materialDetailJSON{ materialListJSON: materialListJSON{ID: 3, Title: "T", Type: "notatka", URL: &url, Tags: []tagJSON{}}, Body: &body, Files: []fileJSON{{ID: 9, URL: "/storage/f.pdf", Name: "f.pdf", Size: 10, Mime: "application/pdf"}}, } t.Run("plain request unchanged", func(t *testing.T) { got := keysOf(t, materialView(detail, viaMCP(httptest.NewRequest(http.MethodGet, "/", nil)), false)) want := keysOf(t, detail) gotRaw, _ := json.Marshal(got) wantRaw, _ := json.Marshal(want) if string(gotRaw) != string(wantRaw) { t.Errorf("plain view = %s, want %s", gotRaw, wantRaw) } }) t.Run("MCP without include_body", func(t *testing.T) { got := keysOf(t, materialView(detail, viaMCP(mcpRequest(http.MethodGet, "/")), includeBody(mcpRequest(http.MethodGet, "/")))) if _, ok := got["body"]; ok { t.Errorf("body present: %v", got) } if got["body_omitted"] != true { t.Errorf("body_omitted = %v, want true", got["body_omitted"]) } files, _ := got["files"].([]any) if len(files) != 1 { t.Fatalf("files = %v", got["files"]) } f := files[0].(map[string]any) for _, k := range []string{"id", "name", "size", "mime", "url"} { if _, ok := f[k]; !ok { t.Errorf("file lacks %s: %v", k, f) } } if got["title"] != "T" || got["url"] != url { t.Errorf("list fields lost: %v", got) } }) t.Run("MCP without include_body, empty body", func(t *testing.T) { empty := detail empty.Body = nil got := keysOf(t, materialView(empty, true, false)) if _, ok := got["body"]; ok { t.Errorf("body present: %v", got) } if _, ok := got["body_omitted"]; ok { t.Errorf("body_omitted set for an empty body: %v", got) } }) t.Run("MCP with include_body", func(t *testing.T) { got := keysOf(t, materialView(detail, true, includeBody(mcpRequest(http.MethodGet, "/?include_body=true")))) if got["body"] != body { t.Errorf("body = %v, want %q", got["body"], body) } if _, ok := got["body_omitted"]; ok { t.Errorf("body_omitted set with include_body: %v", got) } }) managed := managedMaterialJSON{ID: 3, Title: "T", Type: "notatka", Body: &body, Tags: []tagJSON{}} t.Run("managed plain unchanged", func(t *testing.T) { got := keysOf(t, managedMaterialView(managed, false, false)) if got["body"] != body { t.Errorf("plain managed body = %v", got["body"]) } if _, ok := got["body_omitted"]; ok { t.Errorf("plain managed has body_omitted: %v", got) } }) t.Run("managed MCP read", func(t *testing.T) { got := keysOf(t, managedMaterialView(managed, true, false)) if _, ok := got["body"]; ok || got["body_omitted"] != true { t.Errorf("managed MCP read = %v, want no body and body_omitted", got) } got = keysOf(t, managedMaterialView(managed, true, includeBody(mcpRequest(http.MethodGet, "/?include_body=1")))) if got["body"] != body { t.Errorf("managed MCP read with include_body = %v", got) } }) // A write answer passes withBody false whatever the request asks. t.Run("managed MCP write never echoes the body", func(t *testing.T) { got := keysOf(t, managedMaterialView(managed, true, false)) if _, ok := got["body"]; ok || got["body_omitted"] != true { t.Errorf("managed MCP write = %v, want no body and body_omitted", got) } d := managedMaterialDetailJSON{managedMaterialJSON: managed, Files: []fileJSON{}} got = keysOf(t, managedMaterialDetailView(d, true, false)) if _, ok := got["body"]; ok || got["body_omitted"] != true { t.Errorf("managed MCP write detail = %v, want no body and body_omitted", got) } if _, ok := got["files"]; !ok { t.Errorf("managed MCP write detail lost files: %v", got) } }) }