格式修改
This commit is contained in:
+1
-1
@@ -10,7 +10,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PlatformExpressCompanyAllTenantQueryContractTest {
|
||||
@Test
|
||||
void 分页租户参数可选但详情写入启停和导入仍然必填() {
|
||||
void keepsTenantRequiredOutsidePaging() {
|
||||
Method page = method("page");
|
||||
assertThat(page.getParameterTypes()[1]).isEqualTo(Long.class);
|
||||
assertThat(page.getParameters()[1].getAnnotation(RequestParam.class).required()).isFalse();
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PlatformLocationControllerContractTest {
|
||||
@Test
|
||||
void 库位接口路径权限和Swagger说明完整() {
|
||||
void shouldHandleCase01() {
|
||||
assertThat(PlatformLocationController.class.getAnnotation(RequestMapping.class).value())
|
||||
.containsExactly("/api/platform/v1/locations");
|
||||
assertMethod("page", GetMapping.class, "platform:location:list");
|
||||
@@ -31,7 +31,7 @@ class PlatformLocationControllerContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 分页查询的企业租户参数可选但写接口仍然必填() {
|
||||
void keepsTenantRequiredForWrites() {
|
||||
Method page = method("page");
|
||||
assertThat(page.getParameterTypes()[1]).isEqualTo(Long.class);
|
||||
assertThat(page.getParameters()[1].getAnnotation(RequestParam.class).required()).isFalse();
|
||||
|
||||
+4
-4
@@ -17,7 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PlatformMasterDataControllerContractTest {
|
||||
@Test
|
||||
void 往来单位分页支持全部业务类型并拒绝未知类型() {
|
||||
void shouldHandleCase01() {
|
||||
try (var factory = Validation.buildDefaultValidatorFactory()) {
|
||||
var validator = factory.getValidator();
|
||||
for (String type : java.util.List.of(
|
||||
@@ -36,7 +36,7 @@ class PlatformMasterDataControllerContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 仓库平台接口按读取新增编辑和启停权限隔离() {
|
||||
void shouldHandleCase02() {
|
||||
RequestMapping mapping = PlatformWarehouseController.class.getAnnotation(RequestMapping.class);
|
||||
assertThat(mapping.value()).containsExactly("/api/platform/v1/warehouse-admin");
|
||||
|
||||
@@ -48,7 +48,7 @@ class PlatformMasterDataControllerContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位分页路径权限和接口说明完整() throws Exception {
|
||||
void shouldHandleCase03() throws Exception {
|
||||
assertContract(PlatformPartnerController.class, "platform:counterparty:list", "/api/platform/v1/partners");
|
||||
assertMethod(PlatformPartnerController.class, "detail", GetMapping.class, "platform:counterparty:list");
|
||||
assertMethod(PlatformPartnerController.class, "create", PostMapping.class, "platform:counterparty:create");
|
||||
@@ -59,7 +59,7 @@ class PlatformMasterDataControllerContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司分页路径权限和接口说明完整() throws Exception {
|
||||
void shouldHandleCase04() throws Exception {
|
||||
assertContract(PlatformExpressCompanyController.class, "platform:express:list", "/api/platform/v1/express-companies");
|
||||
assertMethod(PlatformExpressCompanyController.class, "detail", GetMapping.class, "platform:express:list");
|
||||
assertMethod(PlatformExpressCompanyController.class, "create", PostMapping.class, "platform:express:create");
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PlatformPalletControllerContractTest {
|
||||
@Test
|
||||
void 托盘接口路径和按钮权限完整() {
|
||||
void shouldHandleCase01() {
|
||||
assertThat(PlatformPalletController.class.getAnnotation(RequestMapping.class).value())
|
||||
.containsExactly("/api/platform/v1/pallets");
|
||||
assertMethod("page", GetMapping.class, "platform:pallet:list");
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PlatformPartnerAllTenantQueryContractTest {
|
||||
@Test
|
||||
void 平台分页租户可选但详情写入和导入仍要求租户() {
|
||||
void keepsTenantRequiredOutsidePaging() {
|
||||
Method page = method(PlatformPartnerController.class, "page");
|
||||
assertThat(page.getParameterTypes()[1]).isEqualTo(Long.class);
|
||||
assertThat(page.getParameters()[1].getAnnotation(RequestParam.class).required()).isFalse();
|
||||
@@ -28,7 +28,7 @@ class PlatformPartnerAllTenantQueryContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 分页链路使用可选租户而其他仓储方法保持原有强租户边界() throws Exception {
|
||||
void keepsTenantScopeForOtherMethods() throws Exception {
|
||||
assertThat(PlatformPartnerQueryService.class.getMethod("page", Long.class, PartnerPageQuery.class))
|
||||
.isNotNull();
|
||||
assertThat(PartnerRepository.class.getMethod("page", Long.class, PartnerPageQuery.class))
|
||||
@@ -40,7 +40,7 @@ class PlatformPartnerAllTenantQueryContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 类型筛选在数据库内关联分页且租户条件可选() throws Exception {
|
||||
void supportsOptionalTenantByType() throws Exception {
|
||||
Method method = PartnerMapper.class.getMethod("selectPartnerPageByType",
|
||||
Page.class, Long.class, String.class, String.class, String.class);
|
||||
String sql = String.join("\n", method.getAnnotation(Select.class).value());
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
class WarehouseDataAccessExceptionHandlerTest {
|
||||
@Test
|
||||
void 数据源故障统一返回503并保留请求标识() {
|
||||
void shouldHandleCase01() {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getAttribute("requestId")).thenReturn("request-1");
|
||||
when(request.getAttribute("traceId")).thenReturn("trace-1");
|
||||
|
||||
+8
-3
@@ -1,20 +1,25 @@
|
||||
package com.baiyue.warehouse.controller;
|
||||
|
||||
import com.baiyue.warehouse.service.WarehouseSchemaReadinessService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(WarehouseHealthController.class)
|
||||
class WarehouseHealthControllerTest {
|
||||
@MockBean private WarehouseSchemaReadinessService service;
|
||||
@Resource private WarehouseHealthController controller;
|
||||
@Test
|
||||
void 表结构漂移时状态接口返回503() {
|
||||
WarehouseSchemaReadinessService service = mock(WarehouseSchemaReadinessService.class);
|
||||
void shouldHandleCase01() {
|
||||
when(service.readiness()).thenReturn(
|
||||
new WarehouseSchemaReadinessService.Readiness(false, "DEGRADED", "需要执行迁移"));
|
||||
|
||||
var response = new WarehouseHealthController(service).status();
|
||||
var response = controller.status();
|
||||
|
||||
assertThat(response.getStatusCode().value()).isEqualTo(503);
|
||||
assertThat(response.getBody()).isNotNull();
|
||||
|
||||
@@ -11,7 +11,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class LocationMapperContractTest {
|
||||
@Test
|
||||
void 平台分页的企业和仓库条件均为可选且仍返回仓库快照() throws NoSuchMethodException {
|
||||
void supportsOptionalPageFilters() throws NoSuchMethodException {
|
||||
Method page = LocationMapper.class.getMethod("selectLocationPage", Page.class,
|
||||
Long.class, Long.class, String.class, String.class, String.class, String.class);
|
||||
String pageSql = sql(page.getAnnotation(Select.class).value());
|
||||
@@ -27,7 +27,7 @@ class LocationMapperContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 可用库位按库区和库位数字自然顺序临近分配() throws NoSuchMethodException {
|
||||
void shouldHandleCase01() throws NoSuchMethodException {
|
||||
String selectSql = sql(LocationMapper.class.getMethod(
|
||||
"selectAvailable", long.class, long.class, int.class).getAnnotation(Select.class).value());
|
||||
String lockSql = sql(LocationMapper.class.getMethod(
|
||||
@@ -39,7 +39,7 @@ class LocationMapperContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void A0依靠唯一编码并发创建后加锁复用() throws NoSuchMethodException {
|
||||
void shouldHandleCase02() throws NoSuchMethodException {
|
||||
Method insert = LocationMapper.class.getMethod(
|
||||
"insertSharedOverflowIfAbsent", long.class, long.class, long.class, long.class);
|
||||
Method lock = LocationMapper.class.getMethod("lockSharedOverflow", long.class, long.class);
|
||||
|
||||
+11
-7
@@ -11,6 +11,9 @@ import org.apache.ibatis.session.Configuration;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -18,18 +21,20 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(ExpressCompanyRepository.class)
|
||||
class ExpressCompanyRepositoryTest {
|
||||
@MockBean private ExpressCompanyMapper mapper;
|
||||
@Resource private ExpressCompanyRepository repository;
|
||||
@BeforeAll
|
||||
static void 初始化实体字段缓存() {
|
||||
static void setUpCase01() {
|
||||
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new Configuration(), "test"), ExpressCompanyEntity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页传入租户时按租户并支持筛选() {
|
||||
ExpressCompanyMapper mapper = mock(ExpressCompanyMapper.class);
|
||||
void shouldHandleCase02() {
|
||||
when(mapper.selectPage(any(Page.class), any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
new ExpressCompanyRepository(mapper).page(10001L,
|
||||
repository.page(10001L,
|
||||
new ExpressCompanyPageQuery(1, 20, "顺丰", "ACTIVE"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -42,11 +47,10 @@ class ExpressCompanyRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页不传租户时查询全部企业并保留其他筛选() {
|
||||
ExpressCompanyMapper mapper = mock(ExpressCompanyMapper.class);
|
||||
void pagesAllTenantsWithFilters() {
|
||||
when(mapper.selectPage(any(Page.class), any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
new ExpressCompanyRepository(mapper).page(null,
|
||||
repository.page(null,
|
||||
new ExpressCompanyPageQuery(1, 20, "顺丰", "ACTIVE"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -11,6 +11,9 @@ import org.apache.ibatis.session.Configuration;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -20,37 +23,39 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(PalletRepository.class)
|
||||
class PalletRepositoryTest {
|
||||
@MockBean private PalletMapper mapper;
|
||||
@Resource private PalletRepository repository;
|
||||
@BeforeAll
|
||||
static void 初始化实体字段缓存() {
|
||||
static void initEntityMetadata() {
|
||||
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new Configuration(), "test"), PalletEntity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页默认不限制企业和仓库() {
|
||||
void pagesWithoutFilters() {
|
||||
Collection<Object> values = queryValues(null, null);
|
||||
assertThat(values).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页可单独按企业筛选() {
|
||||
void pagesByTenant() {
|
||||
Collection<Object> values = queryValues(10001L, null);
|
||||
assertThat(values).containsExactly(10001L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页可同时按企业和仓库筛选() {
|
||||
void pagesByTenantAndWarehouse() {
|
||||
Collection<Object> values = queryValues(10001L, 20L);
|
||||
assertThat(values).containsExactlyInAnyOrder(10001L, 20L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页可按全局唯一仓库筛选且写查询仍保留联合边界() {
|
||||
void keepsWriteScopeForWarehouseFilter() {
|
||||
Collection<Object> pageValues = queryValues(null, 20L);
|
||||
assertThat(pageValues).containsExactly(20L);
|
||||
|
||||
PalletMapper mapper = mapper();
|
||||
new PalletRepository(mapper).findOwned(10001L, 20L, 30L);
|
||||
repository.findOwned(10001L, 20L, 30L);
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<LambdaQueryWrapper<PalletEntity>> wrapper = ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
||||
verify(mapper).selectOne(wrapper.capture());
|
||||
@@ -59,9 +64,9 @@ class PalletRepositoryTest {
|
||||
.containsExactlyInAnyOrder(10001L, 20L, 30L);
|
||||
}
|
||||
|
||||
private static Collection<Object> queryValues(Long tenantId, Long warehouseId) {
|
||||
PalletMapper mapper = mapper();
|
||||
new PalletRepository(mapper).page(tenantId,
|
||||
private Collection<Object> queryValues(Long tenantId, Long warehouseId) {
|
||||
when(mapper.selectPage(any(Page.class), any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
repository.page(tenantId,
|
||||
new PalletRequests.PageQuery(1, 20, warehouseId, null, null));
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<LambdaQueryWrapper<PalletEntity>> wrapper = ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
||||
@@ -70,9 +75,4 @@ class PalletRepositoryTest {
|
||||
return wrapper.getValue().getParamNameValuePairs().values();
|
||||
}
|
||||
|
||||
private static PalletMapper mapper() {
|
||||
PalletMapper mapper = mock(PalletMapper.class);
|
||||
when(mapper.selectPage(any(Page.class), any())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
return mapper;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-15
@@ -13,18 +13,24 @@ import org.apache.ibatis.session.Configuration;
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baiyue.warehouse.dto.MasterDataQueries.PartnerPageQuery;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@SpringJUnitConfig(PartnerRepository.class)
|
||||
class PartnerRepositoryTest {
|
||||
@BeforeAll static void 初始化实体字段缓存() {
|
||||
@MockBean private PartnerMapper mapper;
|
||||
@Resource private PartnerRepository repository;
|
||||
@BeforeAll static void setUpCase01() {
|
||||
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new Configuration(), "test"), PartnerEntity.class);
|
||||
}
|
||||
@Test void 候选查询强制租户和启用状态() {
|
||||
PartnerMapper mapper=mock(PartnerMapper.class); when(mapper.selectList(any())).thenReturn(List.of());
|
||||
@Test void shouldHandleCase02() {
|
||||
when(mapper.selectList(any())).thenReturn(List.of());
|
||||
when(mapper.selectPartnerIdsByType(10001,"SHIPPER")).thenReturn(List.of(1L));
|
||||
new PartnerRepository(mapper).activeCandidates(10001,"示例","SHIPPER");
|
||||
repository.activeCandidates(10001,"示例","SHIPPER");
|
||||
@SuppressWarnings("unchecked") ArgumentCaptor<LambdaQueryWrapper<PartnerEntity>> c=ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
||||
verify(mapper).selectList(c.capture()); c.getValue().getSqlSegment();
|
||||
assertThat(c.getValue().getParamNameValuePairs().values()).contains(10001L,"ACTIVE",1L);
|
||||
@@ -34,32 +40,30 @@ class PartnerRepositoryTest {
|
||||
@Test
|
||||
@DisplayName("默认候选只包含发货单位和收货单位")
|
||||
void shouldLimitDefaultCandidatesToOrderPartyTypes() {
|
||||
PartnerMapper mapper=mock(PartnerMapper.class);
|
||||
when(mapper.selectPartnerIdsByType(10001L,"SHIPPER")).thenReturn(List.of(1L));
|
||||
when(mapper.selectPartnerIdsByType(10001L,"CONSIGNEE")).thenReturn(List.of(2L,1L));
|
||||
when(mapper.selectList(any())).thenReturn(List.of());
|
||||
|
||||
new PartnerRepository(mapper).activeCandidates(10001L,null,null);
|
||||
repository.activeCandidates(10001L,null,null);
|
||||
|
||||
@SuppressWarnings("unchecked") ArgumentCaptor<LambdaQueryWrapper<PartnerEntity>> wrapper=ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
||||
verify(mapper).selectList(wrapper.capture());
|
||||
wrapper.getValue().getSqlSegment();
|
||||
assertThat(wrapper.getValue().getParamNameValuePairs().values()).contains(10001L,"ACTIVE",1L,2L);
|
||||
}
|
||||
@Test void 详情查询强制租户和启用状态() {
|
||||
PartnerMapper mapper=mock(PartnerMapper.class); when(mapper.selectOne(any())).thenReturn(null);
|
||||
new PartnerRepository(mapper).findActive(10002,9);
|
||||
@Test void shouldHandleCase03() {
|
||||
when(mapper.selectOne(any())).thenReturn(null);
|
||||
repository.findActive(10002,9);
|
||||
@SuppressWarnings("unchecked") ArgumentCaptor<LambdaQueryWrapper<PartnerEntity>> c=ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
||||
verify(mapper).selectOne(c.capture()); c.getValue().getSqlSegment();
|
||||
assertThat(c.getValue().getParamNameValuePairs().values()).contains(10002L,9L,"ACTIVE");
|
||||
}
|
||||
|
||||
@Test void 平台分页强制租户并支持筛选() {
|
||||
PartnerMapper mapper=mock(PartnerMapper.class);
|
||||
@Test void shouldHandleCase04() {
|
||||
when(mapper.selectPartnerPageByType(any(Page.class), eq(10001L), eq("CUSTOMER"),
|
||||
eq("ACTIVE"), eq("示例"))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
new PartnerRepository(mapper).page(10001L,
|
||||
repository.page(10001L,
|
||||
new PartnerPageQuery(1, 20, "示例", "CUSTOMER", "ACTIVE"));
|
||||
|
||||
verify(mapper).selectPartnerPageByType(any(Page.class), eq(10001L), eq("CUSTOMER"),
|
||||
@@ -67,12 +71,11 @@ class PartnerRepositoryTest {
|
||||
verify(mapper, never()).selectPartnerIdsByType(anyLong(), anyString());
|
||||
}
|
||||
|
||||
@Test void 平台分页不传租户时查询全部企业并支持承运商类型筛选() {
|
||||
PartnerMapper mapper=mock(PartnerMapper.class);
|
||||
@Test void pagesAllTenantsByCarrier() {
|
||||
when(mapper.selectPartnerPageByType(any(Page.class), isNull(), eq("CARRIER"),
|
||||
eq("ACTIVE"), isNull())).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
new PartnerRepository(mapper).page(null,
|
||||
repository.page(null,
|
||||
new PartnerPageQuery(1, 20, null, "CARRIER", "ACTIVE"));
|
||||
|
||||
verify(mapper).selectPartnerPageByType(any(Page.class), isNull(), eq("CARRIER"),
|
||||
|
||||
+6
-6
@@ -10,7 +10,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class WarehouseSchemaContractTest {
|
||||
@Test
|
||||
void 仓库三张表包含实体全部持久化字段() throws IOException {
|
||||
void shouldHandleCase01() throws IOException {
|
||||
String sql = read("warehouse.sql");
|
||||
assertColumns(sql, "wh_warehouse", "warehouse_code", "warehouse_name", "warehouse_type", "country_code",
|
||||
"timezone", "contact_name", "contact_phone", "contact_email", "status", "remark");
|
||||
@@ -22,7 +22,7 @@ class WarehouseSchemaContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位表包含实体全部持久化字段() throws IOException {
|
||||
void shouldHandleCase02() throws IOException {
|
||||
String sql = read("warehouse-partner.sql");
|
||||
assertColumns(sql, "wh_partner", "data_scope_id", "partner_code", "partner_name", "partner_type", "contact_name",
|
||||
"contact_phone", "contact_email", "country_code", "province", "city", "district", "address_line",
|
||||
@@ -33,7 +33,7 @@ class WarehouseSchemaContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司表包含实体全部持久化字段() throws IOException {
|
||||
void shouldHandleCase03() throws IOException {
|
||||
String sql = read("warehouse-express-company.sql");
|
||||
assertColumns(sql, "wh_express_company", "company_code", "company_name", "service_phone", "website",
|
||||
"tracking_url_template", "status", "remark");
|
||||
@@ -41,7 +41,7 @@ class WarehouseSchemaContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 二期库位共用表覆盖基础资料预占占用和并发约束() throws IOException {
|
||||
void shouldHandleCase04() throws IOException {
|
||||
String sql = read("phase2-pallet-location-schema.sql");
|
||||
assertColumns(sql, "wh_location", "tenant_id", "warehouse_id", "zone_code", "zone_name",
|
||||
"location_code", "location_type", "max_weight_kg", "shared_overflow", "status", "remark", "deleted", "version");
|
||||
@@ -59,7 +59,7 @@ class WarehouseSchemaContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void A0迁移允许共享库位多占用但仍限制托盘唯一活动占用() throws IOException {
|
||||
void shouldHandleCase05() throws IOException {
|
||||
String sql = read("phase2-location-overflow-migration.sql");
|
||||
assertThat(sql).contains("'wh_location', 'shared_overflow'")
|
||||
.contains("'wh_location_reservation', 'shared_overflow'")
|
||||
@@ -78,7 +78,7 @@ class WarehouseSchemaContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 既有库增量迁移覆盖全部仓储实体表和列表索引() throws IOException {
|
||||
void shouldHandleCase06() throws IOException {
|
||||
String sql = read("phase1-warehouse-schema-migration.sql");
|
||||
assertThat(sql).contains("FROM information_schema.columns")
|
||||
.contains("CREATE PROCEDURE add_column_if_missing")
|
||||
|
||||
+6
-4
@@ -5,6 +5,9 @@ import com.baiyue.warehouse.repository.ExpressCompanyRepository;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -16,12 +19,13 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@DisplayName("快递公司批量导入")
|
||||
@SpringJUnitConfig(ExpressCompanyImportService.class)
|
||||
class ExpressCompanyImportServiceTest {
|
||||
@MockBean private ExpressCompanyRepository repository;
|
||||
@Resource private ExpressCompanyImportService service;
|
||||
@Test
|
||||
@DisplayName("标准模板通过整批校验后写入全部数据")
|
||||
void shouldImportValidWorkbookAfterFullValidation() throws Exception {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
ExpressCompanyImportService service = new ExpressCompanyImportService(repository);
|
||||
byte[] workbook = withRows(service.template(), new String[][] {
|
||||
{"SF", "顺丰速运", "95338", "https://www.sf-express.com", "https://example.com/{trackingNo}", "ACTIVE", "国内件"}
|
||||
});
|
||||
@@ -39,8 +43,6 @@ class ExpressCompanyImportServiceTest {
|
||||
@Test
|
||||
@DisplayName("文件内重复名称时整批拒绝且不写入")
|
||||
void shouldRejectWholeWorkbookWhenAnyRowIsInvalid() throws Exception {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
ExpressCompanyImportService service = new ExpressCompanyImportService(repository);
|
||||
byte[] workbook = withRows(service.template(), new String[][] {
|
||||
{"SF", "顺丰速运", "", "", "", "ACTIVE", ""},
|
||||
{"SF2", "顺丰速运", "", "", "", "ACTIVE", ""}
|
||||
|
||||
+14
-24
@@ -7,6 +7,9 @@ import com.baiyue.warehouse.entity.LocationEntity;
|
||||
import com.baiyue.warehouse.entity.WarehouseEntity;
|
||||
import com.baiyue.warehouse.repository.LocationRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@@ -18,11 +21,12 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(LocationApplicationService.class)
|
||||
class LocationApplicationServiceTest {
|
||||
@MockBean private LocationRepository repository;
|
||||
@Resource private LocationApplicationService service;
|
||||
@Test
|
||||
void 平台分页不传企业和仓库时查询全部库位() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
LocationApplicationService service = new LocationApplicationService(repository);
|
||||
void pagesAllLocations() {
|
||||
PageQuery query = pageQuery(null);
|
||||
|
||||
service.page(null, query);
|
||||
@@ -32,9 +36,7 @@ class LocationApplicationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页可只按企业筛选全部仓库() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
LocationApplicationService service = new LocationApplicationService(repository);
|
||||
void filtersByTenant() {
|
||||
PageQuery query = pageQuery(null);
|
||||
|
||||
service.page(10001L, query);
|
||||
@@ -43,9 +45,7 @@ class LocationApplicationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页可同时按企业和仓库筛选() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
LocationApplicationService service = new LocationApplicationService(repository);
|
||||
void filtersByTenantAndWarehouse() {
|
||||
PageQuery query = pageQuery(88L);
|
||||
|
||||
service.page(10001L, query);
|
||||
@@ -54,9 +54,7 @@ class LocationApplicationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 新增时仓库必须属于当前企业租户() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
LocationApplicationService service = new LocationApplicationService(repository);
|
||||
void shouldHandleCase01() {
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, request("AVAILABLE", null)))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("企业租户");
|
||||
@@ -64,23 +62,19 @@ class LocationApplicationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 同一租户仓库的库位编码必须唯一() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase02() {
|
||||
when(repository.findWarehouse(10001L, 88L)).thenReturn(warehouse("ACTIVE"));
|
||||
when(repository.existsCode(10001L, 88L, "A1-01", null)).thenReturn(true);
|
||||
LocationApplicationService service = new LocationApplicationService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, request("AVAILABLE", null)))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("编码");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 活动预占或占用库位不能停用() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase03() {
|
||||
LocationEntity location = location("AVAILABLE", 3);
|
||||
when(repository.findOwned(10001L, 88L, 9L)).thenReturn(location);
|
||||
when(repository.hasActiveResource(10001L, 9L)).thenReturn(true);
|
||||
LocationApplicationService service = new LocationApplicationService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.changeStatus(10001L, 88L, 9L, "DISABLED", 3, 7L))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("不能停用");
|
||||
@@ -88,10 +82,8 @@ class LocationApplicationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 删除前必须先停用且没有活动资源() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase04() {
|
||||
when(repository.findOwned(10001L, 88L, 9L)).thenReturn(location("AVAILABLE", 3));
|
||||
LocationApplicationService service = new LocationApplicationService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.delete(10001L, 88L, 9L, 3, 7L))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("先停用");
|
||||
@@ -99,12 +91,10 @@ class LocationApplicationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 条件更新失败统一转换为乐观锁冲突() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase05() {
|
||||
when(repository.findOwned(10001L, 88L, 9L)).thenReturn(location("DISABLED", 3));
|
||||
when(repository.findWarehouse(10001L, 88L)).thenReturn(warehouse("ACTIVE"));
|
||||
when(repository.changeStatus(10001L, 88L, 9L, "DISABLED", "AVAILABLE", 3, 7L)).thenReturn(0);
|
||||
LocationApplicationService service = new LocationApplicationService(repository);
|
||||
|
||||
assertThatThrownBy(() -> service.changeStatus(10001L, 88L, 9L, "AVAILABLE", 3, 7L))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("刷新");
|
||||
|
||||
+12
-18
@@ -11,6 +11,9 @@ import com.baiyue.warehouse.entity.WarehouseEntity;
|
||||
import com.baiyue.warehouse.repository.LocationRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -26,15 +29,16 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(LocationResourceService.class)
|
||||
class LocationResourceServiceTest {
|
||||
@MockBean private LocationRepository repository;
|
||||
@Resource private LocationResourceService service;
|
||||
@Test
|
||||
void 普通库位不足时优先分配普通位并将剩余托盘共享到A0() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase01() {
|
||||
when(repository.findWarehouse(10001L, 88L)).thenReturn(warehouse());
|
||||
when(repository.lockAvailable(10001L, 88L, 2)).thenReturn(List.of(location(9L, "A1")));
|
||||
when(repository.lockOrCreateSharedOverflow(10001L, 88L, 7L)).thenReturn(overflow());
|
||||
when(repository.changeStatus(10001L, 88L, 9L, "AVAILABLE", "RESERVED", 0, 7L)).thenReturn(1);
|
||||
LocationResourceService service = new LocationResourceService(repository);
|
||||
|
||||
var result = service.reserveAvailable(reserveCommand());
|
||||
|
||||
@@ -46,12 +50,10 @@ class LocationResourceServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 无普通库位时同一请求的所有不足目标复用同一个A0() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase02() {
|
||||
when(repository.findWarehouse(10001L, 88L)).thenReturn(warehouse());
|
||||
when(repository.lockAvailable(10001L, 88L, 2)).thenReturn(List.of());
|
||||
when(repository.lockOrCreateSharedOverflow(10001L, 88L, 7L)).thenReturn(overflow());
|
||||
LocationResourceService service = new LocationResourceService(repository);
|
||||
|
||||
var result = service.reserveAvailable(reserveCommand());
|
||||
|
||||
@@ -62,14 +64,12 @@ class LocationResourceServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 单事务按托盘顺序锁定并条件预占库位() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase03() {
|
||||
when(repository.findWarehouse(10001L, 88L)).thenReturn(warehouse());
|
||||
when(repository.lockAvailable(10001L, 88L, 2))
|
||||
.thenReturn(List.of(location(9L, "A1"), location(10L, "A2")));
|
||||
when(repository.changeStatus(10001L, 88L, 9L, "AVAILABLE", "RESERVED", 0, 7L)).thenReturn(1);
|
||||
when(repository.changeStatus(10001L, 88L, 10L, "AVAILABLE", "RESERVED", 0, 7L)).thenReturn(1);
|
||||
LocationResourceService service = new LocationResourceService(repository);
|
||||
|
||||
var result = service.reserveAvailable(reserveCommand());
|
||||
|
||||
@@ -81,8 +81,7 @@ class LocationResourceServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 已确认预占按占用事实幂等返回() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase04() {
|
||||
when(repository.findWarehouse(10001L, 88L)).thenReturn(warehouse());
|
||||
LocationReservationEntity reservation = reservation("CONFIRMED");
|
||||
when(repository.lockReservation(10001L, 101L)).thenReturn(reservation);
|
||||
@@ -94,7 +93,6 @@ class LocationResourceServiceTest {
|
||||
occupancy.setLocationId(9L);
|
||||
occupancy.setLocationCode("A1");
|
||||
when(repository.findOccupancyByReservation(10001L, 101L)).thenReturn(occupancy);
|
||||
LocationResourceService service = new LocationResourceService(repository);
|
||||
|
||||
var result = service.confirmOccupied(confirmCommand());
|
||||
|
||||
@@ -103,15 +101,13 @@ class LocationResourceServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 确认占用使用预占归属和库位版本条件更新() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase05() {
|
||||
when(repository.findWarehouse(10001L, 88L)).thenReturn(warehouse());
|
||||
LocationReservationEntity reservation = reservation("RESERVED");
|
||||
when(repository.lockReservation(10001L, 101L)).thenReturn(reservation);
|
||||
when(repository.findOwned(10001L, 88L, 9L)).thenReturn(location(9L, "A1"));
|
||||
when(repository.changeStatus(10001L, 88L, 9L, "RESERVED", "OCCUPIED", 0, 7L)).thenReturn(1);
|
||||
when(repository.confirmReservation(reservation)).thenReturn(1);
|
||||
LocationResourceService service = new LocationResourceService(repository);
|
||||
|
||||
var result = service.confirmOccupied(confirmCommand());
|
||||
|
||||
@@ -121,8 +117,7 @@ class LocationResourceServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 确认A0占用时保持共享库位AVAILABLE() {
|
||||
LocationRepository repository = mock(LocationRepository.class);
|
||||
void shouldHandleCase06() {
|
||||
when(repository.findWarehouse(10001L, 88L)).thenReturn(warehouse());
|
||||
LocationReservationEntity reservation = reservation("RESERVED");
|
||||
reservation.setLocationId(99L);
|
||||
@@ -131,7 +126,6 @@ class LocationResourceServiceTest {
|
||||
when(repository.lockReservation(10001L, 101L)).thenReturn(reservation);
|
||||
when(repository.findOwned(10001L, 88L, 99L)).thenReturn(overflow());
|
||||
when(repository.confirmReservation(reservation)).thenReturn(1);
|
||||
LocationResourceService service = new LocationResourceService(repository);
|
||||
|
||||
var result = service.confirmOccupied(confirmCommand());
|
||||
|
||||
|
||||
+10
-6
@@ -7,19 +7,23 @@ import com.baiyue.warehouse.entity.PalletEntity;
|
||||
import com.baiyue.warehouse.repository.PalletRepository;
|
||||
import com.baiyue.warehouse.repository.WarehouseRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(PalletApplicationService.class)
|
||||
class PalletApplicationServiceTest {
|
||||
private final PalletRepository repository = mock(PalletRepository.class);
|
||||
private final WarehouseRepository warehouseRepository = mock(WarehouseRepository.class);
|
||||
private final PalletApplicationService service = new PalletApplicationService(repository, warehouseRepository);
|
||||
@MockBean private PalletRepository repository;
|
||||
@MockBean private WarehouseRepository warehouseRepository;
|
||||
@Resource private PalletApplicationService service;
|
||||
|
||||
@Test
|
||||
void 平台详情不暴露内部状态() {
|
||||
void shouldHandleCase01() {
|
||||
PalletEntity entity = pallet("OCCUPIED");
|
||||
when(repository.findOwned(10001, 20, 30)).thenReturn(entity);
|
||||
org.assertj.core.api.Assertions.assertThat(service.detail(10001, 20, 30))
|
||||
@@ -27,12 +31,12 @@ class PalletApplicationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 跨仓库托盘不可见() {
|
||||
void shouldHandleCase02() {
|
||||
assertThatThrownBy(() -> service.detail(10001, 21, 30)).isInstanceOf(BizException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 平台分页允许不指定企业并保留分页结果() {
|
||||
void pagesWithoutTenantFilter() {
|
||||
PalletRequests.PageQuery query = new PalletRequests.PageQuery(1, 20, null, null, null);
|
||||
when(repository.page(null, query)).thenReturn(new PageResult<>(java.util.List.of(pallet("AVAILABLE")),
|
||||
1, 20, 1, 1));
|
||||
|
||||
+19
-9
@@ -6,6 +6,11 @@ import com.baiyue.warehouse.dto.PalletAllocationDtos;
|
||||
import com.baiyue.warehouse.entity.PalletEntity;
|
||||
import com.baiyue.warehouse.repository.PalletRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -19,14 +24,19 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(classes = {PalletLocationAllocationService.class, PalletLocationAllocationServiceTest.TestConfig.class})
|
||||
class PalletLocationAllocationServiceTest {
|
||||
private final PalletRepository pallets = mock(PalletRepository.class);
|
||||
private final LocationResourceService locations = mock(LocationResourceService.class);
|
||||
private final PalletLocationAllocationService service =
|
||||
new PalletLocationAllocationService(pallets, new PalletVolumeSplitter(), locations);
|
||||
@MockBean private PalletRepository pallets;
|
||||
@MockBean private LocationResourceService locations;
|
||||
@Resource private PalletLocationAllocationService service;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TestConfig {
|
||||
@Bean PalletVolumeSplitter splitter() { return new PalletVolumeSplitter(); }
|
||||
}
|
||||
|
||||
@Test
|
||||
void 并发抢占托盘时整批失败且不预占库位() {
|
||||
void shouldHandleCase01() {
|
||||
when(locations.findActiveResources(10001, "FIRSTLEG", 88)).thenReturn(List.of());
|
||||
when(pallets.findAvailable(10001, 20, "木托盘", new BigDecimal("2"), 1))
|
||||
.thenReturn(List.of(pallet(30, "TP-001")));
|
||||
@@ -37,7 +47,7 @@ class PalletLocationAllocationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 未指定类型时默认推荐普通托盘() {
|
||||
void shouldHandleCase02() {
|
||||
when(locations.findActiveResources(10001, "FIRSTLEG", 99)).thenReturn(List.of());
|
||||
when(pallets.findAvailable(10001, 20, "STANDARD", new BigDecimal("2"), 1))
|
||||
.thenReturn(List.of(pallet(30, "TP-001")));
|
||||
@@ -55,7 +65,7 @@ class PalletLocationAllocationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 释放预占后托盘恢复可用并可再次预占() {
|
||||
void shouldHandleCase03() {
|
||||
LocationDtos.ActiveResource resource = new LocationDtos.ActiveResource(
|
||||
101, null, 20, 30, "TP-001", 40, "A-01", false, "RESERVED");
|
||||
when(locations.findActiveResources(10001, "FIRSTLEG", 88)).thenReturn(List.of(resource));
|
||||
@@ -70,7 +80,7 @@ class PalletLocationAllocationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 已确认占用禁止补偿释放避免回滚入库事实() {
|
||||
void shouldHandleCase04() {
|
||||
LocationDtos.ActiveResource resource = new LocationDtos.ActiveResource(
|
||||
101, 201L, 20, 30, "TP-001", 40, "A-01", false, "OCCUPIED");
|
||||
when(locations.findActiveResources(10001, "FIRSTLEG", 88)).thenReturn(List.of(resource));
|
||||
@@ -82,7 +92,7 @@ class PalletLocationAllocationServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 相同业务幂等重试直接返回已有预占() {
|
||||
void shouldHandleCase05() {
|
||||
LocationDtos.ActiveResource resource = new LocationDtos.ActiveResource(
|
||||
101, null, 20, 30, "TP-001", 40, "A-01", false, "RESERVED");
|
||||
when(locations.findActiveResources(10001, "FIRSTLEG", 88)).thenReturn(List.of(resource));
|
||||
|
||||
@@ -12,14 +12,14 @@ class PalletVolumeSplitterTest {
|
||||
private final PalletVolumeSplitter splitter = new PalletVolumeSplitter();
|
||||
|
||||
@Test
|
||||
void 整除时不多拆托盘() {
|
||||
void shouldHandleCase01() {
|
||||
var result = splitter.split(new BigDecimal("20"), new BigDecimal("2"));
|
||||
assertThat(result.palletCount()).isEqualTo(10);
|
||||
assertThat(result.allocations()).allMatch(item -> item.allocatedVolumeCbm().compareTo(new BigDecimal("2")) == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 非整除时向上拆分并保留尾盘体积() {
|
||||
void shouldHandleCase02() {
|
||||
var result = splitter.split(new BigDecimal("20.1"), new BigDecimal("2"));
|
||||
assertThat(result.palletCount()).isEqualTo(11);
|
||||
assertThat(result.allocations().get(10).allocatedVolumeCbm()).isEqualByComparingTo("0.1");
|
||||
@@ -28,7 +28,7 @@ class PalletVolumeSplitterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 拒绝空值零值负值和超大拆分() {
|
||||
void shouldHandleCase03() {
|
||||
assertThatThrownBy(() -> splitter.split(null, BigDecimal.ONE)).isInstanceOf(BizException.class);
|
||||
assertThatThrownBy(() -> splitter.split(BigDecimal.ZERO, BigDecimal.ONE)).isInstanceOf(BizException.class);
|
||||
assertThatThrownBy(() -> splitter.split(BigDecimal.ONE, BigDecimal.ZERO)).isInstanceOf(BizException.class);
|
||||
|
||||
@@ -7,6 +7,9 @@ import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -18,12 +21,13 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@DisplayName("往来单位批量导入")
|
||||
@SpringJUnitConfig(PartnerImportService.class)
|
||||
class PartnerImportServiceTest {
|
||||
@MockBean private PartnerRepository repository;
|
||||
@Resource private PartnerImportService service;
|
||||
@Test
|
||||
@DisplayName("标准模板支持多类型并写入服务端数据范围")
|
||||
void shouldImportValidMultiTypeRow() throws Exception {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
PartnerImportService service = new PartnerImportService(repository);
|
||||
byte[] file = withRows(service.template(), new String[][] {
|
||||
{"CUS-100", "测试单位", "CUSTOMER,SHIPPER", "张三", "13800138000", "test@example.com",
|
||||
"CN", "广东省", "深圳市", "南山区", "测试路 1 号", "518000", "ACTIVE", "测试备注"}
|
||||
@@ -43,8 +47,6 @@ class PartnerImportServiceTest {
|
||||
@Test
|
||||
@DisplayName("文件内任一错误时整批零写入并返回行号")
|
||||
void shouldRejectWholeBatchWhenAnyRowIsInvalid() throws Exception {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
PartnerImportService service = new PartnerImportService(repository);
|
||||
byte[] file = withRows(service.template(), new String[][] {
|
||||
{"CUS-100", "测试单位一", "CUSTOMER", "张三", "13800138000", "", "CN", "", "深圳市", "", "测试路 1 号", "", "ACTIVE", ""},
|
||||
{"CUS-100", "测试单位二", "UNKNOWN", "李四", "13900139000", "bad-email", "C", "", "", "", "", "", "ENABLED", ""}
|
||||
|
||||
@@ -5,45 +5,46 @@ import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.warehouse.entity.PartnerEntity;
|
||||
import com.baiyue.warehouse.repository.PartnerRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(PartnerQueryService.class)
|
||||
class PartnerQueryServiceTest {
|
||||
@MockBean private PartnerRepository repository;
|
||||
@Resource private PartnerQueryService service;
|
||||
@Test void unsupportedCandidateTypeReturnsBadRequest() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
assertThatThrownBy(() -> new PartnerQueryService(repository).candidates(10001L, null, "CUSTOMER"))
|
||||
assertThatThrownBy(() -> service.candidates(10001L, null, "CUSTOMER"))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("SHIPPER");
|
||||
}
|
||||
@Test void missingOrCrossTenantPartnerReturnsNotFound() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
|
||||
assertThatThrownBy(() -> new PartnerQueryService(repository).active(10001L, 7L))
|
||||
assertThatThrownBy(() -> service.active(10001L, 7L))
|
||||
.isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test void 停用往来单位返回409() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
@Test void shouldHandleCase01() {
|
||||
PartnerEntity partner = new PartnerEntity();
|
||||
partner.setId(7L); partner.setTenantId(10001L); partner.setStatus("INACTIVE");
|
||||
when(repository.findOwned(10001L, 7L)).thenReturn(partner);
|
||||
|
||||
assertThatThrownBy(() -> new PartnerQueryService(repository).active(10001L, 7L))
|
||||
assertThatThrownBy(() -> service.active(10001L, 7L))
|
||||
.isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.CONFLICT);
|
||||
}
|
||||
|
||||
@Test void 启用往来单位正常返回() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
@Test void shouldHandleCase02() {
|
||||
PartnerEntity partner = new PartnerEntity();
|
||||
partner.setId(7L); partner.setTenantId(10001L); partner.setStatus("ACTIVE");
|
||||
when(repository.findOwned(10001L, 7L)).thenReturn(partner);
|
||||
|
||||
assertThat(new PartnerQueryService(repository).active(10001L, 7L)).isSameAs(partner);
|
||||
assertThat(service.active(10001L, 7L)).isSameAs(partner);
|
||||
}
|
||||
}
|
||||
|
||||
+45
-37
@@ -9,6 +9,9 @@ import com.baiyue.warehouse.repository.ExpressCompanyRepository;
|
||||
import com.baiyue.warehouse.repository.PartnerRepository;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -21,21 +24,26 @@ import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SpringJUnitConfig(classes = {PlatformPartnerQueryService.class, ExpressCompanyQueryService.class})
|
||||
class PlatformMasterDataManagementServiceTest {
|
||||
@MockBean private PartnerRepository partnerRepository;
|
||||
@MockBean private ExpressCompanyRepository expressRepository;
|
||||
@Resource private PlatformPartnerQueryService partnerService;
|
||||
@Resource private ExpressCompanyQueryService expressService;
|
||||
@Test
|
||||
void 往来单位详情强制租户隔离() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
void shouldHandleCase01() {
|
||||
PartnerRepository repository = partnerRepository;
|
||||
PlatformPartnerQueryService service = partnerService;
|
||||
|
||||
assertThatThrownBy(() -> service.detail(10002L, 1L)).isInstanceOf(BizException.class);
|
||||
verify(repository).findOwned(10002L, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位编码在租户内必须唯一() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
void shouldHandleCase02() {
|
||||
PartnerRepository repository = partnerRepository;
|
||||
when(repository.existsCode(10001L, "CUS-001", null)).thenReturn(true);
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
PlatformPartnerQueryService service = partnerService;
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, partnerRequest()))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("编码");
|
||||
@@ -43,24 +51,24 @@ class PlatformMasterDataManagementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位并发重复编码统一返回业务冲突() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
void shouldHandleCase03() {
|
||||
PartnerRepository repository = partnerRepository;
|
||||
doThrow(new DataIntegrityViolationException("duplicate")).when(repository).insert(any());
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
PlatformPartnerQueryService service = partnerService;
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, partnerRequest()))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("编码");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位新增写入租户和请求字段() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
void shouldHandleCase04() {
|
||||
PartnerRepository repository = partnerRepository;
|
||||
doAnswer(invocation -> {
|
||||
PartnerEntity entity = invocation.getArgument(0);
|
||||
entity.setId(18L);
|
||||
return null;
|
||||
}).when(repository).insert(any());
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
PlatformPartnerQueryService service = partnerService;
|
||||
|
||||
assertThat(service.create(10001L, partnerRequest())).isEqualTo(18L);
|
||||
|
||||
@@ -75,13 +83,13 @@ class PlatformMasterDataManagementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位编辑保留归属并更新字段() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
void shouldHandleCase05() {
|
||||
PartnerRepository repository = partnerRepository;
|
||||
PartnerEntity entity = new PartnerEntity();
|
||||
entity.setId(19L);
|
||||
entity.setTenantId(10001L);
|
||||
when(repository.findOwned(10001L, 19L)).thenReturn(entity);
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
PlatformPartnerQueryService service = partnerService;
|
||||
|
||||
service.update(10001L, 19L, partnerRequest());
|
||||
|
||||
@@ -91,14 +99,14 @@ class PlatformMasterDataManagementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 往来单位停用保留主数据() {
|
||||
PartnerRepository repository = mock(PartnerRepository.class);
|
||||
void shouldHandleCase06() {
|
||||
PartnerRepository repository = partnerRepository;
|
||||
PartnerEntity entity = new PartnerEntity();
|
||||
entity.setId(8L);
|
||||
entity.setTenantId(10001L);
|
||||
entity.setStatus("ACTIVE");
|
||||
when(repository.findOwned(10001L, 8L)).thenReturn(entity);
|
||||
PlatformPartnerQueryService service = new PlatformPartnerQueryService(repository);
|
||||
PlatformPartnerQueryService service = partnerService;
|
||||
|
||||
service.changeStatus(10001L, 8L, "INACTIVE");
|
||||
|
||||
@@ -107,19 +115,19 @@ class PlatformMasterDataManagementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司详情强制租户隔离() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
void shouldHandleCase07() {
|
||||
ExpressCompanyRepository repository = expressRepository;
|
||||
ExpressCompanyQueryService service = expressService;
|
||||
|
||||
assertThatThrownBy(() -> service.detail(10002L, 1L)).isInstanceOf(BizException.class);
|
||||
verify(repository).findOwned(10002L, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司编码在租户内必须唯一() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
void shouldHandleCase08() {
|
||||
ExpressCompanyRepository repository = expressRepository;
|
||||
when(repository.existsCode(10001L, "SF", null)).thenReturn(true);
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
ExpressCompanyQueryService service = expressService;
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, expressRequest()))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("编码");
|
||||
@@ -129,9 +137,9 @@ class PlatformMasterDataManagementServiceTest {
|
||||
@Test
|
||||
@DisplayName("快递公司名称在租户内必须唯一")
|
||||
void shouldRequireUniqueExpressCompanyNameWithinTenant() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
ExpressCompanyRepository repository = expressRepository;
|
||||
when(repository.existsName(10001L, "顺丰速运", null)).thenReturn(true);
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
ExpressCompanyQueryService service = expressService;
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, expressRequest()))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("名称");
|
||||
@@ -141,23 +149,23 @@ class PlatformMasterDataManagementServiceTest {
|
||||
@Test
|
||||
@DisplayName("快递公司并发重复编码统一返回业务冲突")
|
||||
void shouldReturnBusinessConflictForConcurrentDuplicateExpressCompanyCode() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
ExpressCompanyRepository repository = expressRepository;
|
||||
doThrow(new DataIntegrityViolationException("duplicate")).when(repository).insert(any());
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
ExpressCompanyQueryService service = expressService;
|
||||
|
||||
assertThatThrownBy(() -> service.create(10001L, expressRequest()))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("编码");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司新增写入租户和请求字段() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
void shouldHandleCase09() {
|
||||
ExpressCompanyRepository repository = expressRepository;
|
||||
doAnswer(invocation -> {
|
||||
ExpressCompanyEntity entity = invocation.getArgument(0);
|
||||
entity.setId(28L);
|
||||
return null;
|
||||
}).when(repository).insert(any());
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
ExpressCompanyQueryService service = expressService;
|
||||
|
||||
assertThat(service.create(10001L, expressRequest())).isEqualTo(28L);
|
||||
|
||||
@@ -170,13 +178,13 @@ class PlatformMasterDataManagementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司编辑保留归属并更新字段() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
void shouldHandleCase10() {
|
||||
ExpressCompanyRepository repository = expressRepository;
|
||||
ExpressCompanyEntity entity = new ExpressCompanyEntity();
|
||||
entity.setId(29L);
|
||||
entity.setTenantId(10001L);
|
||||
when(repository.findOwned(10001L, 29L)).thenReturn(entity);
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
ExpressCompanyQueryService service = expressService;
|
||||
|
||||
service.update(10001L, 29L, expressRequest());
|
||||
|
||||
@@ -186,14 +194,14 @@ class PlatformMasterDataManagementServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 快递公司停用保留主数据() {
|
||||
ExpressCompanyRepository repository = mock(ExpressCompanyRepository.class);
|
||||
void shouldHandleCase11() {
|
||||
ExpressCompanyRepository repository = expressRepository;
|
||||
ExpressCompanyEntity entity = new ExpressCompanyEntity();
|
||||
entity.setId(9L);
|
||||
entity.setTenantId(10001L);
|
||||
entity.setStatus("ACTIVE");
|
||||
when(repository.findOwned(10001L, 9L)).thenReturn(entity);
|
||||
ExpressCompanyQueryService service = new ExpressCompanyQueryService(repository);
|
||||
ExpressCompanyQueryService service = expressService;
|
||||
|
||||
service.changeStatus(10001L, 9L, "INACTIVE");
|
||||
|
||||
|
||||
+9
-10
@@ -5,35 +5,34 @@ import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.warehouse.entity.WarehouseEntity;
|
||||
import com.baiyue.warehouse.repository.WarehouseRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@SpringJUnitConfig(WarehouseApplicationService.class)
|
||||
class WarehouseApplicationServiceTest {
|
||||
@MockBean private WarehouseRepository repository;
|
||||
@Resource private WarehouseApplicationService service;
|
||||
@Test
|
||||
void 商户详情只返回启用且属于租户的仓库() {
|
||||
WarehouseRepository repository=mock(WarehouseRepository.class);
|
||||
void shouldHandleCase01() {
|
||||
WarehouseEntity warehouse=new WarehouseEntity(); warehouse.setId(1L); warehouse.setTenantId(10001L); warehouse.setStatus("ACTIVE");
|
||||
when(repository.findOwned(10001,1)).thenReturn(warehouse);
|
||||
when(repository.findAddresses(10001,1)).thenReturn(java.util.List.of());
|
||||
when(repository.findCapabilities(10001,1)).thenReturn(java.util.List.of());
|
||||
WarehouseApplicationService service=new WarehouseApplicationService(); ReflectionTestUtils.setField(service,"repository",repository);
|
||||
assertThat(service.activeDetail(10001,1).warehouse()).isSameAs(warehouse);
|
||||
verify(repository).findOwned(10001,1);
|
||||
}
|
||||
@Test
|
||||
void 跨租户或不存在仓库返回404() {
|
||||
WarehouseRepository repository=mock(WarehouseRepository.class);
|
||||
WarehouseApplicationService service=new WarehouseApplicationService(); ReflectionTestUtils.setField(service,"repository",repository);
|
||||
void shouldHandleCase02() {
|
||||
assertThatThrownBy(() -> service.activeDetail(10002,1)).isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode()).isEqualTo(ResultCode.NOT_FOUND);
|
||||
}
|
||||
@Test
|
||||
void 停用仓库返回409() {
|
||||
WarehouseRepository repository=mock(WarehouseRepository.class);
|
||||
void shouldHandleCase03() {
|
||||
WarehouseEntity warehouse=new WarehouseEntity(); warehouse.setId(1L); warehouse.setTenantId(10001L); warehouse.setStatus("INACTIVE");
|
||||
when(repository.findOwned(10001,1)).thenReturn(warehouse);
|
||||
WarehouseApplicationService service=new WarehouseApplicationService(); ReflectionTestUtils.setField(service,"repository",repository);
|
||||
assertThatThrownBy(() -> service.activeDetail(10001,1)).isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode()).isEqualTo(ResultCode.CONFLICT);
|
||||
}
|
||||
|
||||
+10
-7
@@ -3,6 +3,9 @@ package com.baiyue.warehouse.service;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -12,12 +15,13 @@ import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@SpringJUnitConfig(WarehouseSchemaReadinessService.class)
|
||||
class WarehouseSchemaReadinessServiceTest {
|
||||
@MockBean private JdbcTemplate jdbcTemplate;
|
||||
@Resource private WarehouseSchemaReadinessService service;
|
||||
@Test
|
||||
void 全部表字段可查询时返回就绪() {
|
||||
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
|
||||
|
||||
var readiness = new WarehouseSchemaReadinessService(jdbcTemplate).readiness();
|
||||
void shouldHandleCase01() {
|
||||
var readiness = service.readiness();
|
||||
|
||||
assertThat(readiness.ready()).isTrue();
|
||||
assertThat(readiness.status()).isEqualTo("UP");
|
||||
@@ -28,12 +32,11 @@ class WarehouseSchemaReadinessServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void 缺表或缺列时返回降级而不是伪报正常() {
|
||||
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
|
||||
void shouldHandleCase02() {
|
||||
doThrow(new BadSqlGrammarException("probe", "SELECT", new SQLException("missing")))
|
||||
.when(jdbcTemplate).execute(anyString());
|
||||
|
||||
var readiness = new WarehouseSchemaReadinessService(jdbcTemplate).readiness();
|
||||
var readiness = service.readiness();
|
||||
|
||||
assertThat(readiness.ready()).isFalse();
|
||||
assertThat(readiness.status()).isEqualTo("DEGRADED");
|
||||
|
||||
Reference in New Issue
Block a user