package service import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/wangjia/jiu/backend/internal/model" "github.com/wangjia/jiu/backend/testutil" ) func TestLicenseService_Activate_Success(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "LIC001") // 创建许可证 expiry := time.Now().Add(30 * 24 * time.Hour) lic := &model.License{ ShopID: shop.ID, LicenseKey: "AAAAA-BBBBB-CCCCC-DDDDD", IsActive: true, ExpiresAt: &expiry, } require.NoError(t, db.Create(lic).Error) svc := NewLicenseService(db) result, err := svc.Activate("AAAAA-BBBBB-CCCCC-DDDDD", "device-001") require.NoError(t, err) require.NotNil(t, result) assert.Equal(t, "device-001", result.DeviceID) assert.NotNil(t, result.ActivatedAt) } func TestLicenseService_Activate_AlreadyBoundToDifferentDevice(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "LIC002") lic := &model.License{ ShopID: shop.ID, LicenseKey: "EEEEE-FFFFF-GGGGG-HHHHH", DeviceID: "existing-device", IsActive: true, } require.NoError(t, db.Create(lic).Error) svc := NewLicenseService(db) result, err := svc.Activate("EEEEE-FFFFF-GGGGG-HHHHH", "new-device") assert.Error(t, err) assert.Equal(t, ErrDeviceMismatch, err) assert.Nil(t, result) } func TestLicenseService_Activate_SameDevice(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "LIC003") lic := &model.License{ ShopID: shop.ID, LicenseKey: "IIIII-JJJJJ-KKKKK-LLLLL", DeviceID: "same-device", IsActive: true, } require.NoError(t, db.Create(lic).Error) svc := NewLicenseService(db) // 同一设备重新激活应该成功 result, err := svc.Activate("IIIII-JJJJJ-KKKKK-LLLLL", "same-device") require.NoError(t, err) require.NotNil(t, result) assert.Equal(t, "same-device", result.DeviceID) } func TestLicenseService_Activate_NotFound(t *testing.T) { db := testutil.SetupTestDB() svc := NewLicenseService(db) result, err := svc.Activate("NONEX-ISTEN-TTTTT-LICCC", "device-001") assert.Error(t, err) assert.Equal(t, ErrLicenseNotFound, err) assert.Nil(t, result) } func TestLicenseService_Activate_Inactive(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "LIC004") // 先创建激活的许可证,再禁用(避免 GORM 零值跳过问题) lic := &model.License{ ShopID: shop.ID, LicenseKey: "MMMMM-NNNNN-OOOOO-PPPPP", IsActive: true, } require.NoError(t, db.Create(lic).Error) // 禁用 require.NoError(t, db.Model(lic).Update("is_active", false).Error) svc := NewLicenseService(db) result, err := svc.Activate("MMMMM-NNNNN-OOOOO-PPPPP", "device-001") assert.Error(t, err) assert.Equal(t, ErrLicenseInactive, err) assert.Nil(t, result) } func TestLicenseService_Activate_Expired(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "LIC005") // 已过期 expiry := time.Now().Add(-24 * time.Hour) lic := &model.License{ ShopID: shop.ID, LicenseKey: "QQQQQ-RRRRR-SSSSS-TTTTT", IsActive: true, ExpiresAt: &expiry, } require.NoError(t, db.Create(lic).Error) svc := NewLicenseService(db) result, err := svc.Activate("QQQQQ-RRRRR-SSSSS-TTTTT", "device-001") assert.Error(t, err) assert.Equal(t, ErrLicenseExpired, err) assert.Nil(t, result) } func TestLicenseService_Verify_Success(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "LIC006") expiry := time.Now().Add(30 * 24 * time.Hour) lic := &model.License{ ShopID: shop.ID, LicenseKey: "UUUUU-VVVVV-WWWWW-XXXXX", DeviceID: "my-device", IsActive: true, ExpiresAt: &expiry, } require.NoError(t, db.Create(lic).Error) svc := NewLicenseService(db) result, err := svc.Verify(shop.ID, "my-device") require.NoError(t, err) require.NotNil(t, result) assert.Equal(t, "my-device", result.DeviceID) } func TestLicenseService_Verify_Expired(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "LIC007") // 已过期 expiry := time.Now().Add(-1 * time.Hour) lic := &model.License{ ShopID: shop.ID, LicenseKey: "YYYYY-ZZZZZ-AAAAA-BBBBB", DeviceID: "expired-device", IsActive: true, ExpiresAt: &expiry, } require.NoError(t, db.Create(lic).Error) svc := NewLicenseService(db) result, err := svc.Verify(shop.ID, "expired-device") assert.Error(t, err) assert.Equal(t, ErrLicenseExpired, err) assert.Nil(t, result) } func TestLicenseService_Verify_NotFound(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "LIC008") svc := NewLicenseService(db) result, err := svc.Verify(shop.ID, "nonexistent-device") assert.Error(t, err) assert.Equal(t, ErrLicenseNotFound, err) assert.Nil(t, result) } func TestLicenseService_Verify_NoExpiry(t *testing.T) { db := testutil.SetupTestDB() shop := testutil.CreateTestShop(db, "LIC009") // 永久许可证(无过期时间) lic := &model.License{ ShopID: shop.ID, LicenseKey: "CCCCC-DDDDD-EEEEE-FFFFF", DeviceID: "lifetime-device", IsActive: true, ExpiresAt: nil, } require.NoError(t, db.Create(lic).Error) svc := NewLicenseService(db) result, err := svc.Verify(shop.ID, "lifetime-device") require.NoError(t, err) require.NotNil(t, result) } func TestGenerateKey(t *testing.T) { testutil.InitConfig() expiry := time.Now().Add(30 * 24 * time.Hour) key := GenerateKey(1, "annual", &expiry) assert.NotEmpty(t, key) // 格式:XXXXX-XXXXX-XXXXX-XXXXX assert.Equal(t, 23, len(key)) // 4*5 + 3 dashes = 23 assert.Equal(t, '-', rune(key[5])) assert.Equal(t, '-', rune(key[11])) assert.Equal(t, '-', rune(key[17])) }