Files
user-system/internal/service/stats_operation_test.go
long-agent 582ad7a069 test: add comprehensive test coverage and improve code quality
- Add new test files for auth, service, and handler modules
- Improve test organization and coverage
- Refactor code for better maintainability
- Add captcha, settings, stats, and theme handler tests
- Add auth module tests (CAS, OAuth, password, SSO, state)
- Add service layer tests for auth, export, permissions, roles
- All Go tests pass (exit code 0)
- All frontend tests pass (325 tests in 59 files)
2026-04-17 20:43:50 +08:00

270 lines
6.9 KiB
Go

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)
}
})
}