package enterprise_device import ( "context" "fmt" "testing" "time" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/middleware" "github.com/break/junhong_cmp_fiber/tests/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" ) func uniqueServiceTestPrefix() string { return fmt.Sprintf("SVC%d", time.Now().UnixNano()%1000000000) } func createTestContext(userID uint, userType int, shopID uint, enterpriseID uint) context.Context { ctx := context.Background() return middleware.SetUserContext(ctx, &middleware.UserContextInfo{ UserID: userID, UserType: userType, ShopID: shopID, EnterpriseID: enterpriseID, }) } type testEnv struct { service *Service enterprise *model.Enterprise shop *model.Shop devices []*model.Device cards []*model.IotCard bindings []*model.DeviceSimBinding carrier *model.Carrier } func setupTestEnv(t *testing.T, prefix string) *testEnv { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) enterpriseStore := postgres.NewEnterpriseStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb) enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb) enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb) logger := zap.NewNop() svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger) shop := &model.Shop{ ShopName: prefix + "_测试店铺", ShopCode: prefix, Level: 1, Status: 1, } require.NoError(t, tx.Create(shop).Error) enterprise := &model.Enterprise{ EnterpriseName: prefix + "_测试企业", EnterpriseCode: prefix, OwnerShopID: &shop.ID, Status: 1, } require.NoError(t, tx.Create(enterprise).Error) carrier := &model.Carrier{ CarrierName: "测试运营商", CarrierType: "CMCC", Status: 1, } require.NoError(t, tx.Create(carrier).Error) devices := make([]*model.Device, 3) for i := 0; i < 3; i++ { devices[i] = &model.Device{ DeviceNo: fmt.Sprintf("%s_D%03d", prefix, i+1), DeviceName: fmt.Sprintf("测试设备%d", i+1), Status: 2, ShopID: &shop.ID, } require.NoError(t, tx.Create(devices[i]).Error) } cards := make([]*model.IotCard, 4) for i := 0; i < 4; i++ { cards[i] = &model.IotCard{ ICCID: fmt.Sprintf("%s%04d", prefix, i+1), CarrierID: carrier.ID, Status: 2, ShopID: &shop.ID, } require.NoError(t, tx.Create(cards[i]).Error) } now := time.Now() bindings := []*model.DeviceSimBinding{ {DeviceID: devices[0].ID, IotCardID: cards[0].ID, SlotPosition: 1, BindStatus: 1, BindTime: &now}, {DeviceID: devices[0].ID, IotCardID: cards[1].ID, SlotPosition: 2, BindStatus: 1, BindTime: &now}, {DeviceID: devices[1].ID, IotCardID: cards[2].ID, SlotPosition: 1, BindStatus: 1, BindTime: &now}, } for _, b := range bindings { require.NoError(t, tx.Create(b).Error) } return &testEnv{ service: svc, enterprise: enterprise, shop: shop, devices: devices, cards: cards, bindings: bindings, carrier: carrier, } } func TestService_AllocateDevices(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) tests := []struct { name string ctx context.Context req *dto.AllocateDevicesReq wantSuccess int wantFail int wantErr bool }{ { name: "平台用户成功授权设备", ctx: createTestContext(1, constants.UserTypePlatform, 0, 0), req: &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, Remark: "测试授权", }, wantSuccess: 1, wantFail: 0, wantErr: false, }, { name: "代理用户成功授权自己店铺的设备", ctx: createTestContext(2, constants.UserTypeAgent, env.shop.ID, 0), req: &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[1].DeviceNo}, }, wantSuccess: 1, wantFail: 0, wantErr: false, }, { name: "设备不存在时记录失败", ctx: createTestContext(1, constants.UserTypePlatform, 0, 0), req: &dto.AllocateDevicesReq{ DeviceNos: []string{"NOT_EXIST_DEVICE"}, }, wantSuccess: 0, wantFail: 1, wantErr: false, }, { name: "未授权用户返回错误", ctx: context.Background(), req: &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[2].DeviceNo}, }, wantSuccess: 0, wantFail: 0, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, err := env.service.AllocateDevices(tt.ctx, env.enterprise.ID, tt.req) if tt.wantErr { require.Error(t, err) return } require.NoError(t, err) assert.Equal(t, tt.wantSuccess, resp.SuccessCount) assert.Equal(t, tt.wantFail, resp.FailCount) }) } } func TestService_AllocateDevices_DeviceStatusValidation(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) prefix := uniqueServiceTestPrefix() enterpriseStore := postgres.NewEnterpriseStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb) enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb) enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb) logger := zap.NewNop() svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger) enterprise := &model.Enterprise{ EnterpriseName: prefix + "_测试企业", EnterpriseCode: prefix, Status: 1, } require.NoError(t, tx.Create(enterprise).Error) inStockDevice := &model.Device{ DeviceNo: prefix + "_INSTOCK", DeviceName: "在库设备", Status: 1, } require.NoError(t, tx.Create(inStockDevice).Error) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) t.Run("设备状态不是已分销时失败", func(t *testing.T) { req := &dto.AllocateDevicesReq{ DeviceNos: []string{inStockDevice.DeviceNo}, } resp, err := svc.AllocateDevices(ctx, enterprise.ID, req) require.NoError(t, err) assert.Equal(t, 0, resp.SuccessCount) assert.Equal(t, 1, resp.FailCount) assert.Contains(t, resp.FailedItems[0].Reason, "状态不正确") }) } func TestService_AllocateDevices_AgentPermission(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) prefix := uniqueServiceTestPrefix() enterpriseStore := postgres.NewEnterpriseStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb) enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb) enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb) logger := zap.NewNop() svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger) shop1 := &model.Shop{ShopName: prefix + "_店铺1", ShopCode: prefix + "1", Level: 1, Status: 1} require.NoError(t, tx.Create(shop1).Error) shop2 := &model.Shop{ShopName: prefix + "_店铺2", ShopCode: prefix + "2", Level: 1, Status: 1} require.NoError(t, tx.Create(shop2).Error) enterprise := &model.Enterprise{ EnterpriseName: prefix + "_测试企业", EnterpriseCode: prefix, Status: 1, } require.NoError(t, tx.Create(enterprise).Error) device := &model.Device{ DeviceNo: prefix + "_D001", DeviceName: "测试设备", Status: 2, ShopID: &shop1.ID, } require.NoError(t, tx.Create(device).Error) t.Run("代理用户无法授权其他店铺的设备", func(t *testing.T) { ctx := createTestContext(1, constants.UserTypeAgent, shop2.ID, 0) req := &dto.AllocateDevicesReq{ DeviceNos: []string{device.DeviceNo}, } resp, err := svc.AllocateDevices(ctx, enterprise.ID, req) require.NoError(t, err) assert.Equal(t, 0, resp.SuccessCount) assert.Equal(t, 1, resp.FailCount) assert.Contains(t, resp.FailedItems[0].Reason, "无权操作") }) } func TestService_AllocateDevices_DuplicateAuthorization(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) req := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } resp, err := env.service.AllocateDevices(ctx, env.enterprise.ID, req) require.NoError(t, err) assert.Equal(t, 1, resp.SuccessCount) t.Run("重复授权同一设备时失败", func(t *testing.T) { resp2, err := env.service.AllocateDevices(ctx, env.enterprise.ID, req) require.NoError(t, err) assert.Equal(t, 0, resp2.SuccessCount) assert.Equal(t, 1, resp2.FailCount) assert.Contains(t, resp2.FailedItems[0].Reason, "已授权") }) } func TestService_AllocateDevices_CascadeCardAuthorization(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) t.Run("授权设备时级联授权绑定的卡", func(t *testing.T) { req := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } resp, err := env.service.AllocateDevices(ctx, env.enterprise.ID, req) require.NoError(t, err) assert.Equal(t, 1, resp.SuccessCount) assert.Len(t, resp.AuthorizedDevices, 1) assert.Equal(t, 2, resp.AuthorizedDevices[0].CardCount) }) } func TestService_RecallDevices(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo, env.devices[1].DeviceNo}, } _, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq) require.NoError(t, err) tests := []struct { name string req *dto.RecallDevicesReq wantSuccess int wantFail int wantErr bool }{ { name: "成功撤销授权", req: &dto.RecallDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, }, wantSuccess: 1, wantFail: 0, wantErr: false, }, { name: "设备不存在时失败", req: &dto.RecallDevicesReq{ DeviceNos: []string{"NOT_EXIST"}, }, wantSuccess: 0, wantFail: 1, wantErr: false, }, { name: "设备未授权时失败", req: &dto.RecallDevicesReq{ DeviceNos: []string{env.devices[2].DeviceNo}, }, wantSuccess: 0, wantFail: 1, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, err := env.service.RecallDevices(ctx, env.enterprise.ID, tt.req) if tt.wantErr { require.Error(t, err) return } require.NoError(t, err) assert.Equal(t, tt.wantSuccess, resp.SuccessCount) assert.Equal(t, tt.wantFail, resp.FailCount) }) } } func TestService_RecallDevices_Unauthorized(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) t.Run("未授权用户返回错误", func(t *testing.T) { req := &dto.RecallDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } _, err := env.service.RecallDevices(context.Background(), env.enterprise.ID, req) require.Error(t, err) }) } func TestService_ListDevices(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo, env.devices[1].DeviceNo}, } _, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq) require.NoError(t, err) tests := []struct { name string req *dto.EnterpriseDeviceListReq wantTotal int64 wantLen int }{ { name: "获取所有授权设备", req: &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10}, wantTotal: 2, wantLen: 2, }, { name: "分页查询", req: &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 1}, wantTotal: 2, wantLen: 1, }, { name: "按设备号搜索", req: &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10, DeviceNo: env.devices[0].DeviceNo}, wantTotal: 2, wantLen: 1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, err := env.service.ListDevices(ctx, env.enterprise.ID, tt.req) require.NoError(t, err) assert.Equal(t, tt.wantTotal, resp.Total) assert.Len(t, resp.List, tt.wantLen) }) } } func TestService_ListDevices_EnterpriseNotFound(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) t.Run("企业不存在返回错误", func(t *testing.T) { req := &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10} _, err := env.service.ListDevices(ctx, 99999, req) require.Error(t, err) }) } func TestService_ListDevicesForEnterprise(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } _, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq) require.NoError(t, err) t.Run("企业用户获取自己的授权设备", func(t *testing.T) { enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID) req := &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10} resp, err := env.service.ListDevicesForEnterprise(enterpriseCtx, req) require.NoError(t, err) assert.Equal(t, int64(1), resp.Total) }) t.Run("未设置企业ID返回错误", func(t *testing.T) { req := &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10} _, err := env.service.ListDevicesForEnterprise(context.Background(), req) require.Error(t, err) }) } func TestService_GetDeviceDetail(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } _, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq) require.NoError(t, err) enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID) t.Run("成功获取设备详情", func(t *testing.T) { resp, err := env.service.GetDeviceDetail(enterpriseCtx, env.devices[0].ID) require.NoError(t, err) assert.Equal(t, env.devices[0].ID, resp.Device.DeviceID) assert.Equal(t, env.devices[0].DeviceNo, resp.Device.DeviceNo) assert.Len(t, resp.Cards, 2) }) t.Run("设备未授权时返回错误", func(t *testing.T) { _, err := env.service.GetDeviceDetail(enterpriseCtx, env.devices[1].ID) require.Error(t, err) }) t.Run("未设置企业ID返回错误", func(t *testing.T) { _, err := env.service.GetDeviceDetail(context.Background(), env.devices[0].ID) require.Error(t, err) }) } func TestService_SuspendCard(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } _, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq) require.NoError(t, err) enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID) t.Run("成功停机", func(t *testing.T) { req := &dto.DeviceCardOperationReq{Reason: "测试停机"} resp, err := env.service.SuspendCard(enterpriseCtx, env.devices[0].ID, env.cards[0].ID, req) require.NoError(t, err) assert.True(t, resp.Success) }) t.Run("卡不属于设备时返回错误", func(t *testing.T) { req := &dto.DeviceCardOperationReq{Reason: "测试停机"} _, err := env.service.SuspendCard(enterpriseCtx, env.devices[0].ID, env.cards[3].ID, req) require.Error(t, err) }) t.Run("设备未授权时返回错误", func(t *testing.T) { req := &dto.DeviceCardOperationReq{Reason: "测试停机"} _, err := env.service.SuspendCard(enterpriseCtx, env.devices[1].ID, env.cards[2].ID, req) require.Error(t, err) }) t.Run("未设置企业ID返回错误", func(t *testing.T) { req := &dto.DeviceCardOperationReq{Reason: "测试停机"} _, err := env.service.SuspendCard(context.Background(), env.devices[0].ID, env.cards[0].ID, req) require.Error(t, err) }) } func TestService_ResumeCard(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } _, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq) require.NoError(t, err) enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID) t.Run("成功复机", func(t *testing.T) { req := &dto.DeviceCardOperationReq{Reason: "测试复机"} resp, err := env.service.ResumeCard(enterpriseCtx, env.devices[0].ID, env.cards[0].ID, req) require.NoError(t, err) assert.True(t, resp.Success) }) t.Run("卡不属于设备时返回错误", func(t *testing.T) { req := &dto.DeviceCardOperationReq{Reason: "测试复机"} _, err := env.service.ResumeCard(enterpriseCtx, env.devices[0].ID, env.cards[3].ID, req) require.Error(t, err) }) t.Run("设备未授权时返回错误", func(t *testing.T) { req := &dto.DeviceCardOperationReq{Reason: "测试复机"} _, err := env.service.ResumeCard(enterpriseCtx, env.devices[1].ID, env.cards[2].ID, req) require.Error(t, err) }) t.Run("未设置企业ID返回错误", func(t *testing.T) { req := &dto.DeviceCardOperationReq{Reason: "测试复机"} _, err := env.service.ResumeCard(context.Background(), env.devices[0].ID, env.cards[0].ID, req) require.Error(t, err) }) } func TestService_ListDevices_EmptyResult(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) t.Run("企业无授权设备时返回空列表", func(t *testing.T) { req := &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10} resp, err := env.service.ListDevices(ctx, env.enterprise.ID, req) require.NoError(t, err) assert.Equal(t, int64(0), resp.Total) assert.Empty(t, resp.List) }) } func TestService_GetDeviceDetail_WithCarrierInfo(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } _, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq) require.NoError(t, err) enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID) t.Run("获取设备详情包含运营商信息", func(t *testing.T) { resp, err := env.service.GetDeviceDetail(enterpriseCtx, env.devices[0].ID) require.NoError(t, err) assert.Len(t, resp.Cards, 2) for _, card := range resp.Cards { assert.NotEmpty(t, card.CarrierName) } }) } func TestService_GetDeviceDetail_NetworkStatus(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } _, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq) require.NoError(t, err) enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID) t.Run("网络状态名称正确", func(t *testing.T) { resp, err := env.service.GetDeviceDetail(enterpriseCtx, env.devices[0].ID) require.NoError(t, err) for _, card := range resp.Cards { if card.NetworkStatus == 1 { assert.Equal(t, "开机", card.NetworkStatusName) } else { assert.Equal(t, "停机", card.NetworkStatusName) } } }) } func TestService_GetDeviceDetail_DeviceWithoutCards(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) prefix := uniqueServiceTestPrefix() enterpriseStore := postgres.NewEnterpriseStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb) enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb) enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb) logger := zap.NewNop() svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger) enterprise := &model.Enterprise{ EnterpriseName: prefix + "_测试企业", EnterpriseCode: prefix, Status: 1, } require.NoError(t, tx.Create(enterprise).Error) device := &model.Device{ DeviceNo: prefix + "_D001", DeviceName: "无卡设备", Status: 2, } require.NoError(t, tx.Create(device).Error) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{device.DeviceNo}, } _, err := svc.AllocateDevices(ctx, enterprise.ID, allocateReq) require.NoError(t, err) t.Run("设备无绑定卡时返回空卡列表", func(t *testing.T) { enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, enterprise.ID) resp, err := svc.GetDeviceDetail(enterpriseCtx, device.ID) require.NoError(t, err) assert.Equal(t, device.ID, resp.Device.DeviceID) assert.Empty(t, resp.Cards) }) } func TestService_RecallDevices_CascadeRevoke(t *testing.T) { prefix := uniqueServiceTestPrefix() env := setupTestEnv(t, prefix) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } resp, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq) require.NoError(t, err) assert.Equal(t, 2, resp.AuthorizedDevices[0].CardCount) t.Run("撤销设备授权时级联撤销卡授权", func(t *testing.T) { recallReq := &dto.RecallDevicesReq{ DeviceNos: []string{env.devices[0].DeviceNo}, } recallResp, err := env.service.RecallDevices(ctx, env.enterprise.ID, recallReq) require.NoError(t, err) assert.Equal(t, 1, recallResp.SuccessCount) }) } func TestService_GetDeviceDetail_WithNetworkStatusOn(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) prefix := uniqueServiceTestPrefix() enterpriseStore := postgres.NewEnterpriseStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb) enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb) enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb) logger := zap.NewNop() svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger) enterprise := &model.Enterprise{ EnterpriseName: prefix + "_测试企业", EnterpriseCode: prefix, Status: 1, } require.NoError(t, tx.Create(enterprise).Error) carrier := &model.Carrier{ CarrierName: "测试运营商", CarrierType: "CMCC", Status: 1, } require.NoError(t, tx.Create(carrier).Error) device := &model.Device{ DeviceNo: prefix + "_D001", DeviceName: "测试设备", Status: 2, } require.NoError(t, tx.Create(device).Error) card := &model.IotCard{ ICCID: prefix + "0001", CarrierID: carrier.ID, Status: 2, NetworkStatus: 1, } require.NoError(t, tx.Create(card).Error) now := time.Now() binding := &model.DeviceSimBinding{ DeviceID: device.ID, IotCardID: card.ID, SlotPosition: 1, BindStatus: 1, BindTime: &now, } require.NoError(t, tx.Create(binding).Error) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) allocateReq := &dto.AllocateDevicesReq{ DeviceNos: []string{device.DeviceNo}, } _, err := svc.AllocateDevices(ctx, enterprise.ID, allocateReq) require.NoError(t, err) t.Run("开机状态卡显示正确", func(t *testing.T) { enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, enterprise.ID) resp, err := svc.GetDeviceDetail(enterpriseCtx, device.ID) require.NoError(t, err) assert.Len(t, resp.Cards, 1) assert.Equal(t, 1, resp.Cards[0].NetworkStatus) assert.Equal(t, "开机", resp.Cards[0].NetworkStatusName) }) } func TestService_EnterpriseNotFound(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) enterpriseStore := postgres.NewEnterpriseStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb) enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb) enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb) logger := zap.NewNop() svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger) ctx := createTestContext(1, constants.UserTypePlatform, 0, 0) t.Run("AllocateDevices企业不存在", func(t *testing.T) { req := &dto.AllocateDevicesReq{DeviceNos: []string{"D001"}} _, err := svc.AllocateDevices(ctx, 99999, req) require.Error(t, err) }) t.Run("RecallDevices企业不存在", func(t *testing.T) { req := &dto.RecallDevicesReq{DeviceNos: []string{"D001"}} _, err := svc.RecallDevices(ctx, 99999, req) require.Error(t, err) }) } func TestService_ValidateCardOperation_RevokedDeviceAuth(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) prefix := uniqueServiceTestPrefix() enterpriseStore := postgres.NewEnterpriseStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb) enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb) enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb) logger := zap.NewNop() svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger) enterprise := &model.Enterprise{ EnterpriseName: prefix + "_测试企业", EnterpriseCode: prefix, Status: 1, } require.NoError(t, tx.Create(enterprise).Error) carrier := &model.Carrier{ CarrierName: "测试运营商", CarrierType: "CMCC", Status: 1, } require.NoError(t, tx.Create(carrier).Error) device := &model.Device{ DeviceNo: prefix + "_D001", DeviceName: "测试设备", Status: 2, } require.NoError(t, tx.Create(device).Error) card := &model.IotCard{ ICCID: prefix + "0001", CarrierID: carrier.ID, Status: 2, } require.NoError(t, tx.Create(card).Error) now := time.Now() binding := &model.DeviceSimBinding{ DeviceID: device.ID, IotCardID: card.ID, SlotPosition: 1, BindStatus: 1, BindTime: &now, } require.NoError(t, tx.Create(binding).Error) deviceAuth := &model.EnterpriseDeviceAuthorization{ EnterpriseID: enterprise.ID, DeviceID: device.ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2, RevokedBy: ptrUintED(1), RevokedAt: &now, } require.NoError(t, tx.Create(deviceAuth).Error) t.Run("已撤销的设备授权无法操作卡", func(t *testing.T) { enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, enterprise.ID) req := &dto.DeviceCardOperationReq{Reason: "测试"} _, err := svc.SuspendCard(enterpriseCtx, device.ID, card.ID, req) require.Error(t, err) }) } func ptrUintED(v uint) *uint { return &v }