package com.battery.business.web;
|
|
import static org.junit.jupiter.api.Assertions.*;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.sql.DriverManager;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import com.alibaba.fastjson2.JSON;
|
import com.battery.business.domain.TTestDataRevisionAction;
|
import com.battery.business.mapper.TTestMapper;
|
import com.battery.business.service.ITestConsoleDataService;
|
import com.battery.business.service.impl.TestConsoleDataServiceImpl;
|
import com.battery.business.service.impl.TTestServiceImpl;
|
import com.battery.business.service.impl.TestDataQueryServiceImpl;
|
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
|
import org.flywaydb.core.Flyway;
|
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
import org.mybatis.spring.SqlSessionFactoryBean;
|
import org.mybatis.spring.SqlSessionTemplate;
|
import org.springframework.aop.framework.ProxyFactory;
|
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
|
/** 仅在脚本提供的随机隔离库内验证真实 MySQL 迁移、事务和甲方全量样例。 */
|
@EnabledIfEnvironmentVariable(named = "WORKBOOK_TEST_SCHEMA", matches = "ticket04_import_[a-f0-9]{32}")
|
class ConsoleWorkbookImportMysqlTest
|
{
|
@Test void fullWorkbookMigrationTransactionRevisionAndWarningIsolation() throws Exception
|
{
|
String schema = System.getenv("WORKBOOK_TEST_SCHEMA");
|
String user = System.getenv("WORKBOOK_TEST_USER"), password = System.getenv("WORKBOOK_TEST_PASSWORD");
|
String base = "jdbc:mysql://127.0.0.1:6134/";
|
String options = "?useSSL=false&allowPublicKeyRetrieval=true&connectionTimeZone=UTC";
|
try (var admin = DriverManager.getConnection(base + options, user, password); var sql = admin.createStatement())
|
{
|
sql.execute("create database " + schema + " character set utf8mb4 collate utf8mb4_0900_ai_ci");
|
try
|
{
|
String url = base + schema + options;
|
var configuration = Flyway.configure().dataSource(url, user, password).locations("classpath:db/migration-final").cleanDisabled(true);
|
configuration.target("8").load().migrate();
|
var flyway = configuration.target("9").load();
|
assertEquals(1, flyway.migrate().migrationsExecuted);
|
assertEquals(0, flyway.migrate().migrationsExecuted);
|
var source = new UnpooledDataSource("com.mysql.cj.jdbc.Driver", url, user, password);
|
var jdbc = new JdbcTemplate(source);
|
jdbc.execute("insert into t_test(test_id,test_name,creator_id,principal_id,test_type_id,test_purpose,test_status,reception_status) values(1,'三 Sheet 验收',1,1,1,'隔离测试','COMPLETED','ENDED')");
|
jdbc.execute("insert into t_detection_cabinet(cabinet_id,adapter_code,cabinet_code,cabinet_name,vendor_device_type,vendor_device_id) values(1,'adapter-a','CAB1','检测柜',27,1)");
|
jdbc.execute("insert into t_detection_channel(channel_id,adapter_code,cabinet_id,devtype,devid,subdevid,chlid) values(11,'adapter-a',1,27,1,1,2)");
|
jdbc.execute("insert into t_test_battery(test_battery_id,test_id,group_id,battery_no,collector_id) values(4,1,1,'BAT-1',1)");
|
jdbc.execute("insert into t_test_channel_binding(binding_id,test_id,test_battery_id,channel_id) values(5,1,4,11)");
|
jdbc.execute("insert into t_test_warning_threshold(test_id,metric_code,max_value,unit,severity) values(1,'TEMPERATURE',1,'C','WARNING')");
|
var factory = new SqlSessionFactoryBean(); factory.setDataSource(source);
|
factory.setTypeAliasesPackage("com.battery.business.domain");
|
factory.setMapperLocations(new ClassPathResource("mapper/battery/TTestMapper.xml"));
|
var mapper = new SqlSessionTemplate(factory.getObject()).getMapper(TTestMapper.class);
|
var proxy = new ProxyFactory(new TestConsoleDataServiceImpl(mapper));
|
proxy.addAdvice(new TransactionInterceptor(new DataSourceTransactionManager(source), new AnnotationTransactionAttributeSource()));
|
var service = (ITestConsoleDataService) proxy.getProxy();
|
var controller = new TTestController() {
|
@Override public Long getUserId() { return 1L; }
|
@Override public String getUsername() { return "验收操作员"; }
|
};
|
ReflectionTestUtils.setField(controller, "consoleDataService", service);
|
var tests = new TTestServiceImpl();
|
ReflectionTestUtils.setField(tests, "testMapper", mapper);
|
ReflectionTestUtils.setField(controller, "testDataQueryService", new TestDataQueryServiceImpl(mapper, tests));
|
var sample = JSON.parseObject(Files.readString(Path.of(System.getenv("TICKET03_SAMPLE_JSON"))));
|
Map<String, List<Map<String, Object>>> sheets = new LinkedHashMap<>();
|
for (String type : List.of("REALTIME", "STEP", "CYCLE")) sheets.put(type, (List) sample.getJSONArray(type).toJavaList(Map.class));
|
// 在最后一类写入制造数据库错误,确认前两类和修订一起回滚。
|
jdbc.execute("alter table t_test_cycle_record add constraint workbook_probe_failure check (cycle_no <> 2)");
|
assertThrows(RuntimeException.class, () -> submit(controller, sheets));
|
assertTrue(mapper.selectPersistedFinalRealtimeRecords(1L).isEmpty());
|
assertTrue(mapper.selectPersistedFinalStepRecords(1L).isEmpty());
|
assertTrue(mapper.selectPersistedFinalCycleRecords(1L).isEmpty());
|
assertTrue(service.selectActions(new TTestDataRevisionAction()).isEmpty());
|
jdbc.execute("alter table t_test_cycle_record drop constraint workbook_probe_failure");
|
var imported = submit(controller, sheets);
|
assertEquals(7767, imported.get("importedCount"));
|
assertEquals(7605, mapper.selectPersistedFinalRealtimeRecords(1L).size());
|
assertEquals(129, mapper.selectPersistedFinalStepRecords(1L).size());
|
assertEquals(33, mapper.selectPersistedFinalCycleRecords(1L).size());
|
// 通过正式查询入口验证真实 JDBC 时间类型,避免内存库时间类型掩盖接口偏差。
|
var json = tools.jackson.databind.json.JsonMapper.builder().findAndAddModules().build();
|
for (var result : List.of(controller.persistedRecords(1L), controller.persistedSteps(1L), controller.persistedCycles(1L)))
|
{
|
var rows = json.readTree(json.writeValueAsString(result)).get("data");
|
for (var row : rows) for (String field : List.of("deviceTime", "recordedAt", "absoluteTime", "serverReceivedAt"))
|
{
|
var value = row.get(field);
|
if (value != null && !value.isNull()) assertTrue(value.isIntegralNumber(), field + ": " + value);
|
}
|
}
|
var firstRecord = json.readTree(json.writeValueAsString(controller.persistedRecords(1L))).get("data").get(7604);
|
assertEquals(1683517331000L, firstRecord.get("deviceTime").longValue());
|
var actions = service.selectActions(new TTestDataRevisionAction());
|
assertEquals(3, actions.size());
|
assertEquals(3, ((List<?>) imported.get("actionIds")).size());
|
for (var item : actions) {
|
var revision = service.selectActionById(item.getActionId());
|
assertEquals("三 Sheet 共用原因", revision.getReason());
|
int expected = switch (revision.getDataType()) { case "REALTIME" -> 7605; case "STEP" -> 129; default -> 33; };
|
assertEquals((long) expected, revision.getAffectedRecordCount());
|
assertNull(revision.getIdentitySummary());
|
assertNull(revision.getChangesSummary());
|
assertNull(revision.getBeforeContentJson());
|
// 页面只返回各类摘要,数据库仍保留该类全部导入明细。
|
var changes = JSON.parseArray(jdbc.queryForObject("select cast(changes_summary as char) from t_test_data_revision_action where action_id=?", String.class, revision.getActionId()));
|
assertEquals(expected, changes.size());
|
}
|
for (String type : sheets.keySet()) {
|
var query = new TTestDataRevisionAction(); query.setTestId(1L); query.setDataType(type);
|
assertEquals(1, service.selectActions(query).size());
|
}
|
var retry = submit(controller, sheets);
|
assertEquals(0, retry.get("importedCount")); assertEquals(7767, retry.get("skippedCount")); assertNull(retry.get("actionId"));
|
sheets.get("CYCLE").get(32).put("dischargeCapacity", 99);
|
assertThrows(RuntimeException.class, () -> submit(controller, sheets));
|
assertEquals(3, service.selectActions(new TTestDataRevisionAction()).size());
|
assertTrue(mapper.selectWarningExceptions(1L, null).isEmpty());
|
assertEquals("COMPLETED", mapper.selectTestById(1L).getTestStatus());
|
assertEquals("ENDED", mapper.selectTestById(1L).getReceptionStatus());
|
}
|
finally { sql.execute("drop database " + schema); }
|
}
|
}
|
|
private com.ruoyi.common.core.domain.AjaxResult submit(TTestController controller, Map<String, List<Map<String, Object>>> sheets)
|
{
|
return controller.dataAction(1L, new TTestController.ConsoleDataActionRequest("ALL", "IMPORT", "三 Sheet 导入", "[]",
|
JSON.toJSONString(sheets), "三 Sheet 共用原因", List.of()));
|
}
|
}
|