Files
ez-api/test/integration_test.go
zenfun 8645b22b83 feat(auth): implement master key authentication system with child key issuance
Add admin and master authentication layers with JWT support. Replace direct
key creation with hierarchical master/child key system. Update database
schema to support master accounts with configurable limits and epoch-based
key revocation. Add health check endpoint with system status monitoring.

BREAKING CHANGE: Removed direct POST /keys endpoint in favor of master-based
key issuance through /v1/tokens. Database migration requires dropping old User
table and creating Master table with new relationships.
2025-12-05 00:16:47 +08:00

91 lines
2.3 KiB
Go

//go:build integration
package integration
import (
"bytes"
"encoding/json"
"io"
"net/http"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestEndToEnd(t *testing.T) {
apiBase := getenv("E2E_EZAPI_URL", "http://localhost:8080")
adminToken := getenv("EZ_ADMIN_TOKEN", "admin-token") // Make sure this matches docker-compose
client := &http.Client{Timeout: 5 * time.Second}
// 1. Admin creates a Master Key
masterPayload := map[string]interface{}{
"name": "test-master",
"group": "default",
"max_child_keys": 2,
"global_qps": 10,
}
var masterResp struct {
MasterKey string `json:"master_key"`
}
postJSONWithAuth(t, client, apiBase+"/admin/masters", masterPayload, &masterResp, adminToken)
masterKey := masterResp.MasterKey
require.NotEmpty(t, masterKey)
// 2. Master issues a Child Key
childPayload := map[string]interface{}{
"group": "default",
"scopes": "chat:write",
}
var childResp struct {
KeySecret string `json:"key_secret"`
}
postJSONWithAuth(t, client, apiBase+"/v1/tokens", childPayload, &childResp, masterKey)
childKey := childResp.KeySecret
require.NotEmpty(t, childKey)
// 3. (Conceptual) Use Child Key to access balancer - this part can't be fully tested here
// but we've verified the key generation flow.
t.Logf("Admin Token: %s", adminToken)
t.Logf("Master Key: %s", masterKey)
t.Logf("Child Key: %s", childKey)
}
func postJSONWithAuth[T any](t *testing.T, client *http.Client, url string, body interface{}, out T, token string) T {
b, err := json.Marshal(body)
require.NoError(t, err)
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(b))
require.NoError(t, err)
req.Header.Set("Content-Type", "application/json")
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
resp, err := client.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
data, _ := io.ReadAll(resp.Body)
t.Fatalf("expected 200 or 201, got %d. Body: %s", resp.StatusCode, string(data))
}
if out != nil {
data, _ := io.ReadAll(resp.Body)
if len(data) > 0 {
require.NoError(t, json.Unmarshal(data, out))
}
}
return out
}
func getenv(key, def string) string {
if v := os.Getenv(key); v != "" {
return v
}
return def
}