package account_audit import ( "context" "errors" "testing" "time" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) type MockAccountOperationLogStore struct { mock.Mock } func (m *MockAccountOperationLogStore) Create(ctx context.Context, log *model.AccountOperationLog) error { args := m.Called(ctx, log) return args.Error(0) } func TestLogOperation_Success(t *testing.T) { mockStore := new(MockAccountOperationLogStore) service := NewService(mockStore) log := &model.AccountOperationLog{ OperatorID: 1, OperatorType: 2, OperatorName: "admin", OperationType: "create", OperationDesc: "创建账号: testuser", } mockStore.On("Create", mock.Anything, log).Return(nil) ctx := context.Background() service.LogOperation(ctx, log) time.Sleep(50 * time.Millisecond) mockStore.AssertCalled(t, "Create", mock.Anything, log) } func TestLogOperation_Failure(t *testing.T) { mockStore := new(MockAccountOperationLogStore) service := NewService(mockStore) log := &model.AccountOperationLog{ OperatorID: 1, OperatorType: 2, OperatorName: "admin", OperationType: "create", OperationDesc: "创建账号: testuser", } mockStore.On("Create", mock.Anything, log).Return(errors.New("database error")) ctx := context.Background() assert.NotPanics(t, func() { service.LogOperation(ctx, log) }) time.Sleep(50 * time.Millisecond) mockStore.AssertCalled(t, "Create", mock.Anything, log) } func TestLogOperation_NonBlocking(t *testing.T) { mockStore := new(MockAccountOperationLogStore) service := NewService(mockStore) log := &model.AccountOperationLog{ OperatorID: 1, OperatorType: 2, OperatorName: "admin", OperationType: "create", OperationDesc: "创建账号: testuser", } mockStore.On("Create", mock.Anything, log).Run(func(args mock.Arguments) { time.Sleep(100 * time.Millisecond) }).Return(nil) ctx := context.Background() start := time.Now() service.LogOperation(ctx, log) elapsed := time.Since(start) assert.Less(t, elapsed, 50*time.Millisecond, "LogOperation should return immediately") time.Sleep(150 * time.Millisecond) mockStore.AssertCalled(t, "Create", mock.Anything, log) } func TestNewService(t *testing.T) { mockStore := new(MockAccountOperationLogStore) service := NewService(mockStore) assert.NotNil(t, service) assert.Equal(t, mockStore, service.store) } func TestLogOperation_WithAllFields(t *testing.T) { mockStore := new(MockAccountOperationLogStore) service := NewService(mockStore) targetAccountID := uint(10) targetUsername := "targetuser" targetUserType := 3 requestID := "req-12345" ipAddress := "127.0.0.1" userAgent := "Mozilla/5.0" log := &model.AccountOperationLog{ OperatorID: 1, OperatorType: 2, OperatorName: "admin", TargetAccountID: &targetAccountID, TargetUsername: &targetUsername, TargetUserType: &targetUserType, OperationType: "update", OperationDesc: "更新账号: targetuser", BeforeData: model.JSONB{ "username": "oldname", }, AfterData: model.JSONB{ "username": "newname", }, RequestID: &requestID, IPAddress: &ipAddress, UserAgent: &userAgent, } mockStore.On("Create", mock.Anything, log).Return(nil) ctx := context.Background() service.LogOperation(ctx, log) time.Sleep(50 * time.Millisecond) mockStore.AssertCalled(t, "Create", mock.Anything, log) }