更新这个货源
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
package com.nanri.aiimage.modules.similarasin.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
class SimilarAsinImageEmbedderTest {
|
||||
|
||||
private final SimilarAsinImageEmbedder embedder = new SimilarAsinImageEmbedder();
|
||||
|
||||
@Test
|
||||
void resizeImageProducesThumbnailUnderHardCap() throws Exception {
|
||||
BufferedImage src = new BufferedImage(1200, 1600, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g = src.createGraphics();
|
||||
try {
|
||||
g.setColor(new Color(0x33, 0x66, 0x99));
|
||||
g.fillRect(0, 0, 1200, 1600);
|
||||
} finally {
|
||||
g.dispose();
|
||||
}
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageIO.write(src, "jpg", baos);
|
||||
|
||||
byte[] thumb = embedder.resizeImage("https://example.com/big.jpg", baos.toByteArray());
|
||||
|
||||
assertNotNull(thumb);
|
||||
assertTrue(thumb.length > 0, "thumb 不可为空");
|
||||
assertTrue(thumb.length <= SimilarAsinImageEmbedder.MAX_THUMB_SIZE_BYTES,
|
||||
"thumb 字节应 <= 40KB 上限,实际=" + thumb.length);
|
||||
|
||||
BufferedImage decoded = ImageIO.read(new java.io.ByteArrayInputStream(thumb));
|
||||
assertNotNull(decoded, "thumb 应可被 ImageIO 重新解码");
|
||||
int longEdge = Math.max(decoded.getWidth(), decoded.getHeight());
|
||||
assertEquals(SimilarAsinImageEmbedder.TARGET_LONG_EDGE_PX, longEdge,
|
||||
"长边应等于 TARGET_LONG_EDGE_PX=300");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resizeOversizeExceptionCarriesUrlAndSize() {
|
||||
SimilarAsinImageEmbedder.ResizeOversizeException ex =
|
||||
new SimilarAsinImageEmbedder.ResizeOversizeException("https://example.com/huge.jpg", 99999);
|
||||
assertEquals("https://example.com/huge.jpg", ex.url());
|
||||
assertEquals(99999, ex.size());
|
||||
assertTrue(ex.getMessage().contains("oversize"));
|
||||
assertTrue(ex.getMessage().contains("99999"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void resizeUnsupportedFormatThrowsIOException() {
|
||||
byte[] notAnImage = "not an image at all, just some bytes".getBytes();
|
||||
Exception ex = assertThrows(Exception.class,
|
||||
() -> embedder.resizeImage("https://example.com/broken.bin", notAnImage));
|
||||
assertTrue(ex instanceof java.io.IOException || ex instanceof RuntimeException,
|
||||
"应为 IOException 或 RuntimeException 兜底,实际=" + ex.getClass().getSimpleName());
|
||||
assertTrue(ex.getMessage() == null
|
||||
|| ex.getMessage().toLowerCase().contains("unsupported")
|
||||
|| ex.getMessage().toLowerCase().contains("unable"),
|
||||
"异常消息应反映不支持/无法解析");
|
||||
}
|
||||
|
||||
@Test
|
||||
void safeDnsRejectsPrivateIpsOnLookup() {
|
||||
SimilarAsinImageEmbedder.SafeDns safeDns = new SimilarAsinImageEmbedder.SafeDns(
|
||||
hostname -> Collections.singletonList(InetAddress.getByName("127.0.0.1")));
|
||||
UnknownHostException ex = assertThrows(UnknownHostException.class,
|
||||
() -> safeDns.lookup("rebound.example.com"));
|
||||
assertTrue(ex.getMessage().contains("blocked private/loopback ip"),
|
||||
"异常消息应说明被阻断,实际=" + ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void safeDnsAllowsPublicIpResolution() throws Exception {
|
||||
SimilarAsinImageEmbedder.SafeDns safeDns = new SimilarAsinImageEmbedder.SafeDns(
|
||||
hostname -> Collections.singletonList(InetAddress.getByName("8.8.8.8")));
|
||||
List<InetAddress> result = safeDns.lookup("dns.google");
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("8.8.8.8", result.get(0).getHostAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
void safeDnsRejectsMixedResultsContainingPrivateIp() {
|
||||
SimilarAsinImageEmbedder.SafeDns safeDns = new SimilarAsinImageEmbedder.SafeDns(
|
||||
hostname -> List.of(
|
||||
InetAddress.getByName("8.8.8.8"),
|
||||
InetAddress.getByName("10.0.0.5")));
|
||||
// 任一结果落入私网即整体阻断,关闭 DNS rebinding 通道
|
||||
assertThrows(UnknownHostException.class,
|
||||
() -> safeDns.lookup("partial-rebound.example.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isPrivateIpCoversCgnatAndStandardRanges() throws Exception {
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("127.0.0.1")), "loopback");
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("10.0.0.1")), "10/8");
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("192.168.1.1")), "192.168/16");
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("169.254.0.1")), "link-local");
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("172.16.0.1")), "site-local 172.16");
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("100.64.0.1")), "CGNAT lower");
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("100.127.255.255")), "CGNAT upper");
|
||||
assertFalse(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("8.8.8.8")), "public DNS");
|
||||
assertFalse(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("100.63.0.1")), "below CGNAT 段");
|
||||
assertFalse(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("100.128.0.1")), "above CGNAT 段");
|
||||
// 受限广播
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("255.255.255.255")), "受限广播");
|
||||
// IPv6 ULA fc00::/7
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("fc00::1")), "ULA fc00::");
|
||||
assertTrue(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("fd12:3456:789a::1")), "ULA fd::");
|
||||
// IPv6 公网放行
|
||||
assertFalse(SimilarAsinImageEmbedder.isPrivateIp(InetAddress.getByName("2001:4860:4860::8888")), "Google IPv6 DNS");
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateHttpsUrlRejectsHttpAndPrivateHosts() {
|
||||
assertThrows(SimilarAsinImageEmbedder.UnsupportedUrlException.class,
|
||||
() -> SimilarAsinImageEmbedder.validateHttpsUrl("http://example.com/a.jpg"));
|
||||
assertThrows(SimilarAsinImageEmbedder.UnsupportedUrlException.class,
|
||||
() -> SimilarAsinImageEmbedder.validateHttpsUrl("https://localhost/a.jpg"));
|
||||
assertThrows(SimilarAsinImageEmbedder.UnsupportedUrlException.class,
|
||||
() -> SimilarAsinImageEmbedder.validateHttpsUrl("https://127.0.0.1/a.jpg"));
|
||||
assertThrows(SimilarAsinImageEmbedder.UnsupportedUrlException.class,
|
||||
() -> SimilarAsinImageEmbedder.validateHttpsUrl("https://10.0.0.5/a.jpg"));
|
||||
assertThrows(SimilarAsinImageEmbedder.UnsupportedUrlException.class,
|
||||
() -> SimilarAsinImageEmbedder.validateHttpsUrl("https://192.168.1.1/a.jpg"));
|
||||
assertThrows(SimilarAsinImageEmbedder.UnsupportedUrlException.class,
|
||||
() -> SimilarAsinImageEmbedder.validateHttpsUrl("https://172.16.0.1/a.jpg"));
|
||||
// 公网 https 应通过
|
||||
SimilarAsinImageEmbedder.validateHttpsUrl("https://m.media-amazon.com/images/I/abc.jpg");
|
||||
SimilarAsinImageEmbedder.validateHttpsUrl("https://cbu01.alicdn.com/img/ibank/xxx.jpg");
|
||||
}
|
||||
|
||||
@Test
|
||||
void downloadOversizeExceptionCarriesUrlAndSize() {
|
||||
SimilarAsinImageEmbedder.DownloadOversizeException ex =
|
||||
new SimilarAsinImageEmbedder.DownloadOversizeException("https://example.com/big.jpg", 12345678L);
|
||||
assertEquals("https://example.com/big.jpg", ex.url());
|
||||
assertEquals(12345678L, ex.size());
|
||||
assertTrue(ex.getMessage().contains("oversize"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user