mirror of
https://github.com/EZ-Api/ez-api.git
synced 2026-01-13 17:47:51 +00:00
feat(api): add API key stats flush and summary endpoints
Introduce internal endpoint for flushing accumulated APIKey statistics from data plane to control plane database, updating both individual API keys and their parent provider groups with request counts and success/failure rates. Add admin endpoint to retrieve aggregated API key statistics summary across all provider groups, including total requests, success/failure counts, and calculated rates.
This commit is contained in:
68
internal/api/apikey_stats_handler_test.go
Normal file
68
internal/api/apikey_stats_handler_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/ez-api/ez-api/internal/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestAdminHandler_GetAPIKeyStatsSummary(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("open sqlite: %v", err)
|
||||
}
|
||||
if err := db.AutoMigrate(&model.APIKey{}); err != nil {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
|
||||
if err := db.Create(&model.APIKey{
|
||||
GroupID: 1,
|
||||
APIKey: "k1",
|
||||
TotalRequests: 10,
|
||||
SuccessRequests: 7,
|
||||
FailureRequests: 3,
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("create key1: %v", err)
|
||||
}
|
||||
if err := db.Create(&model.APIKey{
|
||||
GroupID: 1,
|
||||
APIKey: "k2",
|
||||
TotalRequests: 5,
|
||||
SuccessRequests: 5,
|
||||
FailureRequests: 0,
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("create key2: %v", err)
|
||||
}
|
||||
|
||||
handler := &AdminHandler{db: db}
|
||||
r := gin.New()
|
||||
r.GET("/admin/apikey-stats/summary", handler.GetAPIKeyStatsSummary)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/admin/apikey-stats/summary", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
r.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("unexpected status: got=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
var resp APIKeyStatsSummaryResponse
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if resp.TotalRequests != 15 || resp.SuccessRequests != 12 || resp.FailureRequests != 3 {
|
||||
t.Fatalf("totals mismatch: %+v", resp)
|
||||
}
|
||||
if math.Abs(resp.SuccessRate-0.8) > 1e-6 || math.Abs(resp.FailureRate-0.2) > 1e-6 {
|
||||
t.Fatalf("rates mismatch: success=%f failure=%f", resp.SuccessRate, resp.FailureRate)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user