- 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)
502 lines
13 KiB
Go
502 lines
13 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"
|
|
)
|
|
|
|
// =============================================================================
|
|
// Device Service Tests
|
|
// =============================================================================
|
|
|
|
func setupDeviceTestEnv(t *testing.T) (*service.DeviceService, *gorm.DB) {
|
|
t.Helper()
|
|
|
|
db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{
|
|
DriverName: "sqlite",
|
|
DSN: "file:device_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.User{}, &domain.Device{}); err != nil {
|
|
t.Fatalf("failed to migrate: %v", err)
|
|
}
|
|
|
|
// Create test user
|
|
db.Create(&domain.User{Username: "deviceuser", Status: domain.UserStatusActive})
|
|
|
|
deviceRepo := repository.NewDeviceRepository(db)
|
|
userRepo := repository.NewUserRepository(db)
|
|
deviceSvc := service.NewDeviceService(deviceRepo, userRepo)
|
|
|
|
return deviceSvc, db
|
|
}
|
|
|
|
func TestDeviceService_CreateDevice(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
t.Run("Create device success", func(t *testing.T) {
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "device001",
|
|
DeviceName: "Test Device",
|
|
DeviceType: int(domain.DeviceTypeDesktop),
|
|
DeviceOS: "Windows",
|
|
DeviceBrowser: "Chrome",
|
|
IP: "192.168.1.1",
|
|
Location: "Beijing",
|
|
}
|
|
device, err := svc.CreateDevice(ctx, 1, req)
|
|
if err != nil {
|
|
t.Fatalf("CreateDevice failed: %v", err)
|
|
}
|
|
if device.DeviceID != "device001" {
|
|
t.Errorf("Expected device ID 'device001', got %s", device.DeviceID)
|
|
}
|
|
})
|
|
|
|
t.Run("Create device for non-existent user", func(t *testing.T) {
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "device002",
|
|
}
|
|
_, err := svc.CreateDevice(ctx, 9999, req)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent user")
|
|
}
|
|
})
|
|
|
|
t.Run("Create duplicate device updates last active time", func(t *testing.T) {
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "device003",
|
|
DeviceName: "First",
|
|
}
|
|
svc.CreateDevice(ctx, 1, req)
|
|
|
|
// Create again with same device ID
|
|
req2 := &service.CreateDeviceRequest{
|
|
DeviceID: "device003",
|
|
DeviceName: "Second",
|
|
}
|
|
device, err := svc.CreateDevice(ctx, 1, req2)
|
|
if err != nil {
|
|
t.Fatalf("CreateDevice failed: %v", err)
|
|
}
|
|
// Should return existing device with first name (not updated)
|
|
if device.DeviceName != "First" {
|
|
t.Logf("Device name: %s", device.DeviceName)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_UpdateDevice(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create device first
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "update_device",
|
|
DeviceName: "Original",
|
|
}
|
|
device, _ := svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Update device success", func(t *testing.T) {
|
|
updateReq := &service.UpdateDeviceRequest{
|
|
DeviceName: "Updated",
|
|
DeviceOS: "macOS",
|
|
}
|
|
updated, err := svc.UpdateDevice(ctx, device.ID, updateReq)
|
|
if err != nil {
|
|
t.Fatalf("UpdateDevice failed: %v", err)
|
|
}
|
|
if updated.DeviceName != "Updated" {
|
|
t.Errorf("Expected name 'Updated', got %s", updated.DeviceName)
|
|
}
|
|
})
|
|
|
|
t.Run("Update non-existent device", func(t *testing.T) {
|
|
updateReq := &service.UpdateDeviceRequest{
|
|
DeviceName: "NotExist",
|
|
}
|
|
_, err := svc.UpdateDevice(ctx, 9999, updateReq)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent device")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_GetDevice(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "get_device",
|
|
}
|
|
device, _ := svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Get device success", func(t *testing.T) {
|
|
got, err := svc.GetDevice(ctx, device.ID)
|
|
if err != nil {
|
|
t.Fatalf("GetDevice failed: %v", err)
|
|
}
|
|
if got.DeviceID != "get_device" {
|
|
t.Errorf("Expected device ID 'get_device', got %s", got.DeviceID)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_GetUserDevices(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create multiple devices
|
|
for i := 0; i < 3; i++ {
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: string(rune('a' + i)),
|
|
}
|
|
svc.CreateDevice(ctx, 1, req)
|
|
}
|
|
|
|
t.Run("Get user devices", func(t *testing.T) {
|
|
devices, total, err := svc.GetUserDevices(ctx, 1, 1, 10)
|
|
if err != nil {
|
|
t.Fatalf("GetUserDevices failed: %v", err)
|
|
}
|
|
if total < 3 {
|
|
t.Errorf("Expected total >= 3, got %d", total)
|
|
}
|
|
if len(devices) < 3 {
|
|
t.Logf("Got %d devices", len(devices))
|
|
}
|
|
})
|
|
|
|
t.Run("Get user devices with default pagination", func(t *testing.T) {
|
|
_, _, err := svc.GetUserDevices(ctx, 1, 0, 0)
|
|
if err != nil {
|
|
t.Fatalf("GetUserDevices failed: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_TrustDevice(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "trust_device",
|
|
}
|
|
device, _ := svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Trust device success", func(t *testing.T) {
|
|
err := svc.TrustDevice(ctx, device.ID, 24*time.Hour)
|
|
if err != nil {
|
|
t.Fatalf("TrustDevice failed: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Trust non-existent device", func(t *testing.T) {
|
|
err := svc.TrustDevice(ctx, 9999, time.Hour)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent device")
|
|
}
|
|
})
|
|
|
|
t.Run("Untrust device", func(t *testing.T) {
|
|
err := svc.UntrustDevice(ctx, device.ID)
|
|
if err != nil {
|
|
t.Fatalf("UntrustDevice failed: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_TrustDeviceByDeviceID(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "trust_by_id",
|
|
}
|
|
svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Trust device by device ID", func(t *testing.T) {
|
|
err := svc.TrustDeviceByDeviceID(ctx, 1, "trust_by_id", time.Hour)
|
|
if err != nil {
|
|
t.Fatalf("TrustDeviceByDeviceID failed: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Trust non-existent device by device ID", func(t *testing.T) {
|
|
err := svc.TrustDeviceByDeviceID(ctx, 1, "not_exist", time.Hour)
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent device")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_GetActiveDevices(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "active_device",
|
|
}
|
|
svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Get active devices", func(t *testing.T) {
|
|
devices, _, err := svc.GetActiveDevices(ctx, 1, 10)
|
|
if err != nil {
|
|
t.Fatalf("GetActiveDevices failed: %v", err)
|
|
}
|
|
if len(devices) == 0 {
|
|
t.Log("No active devices")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_GetAllDevices(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "all_device",
|
|
}
|
|
svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Get all devices", func(t *testing.T) {
|
|
req := &service.GetAllDevicesRequest{
|
|
Page: 1,
|
|
PageSize: 10,
|
|
}
|
|
devices, total, err := svc.GetAllDevices(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("GetAllDevices failed: %v", err)
|
|
}
|
|
if total < 1 {
|
|
t.Error("Expected at least 1 device")
|
|
}
|
|
_ = devices
|
|
})
|
|
|
|
t.Run("Get all devices with status filter", func(t *testing.T) {
|
|
status := int(domain.DeviceStatusActive)
|
|
req := &service.GetAllDevicesRequest{
|
|
Page: 1,
|
|
PageSize: 10,
|
|
Status: &status,
|
|
}
|
|
_, _, err := svc.GetAllDevices(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("GetAllDevices failed: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Get all devices with trusted filter", func(t *testing.T) {
|
|
isTrusted := true
|
|
req := &service.GetAllDevicesRequest{
|
|
Page: 1,
|
|
PageSize: 10,
|
|
IsTrusted: &isTrusted,
|
|
}
|
|
_, _, err := svc.GetAllDevices(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("GetAllDevices failed: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_DeleteDevice(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "delete_device",
|
|
}
|
|
device, _ := svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Delete device", func(t *testing.T) {
|
|
err := svc.DeleteDevice(ctx, device.ID)
|
|
if err != nil {
|
|
t.Fatalf("DeleteDevice failed: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_UpdateDeviceStatus(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "status_device",
|
|
}
|
|
device, _ := svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Update device status", func(t *testing.T) {
|
|
err := svc.UpdateDeviceStatus(ctx, device.ID, domain.DeviceStatusInactive)
|
|
if err != nil {
|
|
t.Fatalf("UpdateDeviceStatus failed: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_GetTrustedDevices(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "trusted_device",
|
|
}
|
|
device, _ := svc.CreateDevice(ctx, 1, req)
|
|
svc.TrustDevice(ctx, device.ID, time.Hour)
|
|
|
|
t.Run("Get trusted devices", func(t *testing.T) {
|
|
devices, err := svc.GetTrustedDevices(ctx, 1)
|
|
if err != nil {
|
|
t.Fatalf("GetTrustedDevices failed: %v", err)
|
|
}
|
|
if len(devices) == 0 {
|
|
t.Log("No trusted devices")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_UpdateLastActiveTime(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "last_active_device",
|
|
}
|
|
device, _ := svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Update last active time", func(t *testing.T) {
|
|
err := svc.UpdateLastActiveTime(ctx, device.ID)
|
|
if err != nil {
|
|
t.Fatalf("UpdateLastActiveTime failed: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("Update last active time for non-existent device", func(t *testing.T) {
|
|
err := svc.UpdateLastActiveTime(ctx, 9999)
|
|
// May not return error depending on implementation
|
|
_ = err
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_LogoutAllOtherDevices(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create multiple devices
|
|
var firstDeviceID int64
|
|
for i := 0; i < 3; i++ {
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "logout_device_" + string(rune('a'+i)),
|
|
}
|
|
device, _ := svc.CreateDevice(ctx, 1, req)
|
|
if i == 0 {
|
|
firstDeviceID = device.ID
|
|
}
|
|
}
|
|
|
|
t.Run("Logout all other devices", func(t *testing.T) {
|
|
err := svc.LogoutAllOtherDevices(ctx, 1, firstDeviceID)
|
|
// May not return error
|
|
_ = err
|
|
t.Logf("LogoutAllOtherDevices returned: %v", err)
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_GetAllDevicesCursor(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
// Create multiple devices
|
|
for i := 0; i < 5; i++ {
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "cursor_device_" + string(rune('a'+i)),
|
|
}
|
|
svc.CreateDevice(ctx, 1, req)
|
|
}
|
|
|
|
t.Run("Get all devices with cursor", func(t *testing.T) {
|
|
req := &service.GetAllDevicesRequest{
|
|
Cursor: "",
|
|
Size: 3,
|
|
}
|
|
resp, err := svc.GetAllDevicesCursor(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("GetAllDevicesCursor failed: %v", err)
|
|
}
|
|
if resp == nil {
|
|
t.Error("Expected response")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestDeviceService_GetDeviceByDeviceID(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "get_by_device_id",
|
|
}
|
|
svc.CreateDevice(ctx, 1, req)
|
|
|
|
t.Run("Get device by device ID", func(t *testing.T) {
|
|
device, err := svc.GetDeviceByDeviceID(ctx, 1, "get_by_device_id")
|
|
if err != nil {
|
|
t.Fatalf("GetDeviceByDeviceID failed: %v", err)
|
|
}
|
|
if device.DeviceID != "get_by_device_id" {
|
|
t.Errorf("Expected device ID 'get_by_device_id', got %s", device.DeviceID)
|
|
}
|
|
})
|
|
|
|
t.Run("Get non-existent device by device ID", func(t *testing.T) {
|
|
_, err := svc.GetDeviceByDeviceID(ctx, 1, "not_exist")
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent device")
|
|
}
|
|
})
|
|
}
|
|
|
|
// =============================================================================
|
|
// Get Active Devices Extended Tests
|
|
// =============================================================================
|
|
|
|
func TestDeviceService_GetActiveDevices_Extended(t *testing.T) {
|
|
svc, _ := setupDeviceTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
t.Run("Get active devices with pagination", func(t *testing.T) {
|
|
// Create some devices
|
|
for i := 0; i < 5; i++ {
|
|
req := &service.CreateDeviceRequest{
|
|
DeviceID: "active_device_paged_" + string(rune('0'+i)),
|
|
DeviceName: "Device " + string(rune('0'+i)),
|
|
}
|
|
svc.CreateDevice(ctx, 1, req)
|
|
}
|
|
|
|
devices, total, err := svc.GetActiveDevices(ctx, 1, 3)
|
|
if err != nil {
|
|
t.Fatalf("GetActiveDevices failed: %v", err)
|
|
}
|
|
if len(devices) > 3 {
|
|
t.Errorf("Expected at most 3 devices, got %d", len(devices))
|
|
}
|
|
_ = total
|
|
})
|
|
}
|