package com.battery.business.report;
|
|
import static org.junit.jupiter.api.Assertions.*;
|
import static org.mockito.Mockito.*;
|
import java.util.*;
|
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSONObject;
|
import com.battery.business.domain.*;
|
import com.battery.business.service.*;
|
import com.battery.device.api.StepDirectionResolver;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import org.h2.jdbcx.JdbcDataSource;
|
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.provider.ValueSource;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
class ReportTestDetailPersistenceTest
|
{
|
private final ObjectMapper mapper = new ObjectMapper();
|
|
@ParameterizedTest
|
@ValueSource(strings = { "compare", "formation", "splice" })
|
void reportOwnsAddedAndRemovedFieldsAcrossSaveAndReopen(String type) throws Exception
|
{
|
var database = new JdbcDataSource();
|
database.setURL("jdbc:h2:mem:detail_" + UUID.randomUUID() + ";MODE=MySQL;DB_CLOSE_DELAY=-1");
|
var jdbc = new JdbcTemplate(database);
|
jdbc.execute("CREATE TABLE t_" + type + "_report(report_id BIGINT AUTO_INCREMENT PRIMARY KEY, report_name VARCHAR(100), creator_id BIGINT, creator_name VARCHAR(100), created_at_utc TIMESTAMP)");
|
jdbc.execute("CREATE TABLE t_" + type + "_report_version(report_id BIGINT, version_no INT, snapshot_json CLOB, operator_id BIGINT, operator_name VARCHAR(100), created_at_utc TIMESTAMP, change_summary VARCHAR(500), PRIMARY KEY(report_id,version_no))");
|
var tests = mock(ITTestService.class);
|
var data = mock(ITestDataQueryService.class);
|
var definitions = mock(ITBatteryGroupFieldService.class);
|
List<TTest> originals = new ArrayList<>();
|
for (long id : List.of(1L, 2L)) {
|
var battery = new TTestBattery();
|
battery.setTestBatteryId(id); battery.setGroupId(id); battery.setGroupName("组" + id);
|
battery.setBatteryNo("同名电池"); battery.setFields(List.of());
|
var test = new TTest();
|
test.setTestId(id); test.setTestName("测试" + id); test.setTestTypeName("化成");
|
test.setTestStatus("COMPLETED"); test.setBatteries(List.of(battery)); test.setLogicStepMappings(List.of());
|
var detail = new TTestConsoleDetail();
|
detail.setExperimentName("仅控制台实验"); detail.setBatteryFields(List.of("额定容量")); detail.setSpecialFields(List.of("待删除"));
|
detail.setFieldValues(new LinkedHashMap<>(Map.of("额定容量", Map.of("同名电池", "来源" + id), "待删除", Map.of("同名电池", "原值"))));
|
test.setConsoleDetail(detail); originals.add(test);
|
when(tests.selectTestById(id)).thenReturn(test);
|
Map<String, Object> row = Map.of("testBatteryId", id, "batteryNo", "同名电池", "cycleNo", 1,
|
"stepNo", 1, "stepName", "充电", "sourceType", "SNAPSHOT", "deviceTime", 1000L, "voltage", 3);
|
when(data.records(id)).thenReturn(List.of(row));
|
when(data.cycles(id)).thenReturn(List.of()); when(data.steps(id)).thenReturn(List.of());
|
}
|
var compare = new CompareReportService(tests, data, new CompareReportRepository(database));
|
var formation = new FormationReportService(tests, data, new FormationReportRepository(database), definitions, value -> StepDirectionResolver.Direction.UNKNOWN);
|
var splice = new SpliceReportService(tests, data, new SpliceReportRepository(database), new SpliceFieldTemplateService(database, definitions));
|
var settings = JSON.parseObject(switch (type) {
|
case "compare" -> "{\"metrics\":[],\"seriesColors\":[],\"batteryTemplateFields\":[],\"specialFields\":[],\"fieldStructure\":[],\"detailFieldValues\":{}}";
|
case "formation" -> "{\"fields\":[{\"key\":\"chargeCapacity\",\"scope\":\"cycle\",\"kind\":\"metric\",\"displayName\":\"充电容量\",\"unit\":\"mAh\"}],\"values\":{},\"chargeStepSelections\":{},\"metrics\":[],\"seriesColors\":{}}";
|
default -> "{\"fieldStructure\":[],\"detailFieldValues\":{}}";
|
});
|
var details = JSON.parseObject("""
|
{"1|1":{"batteryFields":["额定容量"],"specialFields":["新字段"],"fieldValues":{"battery|额定容量":"报表甲","special|新字段":""}},
|
"2|2":{"batteryFields":["额定容量"],"specialFields":["新字段"],"fieldValues":{"battery|额定容量":"报表乙","special|新字段":"乙值"}}}
|
""");
|
settings.put("sourceDetailOverrides", details);
|
var request = new JSONObject(); request.put("name", "独立详情"); request.put("description", ""); request.put("settings", settings);
|
request.put("selections", type.equals("compare") ? List.of(Map.of("testId", 1, "testBatteryId", 1, "cycleNo", 1, "stepNo", 1), Map.of("testId", 2, "testBatteryId", 2, "cycleNo", 1, "stepNo", 1))
|
: List.of(Map.of("testId", 1, "testBatteryId", 1), Map.of("testId", 2, "testBatteryId", 2)));
|
Map<String, Object> created = switch (type) {
|
case "compare" -> compare.create(mapper.readValue(request.toJSONString(), CompareReportRequest.class), 1, "操作员");
|
case "formation" -> formation.create(mapper.readValue(request.toJSONString(), FormationReportRequest.class), 1, "操作员");
|
default -> splice.create(mapper.readValue(request.toJSONString(), SpliceReportRequest.class), 1, "操作员");
|
};
|
long id = ((Number) created.get("id")).longValue();
|
assertEquals(details, JSON.parseObject(JSON.toJSONString(created.get("settings"))).getJSONObject("sourceDetailOverrides"));
|
clearInvocations(tests, data);
|
details.getJSONObject("1|1").put("batteryFields", List.of());
|
details.getJSONObject("1|1").put("specialFields", List.of());
|
details.getJSONObject("1|1").put("fieldValues", Map.of());
|
details.getJSONObject("2|2").getJSONObject("fieldValues").put("special|新字段", "二次修改");
|
request.remove("selections"); request.put("baseVersionNo", 1); request.put("changeSummary", "修改本报表详情");
|
switch (type) {
|
case "compare" -> compare.edit(id, mapper.readValue(request.toJSONString(), CompareReportEditRequest.class), 1, "操作员");
|
case "formation" -> formation.edit(id, mapper.readValue(request.toJSONString(), FormationReportRequest.Edit.class), 1, "操作员");
|
default -> splice.edit(id, mapper.readValue(request.toJSONString(), SpliceReportRequest.Edit.class), 1, "操作员");
|
}
|
Map<String, Object> reopened = switch (type) {
|
case "compare" -> compare.get(id); case "formation" -> formation.get(id, null); default -> splice.get(id, null);
|
};
|
var savedDetails = JSON.parseObject(JSON.toJSONString(reopened.get("settings"))).getJSONObject("sourceDetailOverrides");
|
assertEquals(details, savedDetails);
|
assertTrue(savedDetails.getJSONObject("1|1").getJSONArray("specialFields").isEmpty());
|
assertEquals("二次修改", savedDetails.getJSONObject("2|2").getJSONObject("fieldValues").getString("special|新字段"));
|
Map<String, Object> history = switch (type) {
|
case "compare" -> compare.get(id, 1); case "formation" -> formation.get(id, 1); default -> splice.get(id, 1);
|
};
|
assertEquals("", JSON.parseObject(JSON.toJSONString(history.get("settings"))).getJSONObject("sourceDetailOverrides").getJSONObject("1|1").getJSONObject("fieldValues").getString("special|新字段"));
|
verifyNoInteractions(tests, data);
|
for (var original : originals) {
|
assertEquals(List.of("待删除"), original.getConsoleDetail().getSpecialFields());
|
assertEquals("来源" + original.getTestId(), original.getConsoleDetail().getFieldValues().get("额定容量").get("同名电池"));
|
}
|
}
|
}
|