package service_test import ( "context" "testing" "time" "github.com/user-management-system/internal/domain" "github.com/user-management-system/internal/repository" "github.com/user-management-system/internal/service" gormsqlite "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" ) // ============================================================================= // Operation Log Service Tests // ============================================================================= func setupOperationLogTestEnv(t *testing.T) (*service.OperationLogService, *gorm.DB) { t.Helper() db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{ DriverName: "sqlite", DSN: "file:oplog_test?mode=memory&cache=shared", }), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) if err != nil { t.Fatalf("failed to connect database: %v", err) } if err := db.AutoMigrate(&domain.OperationLog{}); err != nil { t.Fatalf("failed to migrate: %v", err) } operationLogRepo := repository.NewOperationLogRepository(db) opLogSvc := service.NewOperationLogService(operationLogRepo) return opLogSvc, db } func TestOperationLogService_RecordOperation(t *testing.T) { svc, _ := setupOperationLogTestEnv(t) ctx := context.Background() t.Run("Record operation success", func(t *testing.T) { req := &service.RecordOperationRequest{ UserID: 1, OperationType: "create", OperationName: "创建用户", RequestMethod: "POST", RequestPath: "/api/users", RequestParams: `{"name":"test"}`, ResponseStatus: 200, IP: "192.168.1.1", UserAgent: "Mozilla/5.0", } err := svc.RecordOperation(ctx, req) if err != nil { t.Fatalf("RecordOperation failed: %v", err) } }) t.Run("Record operation without user ID", func(t *testing.T) { req := &service.RecordOperationRequest{ OperationType: "delete", OperationName: "删除用户", RequestMethod: "DELETE", RequestPath: "/api/users/1", ResponseStatus: 204, IP: "192.168.1.2", } err := svc.RecordOperation(ctx, req) if err != nil { t.Fatalf("RecordOperation failed: %v", err) } }) } func TestOperationLogService_GetOperationLogs(t *testing.T) { svc, _ := setupOperationLogTestEnv(t) ctx := context.Background() // Create test logs for i := 0; i < 5; i++ { req := &service.RecordOperationRequest{ UserID: 1, OperationType: "test", OperationName: "测试操作", RequestMethod: "GET", RequestPath: "/api/test", ResponseStatus: 200, IP: "192.168.1.1", } svc.RecordOperation(ctx, req) } t.Run("Get operation logs with pagination", func(t *testing.T) { req := &service.ListOperationLogRequest{ Page: 1, PageSize: 3, } logs, total, err := svc.GetOperationLogs(ctx, req) if err != nil { t.Fatalf("GetOperationLogs failed: %v", err) } if len(logs) > 3 { t.Errorf("Expected max 3 logs, got %d", len(logs)) } if total < 5 { t.Errorf("Expected total >= 5, got %d", total) } }) t.Run("Get operation logs by user ID", func(t *testing.T) { req := &service.ListOperationLogRequest{ UserID: 1, Page: 1, PageSize: 10, } logs, _, err := svc.GetOperationLogs(ctx, req) if err != nil { t.Fatalf("GetOperationLogs failed: %v", err) } if len(logs) < 5 { t.Errorf("Expected at least 5 logs, got %d", len(logs)) } }) t.Run("Get operation logs by method", func(t *testing.T) { req := &service.ListOperationLogRequest{ Method: "GET", Page: 1, PageSize: 10, } _, _, err := svc.GetOperationLogs(ctx, req) if err != nil { t.Fatalf("GetOperationLogs failed: %v", err) } }) t.Run("Get operation logs by keyword", func(t *testing.T) { req := &service.ListOperationLogRequest{ Keyword: "测试", Page: 1, PageSize: 10, } logs, _, err := svc.GetOperationLogs(ctx, req) if err != nil { t.Fatalf("GetOperationLogs failed: %v", err) } if len(logs) < 5 { t.Errorf("Expected at least 5 logs, got %d", len(logs)) } }) t.Run("Get operation logs by time range", func(t *testing.T) { req := &service.ListOperationLogRequest{ StartAt: time.Now().Add(-24 * time.Hour).Format(time.RFC3339), EndAt: time.Now().Add(24 * time.Hour).Format(time.RFC3339), Page: 1, PageSize: 10, } _, _, err := svc.GetOperationLogs(ctx, req) if err != nil { t.Fatalf("GetOperationLogs failed: %v", err) } }) t.Run("Get operation logs with default pagination", func(t *testing.T) { req := &service.ListOperationLogRequest{} _, _, err := svc.GetOperationLogs(ctx, req) if err != nil { t.Fatalf("GetOperationLogs failed: %v", err) } }) } func TestOperationLogService_GetOperationLogsCursor(t *testing.T) { svc, _ := setupOperationLogTestEnv(t) ctx := context.Background() // Create test logs for i := 0; i < 5; i++ { req := &service.RecordOperationRequest{ UserID: 1, OperationType: "cursor_test", OperationName: "游标测试", RequestMethod: "GET", RequestPath: "/api/cursor", ResponseStatus: 200, IP: "192.168.1.1", } svc.RecordOperation(ctx, req) } t.Run("Get operation logs with cursor", func(t *testing.T) { req := &service.ListOperationLogRequest{ Size: 3, } result, err := svc.GetOperationLogsCursor(ctx, req) if err != nil { t.Fatalf("GetOperationLogsCursor failed: %v", err) } if result.PageSize != 3 { t.Errorf("Expected page size 3, got %d", result.PageSize) } }) t.Run("Get operation logs with invalid cursor", func(t *testing.T) { req := &service.ListOperationLogRequest{ Cursor: "invalid-cursor", } _, err := svc.GetOperationLogsCursor(ctx, req) if err == nil { t.Error("Expected error for invalid cursor") } }) } func TestOperationLogService_GetMyOperationLogs(t *testing.T) { svc, _ := setupOperationLogTestEnv(t) ctx := context.Background() // Create test logs for i := 0; i < 3; i++ { req := &service.RecordOperationRequest{ UserID: 1, OperationType: "my_test", OperationName: "我的操作", RequestMethod: "GET", RequestPath: "/api/my", ResponseStatus: 200, IP: "192.168.1.1", } svc.RecordOperation(ctx, req) } t.Run("Get my operation logs", func(t *testing.T) { logs, total, err := svc.GetMyOperationLogs(ctx, 1, 1, 10) if err != nil { t.Fatalf("GetMyOperationLogs failed: %v", err) } if total < 3 { t.Errorf("Expected total >= 3, got %d", total) } _ = logs }) t.Run("Get my operation logs with default pagination", func(t *testing.T) { _, _, err := svc.GetMyOperationLogs(ctx, 1, 0, 0) if err != nil { t.Fatalf("GetMyOperationLogs failed: %v", err) } }) } func TestOperationLogService_CleanupOldLogs(t *testing.T) { svc, _ := setupOperationLogTestEnv(t) ctx := context.Background() t.Run("Cleanup old logs", func(t *testing.T) { err := svc.CleanupOldLogs(ctx, 30) if err != nil { t.Fatalf("CleanupOldLogs failed: %v", err) } }) }