优化
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package com.baiyue.file.controller;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.file.service.ProductImageService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
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.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class ProductImageControllerContractTest {
|
||||
@Test
|
||||
void merchantRouteUsesMultipartAndOrderPermissions() throws Exception {
|
||||
RequestMapping mapping = MerchantProductImageController.class.getAnnotation(RequestMapping.class);
|
||||
assertThat(mapping.value()).contains("/api/merchant/v1/files/product-images");
|
||||
var upload = MerchantProductImageController.class.getDeclaredMethod(
|
||||
"upload", AuthenticatedUser.class, org.springframework.web.multipart.MultipartFile.class);
|
||||
assertThat(upload.getAnnotation(PostMapping.class).consumes())
|
||||
.contains(MediaType.MULTIPART_FORM_DATA_VALUE);
|
||||
assertThat(upload.getAnnotation(PreAuthorize.class).value())
|
||||
.contains("merchant:order:create").contains("merchant:order:edit");
|
||||
}
|
||||
|
||||
@Test
|
||||
void merchantUploadAndDownloadAlwaysUseAuthenticatedCustomer() {
|
||||
ProductImageService service = mock(ProductImageService.class);
|
||||
MerchantProductImageController controller = new MerchantProductImageController();
|
||||
ReflectionTestUtils.setField(controller, "images", service);
|
||||
var user = merchant(10001L);
|
||||
var file = new MockMultipartFile("file", "product.png", "image/png", new byte[] {1});
|
||||
var uploaded = new ProductImageService.UploadResult(31L, "product.png", "image/png", 1L);
|
||||
when(service.upload(10001L, 2L, file)).thenReturn(uploaded);
|
||||
when(service.download(10001L, 31L)).thenReturn(
|
||||
new ProductImageService.Download("product.png", "image/png", new byte[] {1}));
|
||||
|
||||
assertThat(controller.upload(user, file).data()).isEqualTo(uploaded);
|
||||
assertThat(controller.download(user, 31L).getBody()).containsExactly(1);
|
||||
verify(service).upload(10001L, 2L, file);
|
||||
verify(service).download(10001L, 31L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void internalValidationRequiresSharedTokenAndForwardsCustomerScope() {
|
||||
ProductImageService service = mock(ProductImageService.class);
|
||||
InternalProductImageController controller = new InternalProductImageController();
|
||||
ReflectionTestUtils.setField(controller, "images", service);
|
||||
ReflectionTestUtils.setField(controller, "internalToken", "token");
|
||||
controller.initializeToken();
|
||||
var metadata = new ProductImageService.UploadResult(31L, "product.png", "image/png", 1L);
|
||||
when(service.validate(10001L, 31L)).thenReturn(metadata);
|
||||
|
||||
assertThat(controller.validate("token", 10001L, 31L).data()).isEqualTo(metadata);
|
||||
assertThatThrownBy(() -> controller.validate("wrong", 10001L, 31L))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("凭证无效");
|
||||
verify(service).validate(10001L, 31L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsPlatformOrMalformedIdentityBeforeFileAccess() {
|
||||
ProductImageService service = mock(ProductImageService.class);
|
||||
MerchantProductImageController controller = new MerchantProductImageController();
|
||||
ReflectionTestUtils.setField(controller, "images", service);
|
||||
var platform = new AuthenticatedUser(1L, 0L, 0L, 1L, "admin", "PLATFORM", "WEB", Set.of());
|
||||
var file = new MockMultipartFile("file", "product.png", "image/png", new byte[] {1});
|
||||
|
||||
assertThatThrownBy(() -> controller.upload(platform, file)).isInstanceOf(BizException.class);
|
||||
}
|
||||
|
||||
private static AuthenticatedUser merchant(long tenantId) {
|
||||
return new AuthenticatedUser(2L, tenantId, tenantId, 2L, "merchant", "MERCHANT", "WEB", Set.of());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.baiyue.file.service;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
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 javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class ProductImageStorageTest {
|
||||
@TempDir Path root;
|
||||
|
||||
@Test
|
||||
void storesValidatedImageUnderCustomerDirectoryAndReadsItBack() throws Exception {
|
||||
ProductImageStorage storage = storage();
|
||||
byte[] content = png();
|
||||
|
||||
var stored = storage.store(10001L,
|
||||
new MockMultipartFile("file", "../product.png", "image/png", content));
|
||||
|
||||
assertThat(stored.objectKey()).startsWith("product-images/10001/").endsWith(".png");
|
||||
assertThat(stored.originalName()).isEqualTo("product.png");
|
||||
assertThat(storage.read(stored.objectKey())).isEqualTo(content);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsEmptyOversizedForgedAndMismatchedFiles() throws Exception {
|
||||
ProductImageStorage storage = storage();
|
||||
assertThatThrownBy(() -> storage.store(10001L,
|
||||
new MockMultipartFile("file", "empty.png", "image/png", new byte[0])))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("不能为空");
|
||||
assertThatThrownBy(() -> storage.store(10001L,
|
||||
new MockMultipartFile("file", "large.png", "image/png", new byte[5 * 1024 * 1024 + 1])))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("5MB");
|
||||
assertThatThrownBy(() -> storage.store(10001L,
|
||||
new MockMultipartFile("file", "fake.jpg", "image/jpeg", "not-an-image".getBytes())))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("有效图片");
|
||||
assertThatThrownBy(() -> storage.store(10001L,
|
||||
new MockMultipartFile("file", "mismatch.jpg", "image/jpeg", png())))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("不一致");
|
||||
}
|
||||
|
||||
private ProductImageStorage storage() {
|
||||
ProductImageStorage storage = new ProductImageStorage();
|
||||
ReflectionTestUtils.setField(storage, "configuredRoot", root);
|
||||
storage.initializeRoot();
|
||||
return storage;
|
||||
}
|
||||
|
||||
private static byte[] png() throws Exception {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
ImageIO.write(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB), "png", output);
|
||||
return output.toByteArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user