package services import ( "fmt" "os" "strings" "testing" "time" "github.com/stretchr/testify/assert" "golang.org/x/crypto/bcrypt" "git.beifan.cn/trace-system/backend-go/config" "git.beifan.cn/trace-system/backend-go/database" "git.beifan.cn/trace-system/backend-go/logger" "git.beifan.cn/trace-system/backend-go/models" ) func TestMain(m *testing.M) { config.LoadConfig() if err := logger.InitializeLogger("test"); err != nil { fmt.Printf("日志系统初始化失败: %v\n", err) os.Exit(1) } defer logger.Sync() database.InitDB() database.AutoMigrate() database.DB.Unscoped().Where("1 = 1").Delete(&models.User{}) database.DB.Unscoped().Where("1 = 1").Delete(&models.Company{}) database.DB.Unscoped().Where("1 = 1").Delete(&models.Serial{}) database.DB.Unscoped().Where("1 = 1").Delete(&models.EmployeeSerial{}) exitCode := m.Run() database.DB.Unscoped().Where("1 = 1").Delete(&models.User{}) database.DB.Unscoped().Where("1 = 1").Delete(&models.Company{}) database.DB.Unscoped().Where("1 = 1").Delete(&models.Serial{}) database.DB.Unscoped().Where("1 = 1").Delete(&models.EmployeeSerial{}) os.Exit(exitCode) } func TestAuthService_ValidateUser_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "testuser", Password: string(password), Name: "测试用户", Email: "test@example.com", Role: "user", } database.DB.Create(&user) authService := AuthService{} result, err := authService.ValidateUser("testuser", "password123") assert.NoError(t, err) assert.NotNil(t, result) assert.Equal(t, "testuser", result.Username) database.DB.Unscoped().Delete(&user) } func TestAuthService_ValidateUser_WrongPassword(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "testuser2", Password: string(password), Name: "测试用户2", Email: "test2@example.com", Role: "user", } database.DB.Create(&user) authService := AuthService{} _, err := authService.ValidateUser("testuser2", "wrongpassword") assert.Error(t, err) database.DB.Unscoped().Delete(&user) } func TestAuthService_ValidateUser_UserNotFound(t *testing.T) { authService := AuthService{} _, err := authService.ValidateUser("nonexistent", "password") assert.Error(t, err) } func TestAuthService_GenerateToken_Success(t *testing.T) { user := &models.User{ ID: 1, Username: "testuser", Role: "user", } authService := AuthService{} token, err := authService.GenerateToken(user) assert.NoError(t, err) assert.NotEmpty(t, token) assert.NotEmpty(t, "Bearer "+token) } func TestAuthService_GetProfile_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "testuser3", Password: string(password), Name: "测试用户3", Email: "test3@example.com", Role: "user", } database.DB.Create(&user) authService := AuthService{} profile, err := authService.GetProfile(user.ID) assert.NoError(t, err) assert.NotNil(t, profile) assert.Equal(t, "testuser3", profile.Username) assert.Equal(t, "测试用户3", profile.Name) database.DB.Unscoped().Delete(&user) } func TestAuthService_ChangePassword_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("oldpassword"), bcrypt.DefaultCost) user = models.User{ Username: "testuser4", Password: string(password), Name: "测试用户4", Email: "test4@example.com", Role: "user", } database.DB.Create(&user) authService := AuthService{} err := authService.ChangePassword(user.ID, "oldpassword", "newpassword") assert.NoError(t, err) var updatedUser models.User database.DB.First(&updatedUser, user.ID) err = bcrypt.CompareHashAndPassword([]byte(updatedUser.Password), []byte("newpassword")) assert.NoError(t, err) database.DB.Unscoped().Delete(&user) } func TestAuthService_ChangePassword_WrongCurrentPassword(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("oldpassword"), bcrypt.DefaultCost) user = models.User{ Username: "testuser5", Password: string(password), Name: "测试用户5", Email: "test5@example.com", Role: "user", } database.DB.Create(&user) authService := AuthService{} err := authService.ChangePassword(user.ID, "wrongpassword", "newpassword") assert.Error(t, err) database.DB.Unscoped().Delete(&user) } func TestAuthService_UpdateProfile_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "testuser6", Password: string(password), Name: "测试用户6", Email: "test6@example.com", Role: "user", } database.DB.Create(&user) authService := AuthService{} profile, err := authService.UpdateProfile(user.ID, "新名称", "newemail@example.com") assert.NoError(t, err) assert.NotNil(t, profile) assert.Equal(t, "新名称", profile.Name) assert.Equal(t, "newemail@example.com", profile.Email) database.DB.Unscoped().Delete(&user) } func TestSerialsService_Generate_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "adminuser", Password: string(password), Name: "管理员", Email: "admin@example.com", Role: "admin", } database.DB.Create(&user) serialService := SerialsService{} serials, err := serialService.Generate("TestCompany", 5, 30, user.ID) assert.NoError(t, err) assert.Len(t, serials, 5) assert.Equal(t, "TestCompany", serials[0].CompanyName) assert.True(t, serials[0].IsActive) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "TestCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestSerialsService_Generate_WithPrefix(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "adminuser2", Password: string(password), Name: "管理员2", Email: "admin2@example.com", Role: "admin", } database.DB.Create(&user) serialService := SerialsService{} serials, err := serialService.Generate("TestCompany2", 3, 30, user.ID, "TEST") assert.NoError(t, err) assert.Len(t, serials, 3) assert.True(t, len(serials[0].SerialNumber) > 0) assert.Contains(t, serials[0].SerialNumber, "TEST") for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "TestCompany2").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestSerialsService_Query_QuerySuccess(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "adminuser3", Password: string(password), Name: "管理员3", Email: "admin3@example.com", Role: "admin", } database.DB.Create(&user) serialService := SerialsService{} serials, _ := serialService.Generate("TestCompany3", 1, 30, user.ID, "QR") serialNumber := strings.ToUpper(serials[0].SerialNumber) result, err := serialService.Query(serialNumber) assert.NoError(t, err) assert.NotNil(t, result) assert.Equal(t, serialNumber, strings.ToUpper(result.SerialNumber)) assert.True(t, result.IsActive) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "TestCompany3").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestSerialsService_Query_SerialNotFound(t *testing.T) { serialService := SerialsService{} _, err := serialService.Query("NONEXISTENT") assert.Error(t, err) } func TestSerialsService_FindAll_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "adminuser4", Password: string(password), Name: "管理员4", Email: "admin4@example.com", Role: "admin", } database.DB.Create(&user) serialService := SerialsService{} serials, _ := serialService.Generate("TestCompany4", 10, 30, user.ID, "LIST") result, total, totalPages, err := serialService.FindAll(1, 5, "") assert.NoError(t, err) assert.Len(t, result, 5) assert.GreaterOrEqual(t, total, 10) assert.Greater(t, totalPages, 0) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "TestCompany4").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestSerialsService_FindAll_WithSearch(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "adminuser5", Password: string(password), Name: "管理员5", Email: "admin5@example.com", Role: "admin", } database.DB.Create(&user) serialService := SerialsService{} serials, _ := serialService.Generate("SearchCompany", 5, 30, user.ID, "SEARCH") result, _, _, err := serialService.FindAll(1, 10, "SearchCompany") assert.NoError(t, err) assert.Greater(t, len(result), 0) assert.Equal(t, "SearchCompany", result[0].CompanyName) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "SearchCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestSerialsService_Revoke_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "adminuser6", Password: string(password), Name: "管理员6", Email: "admin6@example.com", Role: "admin", } database.DB.Create(&user) serialService := SerialsService{} serials, _ := serialService.Generate("RevokeCompany", 1, 30, user.ID, "REVOKE") serialNumber := serials[0].SerialNumber err := serialService.Revoke(serialNumber) assert.NoError(t, err) var revokedSerial models.Serial database.DB.Where("serial_number = ?", serialNumber).First(&revokedSerial) assert.False(t, revokedSerial.IsActive) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "RevokeCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestSerialsService_Update_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "adminuser7", Password: string(password), Name: "管理员7", Email: "admin7@example.com", Role: "admin", } database.DB.Create(&user) serialService := SerialsService{} serials, _ := serialService.Generate("UpdateCompany", 1, 30, user.ID, "UPDATE") serialNumber := serials[0].SerialNumber newValidUntil := time.Now().AddDate(0, 0, 60) isActive := false updateData := models.UpdateSerialDTO{ ValidUntil: &newValidUntil, IsActive: &isActive, } result, err := serialService.Update(serialNumber, updateData) assert.NoError(t, err) assert.NotNil(t, result) assert.False(t, result.IsActive) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "UpdateCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } // ==================== EmployeeSerialsService 测试 ==================== func TestEmployeeSerialsService_Generate_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin1", Password: string(password), Name: "员工管理员1", Email: "empadmin1@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, err := service.Generate("EmpTestCompany", "技术部", "张三", 5, user.ID) assert.NoError(t, err) assert.Len(t, serials, 5) for _, serial := range serials { assert.Equal(t, "EmpTestCompany", serial.CompanyName) assert.Equal(t, "技术部", serial.Department) assert.Equal(t, "张三", serial.EmployeeName) assert.True(t, serial.IsActive) assert.True(t, strings.HasPrefix(serial.SerialNumber, "EMP")) database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "EmpTestCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestEmployeeSerialsService_Generate_CreateNewCompany(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin2", Password: string(password), Name: "员工管理员2", Email: "empadmin2@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, err := service.Generate("NewEmpCompany", "市场部", "李四", 3, user.ID) assert.NoError(t, err) assert.Len(t, serials, 3) var company models.Company result := database.DB.Where("company_name = ?", "NewEmpCompany").First(&company) assert.NoError(t, result.Error) assert.Equal(t, "NewEmpCompany", company.CompanyName) assert.True(t, company.IsActive) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "NewEmpCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestEmployeeSerialsService_Query_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin3", Password: string(password), Name: "员工管理员3", Email: "empadmin3@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, _ := service.Generate("QueryEmpCompany", "财务部", "王五", 1, user.ID) serialNumber := serials[0].SerialNumber result, err := service.Query(serialNumber) assert.NoError(t, err) assert.NotNil(t, result) assert.Equal(t, strings.ToUpper(serialNumber), strings.ToUpper(result.SerialNumber)) assert.Equal(t, "QueryEmpCompany", result.CompanyName) assert.Equal(t, "财务部", result.Department) assert.Equal(t, "王五", result.EmployeeName) assert.True(t, result.IsActive) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "QueryEmpCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestEmployeeSerialsService_Query_NotFound(t *testing.T) { service := EmployeeSerialsService{} _, err := service.Query("NONEXISTENTEMP") assert.Error(t, err) assert.Contains(t, err.Error(), "序列号不存在") } func TestEmployeeSerialsService_FindAll_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin4", Password: string(password), Name: "员工管理员4", Email: "empadmin4@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, _ := service.Generate("ListEmpCompany", "人事部", "赵六", 10, user.ID) result, total, totalPages, err := service.FindAll(1, 5, "") assert.NoError(t, err) assert.Len(t, result, 5) assert.GreaterOrEqual(t, total, 10) assert.Greater(t, totalPages, 0) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "ListEmpCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestEmployeeSerialsService_FindAll_WithSearch(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin5", Password: string(password), Name: "员工管理员5", Email: "empadmin5@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, _ := service.Generate("SearchEmpCompany", "研发部", "钱七", 5, user.ID) result, _, _, err := service.FindAll(1, 10, "SearchEmpCompany") assert.NoError(t, err) assert.Greater(t, len(result), 0) assert.Equal(t, "SearchEmpCompany", result[0].CompanyName) result2, _, _, err2 := service.FindAll(1, 10, "研发部") assert.NoError(t, err2) assert.Greater(t, len(result2), 0) result3, _, _, err3 := service.FindAll(1, 10, "钱七") assert.NoError(t, err3) assert.Greater(t, len(result3), 0) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "SearchEmpCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestEmployeeSerialsService_Update_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin6", Password: string(password), Name: "员工管理员6", Email: "empadmin6@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, _ := service.Generate("UpdateEmpCompany", "运营部", "孙八", 1, user.ID) serialNumber := serials[0].SerialNumber isActive := false updateData := models.UpdateEmployeeSerialDTO{ CompanyName: "UpdatedEmpCompany", Department: "新部门", EmployeeName: "新名字", IsActive: &isActive, } result, err := service.Update(serialNumber, updateData) assert.NoError(t, err) assert.NotNil(t, result) assert.Equal(t, "UpdatedEmpCompany", result.CompanyName) assert.Equal(t, "新部门", result.Department) assert.Equal(t, "新名字", result.EmployeeName) assert.False(t, result.IsActive) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "UpdateEmpCompany").Delete(&models.Company{}) database.DB.Unscoped().Where("company_name = ?", "UpdatedEmpCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestEmployeeSerialsService_Update_NotFound(t *testing.T) { service := EmployeeSerialsService{} updateData := models.UpdateEmployeeSerialDTO{ CompanyName: "TestCompany", } _, err := service.Update("NONEXISTENT", updateData) assert.Error(t, err) assert.Contains(t, err.Error(), "序列号不存在") } func TestEmployeeSerialsService_Revoke_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin7", Password: string(password), Name: "员工管理员7", Email: "empadmin7@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, _ := service.Generate("RevokeEmpCompany", "测试部", "周九", 1, user.ID) serialNumber := serials[0].SerialNumber err := service.Revoke(serialNumber) assert.NoError(t, err) var revokedSerial models.EmployeeSerial database.DB.Where("serial_number = ?", serialNumber).First(&revokedSerial) assert.False(t, revokedSerial.IsActive) for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "RevokeEmpCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestEmployeeSerialsService_Revoke_NotFound(t *testing.T) { service := EmployeeSerialsService{} err := service.Revoke("NONEXISTENT") assert.Error(t, err) assert.Contains(t, err.Error(), "序列号不存在") } func TestEmployeeSerialsService_Revoke_AlreadyRevoked(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin8", Password: string(password), Name: "员工管理员8", Email: "empadmin8@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, _ := service.Generate("RevokeEmpCompany2", "行政部", "吴十", 1, user.ID) serialNumber := serials[0].SerialNumber service.Revoke(serialNumber) err := service.Revoke(serialNumber) assert.Error(t, err) assert.Contains(t, err.Error(), "已被吊销") for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "RevokeEmpCompany2").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestEmployeeSerialsService_GenerateQRCode_Success(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin9", Password: string(password), Name: "员工管理员9", Email: "empadmin9@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, _ := service.Generate("QREmpCompany", "产品部", "郑十一", 1, user.ID) serialNumber := serials[0].SerialNumber qrCodeBase64, queryUrl, err := service.GenerateQRCode(serialNumber, "", "localhost:3000", "http") assert.NoError(t, err) assert.NotEmpty(t, qrCodeBase64) assert.NotEmpty(t, queryUrl) assert.Contains(t, queryUrl, serialNumber) assert.Contains(t, queryUrl, "query.html") for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "QREmpCompany").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) } func TestEmployeeSerialsService_GenerateQRCode_NotFound(t *testing.T) { service := EmployeeSerialsService{} _, _, err := service.GenerateQRCode("NONEXISTENT", "", "localhost:3000", "http") assert.Error(t, err) assert.Contains(t, err.Error(), "序列号不存在") } func TestEmployeeSerialsService_GenerateQRCode_Inactive(t *testing.T) { var user models.User password, _ := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost) user = models.User{ Username: "empadmin10", Password: string(password), Name: "员工管理员10", Email: "empadmin10@example.com", Role: "admin", } database.DB.Create(&user) service := EmployeeSerialsService{} serials, _ := service.Generate("QREmpCompany2", "设计部", "王十二", 1, user.ID) serialNumber := serials[0].SerialNumber service.Revoke(serialNumber) _, _, err := service.GenerateQRCode(serialNumber, "", "localhost:3000", "http") assert.Error(t, err) assert.Contains(t, err.Error(), "已被禁用") for _, serial := range serials { database.DB.Unscoped().Delete(&serial) } database.DB.Unscoped().Where("company_name = ?", "QREmpCompany2").Delete(&models.Company{}) database.DB.Unscoped().Delete(&user) }