Files
lijiaoqiao/supply-api/internal/audit/service/audit_sampling_test.go
Your Name 8ac23bf7d4 test: improve coverage and fix sanitizer bug
- Fix MaskMap to properly handle []string sensitive fields
- Add missing slice handling in sanitizer
- Add comprehensive tests for GetMetrics and CreateEventsBatch
- Improve audit/handler coverage from 49.8% to 68.8%
- Fix test expectations to match actual sanitizer behavior
- All tests pass
2026-04-08 07:44:58 +08:00

328 lines
8.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"testing"
)
// TestP104_SamplingConfig 验证采样配置
func TestP104_SamplingConfig(t *testing.T) {
config := DefaultAuditSamplingConfig()
if config.SuccessSampleRate != 0.01 {
t.Errorf("expected 0.01 sample rate, got %f", config.SuccessSampleRate)
}
if !config.Enabled {
t.Error("sampling should be enabled by default")
}
if len(config.ForceRecordEventTypes) == 0 {
t.Error("force record event types should not be empty")
}
t.Log("P1-04: 采样配置验证通过")
}
// TestP104_FailureEventsAlwaysRecorded 验证失败事件总是被记录
func TestP104_FailureEventsAlwaysRecorded(t *testing.T) {
sampler := NewAuditSampler(DefaultAuditSamplingConfig())
// 各种失败事件都应该被记录
failureEvents := []string{
"token.authn.fail",
"token.authz.fail",
"account.create.fail",
"api.request.error",
}
for _, event := range failureEvents {
if !sampler.ShouldRecord(event, false) {
t.Errorf("failure event %s should always be recorded", event)
}
}
t.Log("P1-04: 失败事件总是记录验证通过")
}
// TestP104_SuccessEventsSampled 验证成功事件按采样率记录
func TestP104_SuccessEventsSampled(t *testing.T) {
config := &AuditSamplingConfig{
Enabled: true,
SuccessSampleRate: 0.01, // 1%
ForceRecordEventTypes: []string{},
}
sampler := NewAuditSampler(config)
// 运行多次采样测试
successEvent := "token.authn.success"
recorded := 0
total := 10000
for i := 0; i < total; i++ {
if sampler.ShouldRecord(successEvent, true) {
recorded++
}
}
// 采样率应该在合理范围内 (0.5% - 2%)
sampleRate := float64(recorded) / float64(total)
if sampleRate < 0.005 || sampleRate > 0.02 {
t.Errorf("sample rate %f outside expected range [0.005, 0.02]", sampleRate)
}
t.Logf("P1-04: 成功事件采样验证通过 (sample rate: %.2f%%)", sampleRate*100)
}
// TestP104_ForceRecordEvents 验证强制记录事件不受采样影响
func TestP104_ForceRecordEvents(t *testing.T) {
config := &AuditSamplingConfig{
Enabled: true,
SuccessSampleRate: 0.001, // 0.1% - 极低采样率
ForceRecordEventTypes: []string{
"token.revoked",
"account.", // 前缀匹配
"settlement.", // 前缀匹配
},
}
sampler := NewAuditSampler(config)
// 强制记录事件即使成功也应该100%记录
forceEvents := []string{
"token.revoked",
"account.deleted",
"settlement.completed",
}
for _, event := range forceEvents {
if !sampler.ShouldRecord(event, true) {
t.Errorf("force record event %s should always be recorded even if success", event)
}
}
t.Log("P1-04: 强制记录事件验证通过")
}
// TestP104_DisabledSampling 验证禁用采样时全部记录
func TestP104_DisabledSampling(t *testing.T) {
config := &AuditSamplingConfig{
Enabled: false,
SuccessSampleRate: 0.01,
ForceRecordEventTypes: []string{},
}
sampler := NewAuditSampler(config)
// 禁用采样后所有事件都应该被记录
if !sampler.ShouldRecord("token.authn.success", true) {
t.Error("when disabled, all events should be recorded")
}
if !sampler.ShouldRecord("token.authn.fail", false) {
t.Error("when disabled, all events should be recorded")
}
t.Log("P1-04: 禁用采样验证通过")
}
// TestP104_EventClassifier 验证事件分类器
func TestP104_EventClassifier(t *testing.T) {
classifier := NewAuditEventClassifier()
testCases := []struct {
eventName string
success bool
highPriority bool
}{
{"token.authn.fail", false, true},
{"token.authn.success", true, false},
{"account.created", true, true},
{"account.deleted", true, true},
{"settlement.completed", true, true},
{"payment.processed", true, true},
{"api.request.start", true, false},
}
for _, tc := range testCases {
result := classifier.IsHighPriorityEvent(tc.eventName, tc.success)
if result != tc.highPriority {
t.Errorf("event %s (success=%v): expected highPriority=%v, got %v",
tc.eventName, tc.success, tc.highPriority, result)
}
}
t.Log("P1-04: 事件分类器验证通过")
}
// TestP104_SamplingRecommendation 验证采样建议
func TestP104_SamplingRecommendation(t *testing.T) {
classifier := NewAuditEventClassifier()
testCases := []struct {
eventName string
expected string
}{
{"token.authn.success", "1% sampling recommended"},
{"token.authn.fail", "100% record required"},
{"account.created", "100% record required"},
{"settlement.completed", "100% record required"},
{"api.request.start", "1% sampling recommended"},
}
for _, tc := range testCases {
rec := classifier.GetSamplingRecommendation(tc.eventName)
if rec != tc.expected {
t.Errorf("event %s: expected '%s', got '%s'", tc.eventName, tc.expected, rec)
}
}
t.Log("P1-04: 采样建议验证通过")
}
// TestP104_Summary 测试总结
func TestP104_Summary(t *testing.T) {
t.Log("=== P1-04 审计事件采样策略测试总结 ===")
t.Log("问题: token.authn.success对每个请求记录高流量下日均8600万条")
t.Log("")
t.Log("修复方案:")
t.Log(" - 成功事件: 1%采样")
t.Log(" - 失败事件: 100%记录")
t.Log(" - 高优先级事件(admin.*, settlement.*, payment.*): 100%记录")
t.Log("")
t.Log("配置:")
t.Log(" - SuccessSampleRate: 0.01 (1%)")
t.Log(" - ForceRecordEventTypes: token.authn.fail, account.*, settlement.*, payment.*, admin.*")
}
// TestAuditSampler_RecordRate tests the RecordRate function
func TestAuditSampler_RecordRate(t *testing.T) {
config := &AuditSamplingConfig{
Enabled: true,
SuccessSampleRate: 0.05, // 5%
}
sampler := NewAuditSampler(config)
rate := sampler.RecordRate()
expected := 0.95 // 1.0 - 0.05
if rate != expected {
t.Errorf("expected rate %f, got %f", expected, rate)
}
}
// TestAuditSampler_GetConfig tests the GetConfig function
func TestAuditSampler_GetConfig(t *testing.T) {
config := &AuditSamplingConfig{
Enabled: true,
SuccessSampleRate: 0.01,
ForceRecordEventTypes: []string{"test.event"},
}
sampler := NewAuditSampler(config)
returnedConfig := sampler.GetConfig()
if returnedConfig == nil {
t.Fatal("expected non-nil config")
}
if returnedConfig.SuccessSampleRate != 0.01 {
t.Errorf("expected 0.01, got %f", returnedConfig.SuccessSampleRate)
}
if !returnedConfig.Enabled {
t.Error("expected Enabled to be true")
}
if len(returnedConfig.ForceRecordEventTypes) != 1 {
t.Errorf("expected 1 force record type, got %d", len(returnedConfig.ForceRecordEventTypes))
}
}
// TestAuditSampler_NewAuditSampler_NilConfig tests with nil config
func TestAuditSampler_NewAuditSampler_NilConfig(t *testing.T) {
sampler := NewAuditSampler(nil)
if sampler == nil {
t.Fatal("expected non-nil sampler")
}
config := sampler.GetConfig()
if config == nil {
t.Fatal("expected non-nil config")
}
if config.SuccessSampleRate != 0.01 {
t.Errorf("expected default rate 0.01, got %f", config.SuccessSampleRate)
}
}
// TestAuditSampler_PrefixMatching tests prefix matching for force record events
func TestAuditSampler_PrefixMatching(t *testing.T) {
config := &AuditSamplingConfig{
Enabled: true,
SuccessSampleRate: 0.001, // Very low rate
ForceRecordEventTypes: []string{"account.", "settlement."},
}
sampler := NewAuditSampler(config)
// These should always be recorded due to prefix match
events := []string{
"account.created",
"account.updated",
"account.deleted",
"settlement.created",
"settlement.paid",
}
for _, event := range events {
if !sampler.ShouldRecord(event, true) {
t.Errorf("event %s should be recorded due to prefix match", event)
}
}
}
// TestAuditEventClassifier_GetSamplingRecommendation_Default tests default recommendation
func TestAuditEventClassifier_GetSamplingRecommendation_Default(t *testing.T) {
classifier := NewAuditEventClassifier()
rec := classifier.GetSamplingRecommendation("unknown.event")
expected := "10% sampling recommended"
if rec != expected {
t.Errorf("expected '%s', got '%s'", expected, rec)
}
}
// TestAuditEventClassifier_HighPriorityPrefixes tests high priority prefix detection
func TestAuditEventClassifier_HighPriorityPrefixes(t *testing.T) {
classifier := NewAuditEventClassifier()
events := []string{
"token.authn.fail",
"token.authz.fail",
"token.revoked",
"admin.action",
"admin.config",
}
for _, event := range events {
if !classifier.IsHighPriorityEvent(event, true) {
t.Errorf("event %s should be high priority", event)
}
}
}
// TestAuditEventClassifier_LowPriorityPrefixes tests low priority prefix detection
func TestAuditEventClassifier_LowPriorityPrefixes(t *testing.T) {
classifier := NewAuditEventClassifier()
events := []string{
"token.authn.success",
"token.access",
"api.request",
}
for _, event := range events {
if classifier.IsHighPriorityEvent(event, true) {
t.Errorf("event %s should be low priority", event)
}
}
}