package service import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/wangjia/jiu/backend/config" "github.com/wangjia/jiu/backend/internal/model" "github.com/wangjia/jiu/backend/internal/util" "github.com/wangjia/jiu/backend/testutil" ) func TestAuthService_Login_Success(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "HOTEL001") testutil.CreateTestUser(db, shop.ID, "admin", "password123", "admin") svc := NewAuthService(db) pair, user, err := svc.Login("HOTEL001", "admin", "password123", DeviceInfo{Platform: "windows"}) require.NoError(t, err) require.NotNil(t, pair) require.NotNil(t, user) assert.NotEmpty(t, pair.AccessToken) assert.NotEmpty(t, pair.RefreshToken) assert.Equal(t, "admin", user.Username) } func TestAuthService_Login_AutoTrialOnFirstUse(t *testing.T) { db := testutil.SetupTestDB() priv, _, err := util.GenerateEd25519KeyPair() require.NoError(t, err) config.C.License.Ed25519PrivateKey = priv shop := testutil.CreateTestShop(db, "TRIAL001") testutil.CreateTestUser(db, shop.ID, "admin", "password123", "admin") // 前置:门店「未激活」——无任何授权行 var before int64 db.Model(&model.License{}).Where("shop_id = ?", shop.ID).Count(&before) require.EqualValues(t, 0, before) svc := NewAuthService(db) // 首次登录 → 自动签发 30 天 trial _, _, err = svc.Login("TRIAL001", "admin", "password123", DeviceInfo{Platform: "windows"}) require.NoError(t, err) var lic model.License require.NoError(t, db.Where("shop_id = ? AND is_active = 1", shop.ID).First(&lic).Error) assert.Equal(t, "trial", lic.Type) assert.True(t, lic.IsActive) require.NotNil(t, lic.ExpiresAt) days := time.Until(*lic.ExpiresAt).Hours() / 24 assert.InDelta(t, 30, days, 1, "试用期应约为 30 天") // 再次登录不重复发放 _, _, err = svc.Login("TRIAL001", "admin", "password123", DeviceInfo{Platform: "windows"}) require.NoError(t, err) var count int64 db.Model(&model.License{}).Where("shop_id = ?", shop.ID).Count(&count) assert.EqualValues(t, 1, count, "已有有效授权时不应再发放 trial") } func TestAuthService_Login_WrongPassword(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "HOTEL002") testutil.CreateTestUser(db, shop.ID, "admin", "password123", "admin") svc := NewAuthService(db) pair, user, err := svc.Login("HOTEL002", "admin", "wrongpassword", DeviceInfo{Platform: "windows"}) assert.Error(t, err) assert.Equal(t, ErrInvalidCredentials, err) assert.Nil(t, pair) assert.Nil(t, user) } func TestAuthService_Login_WrongHotel(t *testing.T) { db := testutil.SetupTestDB() testutil.CreateTestShop(db, "HOTEL003") svc := NewAuthService(db) pair, user, err := svc.Login("NONEXISTENT", "admin", "password123", DeviceInfo{Platform: "windows"}) assert.Error(t, err) assert.Equal(t, ErrInvalidCredentials, err) assert.Nil(t, pair) assert.Nil(t, user) } func TestAuthService_Login_DisabledUser(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "HOTEL004") user := testutil.CreateTestUser(db, shop.ID, "disabled", "password123", "operator") // 禁用用户 db.Model(user).Update("is_active", false) svc := NewAuthService(db) pair, u, err := svc.Login("HOTEL004", "disabled", "password123", DeviceInfo{Platform: "windows"}) assert.Error(t, err) assert.Equal(t, ErrUserInactive, err) assert.Nil(t, pair) assert.Nil(t, u) } func TestAuthService_Login_WrongUsername(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "HOTEL005") testutil.CreateTestUser(db, shop.ID, "admin", "password123", "admin") svc := NewAuthService(db) pair, user, err := svc.Login("HOTEL005", "nonexistent", "password123", DeviceInfo{Platform: "windows"}) assert.Error(t, err) assert.Equal(t, ErrInvalidCredentials, err) assert.Nil(t, pair) assert.Nil(t, user) } func TestAuthService_RefreshTokens(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "HOTEL006") testutil.CreateTestUser(db, shop.ID, "admin", "password123", "admin") svc := NewAuthService(db) pair, _, err := svc.Login("HOTEL006", "admin", "password123", DeviceInfo{Platform: "windows"}) require.NoError(t, err) require.NotNil(t, pair) // 用 refresh token 换新 token newPair, err := svc.RefreshTokens(pair.RefreshToken) require.NoError(t, err) require.NotNil(t, newPair) assert.NotEmpty(t, newPair.AccessToken) assert.NotEmpty(t, newPair.RefreshToken) } func TestAuthService_RefreshTokens_Invalid(t *testing.T) { db := testutil.SetupTestDB() testutil.InitConfig() svc := NewAuthService(db) newPair, err := svc.RefreshTokens("invalid.token.here") assert.Error(t, err) assert.Nil(t, newPair) } func TestHashPassword(t *testing.T) { hash, err := HashPassword("mypassword") require.NoError(t, err) assert.NotEmpty(t, hash) assert.NotEqual(t, "mypassword", hash) // 第二次哈希应不同(bcrypt 加 salt) hash2, err := HashPassword("mypassword") require.NoError(t, err) assert.NotEqual(t, hash, hash2) } func TestInitConfig(t *testing.T) { testutil.InitConfig() } func init() { testutil.InitConfig() }