feat(fleet): attach scoped evidence to measured trip records

This commit is contained in:
2026-10-03 16:38:37 +08:00
parent d05ff1cd26
commit e49ad96cc4
22 changed files with 584 additions and 27 deletions
@@ -0,0 +1,79 @@
package com.baiyue.file.service;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.file.entity.FileObjectEntity;
import com.baiyue.file.mapper.FileObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Path;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
class TripOperationEvidenceFileTest {
@TempDir Path root;
private static final String TYPE = "FLEET_TRIP_OPERATION_EVIDENCE";
@Test void platformTripOwnershipIsRequiredAndDistinctFromOtherFleetFiles() {
var category = BusinessFileCategory.require(TYPE);
category.validateOwner(0);
for (long customer : new long[]{-1, 1, 900})
assertThatThrownBy(() -> category.validateOwner(customer)).isInstanceOf(BizException.class).hasMessageContaining("平台");
assertThat(category.storageBusinessId("71")).isEqualTo("71");
for (String id : new String[]{"0", "-1", "TRIP-71", "../71"})
assertThatThrownBy(() -> category.storageBusinessId(id)).isInstanceOf(BizException.class);
assertThat(category).isNotEqualTo(BusinessFileCategory.FLEET_DRIVER_LICENSE)
.isNotEqualTo(BusinessFileCategory.FLEET_VEHICLE_RECORD_PHOTO);
}
@Test void storesPdfAndImagesAndRejectsEmptySpoofedOrOversizeContent() throws Exception {
var storage = storage();
var pdf = new MockMultipartFile("file", "里程凭证.pdf", "application/pdf", "%PDF-1.7\nmeasured".getBytes());
var png = new MockMultipartFile("file", "油表.png", "image/png", image("png"));
var jpeg = new MockMultipartFile("file", "里程.jpg", "image/jpeg", image("jpeg"));
for (var file : new MockMultipartFile[]{pdf,png,jpeg}) {
var saved = storage.store(0,"71",file,BusinessFileCategory.FLEET_TRIP_OPERATION_EVIDENCE);
assertThat(storage.read(saved.objectKey())).isEqualTo(file.getBytes());
}
for (var bad : new MockMultipartFile[]{
new MockMultipartFile("file","empty.pdf","application/pdf",new byte[0]),
new MockMultipartFile("file","fake.pdf","application/pdf","text".getBytes()),
new MockMultipartFile("file","fake.png","image/png","text".getBytes()),
new MockMultipartFile("file","notes.txt","text/plain","text".getBytes())})
assertThatThrownBy(() -> storage.store(0,"71",bad,BusinessFileCategory.FLEET_TRIP_OPERATION_EVIDENCE)).isInstanceOf(BizException.class);
MultipartFile oversized = mock(MultipartFile.class);
when(oversized.isEmpty()).thenReturn(false); when(oversized.getSize()).thenReturn(10L*1024*1024+1);
assertThatThrownBy(() -> storage.store(0,"71",oversized,BusinessFileCategory.FLEET_TRIP_OPERATION_EVIDENCE))
.isInstanceOf(BizException.class).hasMessageContaining("10MB");
verify(oversized,never()).getInputStream();
}
@Test void uploadPreservesTripScopeAndWrongOwnerOrMissingBindingNeverReadsBytes() {
var mapper = mock(FileObjectMapper.class); var storage = storage();
var service = new InternalBusinessFileService();
ReflectionTestUtils.setField(service,"files",mapper); ReflectionTestUtils.setField(service,"storage",storage);
when(mapper.insert(any(FileObjectEntity.class))).thenAnswer(call->{((FileObjectEntity)call.getArgument(0)).setId(501L);return 1;});
var upload = new MockMultipartFile("file","record.pdf","application/pdf","%PDF-1.7\nrecord".getBytes());
var metadata = service.upload(0,TYPE,"71",7,upload);
assertThat(metadata.ownerScope()).isEqualTo("PLATFORM"); assertThat(metadata.businessType()).isEqualTo(TYPE);
assertThat(metadata.businessId()).isEqualTo("71"); assertThat(metadata.fileId()).isEqualTo(501L);
assertThatThrownBy(()->service.metadata(1,TYPE,"71",501)).isInstanceOf(BizException.class).hasMessageContaining("平台");
when(mapper.selectOne(any())).thenReturn(null);
assertThatThrownBy(()->service.download(0,TYPE,"72",501)).isInstanceOf(BizException.class).hasMessageContaining("归属不匹配");
}
private BusinessFileStorage storage() {
var storage = new BusinessFileStorage(); ReflectionTestUtils.setField(storage,"configuredRoot",root);
storage.initializeRoot(); return storage;
}
private byte[] image(String format) throws java.io.IOException {
var bytes = new java.io.ByteArrayOutputStream();
var image = new java.awt.image.BufferedImage(2,2,java.awt.image.BufferedImage.TYPE_INT_RGB);
assertThat(javax.imageio.ImageIO.write(image,format,bytes)).isTrue();
return bytes.toByteArray();
}
}