package com.baiyue.lastleg.merchant; import com.baiyue.common.security.AuthenticatedUser; import com.baiyue.lastleg.inboundplan.controller.MerchantInboundPlanController; import com.baiyue.lastleg.inboundplan.dto.InboundPlanRequests; import com.baiyue.lastleg.inboundplan.service.InboundPlanService; import com.baiyue.lastleg.looseboard.controller.MerchantLocalLooseboardController; import com.baiyue.lastleg.looseboard.dto.LocalLooseboardRequests; import com.baiyue.lastleg.looseboard.service.LocalLooseboardService; import com.baiyue.lastleg.procurement.controller.MerchantOverseasProcurementController; import com.baiyue.lastleg.security.OverseasPermissions; import com.baiyue.lastleg.trucking.controller.MerchantUsTruckOrderController; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.server.ResponseStatusException; import java.util.Arrays; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) class MerchantOverseasCustomerApiContractTest { @Mock LocalLooseboardService looseboardService; @Mock InboundPlanService inboundPlanService; private MerchantLocalLooseboardController looseboard; private MerchantInboundPlanController inbound; @BeforeEach void setUp() { looseboard = new MerchantLocalLooseboardController(); inbound = new MerchantInboundPlanController(); ReflectionTestUtils.setField(looseboard, "service", looseboardService); ReflectionTestUtils.setField(inbound, "service", inboundPlanService); } @Test void merchantControllersUseFrozenPathsAndExistingClientPermissionCodes() { assertController(MerchantOverseasProcurementController.class, "/api/merchant/v1/last-leg/overseas-procurements", OverseasPermissions.MERCHANT_PROCUREMENT); assertController(MerchantUsTruckOrderController.class, "/api/merchant/v1/last-leg/us-truck-orders", OverseasPermissions.MERCHANT_TRUCKING); assertController(MerchantLocalLooseboardController.class, "/api/merchant/v1/last-leg/local-looseboard-orders", OverseasPermissions.MERCHANT_LOOSEBOARD); assertController(MerchantInboundPlanController.class, "/api/merchant/v1/last-leg/inbound-plans", OverseasPermissions.MERCHANT_INBOUND_LIST); } @Test void looseboardAndInboundQueriesUseAuthenticatedCustomerScope() { AuthenticatedUser merchant = user(101L, "MERCHANT"); LocalLooseboardRequests.MerchantQuery looseboardQuery = new LocalLooseboardRequests.MerchantQuery(1, 20, null, null, null, null, null, null); InboundPlanRequests.Query inboundQuery = new InboundPlanRequests.Query(1, 20, null, null, null, null, null, null, null, null, null, null, null, null); looseboard.page(merchant, looseboardQuery); inbound.page(merchant, inboundQuery); verify(looseboardService).page("101", looseboardQuery); verify(inboundPlanService).page("101", inboundQuery); } @Test void merchantQueryDtosDoNotAcceptCustomerScope() { for (Class type : Set.of(LocalLooseboardRequests.MerchantQuery.class, com.baiyue.lastleg.procurement.dto.OverseasProcurementRequests.MerchantQuery.class, com.baiyue.lastleg.trucking.dto.UsTruckOrderRequests.MerchantQuery.class, InboundPlanRequests.Query.class)) { assertThat(Arrays.stream(type.getRecordComponents()).map(component -> component.getName())) .doesNotContain("customerId", "warehouseId", "operatorId"); } } @Test void merchantEndpointsRejectPlatformIdentityBeforeCallingServices() { AuthenticatedUser platform = user(0L, "PLATFORM"); assertThatThrownBy(() -> looseboard.detail(platform, "LB-1")) .isInstanceOf(ResponseStatusException.class).hasMessageContaining("403"); assertThatThrownBy(() -> inbound.detail(platform, "IP-1")) .isInstanceOf(ResponseStatusException.class).hasMessageContaining("403"); } private static void assertController(Class type, String path, String permission) { assertThat(type.getAnnotation(RequestMapping.class).value()).containsExactly(path); assertThat(type.getAnnotation(PreAuthorize.class).value()) .isEqualTo("hasAuthority('" + permission + "')"); } private static AuthenticatedUser user(long customerId, String appCode) { return new AuthenticatedUser(7L, customerId, customerId, 8L, "operator", appCode, "WEB", Set.of()); } }