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