Implements 15 new MCP tools in the `org` domain covering organization CRUD, membership queries, and team management. All tools follow existing patterns and are available via both MCP and CLI modes.
210 lines
5.4 KiB
Go
210 lines
5.4 KiB
Go
package org
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
forgejo_sdk "codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2"
|
|
"codeberg.org/goern/forgejo-mcp/v2/pkg/forgejo"
|
|
"github.com/mark3labs/mcp-go/mcp"
|
|
)
|
|
|
|
func newCallToolRequest(args map[string]interface{}) mcp.CallToolRequest {
|
|
return mcp.CallToolRequest{
|
|
Params: mcp.CallToolParams{
|
|
Arguments: args,
|
|
},
|
|
}
|
|
}
|
|
|
|
func setupOrgMockServer(t *testing.T, handler http.HandlerFunc) *httptest.Server {
|
|
t.Helper()
|
|
srv := httptest.NewServer(handler)
|
|
client, err := forgejo_sdk.NewClient(srv.URL, forgejo_sdk.SetForgejoVersion("7.0.0"))
|
|
if err != nil {
|
|
t.Fatalf("creating test client: %v", err)
|
|
}
|
|
forgejo.SetClientForTesting(client)
|
|
return srv
|
|
}
|
|
|
|
func TestCreateOrgFn_Success(t *testing.T) {
|
|
srv := setupOrgMockServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"id": 1,
|
|
"username": "test-org",
|
|
})
|
|
})
|
|
defer srv.Close()
|
|
|
|
req := newCallToolRequest(map[string]interface{}{
|
|
"name": "test-org",
|
|
})
|
|
result, err := CreateOrgFn(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("CreateOrgFn returned error: %v", err)
|
|
}
|
|
if result.IsError {
|
|
t.Fatal("CreateOrgFn returned tool error")
|
|
}
|
|
}
|
|
|
|
func TestCreateOrgFn_MissingName(t *testing.T) {
|
|
req := newCallToolRequest(map[string]interface{}{})
|
|
_, err := CreateOrgFn(context.Background(), req)
|
|
if err == nil {
|
|
t.Fatal("expected error for missing name, got nil")
|
|
}
|
|
}
|
|
|
|
func TestGetOrgFn_Success(t *testing.T) {
|
|
srv := setupOrgMockServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"id": 1,
|
|
"username": "test-org",
|
|
})
|
|
})
|
|
defer srv.Close()
|
|
|
|
req := newCallToolRequest(map[string]interface{}{
|
|
"org": "test-org",
|
|
})
|
|
result, err := GetOrgFn(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("GetOrgFn returned error: %v", err)
|
|
}
|
|
if result.IsError {
|
|
t.Fatal("GetOrgFn returned tool error")
|
|
}
|
|
}
|
|
|
|
func TestGetOrgFn_MissingOrg(t *testing.T) {
|
|
req := newCallToolRequest(map[string]interface{}{})
|
|
_, err := GetOrgFn(context.Background(), req)
|
|
if err == nil {
|
|
t.Fatal("expected error for missing org, got nil")
|
|
}
|
|
}
|
|
|
|
func TestListMyOrgsFn_Success(t *testing.T) {
|
|
srv := setupOrgMockServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode([]map[string]interface{}{
|
|
{"id": 1, "username": "org1"},
|
|
{"id": 2, "username": "org2"},
|
|
})
|
|
})
|
|
defer srv.Close()
|
|
|
|
req := newCallToolRequest(map[string]interface{}{
|
|
"page": float64(1),
|
|
"limit": float64(10),
|
|
})
|
|
result, err := ListMyOrgsFn(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("ListMyOrgsFn returned error: %v", err)
|
|
}
|
|
if result.IsError {
|
|
t.Fatal("ListMyOrgsFn returned tool error")
|
|
}
|
|
}
|
|
|
|
func TestListUserOrgsFn_Success(t *testing.T) {
|
|
srv := setupOrgMockServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode([]map[string]interface{}{
|
|
{"id": 1, "username": "org1"},
|
|
})
|
|
})
|
|
defer srv.Close()
|
|
|
|
req := newCallToolRequest(map[string]interface{}{
|
|
"user": "testuser",
|
|
})
|
|
result, err := ListUserOrgsFn(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("ListUserOrgsFn returned error: %v", err)
|
|
}
|
|
if result.IsError {
|
|
t.Fatal("ListUserOrgsFn returned tool error")
|
|
}
|
|
}
|
|
|
|
func TestListUserOrgsFn_MissingUser(t *testing.T) {
|
|
req := newCallToolRequest(map[string]interface{}{})
|
|
_, err := ListUserOrgsFn(context.Background(), req)
|
|
if err == nil {
|
|
t.Fatal("expected error for missing user, got nil")
|
|
}
|
|
}
|
|
|
|
func TestEditOrgFn_Success(t *testing.T) {
|
|
callCount := 0
|
|
srv := setupOrgMockServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
callCount++
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if r.Method == "PATCH" {
|
|
w.WriteHeader(http.StatusOK)
|
|
return
|
|
}
|
|
// GET for the follow-up GetOrg
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"id": 1,
|
|
"username": "test-org",
|
|
"description": "updated",
|
|
})
|
|
})
|
|
defer srv.Close()
|
|
|
|
req := newCallToolRequest(map[string]interface{}{
|
|
"org": "test-org",
|
|
"description": "updated",
|
|
})
|
|
result, err := EditOrgFn(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("EditOrgFn returned error: %v", err)
|
|
}
|
|
if result.IsError {
|
|
t.Fatal("EditOrgFn returned tool error")
|
|
}
|
|
}
|
|
|
|
func TestEditOrgFn_MissingOrg(t *testing.T) {
|
|
req := newCallToolRequest(map[string]interface{}{})
|
|
_, err := EditOrgFn(context.Background(), req)
|
|
if err == nil {
|
|
t.Fatal("expected error for missing org, got nil")
|
|
}
|
|
}
|
|
|
|
func TestDeleteOrgFn_Success(t *testing.T) {
|
|
srv := setupOrgMockServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
})
|
|
defer srv.Close()
|
|
|
|
req := newCallToolRequest(map[string]interface{}{
|
|
"org": "test-org",
|
|
})
|
|
result, err := DeleteOrgFn(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("DeleteOrgFn returned error: %v", err)
|
|
}
|
|
if result.IsError {
|
|
t.Fatal("DeleteOrgFn returned tool error")
|
|
}
|
|
}
|
|
|
|
func TestDeleteOrgFn_MissingOrg(t *testing.T) {
|
|
req := newCallToolRequest(map[string]interface{}{})
|
|
_, err := DeleteOrgFn(context.Background(), req)
|
|
if err == nil {
|
|
t.Fatal("expected error for missing org, got nil")
|
|
}
|
|
}
|