package task import ( "context" "testing" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/tests/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" ) func TestDeviceImportHandler_ProcessBatch_AllOrNothingValidation(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) logger := zap.NewNop() importTaskStore := postgres.NewDeviceImportTaskStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) bindingStore := postgres.NewDeviceSimBindingStore(tx, rdb) cardStore := postgres.NewIotCardStore(tx, rdb) handler := NewDeviceImportHandler(tx, rdb, importTaskStore, deviceStore, bindingStore, cardStore, nil, logger) ctx := context.Background() shopID := uint(100) platformCard := &model.IotCard{ICCID: "89860012345670001001", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil} platformCard2 := &model.IotCard{ICCID: "89860012345670001003", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil} shopCard := &model.IotCard{ICCID: "89860012345670001002", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: &shopID} require.NoError(t, cardStore.Create(ctx, platformCard)) require.NoError(t, cardStore.Create(ctx, platformCard2)) require.NoError(t, cardStore.Create(ctx, shopCard)) t.Run("所有卡可用-成功", func(t *testing.T) { task := &model.DeviceImportTask{ BatchNo: "TEST_BATCH_001", } task.Creator = 1 batch := []deviceRow{ {Line: 2, DeviceNo: "DEV-OWNER-001", MaxSimSlots: 4, ICCIDs: []string{"89860012345670001001"}}, } result := &deviceImportResult{ skippedItems: make(model.ImportResultItems, 0), failedItems: make(model.ImportResultItems, 0), } handler.processBatch(ctx, task, batch, result) assert.Equal(t, 1, result.successCount) assert.Equal(t, 0, result.failCount) }) t.Run("任一卡分配给店铺-整体失败", func(t *testing.T) { task := &model.DeviceImportTask{ BatchNo: "TEST_BATCH_002", } task.Creator = 1 batch := []deviceRow{ {Line: 3, DeviceNo: "DEV-OWNER-002", MaxSimSlots: 4, ICCIDs: []string{"89860012345670001003", "89860012345670001002"}}, } result := &deviceImportResult{ skippedItems: make(model.ImportResultItems, 0), failedItems: make(model.ImportResultItems, 0), } handler.processBatch(ctx, task, batch, result) assert.Equal(t, 0, result.successCount) assert.Equal(t, 1, result.failCount) require.Len(t, result.failedItems, 1) assert.Contains(t, result.failedItems[0].Reason, "已分配给店铺") }) t.Run("任一卡不存在-整体失败", func(t *testing.T) { task := &model.DeviceImportTask{ BatchNo: "TEST_BATCH_003", } task.Creator = 1 batch := []deviceRow{ {Line: 4, DeviceNo: "DEV-OWNER-003", MaxSimSlots: 4, ICCIDs: []string{"89860012345670001002", "89860012345670009999"}}, } result := &deviceImportResult{ skippedItems: make(model.ImportResultItems, 0), failedItems: make(model.ImportResultItems, 0), } handler.processBatch(ctx, task, batch, result) assert.Equal(t, 0, result.successCount) assert.Equal(t, 1, result.failCount) require.Len(t, result.failedItems, 1) assert.Contains(t, result.failedItems[0].Reason, "卡验证失败") }) t.Run("无指定卡时创建设备成功", func(t *testing.T) { task := &model.DeviceImportTask{ BatchNo: "TEST_BATCH_004", } task.Creator = 1 batch := []deviceRow{ {Line: 5, DeviceNo: "DEV-OWNER-004", MaxSimSlots: 4, ICCIDs: []string{}}, } result := &deviceImportResult{ skippedItems: make(model.ImportResultItems, 0), failedItems: make(model.ImportResultItems, 0), } handler.processBatch(ctx, task, batch, result) assert.Equal(t, 1, result.successCount) assert.Equal(t, 0, result.failCount) }) t.Run("多张卡全部可用-成功", func(t *testing.T) { newCard1 := &model.IotCard{ICCID: "89860012345670001010", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil} newCard2 := &model.IotCard{ICCID: "89860012345670001011", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil} require.NoError(t, cardStore.Create(ctx, newCard1)) require.NoError(t, cardStore.Create(ctx, newCard2)) task := &model.DeviceImportTask{ BatchNo: "TEST_BATCH_005", } task.Creator = 1 batch := []deviceRow{ {Line: 6, DeviceNo: "DEV-OWNER-005", MaxSimSlots: 4, ICCIDs: []string{"89860012345670001010", "89860012345670001011"}}, } result := &deviceImportResult{ skippedItems: make(model.ImportResultItems, 0), failedItems: make(model.ImportResultItems, 0), } handler.processBatch(ctx, task, batch, result) assert.Equal(t, 1, result.successCount) assert.Equal(t, 0, result.failCount) }) } func TestDeviceImportHandler_ProcessImport_AllOrNothing(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) logger := zap.NewNop() importTaskStore := postgres.NewDeviceImportTaskStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) bindingStore := postgres.NewDeviceSimBindingStore(tx, rdb) cardStore := postgres.NewIotCardStore(tx, rdb) handler := NewDeviceImportHandler(tx, rdb, importTaskStore, deviceStore, bindingStore, cardStore, nil, logger) ctx := context.Background() shopID := uint(200) platformCard1 := &model.IotCard{ICCID: "89860012345680001001", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil} platformCard2 := &model.IotCard{ICCID: "89860012345680001002", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil} shopCard := &model.IotCard{ICCID: "89860012345680001003", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: &shopID} require.NoError(t, cardStore.Create(ctx, platformCard1)) require.NoError(t, cardStore.Create(ctx, platformCard2)) require.NoError(t, cardStore.Create(ctx, shopCard)) task := &model.DeviceImportTask{ BatchNo: "TEST_PROCESS_IMPORT", } task.Creator = 1 rows := []deviceRow{ {Line: 2, DeviceNo: "DEV-PI-001", MaxSimSlots: 4, ICCIDs: []string{"89860012345680001001"}}, {Line: 3, DeviceNo: "DEV-PI-002", MaxSimSlots: 4, ICCIDs: []string{"89860012345680001002", "89860012345680001003"}}, {Line: 4, DeviceNo: "DEV-PI-003", MaxSimSlots: 4, ICCIDs: []string{"89860012345680001003", "89860012345680009999"}}, } result := handler.processImport(ctx, task, rows, len(rows)) assert.Equal(t, 1, result.successCount, "只有第一个设备应该成功(所有卡都可用)") assert.Equal(t, 2, result.failCount, "第二和第三个设备应该失败(有卡不可用)") assert.Len(t, result.failedItems, 2) assert.Equal(t, 3, result.failedItems[0].Line) assert.Contains(t, result.failedItems[0].Reason, "已分配给店铺") assert.Equal(t, 4, result.failedItems[1].Line) assert.Contains(t, result.failedItems[1].Reason, "卡验证失败") }