Files
sentryagent-idp/sdk-go/agents_test.go
SentryAgent.ai Developer 91c759f455 feat: Phase 2 Workstream 3 — Go SDK (github.com/sentryagent/idp-sdk-go)
Single-package agentidp SDK in sdk-go/:
- AgentIdPClient composing AgentRegistryClient, CredentialClient,
  TokenServiceClient, AuditClient — all 14 endpoints covered
- Goroutine-safe TokenManager (sync.Mutex) with 60s refresh buffer
- AgentIdPError implementing error interface with Code/HTTPStatus/Details
- Context-aware: all service methods take context.Context as first arg
- doRequest shared helper; token endpoints use form-encoded POST directly
- go vet: 0 warnings | staticcheck: 0 warnings
- go test ./...: 37/37 passed | coverage: 81.0% (>80% gate)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 15:23:02 +00:00

182 lines
5.4 KiB
Go

package agentidp
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
// mockAgent is the canonical test agent fixture.
var mockAgent = Agent{
AgentID: "uuid-1",
Email: "a@b.ai",
AgentType: "screener",
Version: "1.0.0",
Capabilities: []string{"read"},
Owner: "team",
DeploymentEnv: "production",
Status: "active",
CreatedAt: "2026-01-01T00:00:00Z",
UpdatedAt: "2026-01-01T00:00:00Z",
}
var mockPaginatedAgents = PaginatedAgents{
Data: []Agent{mockAgent},
Total: 1,
Page: 1,
Limit: 20,
}
// staticToken returns a fixed token for all test service clients.
func staticToken(_ context.Context) (string, error) {
return "test-bearer-token", nil
}
func newAgentServer(t *testing.T, method, path string, status int, body interface{}) *httptest.Server {
t.Helper()
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != method {
t.Errorf("expected method %s, got %s", method, r.Method)
}
if r.URL.Path != path {
t.Errorf("expected path %s, got %s", path, r.URL.Path)
}
if r.Header.Get("Authorization") == "" {
t.Error("missing Authorization header")
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
if body != nil {
_ = json.NewEncoder(w).Encode(body)
}
}))
}
func TestAgentRegistryClient_RegisterAgent(t *testing.T) {
srv := newAgentServer(t, http.MethodPost, "/api/v1/agents", 201, mockAgent)
defer srv.Close()
client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
agent, err := client.RegisterAgent(context.Background(), RegisterAgentRequest{
Email: "a@b.ai", AgentType: "screener", Version: "1.0.0",
Capabilities: []string{"read"}, Owner: "team", DeploymentEnv: "production",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if agent.AgentID != "uuid-1" {
t.Errorf("expected uuid-1, got %q", agent.AgentID)
}
}
func TestAgentRegistryClient_ListAgents(t *testing.T) {
srv := newAgentServer(t, http.MethodGet, "/api/v1/agents", 200, mockPaginatedAgents)
defer srv.Close()
client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
result, err := client.ListAgents(context.Background(), nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result.Total != 1 {
t.Errorf("expected total 1, got %d", result.Total)
}
if len(result.Data) != 1 || result.Data[0].AgentID != "uuid-1" {
t.Error("unexpected data in paginated result")
}
}
func TestAgentRegistryClient_ListAgents_WithParams(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("status") != "active" {
t.Errorf("expected status=active, got %q", r.URL.Query().Get("status"))
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(mockPaginatedAgents)
}))
defer srv.Close()
client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
_, err := client.ListAgents(context.Background(), &ListAgentsParams{Status: "active"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
func TestAgentRegistryClient_GetAgent(t *testing.T) {
srv := newAgentServer(t, http.MethodGet, "/api/v1/agents/uuid-1", 200, mockAgent)
defer srv.Close()
client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
agent, err := client.GetAgent(context.Background(), "uuid-1")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if agent.AgentID != "uuid-1" {
t.Errorf("expected uuid-1, got %q", agent.AgentID)
}
}
func TestAgentRegistryClient_GetAgent_NotFound(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(404)
_ = json.NewEncoder(w).Encode(map[string]string{
"code": "AgentNotFoundError",
"message": "Agent not found.",
})
}))
defer srv.Close()
client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
_, err := client.GetAgent(context.Background(), "bad-id")
if err == nil {
t.Fatal("expected error, got nil")
}
apiErr, ok := err.(*AgentIdPError)
if !ok {
t.Fatalf("expected *AgentIdPError, got %T", err)
}
if apiErr.Code != "AgentNotFoundError" {
t.Errorf("expected AgentNotFoundError, got %q", apiErr.Code)
}
if apiErr.HTTPStatus != 404 {
t.Errorf("expected 404, got %d", apiErr.HTTPStatus)
}
}
func TestAgentRegistryClient_UpdateAgent(t *testing.T) {
updated := mockAgent
updated.Version = "2.0.0"
srv := newAgentServer(t, http.MethodPatch, "/api/v1/agents/uuid-1", 200, updated)
defer srv.Close()
v := "2.0.0"
client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
agent, err := client.UpdateAgent(context.Background(), "uuid-1", UpdateAgentRequest{Version: &v})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if agent.Version != "2.0.0" {
t.Errorf("expected version 2.0.0, got %q", agent.Version)
}
}
func TestAgentRegistryClient_DecommissionAgent(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
t.Errorf("expected DELETE, got %s", r.Method)
}
w.WriteHeader(204)
}))
defer srv.Close()
client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
err := client.DecommissionAgent(context.Background(), "uuid-1")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}