package com.baiyue.lastleg.looseboard; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; import com.baiyue.lastleg.looseboard.entity.LocalLooseboardOrder; import com.baiyue.lastleg.looseboard.mapper.*; import org.junit.jupiter.api.Test; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.UUID; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; class LocalLooseboardPersistenceTest { /** 使用模块基线和真实 Mapper 验证四项联系人、取送时间保存回读、更新及客户隔离。 */ @Test void contactsAndLocalMinuteTimesRoundTripThroughActualMapper() throws Exception { var ds = new DriverManagerDataSource("jdbc:h2:mem:" + UUID.randomUUID() + ";MODE=MySQL;DB_CLOSE_DELAY=-1", "sa", ""); String baseline; try (var input = getClass().getResourceAsStream("/db/lastleg.sql")) { baseline = new String(input.readAllBytes(), StandardCharsets.UTF_8); } int start = baseline.indexOf("CREATE TABLE IF NOT EXISTS ll_local_looseboard_order ("); String ddl = baseline.substring(start, baseline.indexOf(';', start)); // H2 使用真实字段定义,去掉 MySQL 专属的索引和表选项。 ddl = ddl.replaceAll("(?m)^\\s*(?:UNIQUE KEY|KEY) [^\\n]*\\n?", ""); ddl = ddl.substring(0, ddl.indexOf(") ENGINE=")) + ")"; ddl = ddl.replaceAll(",\\s*\\)$", ")"); new JdbcTemplate(ds).execute(ddl); var config = new MybatisConfiguration(); config.setMapUnderscoreToCamelCase(true); config.addMapper(LocalLooseboardOrderMapper.class); var factory = new MybatisSqlSessionFactoryBean(); factory.setDataSource(ds); factory.setConfiguration(config); var mapper = new SqlSessionTemplate(factory.getObject()).getMapper(LocalLooseboardOrderMapper.class); var repository = new com.baiyue.lastleg.looseboard.repository.LocalLooseboardRepository(); org.springframework.test.util.ReflectionTestUtils.setField(repository, "orders", mapper); var order = new LocalLooseboardOrder(); order.setId(1L); order.setCustomerId("C-1"); order.setOrderNo("TRUCK-TEST-1"); order.setOrigin("Los Angeles"); order.setDestination("Ontario"); order.setOriginContactName("发货人"); order.setOriginContactPhone("+1 (555) 0100"); order.setDestinationContactName("收货人"); order.setDestinationContactPhone("+1-555-0101"); order.setPickupAt(LocalDateTime.of(2026, 10, 20, 9, 30)); order.setDeliveryAt(LocalDateTime.of(2026, 10, 20, 15, 45)); order.setTotalWeightKg(BigDecimal.ZERO); order.setTotalVolumeCbm(BigDecimal.ZERO); order.setCurrency("USD"); order.setStatus("PENDING_ACCEPTANCE"); order.setIdempotencyKey("roundtrip"); order.setRequestHash("0".repeat(64)); repository.insertOrder(order); var saved = repository.findNo("C-1", order.getOrderNo()); assertEquals("发货人", saved.getOriginContactName()); assertEquals("+1 (555) 0100", saved.getOriginContactPhone()); assertEquals("收货人", saved.getDestinationContactName()); assertEquals("+1-555-0101", saved.getDestinationContactPhone()); assertEquals(order.getPickupAt(), saved.getPickupAt()); assertEquals(order.getDeliveryAt(), saved.getDeliveryAt()); assertNull(repository.findNo("C-2", order.getOrderNo())); assertNull(repository.findKey("C-2", "roundtrip")); saved.setDestinationContactPhone("+1-555-0102"); saved.setDeliveryAt(saved.getDeliveryAt().plusMinutes(15)); repository.updateOrder(saved); var updated = repository.findKey("C-1", "roundtrip"); assertEquals("+1-555-0102", updated.getDestinationContactPhone()); assertEquals(LocalDateTime.of(2026, 10, 20, 16, 0), updated.getDeliveryAt()); } }