Pulse/internal/api/security_tokens_handlers_test.go

109 lines
3.3 KiB
Go

package api
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
)
func TestSecurityTokens_ListCreateDelete(t *testing.T) {
cfg := &config.Config{}
persistence := config.NewConfigPersistence(t.TempDir())
router := &Router{
config: cfg,
persistence: persistence,
}
req := httptest.NewRequest(http.MethodPost, "/api/security/tokens", nil)
rr := httptest.NewRecorder()
router.handleListAPITokens(rr, req)
if rr.Code != http.StatusMethodNotAllowed {
t.Fatalf("expected status %d, got %d", http.StatusMethodNotAllowed, rr.Code)
}
req = httptest.NewRequest(http.MethodPost, "/api/security/tokens", strings.NewReader("{bad"))
rr = httptest.NewRecorder()
router.handleCreateAPIToken(rr, req)
if rr.Code != http.StatusBadRequest {
t.Fatalf("expected status %d, got %d", http.StatusBadRequest, rr.Code)
}
req = httptest.NewRequest(http.MethodPost, "/api/security/tokens", strings.NewReader(`{"name":"test","scopes":["monitoring:read"]}`))
rr = httptest.NewRecorder()
router.handleCreateAPIToken(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected status %d, got %d", http.StatusOK, rr.Code)
}
var createResp struct {
Token string `json:"token"`
Record apiTokenDTO `json:"record"`
}
if err := json.NewDecoder(rr.Body).Decode(&createResp); err != nil {
t.Fatalf("decode create response: %v", err)
}
if createResp.Token == "" {
t.Fatal("expected raw token in response")
}
if createResp.Record.Name != "test" {
t.Fatalf("expected record name 'test', got %q", createResp.Record.Name)
}
if len(cfg.APITokens) != 1 {
t.Fatalf("expected token stored in config")
}
req = httptest.NewRequest(http.MethodGet, "/api/security/tokens", nil)
rr = httptest.NewRecorder()
router.handleListAPITokens(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected status %d, got %d", http.StatusOK, rr.Code)
}
var listResp struct {
Tokens []apiTokenDTO `json:"tokens"`
}
if err := json.NewDecoder(rr.Body).Decode(&listResp); err != nil {
t.Fatalf("decode list response: %v", err)
}
if len(listResp.Tokens) != 1 {
t.Fatalf("expected 1 token, got %d", len(listResp.Tokens))
}
req = httptest.NewRequest(http.MethodDelete, "/api/security/tokens/", nil)
rr = httptest.NewRecorder()
router.handleDeleteAPIToken(rr, req)
if rr.Code != http.StatusBadRequest {
t.Fatalf("expected status %d, got %d", http.StatusBadRequest, rr.Code)
}
req = httptest.NewRequest(http.MethodDelete, "/api/security/tokens/missing", nil)
rr = httptest.NewRecorder()
router.handleDeleteAPIToken(rr, req)
if rr.Code != http.StatusNotFound {
t.Fatalf("expected status %d, got %d", http.StatusNotFound, rr.Code)
}
// Test deletion of migrated env token suppression
record := config.APITokenRecord{
ID: "migrated",
Name: "Migrated from .env token",
Hash: "hash-migrated",
CreatedAt: time.Now(),
}
cfg.APITokens = append(cfg.APITokens, record)
req = httptest.NewRequest(http.MethodDelete, "/api/security/tokens/migrated", nil)
rr = httptest.NewRecorder()
router.handleDeleteAPIToken(rr, req)
if rr.Code != http.StatusNoContent {
t.Fatalf("expected status %d, got %d", http.StatusNoContent, rr.Code)
}
if !cfg.IsEnvMigrationSuppressed("hash-migrated") {
t.Fatalf("expected env migration suppression to be recorded")
}
}