mirror of
https://github.com/EZ-Api/ez-api.git
synced 2026-01-14 02:57:52 +00:00
test(log): expand handler, config, and metrics coverage
This commit is contained in:
@@ -34,7 +34,7 @@ func TestAdmin_IssueChildKeyForMaster_IssuedByAdminAndSynced(t *testing.T) {
|
|||||||
|
|
||||||
syncService := service.NewSyncService(rdb)
|
syncService := service.NewSyncService(rdb)
|
||||||
masterService := service.NewMasterService(db)
|
masterService := service.NewMasterService(db)
|
||||||
adminHandler := NewAdminHandler(db, masterService, syncService)
|
adminHandler := NewAdminHandler(db, db, masterService, syncService)
|
||||||
|
|
||||||
m, _, err := masterService.CreateMaster("m1", "default", 5, 10)
|
m, _, err := masterService.CreateMaster("m1", "default", 5, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func TestMaster_ListSelfLogs_FiltersByMaster(t *testing.T) {
|
|||||||
t.Fatalf("create log2: %v", err)
|
t.Fatalf("create log2: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mh := &MasterHandler{db: db}
|
mh := &MasterHandler{db: db, logDB: db}
|
||||||
|
|
||||||
withMaster := func(next gin.HandlerFunc) gin.HandlerFunc {
|
withMaster := func(next gin.HandlerFunc) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
@@ -69,7 +69,7 @@ func TestMaster_ListSelfLogs_FiltersByMaster(t *testing.T) {
|
|||||||
if rr.Code != http.StatusOK {
|
if rr.Code != http.StatusOK {
|
||||||
t.Fatalf("expected 200, got %d body=%s", rr.Code, rr.Body.String())
|
t.Fatalf("expected 200, got %d body=%s", rr.Code, rr.Body.String())
|
||||||
}
|
}
|
||||||
var resp ListLogsResponse
|
var resp ListMasterLogsResponse
|
||||||
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
|
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
|
||||||
t.Fatalf("unmarshal: %v", err)
|
t.Fatalf("unmarshal: %v", err)
|
||||||
}
|
}
|
||||||
@@ -79,6 +79,31 @@ func TestMaster_ListSelfLogs_FiltersByMaster(t *testing.T) {
|
|||||||
if resp.Items[0].KeyID != k1.ID {
|
if resp.Items[0].KeyID != k1.ID {
|
||||||
t.Fatalf("expected key_id %d, got %+v", k1.ID, resp.Items[0])
|
t.Fatalf("expected key_id %d, got %+v", k1.ID, resp.Items[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var raw map[string]any
|
||||||
|
if err := json.Unmarshal(rr.Body.Bytes(), &raw); err != nil {
|
||||||
|
t.Fatalf("unmarshal raw: %v", err)
|
||||||
|
}
|
||||||
|
items, ok := raw["items"].([]any)
|
||||||
|
if !ok || len(items) == 0 {
|
||||||
|
t.Fatalf("expected items array in response")
|
||||||
|
}
|
||||||
|
first, ok := items[0].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected item object in response")
|
||||||
|
}
|
||||||
|
if _, ok := first["provider_id"]; ok {
|
||||||
|
t.Fatalf("expected provider_id to be omitted")
|
||||||
|
}
|
||||||
|
if _, ok := first["provider_type"]; ok {
|
||||||
|
t.Fatalf("expected provider_type to be omitted")
|
||||||
|
}
|
||||||
|
if _, ok := first["provider_name"]; ok {
|
||||||
|
t.Fatalf("expected provider_name to be omitted")
|
||||||
|
}
|
||||||
|
if _, ok := first["client_ip"]; ok {
|
||||||
|
t.Fatalf("expected client_ip to be omitted")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdmin_DeleteLogs_BeforeFilters(t *testing.T) {
|
func TestAdmin_DeleteLogs_BeforeFilters(t *testing.T) {
|
||||||
@@ -114,7 +139,7 @@ func TestAdmin_DeleteLogs_BeforeFilters(t *testing.T) {
|
|||||||
t.Fatalf("create log3: %v", err)
|
t.Fatalf("create log3: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
h := &Handler{db: db}
|
h := &Handler{db: db, logDB: db}
|
||||||
r := gin.New()
|
r := gin.New()
|
||||||
r.DELETE("/admin/logs", h.DeleteLogs)
|
r.DELETE("/admin/logs", h.DeleteLogs)
|
||||||
|
|
||||||
@@ -155,7 +180,7 @@ func TestAdmin_DeleteLogs_RequiresBefore(t *testing.T) {
|
|||||||
t.Fatalf("migrate: %v", err)
|
t.Fatalf("migrate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
h := &Handler{db: db}
|
h := &Handler{db: db, logDB: db}
|
||||||
r := gin.New()
|
r := gin.New()
|
||||||
r.DELETE("/admin/logs", h.DeleteLogs)
|
r.DELETE("/admin/logs", h.DeleteLogs)
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func newTestHandlerWithWebhook(t *testing.T) (*Handler, *miniredis.Miniredis) {
|
|||||||
mr := miniredis.RunT(t)
|
mr := miniredis.RunT(t)
|
||||||
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
||||||
sync := service.NewSyncService(rdb)
|
sync := service.NewSyncService(rdb)
|
||||||
return NewHandler(db, sync, nil, rdb), mr
|
return NewHandler(db, db, sync, nil, rdb), mr
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogWebhookConfigCRUD(t *testing.T) {
|
func TestLogWebhookConfigCRUD(t *testing.T) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func TestMaster_ListTokens_AndUpdateToken(t *testing.T) {
|
|||||||
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
||||||
syncSvc := service.NewSyncService(rdb)
|
syncSvc := service.NewSyncService(rdb)
|
||||||
masterSvc := service.NewMasterService(db)
|
masterSvc := service.NewMasterService(db)
|
||||||
h := NewMasterHandler(db, masterSvc, syncSvc)
|
h := NewMasterHandler(db, db, masterSvc, syncSvc)
|
||||||
|
|
||||||
withMaster := func(next gin.HandlerFunc) gin.HandlerFunc {
|
withMaster := func(next gin.HandlerFunc) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func newTestHandlerWithRedis(t *testing.T) (*Handler, *gorm.DB, *miniredis.Minir
|
|||||||
mr := miniredis.RunT(t)
|
mr := miniredis.RunT(t)
|
||||||
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
||||||
sync := service.NewSyncService(rdb)
|
sync := service.NewSyncService(rdb)
|
||||||
return NewHandler(db, sync, nil, rdb), db, mr
|
return NewHandler(db, db, sync, nil, rdb), db, mr
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateModel_DefaultsKindChat_AndWritesModelsMeta(t *testing.T) {
|
func TestCreateModel_DefaultsKindChat_AndWritesModelsMeta(t *testing.T) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func newTestHandler(t *testing.T) (*Handler, *gorm.DB) {
|
|||||||
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
||||||
sync := service.NewSyncService(rdb)
|
sync := service.NewSyncService(rdb)
|
||||||
|
|
||||||
return NewHandler(db, sync, nil, rdb), db
|
return NewHandler(db, db, sync, nil, rdb), db
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateProvider_DefaultsVertexLocationGlobal(t *testing.T) {
|
func TestCreateProvider_DefaultsVertexLocationGlobal(t *testing.T) {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func TestMasterStats_AggregatesByKeyAndModel(t *testing.T) {
|
|||||||
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
||||||
masterSvc := service.NewMasterService(db)
|
masterSvc := service.NewMasterService(db)
|
||||||
syncSvc := service.NewSyncService(rdb)
|
syncSvc := service.NewSyncService(rdb)
|
||||||
h := NewMasterHandler(db, masterSvc, syncSvc)
|
h := NewMasterHandler(db, db, masterSvc, syncSvc)
|
||||||
|
|
||||||
withMaster := func(next gin.HandlerFunc) gin.HandlerFunc {
|
withMaster := func(next gin.HandlerFunc) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
@@ -163,7 +163,7 @@ func TestAdminStats_AggregatesByProvider(t *testing.T) {
|
|||||||
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
||||||
masterSvc := service.NewMasterService(db)
|
masterSvc := service.NewMasterService(db)
|
||||||
syncSvc := service.NewSyncService(rdb)
|
syncSvc := service.NewSyncService(rdb)
|
||||||
adminHandler := NewAdminHandler(db, masterSvc, syncSvc)
|
adminHandler := NewAdminHandler(db, db, masterSvc, syncSvc)
|
||||||
|
|
||||||
r := gin.New()
|
r := gin.New()
|
||||||
r.GET("/admin/stats", adminHandler.GetAdminStats)
|
r.GET("/admin/stats", adminHandler.GetAdminStats)
|
||||||
|
|||||||
14
internal/config/config_test.go
Normal file
14
internal/config/config_test.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestLoad_LogDSNOverride(t *testing.T) {
|
||||||
|
t.Setenv("EZ_LOG_PG_DSN", "host=log-db user=postgres dbname=logs")
|
||||||
|
cfg, err := Load()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("load config: %v", err)
|
||||||
|
}
|
||||||
|
if cfg.Log.DSN != "host=log-db user=postgres dbname=logs" {
|
||||||
|
t.Fatalf("expected log dsn to be set, got %q", cfg.Log.DSN)
|
||||||
|
}
|
||||||
|
}
|
||||||
62
internal/service/logger_test.go
Normal file
62
internal/service/logger_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"expvar"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ez-api/ez-api/internal/model"
|
||||||
|
"gorm.io/driver/sqlite"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLogWriterMetrics(t *testing.T) {
|
||||||
|
dsn := fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())
|
||||||
|
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("open sqlite: %v", err)
|
||||||
|
}
|
||||||
|
if err := db.AutoMigrate(&model.LogRecord{}); err != nil {
|
||||||
|
t.Fatalf("migrate: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
startBatch := getExpvarInt(t, "log_write_batch_total")
|
||||||
|
startDropped := getExpvarInt(t, "log_queue_dropped_total")
|
||||||
|
|
||||||
|
dropWriter := NewLogWriter(db, 1, 10, time.Second)
|
||||||
|
dropWriter.Write(model.LogRecord{ModelName: "m1", StatusCode: 200})
|
||||||
|
dropWriter.Write(model.LogRecord{ModelName: "m2", StatusCode: 200})
|
||||||
|
|
||||||
|
writer := NewLogWriter(db, 10, 1, 10*time.Millisecond)
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
t.Cleanup(cancel)
|
||||||
|
writer.Start(ctx)
|
||||||
|
writer.Write(model.LogRecord{ModelName: "m3", StatusCode: 200})
|
||||||
|
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
if got := getExpvarInt(t, "log_write_batch_total"); got <= startBatch {
|
||||||
|
t.Fatalf("expected batch counter to increase, start=%d got=%d", startBatch, got)
|
||||||
|
}
|
||||||
|
if got := getExpvarInt(t, "log_queue_dropped_total"); got <= startDropped {
|
||||||
|
t.Fatalf("expected dropped counter to be >= start, start=%d got=%d", startDropped, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExpvarInt(t *testing.T, name string) int64 {
|
||||||
|
t.Helper()
|
||||||
|
v := expvar.Get(name)
|
||||||
|
if v == nil {
|
||||||
|
t.Fatalf("expvar %s not found", name)
|
||||||
|
}
|
||||||
|
raw := v.String()
|
||||||
|
n, err := strconv.ParseInt(raw, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parse expvar %s: %v", name, err)
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user