因为数据库连接问题导致的插入数据库异常
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
package com.rj.integration;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.rj.dto.hxr.HxrOrderRow;
|
||||
import com.rj.dto.hxr.HxrOrderSelectResponse;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* 手动调用 hxrd 后台「订单列表」JSON 接口(需有效 PHPSID)。
|
||||
* <p>
|
||||
* 推荐:将 {@code src/test/resources/hxr-order-integration.example.properties} 复制为
|
||||
* {@code hxr-order-integration.properties},填写 {@code hxr.order.cookie} 或 {@code hxr.order.phpsid}
|
||||
* (该文件已加入 .gitignore)。
|
||||
* <p>
|
||||
* 覆盖优先级(从高到低):JVM 系统属性({@code -Dhxr.order.cookie} / {@code -Dhxr.order.phpsid})
|
||||
* > 环境变量 {@code HXR_ORDER_COOKIE} > classpath 配置文件 {@code hxr-order-integration.properties}。
|
||||
* <p>
|
||||
* 不要手动设置含 {@code br}、{@code zstd} 的 {@code Accept-Encoding}:{@link HttpClient} 只会对默认协商的编码自动解压,
|
||||
* 否则服务端可能返回 Brotli/zstd,响应体会变成乱码。
|
||||
*/
|
||||
class HxrAdminOrderSelectHttpTest {
|
||||
|
||||
private static final String CONFIG_RESOURCE = "hxr-order-integration.properties";
|
||||
|
||||
private static final String PROP_COOKIE = "hxr.order.cookie";
|
||||
private static final String PROP_PHPSID = "hxr.order.phpsid";
|
||||
private static final String ENV_COOKIE = "HXR_ORDER_COOKIE";
|
||||
|
||||
private static final String BASE_URL = "https://hxrdhoutai.hxrdsm.cn/app/admin/order/select";
|
||||
|
||||
private static final String QUERY =
|
||||
"?page=1&limit=20"
|
||||
+ "&order_sn%5B0%5D=like&order_sn%5B1%5D="
|
||||
+ "&seller_id=&buyer_id=&status=&is_resell=0&is_show="
|
||||
+ "&buy_time%5B0%5D=&buy_time%5B1%5D=&confirm_time%5B0%5D=&confirm_time%5B1%5D=";
|
||||
|
||||
private static volatile Properties integrationProps;
|
||||
|
||||
private static final ObjectMapper HXR_ORDER_JSON = new ObjectMapper()
|
||||
.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
|
||||
@Test
|
||||
void getOrderSelectJson() throws Exception {
|
||||
String cookie = resolveCookie();
|
||||
Assumptions.assumeFalse(
|
||||
cookie == null || cookie.isBlank(),
|
||||
"跳过:请在 src/test/resources/ 下复制 "
|
||||
+ "hxr-order-integration.example.properties 为 "
|
||||
+ CONFIG_RESOURCE
|
||||
+ " 并填写 hxr.order.cookie 或 hxr.order.phpsid;或设置环境变量 "
|
||||
+ ENV_COOKIE
|
||||
+ " / VM 选项 -D"
|
||||
+ PROP_COOKIE
|
||||
+ " / -D"
|
||||
+ PROP_PHPSID);
|
||||
|
||||
HttpClient client = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(15))
|
||||
.followRedirects(HttpClient.Redirect.NORMAL)
|
||||
.build();
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(BASE_URL + QUERY))
|
||||
.timeout(Duration.ofSeconds(60))
|
||||
.header("Accept", "application/json, text/javascript, */*; q=0.01")
|
||||
.header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
|
||||
.header("Cookie", cookie)
|
||||
.header("Priority", "u=1, i")
|
||||
.header("Referer", "https://hxrdhoutai.hxrdsm.cn/app/admin/order/index")
|
||||
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0")
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
System.out.println("HTTP " + response.statusCode());
|
||||
assertTrue(
|
||||
response.statusCode() >= 200 && response.statusCode() < 300,
|
||||
"unexpected status: " + response.statusCode());
|
||||
|
||||
HxrOrderSelectResponse body = HXR_ORDER_JSON.readValue(response.body(), HxrOrderSelectResponse.class);
|
||||
assertEquals(0, body.code(), () -> "api code != 0, msg=" + body.msg() + ", body=" + response.body());
|
||||
for (HxrOrderRow row : body.data()) {
|
||||
System.out.println(HXR_ORDER_JSON.writeValueAsString(row));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void parseSampleJson_printsOneLinePerOrder() throws Exception {
|
||||
String json =
|
||||
"""
|
||||
{"code":0,"msg":"ok","count":7,"data":[{"id":358078,"old_id":null,"seller_id":97154,"buyer_id":97374,"order_sn":"47379117788104684482","total_money":"23423.95","pay_time":"2026-05-15 10:04:32","pay_img":"\\/upload\\/image\\/20260515\\/ec791c7a9ed2f5ade9450c0f50efd819_6a067f2f9317d.jpeg","status":2,"is_resell":0,"is_show":1,"consignee":"陈科亦","phone":"18810005315","province":"河北省","city":"廊坊市","area":"三河市","address":"燕郊开发区金谷爱舒荷","merchandise_id":344196,"confirm_time":"2026-05-15 10:08:04","buy_time":"2026-05-15 10:01:08","created_at":"2026-05-15 10:01:08","updated_at":"2026-05-15 10:08:04"},{"id":357968,"old_id":null,"seller_id":98719,"buyer_id":96030,"order_sn":"03069117788104035736","total_money":"27037.65","pay_time":"2026-05-15 10:02:48","pay_img":"\\/upload\\/image\\/20260515\\/37d6d7d09447d6c8ce41abd0727a39d5_6a067ec77a519.jpeg","status":1,"is_resell":0,"is_show":1,"consignee":"陈晓琴","phone":"17733627528","province":"河北省","city":"廊坊市","area":"三河市","address":"燕郊镇金谷爰舒荷十号楼","merchandise_id":344269,"confirm_time":null,"buy_time":"2026-05-15 10:00:03","created_at":"2026-05-15 10:00:03","updated_at":"2026-05-15 10:02:48"}],"all_money":"182851.70"}
|
||||
""";
|
||||
HxrOrderSelectResponse body = HXR_ORDER_JSON.readValue(json.trim(), HxrOrderSelectResponse.class);
|
||||
assertEquals(0, body.code());
|
||||
assertEquals(2, body.data().size());
|
||||
for (HxrOrderRow row : body.data()) {
|
||||
System.out.println(HXR_ORDER_JSON.writeValueAsString(row));
|
||||
}
|
||||
}
|
||||
|
||||
private static String resolveCookie() {
|
||||
String fromFileCookie = firstNonBlank(integrationProps().getProperty(PROP_COOKIE));
|
||||
String fromFilePhpsid = firstNonBlank(integrationProps().getProperty(PROP_PHPSID));
|
||||
|
||||
String fromProp = firstNonBlank(System.getProperty(PROP_COOKIE));
|
||||
String phpsidProp = firstNonBlank(System.getProperty(PROP_PHPSID));
|
||||
String fromEnv = firstNonBlank(System.getenv(ENV_COOKIE));
|
||||
|
||||
if (fromProp != null) {
|
||||
return fromProp;
|
||||
}
|
||||
if (phpsidProp != null) {
|
||||
return "PHPSID=" + phpsidProp;
|
||||
}
|
||||
if (fromEnv != null) {
|
||||
return fromEnv;
|
||||
}
|
||||
if (fromFileCookie != null) {
|
||||
return fromFileCookie;
|
||||
}
|
||||
if (fromFilePhpsid != null) {
|
||||
return "PHPSID=" + fromFilePhpsid;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String firstNonBlank(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
String t = s.trim();
|
||||
return t.isEmpty() ? null : t;
|
||||
}
|
||||
|
||||
private static Properties integrationProps() {
|
||||
if (integrationProps != null) {
|
||||
return integrationProps;
|
||||
}
|
||||
synchronized (HxrAdminOrderSelectHttpTest.class) {
|
||||
if (integrationProps != null) {
|
||||
return integrationProps;
|
||||
}
|
||||
Properties p = new Properties();
|
||||
try (InputStream in =
|
||||
HxrAdminOrderSelectHttpTest.class.getClassLoader().getResourceAsStream(CONFIG_RESOURCE)) {
|
||||
if (in != null) {
|
||||
try (InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
|
||||
p.load(reader);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
integrationProps = p;
|
||||
return integrationProps;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.rj.scheduler;
|
||||
|
||||
import com.rj.service.HxrAdminOrderSelectService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* {@link LBAdminPullScheduler#pullAdminOrders()} 集成测试:全量 Spring 上下文 + {@link LBAdminPullSchedulerTestClockConfiguration},
|
||||
* HTTP 拉单由 {@link MockitoBean} 替身,避免外网与真实 Cookie。
|
||||
*
|
||||
* <p>另见:{@link LBAdminPullSchedulerWhenHxrDisabledIntegrationTest}、{@link LBAdminPullSchedulerWhenGlobalSchedulerOffIntegrationTest}。
|
||||
*/
|
||||
@SpringBootTest
|
||||
@TestPropertySource(
|
||||
properties = {
|
||||
"spring.task.scheduling.enabled=false",
|
||||
"hxr.admin.pull-initial-delay-ms=604800000",
|
||||
"app.scheduler.start=true",
|
||||
"hxr.admin.enabled=true",
|
||||
"app.timezone=Asia/Shanghai"
|
||||
})
|
||||
@Import(LBAdminPullSchedulerTestClockConfiguration.class)
|
||||
@ActiveProfiles("test")
|
||||
class LBAdminPullSchedulerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private LBAdminPullScheduler lbAdminPullScheduler;
|
||||
|
||||
@Autowired
|
||||
private LBAdminPullSchedulerTestClockConfiguration.MutableClock mutableClock;
|
||||
|
||||
@MockitoBean
|
||||
private HxrAdminOrderSelectService hxrAdminOrderSelectService;
|
||||
|
||||
@BeforeEach
|
||||
void resetInvocationHistory() {
|
||||
Mockito.clearInvocations(hxrAdminOrderSelectService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void pullAdminOrders_eveningWindow_invokesOrderSelectService() throws Exception {
|
||||
mutableClock.setTo(
|
||||
ZonedDateTime.of(LocalDate.of(2026, 5, 15), LocalTime.of(20, 0), ZoneId.of("Asia/Shanghai")));
|
||||
|
||||
lbAdminPullScheduler.pullAdminOrders();
|
||||
|
||||
verify(hxrAdminOrderSelectService).fetchAndLogEachOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
void pullAdminOrders_exactly1810_invokesOrderSelectService() throws Exception {
|
||||
mutableClock.setTo(
|
||||
ZonedDateTime.of(LocalDate.of(2026, 5, 15), LocalTime.of(18, 10), ZoneId.of("Asia/Shanghai")));
|
||||
|
||||
lbAdminPullScheduler.pullAdminOrders();
|
||||
|
||||
verify(hxrAdminOrderSelectService).fetchAndLogEachOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
void pullAdminOrders_beforeWindow_doesNotInvoke() throws Exception {
|
||||
mutableClock.setTo(
|
||||
ZonedDateTime.of(LocalDate.of(2026, 5, 15), LocalTime.of(12, 0), ZoneId.of("Asia/Shanghai")));
|
||||
|
||||
lbAdminPullScheduler.pullAdminOrders();
|
||||
|
||||
verify(hxrAdminOrderSelectService, never()).fetchAndLogEachOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
void pullAdminOrders_saturdayEveningInTimeWindow_doesNotInvoke() throws Exception {
|
||||
mutableClock.setTo(
|
||||
ZonedDateTime.of(LocalDate.of(2026, 5, 16), LocalTime.of(20, 0), ZoneId.of("Asia/Shanghai")));
|
||||
|
||||
lbAdminPullScheduler.pullAdminOrders();
|
||||
|
||||
verify(hxrAdminOrderSelectService, never()).fetchAndLogEachOrder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.rj.scheduler;
|
||||
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
/**
|
||||
* 为 {@link LBAdminPullScheduler} 集成测试提供可拨 {@link Clock}({@link MutableClock})。
|
||||
*/
|
||||
@TestConfiguration
|
||||
public class LBAdminPullSchedulerTestClockConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
MutableClock lbAdminPullTestMutableClock() {
|
||||
return new MutableClock();
|
||||
}
|
||||
|
||||
/** 测试中可切换时刻的 {@link Clock},用于固定 18:10~23:59 时间窗口。 */
|
||||
public static final class MutableClock extends Clock {
|
||||
|
||||
private volatile Clock delegate = Clock.systemDefaultZone();
|
||||
|
||||
public void setTo(ZonedDateTime zdt) {
|
||||
delegate = Clock.fixed(zdt.toInstant(), zdt.getZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZoneId getZone() {
|
||||
return delegate.getZone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clock withZone(ZoneId zone) {
|
||||
return delegate.withZone(zone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant instant() {
|
||||
return delegate.instant();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.rj.scheduler;
|
||||
|
||||
import com.rj.service.HxrAdminOrderSelectService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@SpringBootTest
|
||||
@TestPropertySource(
|
||||
properties = {
|
||||
"spring.task.scheduling.enabled=false",
|
||||
"hxr.admin.pull-initial-delay-ms=604800000",
|
||||
"app.scheduler.start=false",
|
||||
"hxr.admin.enabled=true",
|
||||
"app.timezone=Asia/Shanghai"
|
||||
})
|
||||
@Import(LBAdminPullSchedulerTestClockConfiguration.class)
|
||||
@ActiveProfiles("test")
|
||||
class LBAdminPullSchedulerWhenGlobalSchedulerOffIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private LBAdminPullScheduler lbAdminPullScheduler;
|
||||
|
||||
@Autowired
|
||||
private LBAdminPullSchedulerTestClockConfiguration.MutableClock mutableClock;
|
||||
|
||||
@MockitoBean
|
||||
private HxrAdminOrderSelectService hxrAdminOrderSelectService;
|
||||
|
||||
@Test
|
||||
void pullAdminOrders_skipsWhenAppSchedulerStartFalse() throws Exception {
|
||||
mutableClock.setTo(
|
||||
ZonedDateTime.of(LocalDate.of(2026, 5, 15), LocalTime.of(20, 0), ZoneId.of("Asia/Shanghai")));
|
||||
|
||||
lbAdminPullScheduler.pullAdminOrders();
|
||||
|
||||
verify(hxrAdminOrderSelectService, never()).fetchAndLogEachOrder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.rj.scheduler;
|
||||
|
||||
import com.rj.service.HxrAdminOrderSelectService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@SpringBootTest
|
||||
@TestPropertySource(
|
||||
properties = {
|
||||
"spring.task.scheduling.enabled=false",
|
||||
"hxr.admin.pull-initial-delay-ms=604800000",
|
||||
"app.scheduler.start=true",
|
||||
"hxr.admin.enabled=false",
|
||||
"app.timezone=Asia/Shanghai"
|
||||
})
|
||||
@Import(LBAdminPullSchedulerTestClockConfiguration.class)
|
||||
@ActiveProfiles("test")
|
||||
class LBAdminPullSchedulerWhenHxrDisabledIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private LBAdminPullScheduler lbAdminPullScheduler;
|
||||
|
||||
@Autowired
|
||||
private LBAdminPullSchedulerTestClockConfiguration.MutableClock mutableClock;
|
||||
|
||||
@MockitoBean
|
||||
private HxrAdminOrderSelectService hxrAdminOrderSelectService;
|
||||
|
||||
@Test
|
||||
void pullAdminOrders_eveningWindow_stillSkips() throws Exception {
|
||||
mutableClock.setTo(
|
||||
ZonedDateTime.of(LocalDate.of(2026, 5, 15), LocalTime.of(20, 0), ZoneId.of("Asia/Shanghai")));
|
||||
|
||||
lbAdminPullScheduler.pullAdminOrders();
|
||||
|
||||
verify(hxrAdminOrderSelectService, never()).fetchAndLogEachOrder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# 复制本文件为 hxr-order-integration.properties 后填写(后者已加入 .gitignore,勿提交真实 Cookie)
|
||||
# 二选一:
|
||||
# hxr.order.cookie=PHPSID=你的会话值
|
||||
# hxr.order.phpsid=仅填PHPSID的值(不含 PHPSID= 前缀)
|
||||
|
||||
hxr.order.cookie=
|
||||
# hxr.order.phpsid=
|
||||
Reference in New Issue
Block a user