店铺数据抓取累计文件改为店铺级共享,按国家覆盖更新
同店同日在不同账号下产生多份互不相干的累计文件(唯一键含 user_id), 后台管理页每店只显示最新一份,其他账号抓的国家看起来丢失。 - V95 迁移:加 shop_key/country_codes_json/compensation_done 列,按店铺 合并存量 daily_file 与成员行,唯一键改为 (shop_key, business_date) - DailyFileService:findForUpdate/findOlder/acquireLock 去 user 维度, 店铺级锁跨账号串行 - TaskService:聚合按店铺定位;applyCountryCoverage 按国家覆盖(本次 回传的国家替换旧行,未更新的国家保留);启动补偿组件按成员快照重建 合并文件并回填国家列表 - 管理页:country_codes 改从 daily_file.country_codes_json 取,行数用 累计文件实际值
This commit is contained in:
+15
-16
@@ -278,11 +278,11 @@ class ShopDataCrawlCleanupTest {
|
||||
FileResultEntity row = invocation.getArgument(0);
|
||||
return row == null ? null : row.getSourceFilename();
|
||||
});
|
||||
lenient().when(dailyFileService.acquireLock(anyLong(), anyString()))
|
||||
lenient().when(dailyFileService.acquireLock(anyString()))
|
||||
.thenReturn(mock(TaskDistributedLockService.LockHandle.class));
|
||||
lenient().when(dailyFileService.findForUpdate(anyLong(), anyString(), any())).thenAnswer(invocation ->
|
||||
copyDailyFile(findDailyFile(invocation.getArgument(0), invocation.getArgument(1))));
|
||||
lenient().when(dailyFileService.findOlder(anyLong(), anyString(), any())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findForUpdate(anyString(), any())).thenAnswer(invocation ->
|
||||
copyDailyFile(findDailyFile(invocation.getArgument(0))));
|
||||
lenient().when(dailyFileService.findOlder(anyString(), any())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findByLatestResultId(anyLong())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findById(anyLong())).thenReturn(null);
|
||||
lenient().when(dailyFileService.countObjectReferences(anyString())).thenAnswer(invocation -> {
|
||||
@@ -423,7 +423,7 @@ class ShopDataCrawlCleanupTest {
|
||||
taskStore.put(1L, task);
|
||||
|
||||
lenient().when(dailyFileService.findByLatestResultId(8102L))
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile(1L, "hash:" + SHOP_NAME))));
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile("hash:" + SHOP_NAME))));
|
||||
String newObjectKey = "oss/daily/rebuilt.xlsx";
|
||||
lenient().when(ossStorageService.uploadResultFile(any(), eq(MODULE_TYPE))).thenReturn(newObjectKey);
|
||||
doAnswer(invocation -> {
|
||||
@@ -459,7 +459,7 @@ class ShopDataCrawlCleanupTest {
|
||||
taskStore.put(1L, task);
|
||||
|
||||
lenient().when(dailyFileService.findByLatestResultId(8105L))
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile(1L, "hash:" + SHOP_NAME))));
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile("hash:" + SHOP_NAME))));
|
||||
lenient().when(taskResultItemService.getResultSnapshot(1L, MODULE_TYPE, 8103L,
|
||||
ShopDataCrawlResultItemVo.class)).thenReturn(snapshot(8103L));
|
||||
lenient().when(taskResultItemService.getResultSnapshot(1L, MODULE_TYPE, 8104L,
|
||||
@@ -531,7 +531,7 @@ class ShopDataCrawlCleanupTest {
|
||||
FileTaskEntity task = taskEntity(1L, "SUCCESS");
|
||||
taskStore.put(1L, task);
|
||||
lenient().when(dailyFileService.findByLatestResultId(8107L))
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile(1L, "hash:" + SHOP_NAME))));
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile("hash:" + SHOP_NAME))));
|
||||
|
||||
service.deleteHistory(8107L, USER_ID);
|
||||
|
||||
@@ -588,7 +588,7 @@ class ShopDataCrawlCleanupTest {
|
||||
FileTaskEntity task = taskEntity(1L, "SUCCESS");
|
||||
taskStore.put(1L, task);
|
||||
lenient().when(dailyFileService.findByLatestResultId(resultIds[11]))
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile(1L, "hash:" + SHOP_NAME))));
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile("hash:" + SHOP_NAME))));
|
||||
|
||||
for (long resultId : resultIds) {
|
||||
service.deleteHistory(resultId, USER_ID);
|
||||
@@ -652,7 +652,7 @@ class ShopDataCrawlCleanupTest {
|
||||
FileTaskEntity task = taskEntity(1L, "SUCCESS");
|
||||
taskStore.put(1L, task);
|
||||
lenient().when(dailyFileService.findByLatestResultId(8112L))
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile(1L, "hash:" + SHOP_NAME))));
|
||||
.thenReturn(List.of(copyDailyFile(findDailyFile("hash:" + SHOP_NAME))));
|
||||
lenient().when(taskResultItemService.getResultSnapshot(1L, MODULE_TYPE, 8111L,
|
||||
ShopDataCrawlResultItemVo.class)).thenReturn(snapshot(8111L));
|
||||
doAnswer(invocation -> {
|
||||
@@ -824,15 +824,14 @@ class ShopDataCrawlCleanupTest {
|
||||
lastJobTaskId = 2L;
|
||||
TaskFileJobEntity job2 = jobEntity(2L, 2L, MODULE_TYPE, 8402L);
|
||||
AtomicLong calls = new AtomicLong();
|
||||
lenient().when(dailyFileService.findForUpdate(anyLong(), anyString(), any())).thenAnswer(invocation -> {
|
||||
Long userId = invocation.getArgument(0);
|
||||
String shopKeyHash = invocation.getArgument(1);
|
||||
lenient().when(dailyFileService.findForUpdate(anyString(), any())).thenAnswer(invocation -> {
|
||||
String shopKeyHash = invocation.getArgument(0);
|
||||
if (calls.incrementAndGet() == 2L) {
|
||||
ShopDataCrawlDailyFileEntity conflicting = copyDailyFile(findDailyFile(userId, shopKeyHash));
|
||||
ShopDataCrawlDailyFileEntity conflicting = copyDailyFile(findDailyFile(shopKeyHash));
|
||||
conflicting.setVersion(99L);
|
||||
return conflicting;
|
||||
}
|
||||
return copyDailyFile(findDailyFile(userId, shopKeyHash));
|
||||
return copyDailyFile(findDailyFile(shopKeyHash));
|
||||
});
|
||||
|
||||
service.processResultFileJob(job2);
|
||||
@@ -1171,9 +1170,9 @@ class ShopDataCrawlCleanupTest {
|
||||
return DigestUtil.sha256Hex("result-chunks:" + SHOP_NAME);
|
||||
}
|
||||
|
||||
private ShopDataCrawlDailyFileEntity findDailyFile(Long userId, String shopKeyHash) {
|
||||
private ShopDataCrawlDailyFileEntity findDailyFile(String shopKeyHash) {
|
||||
for (ShopDataCrawlDailyFileEntity f : dbDailyFiles) {
|
||||
if (Objects.equals(f.getUserId(), userId) && Objects.equals(f.getShopKeyHash(), shopKeyHash)) {
|
||||
if (Objects.equals(f.getShopKeyHash(), shopKeyHash)) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
+60
-8
@@ -194,7 +194,7 @@ class ShopDataCrawlDailyFileIncrementalTest {
|
||||
});
|
||||
|
||||
// 店铺级锁:每次返回独立 mock 句柄,供失败路径验证 close()。
|
||||
lenient().when(dailyFileService.acquireLock(anyLong(), anyString())).thenAnswer(invocation -> {
|
||||
lenient().when(dailyFileService.acquireLock(anyString())).thenAnswer(invocation -> {
|
||||
TaskDistributedLockService.LockHandle handle = mock(TaskDistributedLockService.LockHandle.class);
|
||||
lastLock.set(handle);
|
||||
return handle;
|
||||
@@ -209,9 +209,9 @@ class ShopDataCrawlDailyFileIncrementalTest {
|
||||
FileResultEntity row = invocation.getArgument(0);
|
||||
return row == null ? null : row.getSourceFilename();
|
||||
});
|
||||
lenient().when(dailyFileService.findForUpdate(anyLong(), anyString(), any()))
|
||||
.thenAnswer(invocation -> findDailyFile(invocation.getArgument(0), invocation.getArgument(1)));
|
||||
lenient().when(dailyFileService.findOlder(anyLong(), anyString(), any())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findForUpdate(anyString(), any()))
|
||||
.thenAnswer(invocation -> findDailyFile(invocation.getArgument(0)));
|
||||
lenient().when(dailyFileService.findOlder(anyString(), any())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findByLatestResultId(anyLong())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findById(anyLong())).thenReturn(null);
|
||||
lenient().when(dailyFileService.countObjectReferences(anyString())).thenReturn(0L);
|
||||
@@ -482,8 +482,7 @@ class ShopDataCrawlDailyFileIncrementalTest {
|
||||
ShopDataCrawlDailyFileEntity entity = invocation.getArgument(0);
|
||||
for (int i = 0; i < dbDailyFiles.size(); i++) {
|
||||
ShopDataCrawlDailyFileEntity existing = dbDailyFiles.get(i);
|
||||
if (Objects.equals(existing.getUserId(), entity.getUserId())
|
||||
&& Objects.equals(existing.getShopKeyHash(), entity.getShopKeyHash())
|
||||
if (Objects.equals(existing.getShopKeyHash(), entity.getShopKeyHash())
|
||||
&& Objects.equals(existing.getBusinessDate(), entity.getBusinessDate())) {
|
||||
entity.setId(existing.getId());
|
||||
dbDailyFiles.set(i, entity);
|
||||
@@ -517,9 +516,9 @@ class ShopDataCrawlDailyFileIncrementalTest {
|
||||
});
|
||||
}
|
||||
|
||||
private ShopDataCrawlDailyFileEntity findDailyFile(Long userId, String shopKeyHash) {
|
||||
private ShopDataCrawlDailyFileEntity findDailyFile(String shopKeyHash) {
|
||||
for (ShopDataCrawlDailyFileEntity f : dbDailyFiles) {
|
||||
if (Objects.equals(f.getUserId(), userId) && Objects.equals(f.getShopKeyHash(), shopKeyHash)) {
|
||||
if (Objects.equals(f.getShopKeyHash(), shopKeyHash)) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
@@ -535,4 +534,57 @@ class ShopDataCrawlDailyFileIncrementalTest {
|
||||
FileResultEntity row = addResultRow(900L, 900L, 1, SHOP_NAME, null);
|
||||
processJob(900L, List.of(row), snapshot(900L, SHOP_NAME, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_task_095_shop_level_country_coverage_keeps_unupdated_countries() {
|
||||
// V95 店铺级共享:跨账号同店结果汇聚到同一份累计文件,
|
||||
// 同国家覆盖更新,未更新的国家保留。
|
||||
// 账号A(user 7)先抓英国;账号B(user 8)抓德国;账号A再抓英国(覆盖)。
|
||||
FileResultEntity uk1 = addResultRow(9501L, 9501L, 1, SHOP_NAME, null);
|
||||
processJob(9501L, List.of(uk1), snapshotWithCountry(9501L, "UK", 100));
|
||||
|
||||
FileResultEntity de1 = addResultRow(9502L, 9502L, 1, SHOP_NAME, null);
|
||||
de1.setUserId(8L); // 不同账号
|
||||
processJob(9502L, List.of(de1), snapshotWithCountry(9502L, "DE", 200));
|
||||
|
||||
FileResultEntity uk2 = addResultRow(9503L, 9503L, 1, SHOP_NAME, null);
|
||||
processJob(9503L, List.of(uk2), snapshotWithCountry(9503L, "UK", 150));
|
||||
|
||||
assertEquals(1, dbDailyFiles.size(), "跨账号同店同日只保留一份累计文件");
|
||||
assertEquals(3, dbMembers.size(), "三个结果各有一个成员行");
|
||||
|
||||
// 整表重建:英国以最后一次(9503)为准,德国(9502)保留
|
||||
triggerRebuild();
|
||||
assertEquals(4, lastAssembledItems.size(), "成员快照按创建顺序累积,item 结构保持");
|
||||
Map<String, Integer> countryRows = new java.util.HashMap<>();
|
||||
for (ShopDataCrawlResultItemVo item : lastAssembledItems) {
|
||||
if (item.getCountryResults() == null) continue;
|
||||
for (com.nanri.aiimage.modules.shopdatacrawl.model.dto.ShopDataCrawlCountryResultDto cr
|
||||
: item.getCountryResults()) {
|
||||
countryRows.put(cr.getCountry(), cr.getItems() == null ? 0 : cr.getItems().size());
|
||||
}
|
||||
}
|
||||
assertEquals(150, countryRows.getOrDefault("UK", -1), "英国以最后一次抓取为准(覆盖更新)");
|
||||
assertEquals(200, countryRows.getOrDefault("DE", -1), "德国未更新,保留之前抓取的数据");
|
||||
verify(ossStorageService, never()).readObjectBytes(anyString());
|
||||
}
|
||||
|
||||
private ShopDataCrawlResultItemVo snapshotWithCountry(long resultId, String country, int rows) {
|
||||
ShopDataCrawlResultItemVo item = snapshot(resultId, SHOP_NAME, rows);
|
||||
com.nanri.aiimage.modules.shopdatacrawl.model.dto.ShopDataCrawlCountryResultDto countryResult =
|
||||
new com.nanri.aiimage.modules.shopdatacrawl.model.dto.ShopDataCrawlCountryResultDto();
|
||||
countryResult.setCountry(country);
|
||||
List<com.nanri.aiimage.modules.shopdatacrawl.model.dto.ShopDataCrawlRowDto> rowList = new ArrayList<>();
|
||||
for (int i = 0; i < rows; i++) {
|
||||
com.nanri.aiimage.modules.shopdatacrawl.model.dto.ShopDataCrawlRowDto row =
|
||||
new com.nanri.aiimage.modules.shopdatacrawl.model.dto.ShopDataCrawlRowDto();
|
||||
row.setAsin("B0" + String.format("%08d", i));
|
||||
row.setDate("2026-07-25");
|
||||
rowList.add(row);
|
||||
}
|
||||
countryResult.setItems(rowList);
|
||||
item.setCountryResults(List.of(countryResult));
|
||||
item.setCountryCodes(List.of(country));
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -221,11 +221,11 @@ class ShopDataCrawlDailyFileJobSplitTest {
|
||||
FileResultEntity row = invocation.getArgument(0);
|
||||
return row == null ? null : row.getSourceFilename();
|
||||
});
|
||||
lenient().when(dailyFileService.acquireLock(anyLong(), anyString()))
|
||||
lenient().when(dailyFileService.acquireLock(anyString()))
|
||||
.thenReturn(mock(TaskDistributedLockService.LockHandle.class));
|
||||
lenient().when(dailyFileService.findForUpdate(anyLong(), anyString(), any())).thenAnswer(invocation ->
|
||||
copyDailyFile(findDailyFile(invocation.getArgument(0), invocation.getArgument(1))));
|
||||
lenient().when(dailyFileService.findOlder(anyLong(), anyString(), any())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findForUpdate(anyString(), any())).thenAnswer(invocation ->
|
||||
copyDailyFile(findDailyFile(invocation.getArgument(0))));
|
||||
lenient().when(dailyFileService.findOlder(anyString(), any())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findByLatestResultId(anyLong())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findById(anyLong())).thenReturn(null);
|
||||
lenient().when(dailyFileService.countObjectReferences(anyString())).thenReturn(0L);
|
||||
@@ -622,9 +622,9 @@ class ShopDataCrawlDailyFileJobSplitTest {
|
||||
});
|
||||
}
|
||||
|
||||
private ShopDataCrawlDailyFileEntity findDailyFile(Long userId, String shopKeyHash) {
|
||||
private ShopDataCrawlDailyFileEntity findDailyFile(String shopKeyHash) {
|
||||
for (ShopDataCrawlDailyFileEntity f : dbDailyFiles) {
|
||||
if (Objects.equals(f.getUserId(), userId) && Objects.equals(f.getShopKeyHash(), shopKeyHash)) {
|
||||
if (Objects.equals(f.getShopKeyHash(), shopKeyHash)) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-9
@@ -200,7 +200,7 @@ class ShopDataCrawlDailyFileLockTest {
|
||||
}).when(excelAssemblyService).writeWorkbook(any(), any());
|
||||
|
||||
// 店铺级锁:每次获取返回独立句柄并计数(两次短临界区各取一次)。
|
||||
lenient().when(dailyFileService.acquireLock(anyLong(), anyString())).thenAnswer(invocation -> {
|
||||
lenient().when(dailyFileService.acquireLock(anyString())).thenAnswer(invocation -> {
|
||||
TaskDistributedLockService.LockHandle handle = mock(TaskDistributedLockService.LockHandle.class);
|
||||
lockAcquireCount.incrementAndGet();
|
||||
lastLock.set(handle);
|
||||
@@ -217,10 +217,9 @@ class ShopDataCrawlDailyFileLockTest {
|
||||
FileResultEntity row = invocation.getArgument(0);
|
||||
return row == null ? null : row.getSourceFilename();
|
||||
});
|
||||
lenient().when(dailyFileService.findForUpdate(anyLong(), anyString(), any()))
|
||||
.thenAnswer(invocation -> copyDailyFile(findDailyFile(
|
||||
invocation.getArgument(0), invocation.getArgument(1))));
|
||||
lenient().when(dailyFileService.findOlder(anyLong(), anyString(), any())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findForUpdate(anyString(), any()))
|
||||
.thenAnswer(invocation -> copyDailyFile(findDailyFile(invocation.getArgument(0))));
|
||||
lenient().when(dailyFileService.findOlder(anyString(), any())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findByLatestResultId(anyLong())).thenReturn(List.of());
|
||||
lenient().when(dailyFileService.findById(anyLong())).thenReturn(null);
|
||||
lenient().when(dailyFileService.countObjectReferences(anyString())).thenReturn(0L);
|
||||
@@ -345,14 +344,14 @@ class ShopDataCrawlDailyFileLockTest {
|
||||
seedDailyFile();
|
||||
FileResultEntity row = addResultRow(7207L, 1L, 1, SHOP_NAME, null);
|
||||
lenient().doAnswer(invocation -> {
|
||||
ShopDataCrawlDailyFileEntity current = findDailyFile(invocation.getArgument(0), invocation.getArgument(1));
|
||||
ShopDataCrawlDailyFileEntity current = findDailyFile(invocation.getArgument(0));
|
||||
if (current == null) {
|
||||
return null;
|
||||
}
|
||||
ShopDataCrawlDailyFileEntity readCopy = copyDailyFile(current);
|
||||
current.setVersion(readCopy.getVersion() + 1L);
|
||||
return readCopy;
|
||||
}).when(dailyFileService).findForUpdate(anyLong(), anyString(), any());
|
||||
}).when(dailyFileService).findForUpdate(anyString(), any());
|
||||
|
||||
Exception ex = assertThrows(BusinessException.class,
|
||||
() -> processJob(1L, List.of(row), snapshot(7207L)));
|
||||
@@ -566,9 +565,9 @@ class ShopDataCrawlDailyFileLockTest {
|
||||
});
|
||||
}
|
||||
|
||||
private ShopDataCrawlDailyFileEntity findDailyFile(Long userId, String shopKeyHash) {
|
||||
private ShopDataCrawlDailyFileEntity findDailyFile(String shopKeyHash) {
|
||||
for (ShopDataCrawlDailyFileEntity f : dbDailyFiles) {
|
||||
if (Objects.equals(f.getUserId(), userId) && Objects.equals(f.getShopKeyHash(), shopKeyHash)) {
|
||||
if (Objects.equals(f.getShopKeyHash(), shopKeyHash)) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-18
@@ -127,10 +127,10 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
when(dailyFileService.currentBusinessDateTime()).thenReturn(BUSINESS_TIME);
|
||||
when(dailyFileService.shopKey(any())).thenReturn("shop-id:shop-1");
|
||||
when(dailyFileService.shopKeyHash(anyString())).thenReturn("hash-1");
|
||||
when(dailyFileService.acquireLock(eq(USER_ID), eq("shop-id:shop-1")))
|
||||
when(dailyFileService.acquireLock("shop-id:shop-1"))
|
||||
.thenReturn(mock(TaskDistributedLockService.LockHandle.class));
|
||||
when(dailyFileService.findMembersByResultId(RESULT_ID)).thenReturn(List.of());
|
||||
when(dailyFileService.findOlder(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(List.of());
|
||||
when(dailyFileService.findOlder("hash-1", BUSINESS_DATE)).thenReturn(List.of());
|
||||
when(dailyFileService.countObjectReferences(anyString())).thenReturn(0L);
|
||||
when(dailyFileService.addMemberWithPayload(anyLong(), anyLong(), anyLong(), anyString())).thenReturn(true);
|
||||
when(transactionManager.getTransaction(any())).thenReturn(transactionStatus);
|
||||
@@ -144,7 +144,7 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
@Test
|
||||
void firstSuccessCreatesDailyWorkbookAndMembership() {
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow), List.of(currentRow));
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(null);
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(null);
|
||||
when(ossStorageService.uploadResultFile(any(), eq(MODULE_TYPE))).thenReturn("result/new.xlsx");
|
||||
when(excelAssemblyService.writeWorkbook(any(), any())).thenReturn(1);
|
||||
|
||||
@@ -176,7 +176,7 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
+ "\"shopId\":\"shop-1\",\"success\":true,\"countryResults\":[]}");
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow), List.of(previous, currentRow));
|
||||
when(fileTaskMapper.selectBatchIds(List.of(100L))).thenReturn(List.of(previousTask));
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.containsResult(301L, RESULT_ID)).thenReturn(false);
|
||||
when(dailyFileService.listMembers(301L)).thenReturn(List.of(previousMember));
|
||||
when(taskResultItemService.getResultSnapshot(
|
||||
@@ -192,7 +192,8 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
verify(ossStorageService, never()).readObjectBytes(anyString());
|
||||
verify(dailyFileService).update(daily);
|
||||
verify(ossStorageService).deleteObject("result/old.xlsx");
|
||||
assertNull(previous.getResultFileUrl());
|
||||
// 店铺级共享:历史结果行保留旧对象指针(可继续下载),累计文件本体被新对象取代
|
||||
assertEquals("result/old.xlsx", previous.getResultFileUrl());
|
||||
assertEquals("result/new.xlsx", currentRow.getResultFileUrl());
|
||||
assertEquals(2, currentRow.getRowCount());
|
||||
}
|
||||
@@ -215,7 +216,7 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
|
||||
ShopDataCrawlDailyFileEntity daily = daily("result/old.xlsx", 2);
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow));
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.containsResult(301L, RESULT_ID)).thenReturn(false);
|
||||
doAnswer(invocation -> {
|
||||
assertFalse(transactionActive.get(), "row counting must run outside the database transaction");
|
||||
@@ -248,7 +249,7 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
ShopDataCrawlDailyFileEntity daily = daily("result/current.xlsx", 3);
|
||||
daily.setLatestResultId(RESULT_ID);
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow));
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.containsResult(301L, RESULT_ID)).thenReturn(true);
|
||||
|
||||
service.processResultFileJob(job);
|
||||
@@ -264,7 +265,7 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
void zeroNewRowsReuseDailyObjectWithoutWorkbookIo() {
|
||||
ShopDataCrawlDailyFileEntity daily = daily("result/current.xlsx", 3);
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow));
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.containsResult(301L, RESULT_ID)).thenReturn(false);
|
||||
when(excelAssemblyService.countRows(any())).thenReturn(0);
|
||||
|
||||
@@ -291,7 +292,7 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow), List.of(previous, currentRow));
|
||||
when(fileTaskMapper.selectBatchIds(List.of(100L))).thenReturn(List.of(previousTask));
|
||||
when(fileResultMapper.selectCount(any())).thenReturn(1L);
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.containsResult(301L, RESULT_ID)).thenReturn(false);
|
||||
when(dailyFileService.listMembers(301L)).thenReturn(List.of());
|
||||
when(taskResultItemService.getResultSnapshot(
|
||||
@@ -314,7 +315,7 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
yesterday.setLatestResultId(RESULT_ID);
|
||||
ShopDataCrawlDailyMemberEntity member = member(301L, TASK_ID, RESULT_ID, BUSINESS_TIME.minusDays(1));
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow));
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(today);
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(today);
|
||||
when(dailyFileService.findMembersByResultId(RESULT_ID)).thenReturn(List.of(member));
|
||||
when(dailyFileService.findById(301L)).thenReturn(yesterday);
|
||||
|
||||
@@ -333,8 +334,8 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
yesterday.setId(300L);
|
||||
yesterday.setBusinessDate(BUSINESS_DATE.minusDays(1));
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow), List.of(previous, currentRow));
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(null);
|
||||
when(dailyFileService.findOlder(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(List.of(yesterday));
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(null);
|
||||
when(dailyFileService.findOlder("hash-1", BUSINESS_DATE)).thenReturn(List.of(yesterday));
|
||||
when(dailyFileService.listMembers(300L)).thenReturn(List.of());
|
||||
when(excelAssemblyService.writeWorkbook(any(), any())).thenReturn(1);
|
||||
when(ossStorageService.uploadResultFile(any(), eq(MODULE_TYPE))).thenReturn("result/today.xlsx");
|
||||
@@ -350,7 +351,8 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
verify(ossStorageService).deleteObject("result/yesterday.xlsx");
|
||||
assertEquals("result/today.xlsx", currentRow.getResultFileUrl());
|
||||
assertEquals(1, currentRow.getRowCount());
|
||||
assertNull(previous.getResultFileUrl());
|
||||
// 店铺级共享:旧日历史结果行保留旧对象指针(可下载),仅累计文件行被删除
|
||||
assertEquals("result/yesterday.xlsx", previous.getResultFileUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -359,8 +361,8 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
yesterday.setId(300L);
|
||||
yesterday.setBusinessDate(BUSINESS_DATE.minusDays(1));
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow));
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(null);
|
||||
when(dailyFileService.findOlder(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(List.of(yesterday));
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(null);
|
||||
when(dailyFileService.findOlder("hash-1", BUSINESS_DATE)).thenReturn(List.of(yesterday));
|
||||
when(dailyFileService.listMembers(300L)).thenReturn(List.of());
|
||||
when(excelAssemblyService.writeWorkbook(any(), any())).thenReturn(4);
|
||||
doThrow(new IllegalStateException("upload failed"))
|
||||
@@ -378,8 +380,8 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
yesterday.setId(300L);
|
||||
yesterday.setBusinessDate(BUSINESS_DATE.minusDays(1));
|
||||
when(fileResultMapper.selectList(any())).thenReturn(List.of(currentRow));
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(null);
|
||||
when(dailyFileService.findOlder(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(List.of(yesterday));
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(null);
|
||||
when(dailyFileService.findOlder("hash-1", BUSINESS_DATE)).thenReturn(List.of(yesterday));
|
||||
when(dailyFileService.listMembers(300L)).thenReturn(List.of());
|
||||
when(excelAssemblyService.writeWorkbook(any(), any())).thenReturn(4);
|
||||
when(ossStorageService.uploadResultFile(any(), eq(MODULE_TYPE))).thenReturn("result/new.xlsx");
|
||||
@@ -418,7 +420,7 @@ class ShopDataCrawlTaskServiceRetentionTest {
|
||||
when(dailyFileService.findByLatestResultId(RESULT_ID)).thenReturn(List.of(daily));
|
||||
when(dailyFileService.findMembersByResultId(RESULT_ID)).thenReturn(List.of(removedMember));
|
||||
when(dailyFileService.findById(301L)).thenReturn(daily);
|
||||
when(dailyFileService.findForUpdate(USER_ID, "hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.findForUpdate("hash-1", BUSINESS_DATE)).thenReturn(daily);
|
||||
when(dailyFileService.listMembers(301L)).thenReturn(List.of(removedMember, previousMember));
|
||||
when(taskResultItemService.getResultSnapshot(
|
||||
100L, MODULE_TYPE, 200L, ShopDataCrawlResultItemVo.class)).thenReturn(previousSnapshot);
|
||||
|
||||
Reference in New Issue
Block a user