+116
-3
@@ -13,6 +13,7 @@ import com.nanri.aiimage.modules.dedupe.model.vo.DedupeTotalDataPageVo;
|
||||
import com.nanri.aiimage.modules.permission.mapper.AdminUserMapper;
|
||||
import com.nanri.aiimage.modules.permission.model.entity.AdminUserEntity;
|
||||
import com.nanri.aiimage.modules.shopkey.mapper.ShopManageGroupMapper;
|
||||
import com.nanri.aiimage.modules.shopkey.model.entity.ShopManageGroupEntity;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -65,6 +66,7 @@ class DedupeTotalDataServiceTest {
|
||||
void createRecordsUploaderIdentity() {
|
||||
AdminUserEntity uploader = user(23L, "normal", "member-a");
|
||||
when(adminUserMapper.selectById(23L)).thenReturn(uploader);
|
||||
stubWritableGroup(23L, 7L);
|
||||
when(dedupeTotalDataMapper.selectOne(any())).thenReturn(null);
|
||||
when(dedupeTotalDataMapper.insert(any(DedupeTotalDataEntity.class))).thenAnswer(invocation -> {
|
||||
DedupeTotalDataEntity entity = invocation.getArgument(0);
|
||||
@@ -75,6 +77,7 @@ class DedupeTotalDataServiceTest {
|
||||
DedupeTotalDataEntity entity = new DedupeTotalDataEntity();
|
||||
entity.setId(91L);
|
||||
entity.setDataValue("B012345678");
|
||||
entity.setGroupId(7L);
|
||||
entity.setUploaderUserId(23L);
|
||||
entity.setUploaderUsername("member-a");
|
||||
return entity;
|
||||
@@ -82,6 +85,7 @@ class DedupeTotalDataServiceTest {
|
||||
|
||||
DedupeTotalDataCreateRequest request = new DedupeTotalDataCreateRequest();
|
||||
request.setDataValue(" b012345678 ");
|
||||
request.setGroupId(7L);
|
||||
DedupeTotalDataItemVo item = service.create(request, 23L);
|
||||
|
||||
ArgumentCaptor<DedupeTotalDataEntity> captor = ArgumentCaptor.forClass(DedupeTotalDataEntity.class);
|
||||
@@ -89,7 +93,10 @@ class DedupeTotalDataServiceTest {
|
||||
assertEquals(23L, captor.getValue().getUploaderUserId());
|
||||
assertEquals("member-a", captor.getValue().getUploaderUsername());
|
||||
assertEquals("B012345678", captor.getValue().getDataValue());
|
||||
assertEquals(7L, captor.getValue().getGroupId());
|
||||
assertEquals("member-a", item.getUsername());
|
||||
assertEquals(7L, item.getGroupId());
|
||||
assertEquals("group-7", item.getGroupName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -117,6 +124,39 @@ class DedupeTotalDataServiceTest {
|
||||
verify(dedupeTotalDataMapper, never()).deleteById(any(Long.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void memberCanDeleteDataInAccessibleGroup() {
|
||||
when(adminUserMapper.selectById(23L)).thenReturn(user(23L, "normal", "member-a"));
|
||||
when(shopManageGroupMapper.selectAccessibleGroupIds(23L)).thenReturn(List.of(7L));
|
||||
when(shopManageGroupMapper.selectUserIdsByGroupIds(List.of(7L))).thenReturn(List.of(23L));
|
||||
when(shopManageGroupMapper.selectManagedMemberUserIds(23L)).thenReturn(List.of());
|
||||
DedupeTotalDataEntity entity = data(91L, 99L);
|
||||
entity.setGroupId(7L);
|
||||
when(dedupeTotalDataMapper.selectById(91L)).thenReturn(entity);
|
||||
|
||||
service.delete(91L, 23L);
|
||||
|
||||
verify(dedupeTotalDataMapper).deleteById(91L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void memberCannotDeleteDataInAnotherGroup() {
|
||||
when(adminUserMapper.selectById(23L)).thenReturn(user(23L, "normal", "member-a"));
|
||||
when(shopManageGroupMapper.selectAccessibleGroupIds(23L)).thenReturn(List.of(7L));
|
||||
when(shopManageGroupMapper.selectUserIdsByGroupIds(List.of(7L))).thenReturn(List.of(23L));
|
||||
when(shopManageGroupMapper.selectManagedMemberUserIds(23L)).thenReturn(List.of());
|
||||
DedupeTotalDataEntity entity = data(91L, 23L);
|
||||
entity.setGroupId(8L);
|
||||
when(dedupeTotalDataMapper.selectById(91L)).thenReturn(entity);
|
||||
|
||||
ResponseStatusException exception = assertThrows(
|
||||
ResponseStatusException.class,
|
||||
() -> service.delete(91L, 23L));
|
||||
|
||||
assertEquals(403, exception.getStatusCode().value());
|
||||
verify(dedupeTotalDataMapper, never()).deleteById(any(Long.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void superAdminCanDeleteAnyUsersData() {
|
||||
when(adminUserMapper.selectById(1L)).thenReturn(user(1L, "super_admin", "root"));
|
||||
@@ -131,10 +171,11 @@ class DedupeTotalDataServiceTest {
|
||||
@Test
|
||||
void duplicateExcelValueKeepsOriginalUploader() throws Exception {
|
||||
when(adminUserMapper.selectById(23L)).thenReturn(user(23L, "normal", "member-a"));
|
||||
stubWritableGroup(23L, 7L);
|
||||
when(dedupeTotalDataMapper.selectOne(any())).thenReturn(data(91L, 99L));
|
||||
MockMultipartFile file = asinWorkbook("B012345678");
|
||||
|
||||
var result = service.importFromExcel(file, 23L);
|
||||
var result = service.importFromExcel(file, 7L, 23L);
|
||||
|
||||
assertEquals(0, result.getInsertedCount());
|
||||
assertEquals(1, result.getSkippedCount());
|
||||
@@ -144,12 +185,13 @@ class DedupeTotalDataServiceTest {
|
||||
@Test
|
||||
void concurrentDuplicateDuringImportIsSkipped() throws Exception {
|
||||
when(adminUserMapper.selectById(23L)).thenReturn(user(23L, "normal", "member-a"));
|
||||
stubWritableGroup(23L, 7L);
|
||||
when(dedupeTotalDataMapper.selectOne(any())).thenReturn(null);
|
||||
when(transactionManager.getTransaction(any())).thenReturn(transactionStatus);
|
||||
when(dedupeTotalDataMapper.insert(any(DedupeTotalDataEntity.class)))
|
||||
.thenThrow(new DuplicateKeyException("duplicate"));
|
||||
|
||||
var result = service.importFromExcel(asinWorkbook("b012345678"), 23L);
|
||||
var result = service.importFromExcel(asinWorkbook("b012345678"), 7L, 23L);
|
||||
|
||||
assertEquals(0, result.getInsertedCount());
|
||||
assertEquals(1, result.getSkippedCount());
|
||||
@@ -172,6 +214,18 @@ class DedupeTotalDataServiceTest {
|
||||
verify(dedupeTotalDataMapper).selectList(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageSupportsUngroupedHistoricalRows() {
|
||||
when(adminUserMapper.selectById(1L)).thenReturn(user(1L, "super_admin", "root"));
|
||||
when(dedupeTotalDataMapper.selectCount(any())).thenReturn(1L);
|
||||
when(dedupeTotalDataMapper.selectList(any())).thenReturn(List.of(data(91L, 23L)));
|
||||
|
||||
DedupeTotalDataPageVo page = service.page(1, 15, "", "", null, null, 1L);
|
||||
|
||||
assertEquals(1L, page.getTotal());
|
||||
assertEquals("", page.getItems().getFirst().getGroupName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
void pageUsesInclusiveDateRange() {
|
||||
@@ -245,7 +299,8 @@ class DedupeTotalDataServiceTest {
|
||||
assertEquals("ASIN值", sheet.getRow(0).getCell(1).getStringCellValue());
|
||||
assertEquals("B012345678", sheet.getRow(1).getCell(1).getStringCellValue());
|
||||
assertEquals("member-a", sheet.getRow(1).getCell(2).getStringCellValue());
|
||||
assertEquals("2026-07-20 12:30:00", sheet.getRow(1).getCell(3).getStringCellValue());
|
||||
assertEquals("", sheet.getRow(1).getCell(3).getStringCellValue());
|
||||
assertEquals("2026-07-20 12:30:00", sheet.getRow(1).getCell(4).getStringCellValue());
|
||||
}
|
||||
|
||||
verify(shopManageGroupMapper).selectManagedMemberUserIds(10L);
|
||||
@@ -262,27 +317,70 @@ class DedupeTotalDataServiceTest {
|
||||
verify(dedupeTotalDataMapper, never()).selectList(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void importProgressAllowsAccessibleGroup() {
|
||||
DedupeTotalDataImportProgressVo progress = registerImportProgress("same-group", 24L, 7L);
|
||||
when(adminUserMapper.selectById(23L)).thenReturn(user(23L, "normal", "member-a"));
|
||||
when(shopManageGroupMapper.selectAccessibleGroupIds(23L)).thenReturn(List.of(7L));
|
||||
when(shopManageGroupMapper.selectUserIdsByGroupIds(List.of(7L))).thenReturn(List.of(23L, 24L));
|
||||
when(shopManageGroupMapper.selectManagedMemberUserIds(23L)).thenReturn(List.of());
|
||||
|
||||
assertEquals(progress, service.getImportProgress("same-group", 23L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void importProgressRejectsVisibleOwnerFromAnotherGroup() {
|
||||
registerImportProgress("other-group", 24L, 8L);
|
||||
when(adminUserMapper.selectById(23L)).thenReturn(user(23L, "normal", "member-a"));
|
||||
when(shopManageGroupMapper.selectAccessibleGroupIds(23L)).thenReturn(List.of(7L));
|
||||
when(shopManageGroupMapper.selectUserIdsByGroupIds(List.of(7L))).thenReturn(List.of(23L, 24L));
|
||||
when(shopManageGroupMapper.selectManagedMemberUserIds(23L)).thenReturn(List.of());
|
||||
|
||||
ResponseStatusException exception = assertThrows(
|
||||
ResponseStatusException.class,
|
||||
() -> service.getImportProgress("other-group", 23L));
|
||||
|
||||
assertEquals(403, exception.getStatusCode().value());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void expiredCompletedProgressIsRemovedOnNextLookup() {
|
||||
Map<String, DedupeTotalDataImportProgressVo> progressMap =
|
||||
(Map<String, DedupeTotalDataImportProgressVo>) ReflectionTestUtils.getField(service, "importProgressMap");
|
||||
Map<String, Long> ownerMap = (Map<String, Long>) ReflectionTestUtils.getField(service, "importOwnerMap");
|
||||
Map<String, Long> groupMap = (Map<String, Long>) ReflectionTestUtils.getField(service, "importGroupMap");
|
||||
Map<String, Long> completedAtMap =
|
||||
(Map<String, Long>) ReflectionTestUtils.getField(service, "importCompletedAtMap");
|
||||
DedupeTotalDataImportProgressVo progress = new DedupeTotalDataImportProgressVo();
|
||||
progress.setStatus("success");
|
||||
progressMap.put("expired", progress);
|
||||
ownerMap.put("expired", 23L);
|
||||
groupMap.put("expired", 7L);
|
||||
completedAtMap.put("expired", System.currentTimeMillis() - (2 * 60 * 60 * 1000L));
|
||||
|
||||
assertThrows(BusinessException.class, () -> service.getImportProgress("expired", 23L));
|
||||
|
||||
assertFalse(progressMap.containsKey("expired"));
|
||||
assertFalse(ownerMap.containsKey("expired"));
|
||||
assertFalse(groupMap.containsKey("expired"));
|
||||
assertFalse(completedAtMap.containsKey("expired"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private DedupeTotalDataImportProgressVo registerImportProgress(String importId, Long ownerId, Long groupId) {
|
||||
Map<String, DedupeTotalDataImportProgressVo> progressMap =
|
||||
(Map<String, DedupeTotalDataImportProgressVo>) ReflectionTestUtils.getField(service, "importProgressMap");
|
||||
Map<String, Long> ownerMap = (Map<String, Long>) ReflectionTestUtils.getField(service, "importOwnerMap");
|
||||
Map<String, Long> groupMap = (Map<String, Long>) ReflectionTestUtils.getField(service, "importGroupMap");
|
||||
DedupeTotalDataImportProgressVo progress = new DedupeTotalDataImportProgressVo();
|
||||
progress.setStatus("running");
|
||||
progressMap.put(importId, progress);
|
||||
ownerMap.put(importId, ownerId);
|
||||
groupMap.put(importId, groupId);
|
||||
return progress;
|
||||
}
|
||||
|
||||
private AdminUserEntity user(Long id, String role, String username) {
|
||||
AdminUserEntity user = new AdminUserEntity();
|
||||
user.setId(id);
|
||||
@@ -301,6 +399,21 @@ class DedupeTotalDataServiceTest {
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void stubWritableGroup(Long operatorId, Long groupId) {
|
||||
when(shopManageGroupMapper.selectAccessibleGroupIds(operatorId)).thenReturn(List.of(groupId));
|
||||
when(shopManageGroupMapper.selectUserIdsByGroupIds(List.of(groupId))).thenReturn(List.of(operatorId));
|
||||
when(shopManageGroupMapper.selectManagedMemberUserIds(operatorId)).thenReturn(List.of());
|
||||
when(shopManageGroupMapper.selectById(groupId)).thenReturn(group(groupId));
|
||||
}
|
||||
|
||||
private ShopManageGroupEntity group(Long id) {
|
||||
ShopManageGroupEntity group = new ShopManageGroupEntity();
|
||||
group.setId(id);
|
||||
group.setGroupName("group-" + id);
|
||||
group.setCreatedById(23L);
|
||||
return group;
|
||||
}
|
||||
|
||||
private MockMultipartFile asinWorkbook(String asin) throws Exception {
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook();
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||
|
||||
Reference in New Issue
Block a user