fix: 系统性修复安全问题、性能问题和错误处理
安全问题修复: - X-Forwarded-For越界检查(auth.go) - checkTokenStatus Context参数传递(auth.go) - Type Assertion安全检查(auth.go) 性能问题修复: - TokenCache过期清理机制 - BruteForceProtection过期清理 - InMemoryIdempotencyStore过期清理 错误处理修复: - AuditStore.Emit返回error - domain层emitAudit辅助方法 - List方法返回空slice而非nil - 金额/价格负数验证 架构一致性: - 统一使用model.RoleHierarchyLevels 新增功能: - Alert API完整实现(CRUD+Resolve) - pkg/error错误码集中管理
This commit is contained in:
249
supply-api/internal/audit/service/batch_buffer_test.go
Normal file
249
supply-api/internal/audit/service/batch_buffer_test.go
Normal file
@@ -0,0 +1,249 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"lijiaoqiao/supply-api/internal/audit/model"
|
||||
)
|
||||
|
||||
// TestBatchBuffer_BatchSize 测试50条/批刷新
|
||||
func TestBatchBuffer_BatchSize(t *testing.T) {
|
||||
const batchSize = 50
|
||||
|
||||
buffer := NewBatchBuffer(batchSize, 100*time.Millisecond) // 100ms超时防止测试卡住
|
||||
ctx := context.Background()
|
||||
|
||||
err := buffer.Start(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Start failed: %v", err)
|
||||
}
|
||||
defer buffer.Close()
|
||||
|
||||
// 收集器:接收批量事件
|
||||
var receivedBatches [][]*model.AuditEvent
|
||||
var mu sync.Mutex
|
||||
|
||||
buffer.SetFlushHandler(func(events []*model.AuditEvent) error {
|
||||
mu.Lock()
|
||||
receivedBatches = append(receivedBatches, events)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
// 添加50条事件,应该触发一次批量刷新
|
||||
for i := 0; i < batchSize; i++ {
|
||||
event := &model.AuditEvent{
|
||||
EventID: "batch-test-001",
|
||||
EventName: "TEST-EVENT",
|
||||
}
|
||||
if err := buffer.Add(event); err != nil {
|
||||
t.Errorf("Add failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 等待刷新完成
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
// 验证:应该收到恰好一个批次
|
||||
mu.Lock()
|
||||
if len(receivedBatches) != 1 {
|
||||
t.Errorf("expected 1 batch, got %d", len(receivedBatches))
|
||||
}
|
||||
if len(receivedBatches) > 0 && len(receivedBatches[0]) != batchSize {
|
||||
t.Errorf("expected batch size %d, got %d", batchSize, len(receivedBatches[0]))
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
// TestBatchBuffer_TimeoutFlush 测试5ms超时刷新
|
||||
func TestBatchBuffer_TimeoutFlush(t *testing.T) {
|
||||
const batchSize = 100 // 大于我们添加的数量
|
||||
const flushInterval = 5 * time.Millisecond
|
||||
|
||||
buffer := NewBatchBuffer(batchSize, flushInterval)
|
||||
ctx := context.Background()
|
||||
|
||||
err := buffer.Start(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Start failed: %v", err)
|
||||
}
|
||||
defer buffer.Close()
|
||||
|
||||
// 收集器
|
||||
var receivedBatches [][]*model.AuditEvent
|
||||
var mu sync.Mutex
|
||||
|
||||
buffer.SetFlushHandler(func(events []*model.AuditEvent) error {
|
||||
mu.Lock()
|
||||
receivedBatches = append(receivedBatches, events)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
// 只添加3条事件,不满50条
|
||||
for i := 0; i < 3; i++ {
|
||||
event := &model.AuditEvent{
|
||||
EventID: "batch-test-002",
|
||||
EventName: "TEST-TIMEOUT",
|
||||
}
|
||||
if err := buffer.Add(event); err != nil {
|
||||
t.Errorf("Add failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 等待5ms超时刷新
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
|
||||
// 验证:应该收到一个批次,包含3条事件
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if len(receivedBatches) != 1 {
|
||||
t.Errorf("expected 1 batch (timeout flush), got %d", len(receivedBatches))
|
||||
}
|
||||
if len(receivedBatches) > 0 && len(receivedBatches[0]) != 3 {
|
||||
t.Errorf("expected 3 events in batch, got %d", len(receivedBatches[0]))
|
||||
}
|
||||
}
|
||||
|
||||
// TestBatchBuffer_ConcurrentAccess 测试并发安全性
|
||||
func TestBatchBuffer_ConcurrentAccess(t *testing.T) {
|
||||
const batchSize = 50
|
||||
const numGoroutines = 10
|
||||
const eventsPerGoroutine = 100
|
||||
|
||||
buffer := NewBatchBuffer(batchSize, 10*time.Millisecond)
|
||||
ctx := context.Background()
|
||||
|
||||
err := buffer.Start(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Start failed: %v", err)
|
||||
}
|
||||
defer buffer.Close()
|
||||
|
||||
var totalReceived int
|
||||
var mu sync.Mutex
|
||||
|
||||
buffer.SetFlushHandler(func(events []*model.AuditEvent) error {
|
||||
mu.Lock()
|
||||
totalReceived += len(events)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
// 并发添加事件
|
||||
var wg sync.WaitGroup
|
||||
for g := 0; g < numGoroutines; g++ {
|
||||
wg.Add(1)
|
||||
go func(goroutineID int) {
|
||||
defer wg.Done()
|
||||
for i := 0; i < eventsPerGoroutine; i++ {
|
||||
event := &model.AuditEvent{
|
||||
EventID: "batch-test-concurrent",
|
||||
EventName: "TEST-CONCURRENT",
|
||||
}
|
||||
if err := buffer.Add(event); err != nil {
|
||||
t.Errorf("Add failed: %v", err)
|
||||
}
|
||||
}
|
||||
}(g)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
time.Sleep(50 * time.Millisecond) // 等待所有刷新完成
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
expectedTotal := numGoroutines * eventsPerGoroutine
|
||||
if totalReceived != expectedTotal {
|
||||
t.Errorf("expected %d total events, got %d", expectedTotal, totalReceived)
|
||||
}
|
||||
}
|
||||
|
||||
// TestBatchBuffer_Close 测试关闭
|
||||
func TestBatchBuffer_Close(t *testing.T) {
|
||||
buffer := NewBatchBuffer(50, 10*time.Millisecond)
|
||||
ctx := context.Background()
|
||||
|
||||
err := buffer.Start(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Start failed: %v", err)
|
||||
}
|
||||
|
||||
// 添加一些事件
|
||||
for i := 0; i < 5; i++ {
|
||||
event := &model.AuditEvent{
|
||||
EventID: "batch-test-close",
|
||||
EventName: "TEST-CLOSE",
|
||||
}
|
||||
if err := buffer.Add(event); err != nil {
|
||||
t.Errorf("Add failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭缓冲区
|
||||
err = buffer.Close()
|
||||
if err != nil {
|
||||
t.Errorf("Close failed: %v", err)
|
||||
}
|
||||
|
||||
// 关闭后添加应该失败
|
||||
event := &model.AuditEvent{
|
||||
EventID: "batch-test-after-close",
|
||||
EventName: "TEST-AFTER-CLOSE",
|
||||
}
|
||||
if err := buffer.Add(event); err == nil {
|
||||
t.Errorf("Add after Close should fail")
|
||||
}
|
||||
}
|
||||
|
||||
// TestBatchBuffer_FlushNow 测试手动刷新
|
||||
func TestBatchBuffer_FlushNow(t *testing.T) {
|
||||
const batchSize = 100 // 足够大,不会自动触发
|
||||
|
||||
buffer := NewBatchBuffer(batchSize, 100*time.Millisecond) // 100ms才自动刷新
|
||||
ctx := context.Background()
|
||||
|
||||
err := buffer.Start(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Start failed: %v", err)
|
||||
}
|
||||
defer buffer.Close()
|
||||
|
||||
var receivedBatches [][]*model.AuditEvent
|
||||
var mu sync.Mutex
|
||||
|
||||
buffer.SetFlushHandler(func(events []*model.AuditEvent) error {
|
||||
mu.Lock()
|
||||
receivedBatches = append(receivedBatches, events)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
// 添加少量事件
|
||||
for i := 0; i < 3; i++ {
|
||||
event := &model.AuditEvent{
|
||||
EventID: "batch-test-manual",
|
||||
EventName: "TEST-MANUAL",
|
||||
}
|
||||
if err := buffer.Add(event); err != nil {
|
||||
t.Errorf("Add failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 立即手动刷新
|
||||
err = buffer.FlushNow()
|
||||
if err != nil {
|
||||
t.Errorf("FlushNow failed: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if len(receivedBatches) != 1 {
|
||||
t.Errorf("expected 1 batch after FlushNow, got %d", len(receivedBatches))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user