internal/adminapi/admin_commands_test.go
Rama main · réplica de lectura del repositorio original.
package adminapi
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"telesrv/internal/domain"
)
type captureAuditService struct {
fakeService
limit int
actor string
cmds []domain.AdminCommand
err error
}
func (s *captureAuditService) ListRecentAdminCommands(_ context.Context, limit int, actor string) ([]domain.AdminCommand, error) {
if s.err != nil {
return nil, s.err
}
s.limit, s.actor = limit, actor
return s.cmds, nil
}
func auditRequest(method, target, token string) *http.Request {
req, _ := http.NewRequest(method, target, nil)
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
return req
}
func TestAdminCommandsListHonoursLimitActorAndTrimsFields(t *testing.T) {
completed := time.Now().UTC().Truncate(time.Second)
svc := &captureAuditService{cmds: []domain.AdminCommand{{
CommandID: "bot-abc", Actor: "777", Action: "set_phone", TargetUserID: 42,
DryRun: false, Status: domain.AdminCommandCompleted, Reason: "Admin number bind",
Error: "", CreatedAt: completed,
}}}
srv := httptest.NewServer((&Server{token: "master", svc: svc}).routes())
defer srv.Close()
res, err := srv.Client().Do(auditRequest(http.MethodGet, srv.URL+"/v1/admin-commands?limit=5&actor=777", "master"))
if err != nil {
t.Fatalf("request: %v", err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
t.Fatalf("status %d, want 200", res.StatusCode)
}
if svc.limit != 5 {
t.Fatalf("limit forwarded is %d, want 5", svc.limit)
}
if svc.actor != "777" {
t.Fatalf("actor forwarded is %q, want 777", svc.actor)
}
var body struct {
Commands []map[string]any `json:"commands"`
}
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
t.Fatalf("decode: %v", err)
}
if len(body.Commands) != 1 {
t.Fatalf("got %d commands, want 1", len(body.Commands))
}
item := body.Commands[0]
for key, want := range map[string]any{
"command_id": "bot-abc",
"actor": "777",
"action": "set_phone",
"dry_run": false,
"status": "completed",
"target_user_id": float64(42),
"reason": "Admin number bind",
"created_at": completed.Format(time.RFC3339),
} {
if item[key] != want {
t.Fatalf("field %q = %#v, want %#v", key, item[key], want)
}
}
if _, leaked := item["result"]; leaked {
t.Fatal("audit response must not include the request/result payloads")
}
if _, leaked := item["request"]; leaked {
t.Fatal("audit response must not include the request/result payloads")
}
}
func TestAdminCommandsListRequiresAuth(t *testing.T) {
srv := httptest.NewServer((&Server{token: "master", svc: &captureAuditService{}}).routes())
defer srv.Close()
res, err := srv.Client().Do(auditRequest(http.MethodGet, srv.URL+"/v1/admin-commands", ""))
if err != nil {
t.Fatalf("request: %v", err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusUnauthorized {
t.Fatalf("status %d, want 401", res.StatusCode)
}
}
func TestAdminCommandsListServiceError(t *testing.T) {
svc := &captureAuditService{err: context.DeadlineExceeded}
srv := httptest.NewServer((&Server{token: "master", svc: svc}).routes())
defer srv.Close()
res, err := srv.Client().Do(auditRequest(http.MethodGet, srv.URL+"/v1/admin-commands", "master"))
if err != nil {
t.Fatalf("request: %v", err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusInternalServerError {
t.Fatalf("status %d, want 500", res.StatusCode)
}
}