- 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)
270 lines
6.9 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|