yeg
2026-09-06 561ff691ae9b58dc534ebe625d63471d040d3160
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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 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 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());
                var actions = service.selectActions(new TTestDataRevisionAction());
                assertEquals(1, actions.size());
                var revision = service.selectActionById(actions.get(0).getActionId());
                assertEquals(imported.get("actionId"), revision.getActionId());
                assertEquals("三 Sheet 共用原因", revision.getReason());
                var changes = JSON.parseArray(revision.getChangesSummary());
                assertEquals(7767, changes.size());
                assertEquals("REALTIME", changes.getJSONObject(0).getString("dataType"));
                assertEquals("STEP", changes.getJSONObject(7605).getString("dataType"));
                assertEquals("CYCLE", changes.getJSONObject(7734).getString("dataType"));
                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(1, 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()));
    }
}