package com.battery.business.web;
|
|
import static org.junit.jupiter.api.Assertions.*;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.LinkedHashMap;
|
import java.util.UUID;
|
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.mybatis.spring.SqlSessionFactoryBean;
|
import org.mybatis.spring.SqlSessionTemplate;
|
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.Test;
|
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.transaction.annotation.AnnotationTransactionAttributeSource;
|
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
import org.springframework.test.util.ReflectionTestUtils;
|
|
/** 使用生产 Mapper 和 Spring 事务验证导入;内存数据库不连接共享开发库。 */
|
public class ConsoleSingleSheetImportDatabaseTest
|
{
|
private java.sql.Connection keepAlive;
|
private TTestController controller;
|
private TTestMapper mapper;
|
private ITestConsoleDataService service;
|
private JdbcTemplate jdbc;
|
|
@BeforeEach void setUp() throws Exception
|
{
|
var source = new UnpooledDataSource("org.h2.Driver", "jdbc:h2:mem:" + UUID.randomUUID() + ";MODE=MySQL;DATABASE_TO_LOWER=TRUE", "sa", "");
|
keepAlive = source.getConnection();
|
jdbc = new JdbcTemplate(source);
|
// H2 无 MySQL JSON_LENGTH;仅在测试中适配计数,真实 SQL 另在 MySQL 验证。
|
jdbc.execute("create alias JSON_LENGTH for 'com.battery.business.web.ConsoleSingleSheetImportDatabaseTest.jsonLength'");
|
jdbc.execute("create table sys_user(user_id bigint, nick_name varchar(64), del_flag varchar(1))");
|
jdbc.execute("create table t_test_type(test_type_id bigint, test_type_name varchar(64), del_flag int)");
|
jdbc.execute("create table t_test(test_id bigint primary key, test_name varchar(100), creator_id bigint, principal_id bigint, test_type_id bigint, test_purpose varchar(100), test_status varchar(20), reception_status varchar(20), monitor_timeout_minutes int, started_at_utc timestamp, reception_boundary_at_utc timestamp, ended_at_utc timestamp, del_flag int default 0, create_by varchar(64), create_time timestamp, update_by varchar(64), update_time timestamp, remark varchar(100), logic_step_mappings_json varchar(100), console_detail_json varchar(100))");
|
jdbc.execute("insert into t_test(test_id,test_name,test_status,reception_status) values(1,'导入测试','COMPLETED','ENDED')");
|
jdbc.execute("create table t_test_battery(test_battery_id bigint primary key, test_id bigint, battery_no varchar(100), del_flag int default 0)");
|
jdbc.execute("insert into t_test_battery values(4,1,'BAT-1',0)");
|
jdbc.execute("create table t_test_channel_binding(binding_id bigint, test_battery_id bigint, channel_id bigint)");
|
jdbc.execute("insert into t_test_channel_binding values(5,4,11)");
|
jdbc.execute("create table t_detection_channel(channel_id bigint, cabinet_id bigint, devtype int, devid int, subdevid int, chlid int)");
|
jdbc.execute("insert into t_detection_channel values(11,1,27,1,1,2)");
|
jdbc.execute("create table t_detection_cabinet(cabinet_id bigint, adapter_code varchar(64))");
|
jdbc.execute("insert into t_detection_cabinet values(1,'adapter-a')");
|
jdbc.execute("create table t_test_data_revision_action(action_id bigint auto_increment primary key, test_id bigint, data_type varchar(20), operation_type varchar(20), scope_summary varchar(200), identity_summary json, before_content_json json, changes_summary json, reason varchar(200), operator_id bigint, operator_name varchar(64), created_at_utc timestamp)");
|
jdbc.execute("alter table t_test_data_revision_action add constraint chk_data_revision_type check (data_type in ('REALTIME','STEP','CYCLE'))");
|
org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(keepAlive,
|
new ClassPathResource("db/migration-final/V9__workbook_import_revision.sql"));
|
String common = "test_id bigint not null, test_battery_id bigint not null, binding_id bigint not null, adapter_code varchar(64) not null, source_identity varchar(256) not null, source_record_id varchar(128), server_received_at_utc timestamp(3), cycle_no int, content_sha256 binary(32) not null, extension_measurements_json varchar(2000)";
|
String metrics = "step_no int, step_name varchar(191), step_type varchar(64), voltage_v decimal(30,12), current_a decimal(30,12), capacity_ah decimal(30,12), energy_wh decimal(30,12) check (energy_wh <> 999)";
|
jdbc.execute("create table t_test_realtime_record(record_id bigint auto_increment primary key," + common + "," + metrics + ", cabinet_devtype int, cabinet_devid int, cabinet_subdevid int, cabinet_chlid int, cabinet_sequence_id bigint, cabinet_device_time_utc timestamp(3), cabinet_device_time_raw varchar(64), cabinet_adapter_timezone_id varchar(64), capture_slot_utc timestamp(3) not null, temperature decimal(30,12), positive_potential decimal(30,12), negative_potential decimal(30,12), collector_id bigint, collector_channel_code varchar(100), collector_device_time_utc timestamp(3), unique(test_id,test_battery_id,capture_slot_utc))");
|
// 从 V7 的非空槽位起点执行生产迁移,覆盖存量库升级路径。
|
org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(keepAlive,
|
new ClassPathResource("db/migration-final/V8__import_records_without_polling_slots.sql"));
|
String deviceTime = "dedupe_key varchar(512) not null, device_time_utc timestamp(3) not null, device_time_raw varchar(64) not null, adapter_timezone_id varchar(64) not null, unique(test_battery_id,source_identity,dedupe_key)";
|
jdbc.execute("create table t_test_step_record(step_record_id bigint auto_increment primary key," + common + "," + metrics + "," + deviceTime + ")");
|
jdbc.execute("create table t_test_cycle_record(cycle_record_id bigint auto_increment primary key," + common + ",charge_capacity_ah decimal(30,12),discharge_capacity_ah decimal(30,12),charge_energy_wh decimal(30,12),discharge_energy_wh decimal(30,12),efficiency decimal(30,12)," + deviceTime + ")");
|
var factory = new SqlSessionFactoryBean(); factory.setDataSource(source);
|
factory.setTypeAliasesPackage("com.battery.business.domain");
|
factory.setMapperLocations(new ClassPathResource("mapper/battery/TTestMapper.xml"));
|
mapper = new SqlSessionTemplate(factory.getObject()).getMapper(TTestMapper.class);
|
var proxy = new ProxyFactory(new TestConsoleDataServiceImpl(mapper));
|
proxy.addAdvice(new TransactionInterceptor(new DataSourceTransactionManager(source), new AnnotationTransactionAttributeSource()));
|
service = (ITestConsoleDataService) proxy.getProxy();
|
controller = new TTestController() {
|
@Override public Long getUserId() { return 1L; }
|
@Override public String getUsername() { return "tester"; }
|
};
|
ReflectionTestUtils.setField(controller, "consoleDataService", service);
|
}
|
|
@AfterEach void closeDatabase() throws Exception { if (keepAlive != null) keepAlive.close(); }
|
|
/** 模拟 JSON 数组长度;H2 的 JSON 参数可能多包一层字符串。 */
|
public static Integer jsonLength(String value)
|
{
|
if (value == null) return null;
|
Object parsed = JSON.parse(value);
|
if (parsed instanceof String text) parsed = JSON.parse(text);
|
return parsed instanceof List<?> rows ? rows.size() : 1;
|
}
|
|
@Test void threeTypesPersistActualBindingsTimesAndNumbersAndSkipRetries()
|
{
|
for (String type : List.of("REALTIME", "STEP", "CYCLE"))
|
{
|
assertEquals(1, submit(type, List.of(row())).get("importedCount"));
|
assertEquals(1, submit(type, List.of(row())).get("skippedCount"));
|
var records = mapper.selectImportDataRecords(1L, type);
|
assertEquals(1, records.size());
|
assertEquals("17", records.get(0).get("source_record_id"));
|
assertEquals("adapter-a:27:1:1:2", records.get(0).get("source_identity"));
|
String timeColumn = type.equals("REALTIME") ? "cabinet_device_time_raw" : "device_time_raw";
|
assertEquals("2023-05-08 11:42:11", records.get(0).get(timeColumn));
|
String storedTimeColumn = type.equals("REALTIME") ? "cabinet_device_time_utc" : "device_time_utc";
|
assertEquals(1683517331000L, ((java.util.Date) records.get(0).get(storedTimeColumn)).getTime());
|
}
|
assertEquals("17", mapper.selectPersistedFinalRealtimeRecords(1L).get(0).get("recordno"));
|
assertEquals(3, service.selectActions(new TTestDataRevisionAction()).size());
|
}
|
|
@Test void databaseFailureRollsBackEarlierRowsAndTheRevision()
|
{
|
var failing = row(); failing.put("recordNo", "18"); failing.put("recordedAt", 1683517391000L); failing.put("energy", 999);
|
assertThrows(RuntimeException.class, () -> submit("REALTIME", List.of(row(), failing)));
|
assertTrue(mapper.selectImportDataRecords(1L, "REALTIME").isEmpty());
|
assertTrue(service.selectActions(new TTestDataRevisionAction()).isEmpty());
|
}
|
|
@Test void importAndDeleteDetailsReturnOnlySummaryWhileAuditRemainsStored() throws Exception
|
{
|
for (String operation : List.of("IMPORT", "DELETE"))
|
{
|
var action = new TTestDataRevisionAction();
|
action.setTestId(1L); action.setDataType("REALTIME"); action.setOperationType(operation);
|
action.setScopeSummary("批量8000条"); action.setReason("摘要查询验证");
|
action.setIdentitySummary(JSON.toJSONString(java.util.stream.IntStream.range(0, 8000).mapToObj(i -> "realtime:" + i).toList()));
|
action.setChangesSummary(JSON.toJSONString(java.util.Collections.nCopies(8000, Map.of("voltage", 1.5))));
|
action.setBeforeContentJson(action.getChangesSummary());
|
mapper.insertDataRevisionAction(action);
|
var summary = service.selectActionById(action.getActionId());
|
assertNull(summary.getIdentitySummary(), "详情查询不得将批量身份 JSON 加载到服务层");
|
assertNull(summary.getChangesSummary(), "详情查询不得将批量变化 JSON 加载到服务层");
|
assertNull(summary.getBeforeContentJson(), "详情查询不得加载完整审计快照");
|
var details = new TTestDataRevisionController();
|
ReflectionTestUtils.setField(details, "service", service);
|
var json = new com.fasterxml.jackson.databind.ObjectMapper();
|
String response = json.writeValueAsString(details.detail(action.getActionId()));
|
assertEquals(8000, json.readTree(response).get("data").get("affectedRecordCount").intValue());
|
assertTrue(response.length() < 1500, "摘要响应不能随批量明细膨胀");
|
// 展示裁剪只发生在 SELECT;数据库审计原文仍完整保留。
|
assertTrue(jdbc.queryForObject("select length(cast(changes_summary as varchar)) from t_test_data_revision_action where action_id=?", Integer.class, action.getActionId()) > 100000);
|
}
|
var list = service.selectActions(new TTestDataRevisionAction());
|
assertEquals(2, list.size());
|
assertTrue(list.stream().allMatch(row -> row.getIdentitySummary() == null && row.getChangesSummary() == null && row.getBeforeContentJson() == null));
|
}
|
|
@Test void stepMedianVoltagesPersistAndRemainIndependentOfLegacyPeaks()
|
{
|
var imported = row();
|
imported.put("chargeMedianVoltage", 0);
|
imported.put("dischargeMedianVoltage", 1.1709);
|
submit("STEP", List.of(imported));
|
var stored = mapper.selectImportDataRecords(1L, "STEP").get(0);
|
var extension = JSON.parseObject(stored.get("extension_measurements_json").toString());
|
assertNotNull(extension.getBigDecimal("chargeMedianVoltage"));
|
assertEquals(0, extension.getBigDecimal("chargeMedianVoltage").signum());
|
assertEquals(new java.math.BigDecimal("1.1709"), extension.getBigDecimal("dischargeMedianVoltage"));
|
assertEquals(1, submit("STEP", List.of(imported)).get("skippedCount"));
|
|
// 旧峰谷值仍是独立事实;不能在查询时作为缺失中值的回退来源。
|
var queryMapper = org.mockito.Mockito.mock(TTestMapper.class);
|
var query = new com.battery.business.service.impl.TestDataQueryServiceImpl(queryMapper,
|
org.mockito.Mockito.mock(com.battery.business.service.ITTestService.class));
|
var current = new LinkedHashMap<String, Object>(Map.of("extensionMeasurementsJson", extension.toJSONString()));
|
var legacy = new LinkedHashMap<String, Object>(Map.of("extensionMeasurementsJson", "{\"chargePeakVoltage\":1.8,\"dischargeValleyVoltage\":0.8}"));
|
org.mockito.Mockito.when(queryMapper.selectPersistedFinalStepRecords(1L)).thenReturn(List.of(current, legacy));
|
var result = query.steps(1L);
|
assertEquals(new java.math.BigDecimal("1.1709"), result.get(0).get("dischargeMedianVoltage"));
|
assertEquals(0.0, ((Number) result.get(0).get("chargeMedianVoltage")).doubleValue());
|
assertNull(result.get(1).get("chargeMedianVoltage"));
|
assertNull(result.get(1).get("dischargeMedianVoltage"));
|
|
imported.put("dischargeMedianVoltage", 1.2);
|
assertTrue(assertThrows(RuntimeException.class, () -> submit("STEP", List.of(imported))).getMessage().contains("冲突拒绝"));
|
assertEquals(1, service.selectActions(new TTestDataRevisionAction()).size());
|
}
|
|
@Test void workbookImportsThreeSheetsWithSeparateRevisionsAndSkipsRetry()
|
{
|
var sheets = Map.of("REALTIME", List.of(row(), row()), "STEP", List.of(row()), "CYCLE", List.of(row()));
|
var result = submitWorkbook(sheets);
|
assertEquals(3, result.get("importedCount"));
|
assertEquals(1, result.get("skippedCount"));
|
assertNotNull(result.get("actionId"));
|
for (String type : List.of("REALTIME", "STEP", "CYCLE"))
|
{
|
assertEquals(1, mapper.selectImportDataRecords(1L, type).size());
|
var query = new TTestDataRevisionAction(); query.setDataType(type);
|
assertEquals(1, service.selectActions(query).size());
|
}
|
var actions = service.selectActions(new TTestDataRevisionAction());
|
assertEquals(3, actions.size());
|
assertEquals(3, ((List<?>) result.get("actionIds")).size());
|
assertEquals(java.util.Set.of("REALTIME", "STEP", "CYCLE"), actions.stream().map(TTestDataRevisionAction::getDataType).collect(java.util.stream.Collectors.toSet()));
|
for (var revision : actions)
|
{
|
String label = switch (revision.getDataType()) { case "REALTIME" -> "实时"; case "STEP" -> "工步"; default -> "循环"; };
|
assertEquals("导入1条" + label + "数据", revision.getScopeSummary());
|
assertEquals(1L, service.selectActionById(revision.getActionId()).getAffectedRecordCount());
|
}
|
assertEquals("三页验收", actions.get(0).getReason());
|
var retry = submitWorkbook(sheets);
|
assertEquals(0, retry.get("importedCount"));
|
assertEquals(4, retry.get("skippedCount"));
|
assertNull(retry.get("actionId"));
|
assertEquals(List.of(), retry.get("actionIds"));
|
assertEquals(3, service.selectActions(new TTestDataRevisionAction()).size());
|
}
|
|
private com.ruoyi.common.core.domain.AjaxResult submitWorkbook(Map<String, List<Map<String, Object>>> sheets)
|
{
|
return controller.dataAction(1L, new TTestController.ConsoleDataActionRequest("ALL", "IMPORT", "三 Sheet 导入", "[]",
|
JSON.toJSONString(sheets), "三页验收", List.of()));
|
}
|
|
@Test void workbookLateDatabaseFailureRollsBackAllSheetsAndRevision()
|
{
|
var cycle = row(); cycle.put("dischargeEnergy", 999);
|
jdbc.execute("alter table t_test_cycle_record add check (discharge_energy_wh <> 999)");
|
assertThrows(RuntimeException.class, () -> submitWorkbook(Map.of("REALTIME", List.of(row()), "STEP", List.of(row()), "CYCLE", List.of(cycle))));
|
assertWorkbookEmpty();
|
}
|
|
@Test void workbookRevisionFailureRollsBackEarlierRevisionsAndAllData()
|
{
|
jdbc.execute("alter table t_test_data_revision_action add check (data_type <> 'CYCLE')");
|
assertThrows(RuntimeException.class, () -> submitWorkbook(Map.of("REALTIME", List.of(row()), "STEP", List.of(row()), "CYCLE", List.of(row()))));
|
assertWorkbookEmpty();
|
}
|
|
@Test void partiallyRepeatedWorkbookRecordsActualPerTypeCounts()
|
{
|
submit("REALTIME", List.of(row()));
|
var result = submitWorkbook(Map.of("REALTIME", List.of(row()), "STEP", List.of(row()), "CYCLE", List.of(row())));
|
assertEquals(2, result.get("importedCount"));
|
assertEquals(1, result.get("skippedCount"));
|
assertEquals(3, ((List<?>) result.get("actionIds")).size());
|
var realtime = new TTestDataRevisionAction(); realtime.setDataType("REALTIME");
|
var revisions = service.selectActions(realtime);
|
assertEquals(2, revisions.size());
|
assertEquals("导入0条实时数据", revisions.get(0).getScopeSummary());
|
assertEquals(0L, service.selectActionById(revisions.get(0).getActionId()).getAffectedRecordCount());
|
var invalid = new TTestDataRevisionAction(); invalid.setDataType("ALL");
|
assertThrows(RuntimeException.class, () -> service.selectActions(invalid));
|
}
|
|
@Test void workbookMissingEmptyInvalidOrConflictingSheetNeverWritesAnySheet()
|
{
|
var sheets = new LinkedHashMap<String, List<Map<String, Object>>>();
|
sheets.put("REALTIME", List.of(row())); sheets.put("STEP", List.of(row()));
|
assertThrows(RuntimeException.class, () -> submitWorkbook(sheets));
|
assertWorkbookEmpty();
|
sheets.put("CYCLE", List.of());
|
assertThrows(RuntimeException.class, () -> submitWorkbook(sheets));
|
assertWorkbookEmpty();
|
var invalid = row(); invalid.put("cycleNo", 0); invalid.put("sourceRow", 23);
|
sheets.put("CYCLE", List.of(invalid));
|
assertTrue(assertThrows(RuntimeException.class, () -> submitWorkbook(sheets)).getMessage().contains("循环工作表,第23行"));
|
assertWorkbookEmpty();
|
var conflict = row(); conflict.put("dischargeCapacity", 88);
|
sheets.put("CYCLE", List.of(row(), conflict));
|
assertTrue(assertThrows(RuntimeException.class, () -> submitWorkbook(sheets)).getMessage().contains("冲突拒绝"));
|
assertWorkbookEmpty();
|
}
|
|
@Test void workbookRejectsDifferentBatterySetsEvenWhenBothBatteriesBelongToTest()
|
{
|
jdbc.execute("insert into t_test_battery values(6,1,'BAT-2',0)");
|
jdbc.execute("insert into t_test_channel_binding values(7,6,11)");
|
var other = row(); other.put("batteryNo", "BAT-2");
|
var sheets = Map.of("REALTIME", List.of(row()), "STEP", List.of(row()), "CYCLE", List.of(other));
|
assertTrue(assertThrows(RuntimeException.class, () -> submitWorkbook(sheets)).getMessage().contains("电池号集合不一致"));
|
assertWorkbookEmpty();
|
other.put("batteryNo", "OTHER");
|
assertTrue(assertThrows(RuntimeException.class, () -> submitWorkbook(sheets)).getMessage().contains("不属于当前测试"));
|
assertWorkbookEmpty();
|
}
|
|
@Test void workbookConflictWithExistingCyclePreservesFactsAndRejectsOtherSheets()
|
{
|
submit("CYCLE", List.of(row()));
|
var conflict = row(); conflict.put("dischargeCapacity", 88);
|
assertThrows(RuntimeException.class, () -> submitWorkbook(Map.of("REALTIME", List.of(row()), "STEP", List.of(row()), "CYCLE", List.of(conflict))));
|
assertTrue(mapper.selectImportDataRecords(1L, "REALTIME").isEmpty());
|
assertTrue(mapper.selectImportDataRecords(1L, "STEP").isEmpty());
|
assertEquals(1, mapper.selectImportDataRecords(1L, "CYCLE").size());
|
assertEquals(1, service.selectActions(new TTestDataRevisionAction()).size());
|
}
|
|
@Test void workbookCannotImportBeforeTestCompletionOrWithoutReason()
|
{
|
var sheets = Map.of("REALTIME", List.of(row()), "STEP", List.of(row()), "CYCLE", List.of(row()));
|
assertThrows(RuntimeException.class, () -> controller.dataAction(1L, new TTestController.ConsoleDataActionRequest("ALL", "IMPORT", "三 Sheet 导入", "[]", JSON.toJSONString(sheets), " ", List.of())));
|
jdbc.update("update t_test set test_status='RUNNING', reception_status='RECEIVING' where test_id=1");
|
assertThrows(RuntimeException.class, () -> submitWorkbook(sheets));
|
assertWorkbookEmpty();
|
}
|
|
@Test void workbookRejectsExistingExtraStepMeasurementInsteadOfSkippingIt()
|
{
|
submit("STEP", List.of(row()));
|
jdbc.update("update t_test_step_record set extension_measurements_json=?", "{\"stepDuration\":3752,\"auxTemperature\":99}");
|
var sheets = Map.of("REALTIME", List.of(row()), "STEP", List.of(row()), "CYCLE", List.of(row()));
|
assertTrue(assertThrows(RuntimeException.class, () -> submitWorkbook(sheets)).getMessage().contains("冲突拒绝"));
|
assertTrue(mapper.selectImportDataRecords(1L, "REALTIME").isEmpty());
|
assertTrue(mapper.selectImportDataRecords(1L, "CYCLE").isEmpty());
|
assertEquals(1, service.selectActions(new TTestDataRevisionAction()).size());
|
}
|
|
private void assertWorkbookEmpty()
|
{
|
for (String type : List.of("REALTIME", "STEP", "CYCLE")) assertTrue(mapper.selectImportDataRecords(1L, type).isEmpty());
|
assertTrue(service.selectActions(new TTestDataRevisionAction()).isEmpty());
|
}
|
|
@Test void differentRecordsInTheSameSecondPreserveDeviceTime()
|
{
|
var next = row(); next.put("recordNo", "18"); next.put("sequenceId", 18); next.put("stepNo", 2);
|
assertEquals(2, submit("REALTIME", List.of(row(), next)).get("importedCount"));
|
assertEquals(2, submit("REALTIME", List.of(row(), next)).get("skippedCount"));
|
var records = mapper.selectImportDataRecords(1L, "REALTIME");
|
assertEquals(2, records.size());
|
for (var record : records) {
|
assertNull(record.get("capture_slot_utc"));
|
assertEquals(1683517331000L, ((java.util.Date) record.get("cabinet_device_time_utc")).getTime());
|
}
|
}
|
|
@Test
|
@org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable(named = "TICKET03_SAMPLE_JSON", matches = ".+")
|
void suppliedPartyWorkbookImportsAllRowsAndSkipsEveryRetry() throws Exception
|
{
|
var sample = JSON.parseObject(java.nio.file.Files.readString(java.nio.file.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));
|
assertEquals(7767, submitWorkbook(sheets).get("importedCount"));
|
assertEquals(7767, submitWorkbook(sheets).get("skippedCount"));
|
for (String type : List.of("REALTIME", "STEP", "CYCLE"))
|
{
|
List<Map<String, Object>> rows = (List) sample.getJSONArray(type).toJavaList(Map.class);
|
int count = switch (type) { case "REALTIME" -> 7605; case "STEP" -> 129; default -> 33; };
|
assertEquals(count, mapper.selectImportDataRecords(1L, type).size());
|
var query = new TTestDataRevisionAction(); query.setDataType(type);
|
var actions = service.selectActions(query);
|
assertEquals(1, actions.size());
|
assertEquals((long) count, service.selectActionById(actions.get(0).getActionId()).getAffectedRecordCount());
|
String label = switch (type) { case "REALTIME" -> "实时"; case "STEP" -> "工步"; default -> "循环"; };
|
assertEquals("导入" + count + "条" + label + "数据", actions.get(0).getScopeSummary());
|
if ("STEP".equals(type))
|
{
|
var persisted = mapper.selectImportDataRecords(1L, type).stream().collect(java.util.stream.Collectors.toMap(
|
record -> record.get("source_record_id").toString(), record -> record));
|
for (var input : rows)
|
{
|
var stored = JSON.parseObject(persisted.get(input.get("recordNo").toString()).get("extension_measurements_json").toString());
|
for (String field : List.of("chargeMedianVoltage", "dischargeMedianVoltage"))
|
if (input.get(field) == null) assertNull(stored.get(field));
|
else assertEquals(0, new java.math.BigDecimal(input.get(field).toString()).compareTo(stored.getBigDecimal(field)), field);
|
}
|
}
|
}
|
assertEquals(3, service.selectActions(new TTestDataRevisionAction()).size());
|
}
|
|
private Map<String, Object> row()
|
{
|
var row = new LinkedHashMap<String, Object>(Map.of("recordNo", "17", "batteryNo", "BAT-1", "recordedAt", 1683517331000L,
|
"cycleNo", 1, "stepNo", 1, "stepName", "恒流放电", "sequenceId", 17, "capacity", 8.5122));
|
row.put("deviceTimeRaw", "2023-05-08 11:42:11"); row.put("adapterTimezoneId", "Asia/Hong_Kong"); row.put("stepDuration", 3752);
|
return row;
|
}
|
|
private com.ruoyi.common.core.domain.AjaxResult submit(String type, List<Map<String, Object>> rows)
|
{
|
return controller.dataAction(1L, new TTestController.ConsoleDataActionRequest(type, "IMPORT", "单页导入", "[]",
|
JSON.toJSONString(rows), "开发测试", List.of()));
|
}
|
}
|