fix(lastleg): complete relabel document contract and regression gates
This commit is contained in:
+27
@@ -34,6 +34,33 @@ class RelabelApplicationControllerTest {
|
||||
assertThrows(ResponseStatusException.class, () -> controller.create(platform(), "0", request()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void uploadRejectsMerchantAndUnknownScopeBeforeResolvingCustomer() {
|
||||
var merchant = new AuthenticatedUser(7L, 101L, 0L, 8L, "customer", "MERCHANT", "WEB", Set.of());
|
||||
assertThrows(ResponseStatusException.class, () -> controller.uploadFile(merchant, "RL-1", "TOTAL", null, null));
|
||||
assertThrows(ResponseStatusException.class, () -> controller.uploadFile(platform(), "RL-1", "PHOTO", null, null));
|
||||
assertThrows(ResponseStatusException.class, () -> controller.uploadFile(platform(), "RL-1", "TOTAL", 22L, null));
|
||||
org.mockito.Mockito.verifyNoInteractions(service);
|
||||
}
|
||||
|
||||
@Test
|
||||
void uploadUsesCustomerResolvedFromApplication() {
|
||||
org.mockito.Mockito.when(service.customerId("RL-1")).thenReturn("101");
|
||||
var file = new org.springframework.mock.web.MockMultipartFile("file", "labels.pdf", "application/pdf", "%PDF-1.7".getBytes());
|
||||
controller.uploadFile(platform(), "RL-1", "ITEM", 22L, file);
|
||||
verify(service).uploadItemFile("101", "RL-1", 22L, 7L, file);
|
||||
}
|
||||
|
||||
@Test
|
||||
void downloadUsesOwnedBindingAndForbidsCaching() {
|
||||
org.mockito.Mockito.when(service.customerId("RL-1")).thenReturn("101");
|
||||
org.mockito.Mockito.when(service.downloadFile("101", "RL-1", "TOTAL", null, 99L))
|
||||
.thenReturn(new com.baiyue.lastleg.relabel.gateway.RelabelDocumentFileGateway.DownloadedFile("%PDF-1.7".getBytes(), "labels.pdf", "application/pdf"));
|
||||
var response = controller.downloadFile(platform(), "RL-1", 99L, "TOTAL", null);
|
||||
org.junit.jupiter.api.Assertions.assertEquals("no-store", response.getHeaders().getCacheControl());
|
||||
org.junit.jupiter.api.Assertions.assertEquals("application/pdf", response.getHeaders().getContentType().toString());
|
||||
}
|
||||
|
||||
private RelabelRequests.Create request() {
|
||||
return new RelabelRequests.Create("CUSTOMER-1", "WH-1",
|
||||
LocalDateTime.of(2026, 8, 20, 10, 0), "Li", "13800000000", null, null, "key-1",
|
||||
|
||||
+3
-1
@@ -230,7 +230,9 @@ class RelabelApplicationServiceTest {
|
||||
|
||||
service.create("10001", "operator-1", request);
|
||||
|
||||
verify(inventoryCommands, times(2)).hold(eq("10001"), eq("operator-1"), any());
|
||||
ArgumentCaptor<InventoryCommandRequests.Move> holds = ArgumentCaptor.forClass(InventoryCommandRequests.Move.class);
|
||||
verify(inventoryCommands, times(2)).hold(eq("10001"), eq("operator-1"), holds.capture());
|
||||
assertEquals(2, holds.getAllValues().stream().map(InventoryCommandRequests.Move::idempotencyKey).distinct().count());
|
||||
verify(items, times(2)).insert(any(RelabelItem.class));
|
||||
}
|
||||
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.baiyue.lastleg.relabel.service;
|
||||
|
||||
import com.baiyue.lastleg.relabel.entity.*;
|
||||
import com.baiyue.lastleg.relabel.mapper.*;
|
||||
import com.baiyue.lastleg.relabel.gateway.RelabelDocumentFileGateway;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
|
||||
class RelabelDocumentServiceTest {
|
||||
final RelabelApplicationMapper applications=mock(RelabelApplicationMapper.class);
|
||||
final RelabelItemMapper items=mock(RelabelItemMapper.class);
|
||||
final RelabelDocumentFileGateway files=mock(RelabelDocumentFileGateway.class);
|
||||
final RelabelApplicationService service=new RelabelApplicationService();
|
||||
final RelabelApplication application=new RelabelApplication();
|
||||
final MockMultipartFile pdf=new MockMultipartFile("file","labels.pdf","application/pdf","%PDF-1.7\nfixture".getBytes());
|
||||
RelabelDocumentServiceTest(){
|
||||
application.setId(11L);application.setCustomerId("101");application.setRelabelNo("RL-1");application.setStatus("PENDING_PROCESSING");
|
||||
ReflectionTestUtils.setField(service,"applications",applications);ReflectionTestUtils.setField(service,"items",items);
|
||||
ReflectionTestUtils.setField(service,"documentFiles",files);ReflectionTestUtils.setField(service,"orders",mock(LastlegOrderMapper.class));
|
||||
ReflectionTestUtils.setField(service,"histories",mock(RelabelStatusHistoryMapper.class));ReflectionTestUtils.setField(service,"objectMapper",new ObjectMapper());
|
||||
when(applications.lockNo("101","RL-1")).thenReturn(application);when(applications.findNo("101","RL-1")).thenReturn(application);
|
||||
}
|
||||
@Test void totalUploadPersistsReturnedMetadataAndExposesSummary(){
|
||||
when(files.upload("101","OVERSEAS_RELABEL_TOTAL_DOCUMENT","11",7L,pdf)).thenReturn(new RelabelDocumentFileGateway.UploadedFile(99L,"labels.pdf","application/pdf",15));
|
||||
var result=service.uploadTotalFile("101","RL-1",7L,pdf);
|
||||
assertThat(result.application().totalFileId()).isEqualTo("99");
|
||||
assertThat(result.application().totalFileName()).isEqualTo("labels.pdf");
|
||||
assertThat(result.application().totalFileUrl()).endsWith("/files/99/download?scope=TOTAL");
|
||||
verify(applications).updateById(application);
|
||||
}
|
||||
@Test void itemUploadBindsOwnCustomerApplicationAndDistinctCategory(){
|
||||
RelabelItem item=item();when(items.selectById(22L)).thenReturn(item);
|
||||
when(files.upload("101","OVERSEAS_RELABEL_ITEM_DOCUMENT","22",7L,pdf)).thenReturn(new RelabelDocumentFileGateway.UploadedFile(98L,"item.pdf","application/pdf",15));
|
||||
service.uploadItemFile("101","RL-1",22L,7L,pdf);
|
||||
assertThat(item.getRelabelFileId()).isEqualTo("98");assertThat(item.getRelabelFileUrl()).endsWith("scope=ITEM&itemId=22");
|
||||
verify(items).updateById(item);
|
||||
}
|
||||
@Test void rejectsCrossCustomerAndCrossApplicationItemsBeforeFileUpload(){
|
||||
assertThatThrownBy(()->service.uploadTotalFile("102","RL-1",7L,pdf)).isInstanceOf(ResponseStatusException.class);
|
||||
RelabelItem item=item();item.setApplicationId(12L);when(items.selectById(22L)).thenReturn(item);
|
||||
assertThatThrownBy(()->service.uploadItemFile("101","RL-1",22L,7L,pdf)).hasMessageContaining("不属于");
|
||||
item.setApplicationId(11L);item.setCustomerId("102");
|
||||
assertThatThrownBy(()->service.uploadItemFile("101","RL-1",22L,7L,pdf)).hasMessageContaining("不属于");
|
||||
verifyNoInteractions(files);
|
||||
}
|
||||
@Test void rejectsFakePdfAndTerminalChangesBeforeUpload(){
|
||||
var fake=new MockMultipartFile("file","labels.pdf","application/pdf","not pdf".getBytes());
|
||||
assertThatThrownBy(()->service.uploadTotalFile("101","RL-1",7L,fake)).hasMessageContaining("不是PDF");
|
||||
application.setStatus("COMPLETED");
|
||||
assertThatThrownBy(()->service.uploadTotalFile("101","RL-1",7L,pdf)).hasMessageContaining("不允许修改资料");
|
||||
verifyNoInteractions(files);
|
||||
}
|
||||
@Test void downloadRequiresCurrentBindingAndExactScope(){
|
||||
application.setTotalFileId("99");
|
||||
service.downloadFile("101","RL-1","TOTAL",null,99L);
|
||||
verify(files).download("101","OVERSEAS_RELABEL_TOTAL_DOCUMENT","11",99L);
|
||||
assertThatThrownBy(()->service.downloadFile("101","RL-1","TOTAL",null,98L)).hasMessageContaining("未绑定");
|
||||
assertThatThrownBy(()->service.downloadFile("101","RL-1","other",null,99L)).hasMessageContaining("资料范围");
|
||||
assertThatThrownBy(()->service.downloadFile("101","RL-1","ITEM",null,99L)).hasMessageContaining("指定明细");
|
||||
verifyNoMoreInteractions(files);
|
||||
}
|
||||
@Test void fileFailureDoesNotPersistBindings(){
|
||||
when(files.upload(anyString(),anyString(),anyString(),anyLong(),any())).thenThrow(new IllegalStateException("offline"));
|
||||
assertThatThrownBy(()->service.uploadTotalFile("101","RL-1",7L,pdf)).hasMessage("offline");
|
||||
verify(applications,never()).updateById(any(RelabelApplication.class));assertThat(application.getTotalFileId()).isNull();
|
||||
}
|
||||
private RelabelItem item(){RelabelItem item=new RelabelItem();item.setId(22L);item.setApplicationId(11L);item.setCustomerId("101");return item;}
|
||||
}
|
||||
Reference in New Issue
Block a user