修复2次关源指令bug
完善数据校验结果接口调用 pqdif功补充
This commit is contained in:
@@ -3,13 +3,16 @@ server:
|
||||
spring:
|
||||
application:
|
||||
name: entrance
|
||||
redis:
|
||||
host: localhost
|
||||
port: 16379
|
||||
datasource:
|
||||
druid:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://192.168.1.24:13306/pqs9100?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
|
||||
# username: root
|
||||
# password: njcnpqs
|
||||
# url: jdbc:mysql://127.0.0.1:3306/pqs9100?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
|
||||
# username: root
|
||||
# password: njcnpqs
|
||||
# url: jdbc:mysql://127.0.0.1:3306/pqs9100?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
|
||||
username: root
|
||||
password: njcnpqs
|
||||
#初始化建立物理连接的个数、最小、最大连接数
|
||||
@@ -67,8 +70,8 @@ sntp:
|
||||
port: 123
|
||||
|
||||
Dip:
|
||||
# 暂态前时间(s)
|
||||
# fPreTime: 2f
|
||||
# 暂态前时间(s)
|
||||
# fPreTime: 2f
|
||||
#写入时间(s)
|
||||
fRampIn: 0.001f
|
||||
#写出时间(s)
|
||||
@@ -86,8 +89,8 @@ Dip:
|
||||
# homeDir: D:\logs
|
||||
# commonLevel: info
|
||||
report:
|
||||
# template: D:\template
|
||||
# reportDir: D:\report
|
||||
# template: D:\template
|
||||
# reportDir: D:\report
|
||||
dateFormat: yyyy年MM月dd日
|
||||
#data:
|
||||
# homeDir: D:\data
|
||||
@@ -133,4 +136,4 @@ activate:
|
||||
public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnFMmIVanMxsW5S/qP8Wcxf/J3/i4631BP3UtWkRzO7jAw9HIAgK4Y7X53hXj6zMbfme1vMjQc0mq7m/KrH4WlTYpFexLO6Gnk8oH40F04tp+ABZIq93zNOydPEaVoZeTPH/LlkwrrxVGAMNNIKuebcqapp25JiWtlSFMv4kH/nDAj+2m8+P4zYVM1Ed6gO01eKDEYE3SBA1Ket2BfHTgviR/F8WKwlXh11enywsJnrHTM5dJQdlUxCjHy214TpheYOz/cv9elQnDfFAbmZW8mH5/hgMSTkm3h4uR7ITin6Erg+yc/t1kGaTWrzloyBRMSiFN/Pwr5yQjj+1wQqqUkwIDAQAB"
|
||||
|
||||
dataCheck:
|
||||
enable: true
|
||||
enable: false
|
||||
@@ -1,170 +0,0 @@
|
||||
package com.njcn;
|
||||
|
||||
import com.njcn.gather.tools.comtrade.comparewave.core.model.CompareWaveDTO;
|
||||
import com.njcn.gather.tools.comtrade.comparewave.service.ICompareWaveService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* 流式文件分析测试
|
||||
* 测试从本地文件读取并转换为流进行分析
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = com.njcn.gather.EntranceApplication.class)
|
||||
public class AnalysisServiceStreamTest {
|
||||
|
||||
@Autowired
|
||||
private ICompareWaveService compareWaveServiceImpl;
|
||||
|
||||
// 测试文件路径 - 请根据实际情况修改
|
||||
private static final String SOURCE_CFG_PATH = "C:\\Users\\Administrator\\Desktop\\wave\\192.168.1.241\\PQ_PQLD2_000177_20251028_112422_833.cfg";
|
||||
private static final String SOURCE_DAT_PATH = "C:\\Users\\Administrator\\Desktop\\wave\\192.168.1.241\\PQ_PQLD2_000177_20251028_112422_833.dat";
|
||||
private static final String TARGET_CFG_PATH = "C:\\Users\\Administrator\\Desktop\\wave\\192.168.1.242\\PQ_PQLD2_000238_20251028_112422_518.cfg";
|
||||
private static final String TARGET_DAT_PATH = "C:\\Users\\Administrator\\Desktop\\wave\\192.168.1.242\\PQ_PQLD2_000238_20251028_112422_518.dat";
|
||||
|
||||
|
||||
// private static final String SOURCE_CFG_PATH = "F:\\hatch\\wavecompare\\数据比对\\统计数据1\\B码\\217\\PQMonitor_PQM1_000006_20200430_115517_889.cfg";
|
||||
// private static final String SOURCE_DAT_PATH = "F:\\hatch\\wavecompare\\数据比对\\统计数据1\\B码\\217\\PQMonitor_PQM1_000006_20200430_115517_889.dat";
|
||||
// private static final String TARGET_CFG_PATH = "F:\\hatch\\wavecompare\\数据比对\\统计数据1\\B码\\216\\PQMonitor_PQM1_000006_20200430_115515_479.cfg";
|
||||
// private static final String TARGET_DAT_PATH = "F:\\hatch\\wavecompare\\数据比对\\统计数据1\\B码\\216\\PQMonitor_PQM1_000006_20200430_115515_479.dat";
|
||||
|
||||
// 输出路径
|
||||
private static final String OUTPUT_PATH = "./test-output/";
|
||||
|
||||
/**
|
||||
* 测试使用文件流进行电能质量分析
|
||||
*/
|
||||
@Test
|
||||
public void testAnalyzeWithStreams() throws Exception {
|
||||
System.out.println("========================================");
|
||||
System.out.println("开始测试流式文件分析");
|
||||
System.out.println("========================================");
|
||||
|
||||
// 验证文件是否存在
|
||||
checkFileExists(SOURCE_CFG_PATH, "源CFG文件");
|
||||
checkFileExists(SOURCE_DAT_PATH, "源DAT文件");
|
||||
checkFileExists(TARGET_CFG_PATH, "目标CFG文件");
|
||||
checkFileExists(TARGET_DAT_PATH, "目标DAT文件");
|
||||
|
||||
// 读取本地文件并创建输入流
|
||||
try (InputStream sourceCfgStream = new FileInputStream(SOURCE_CFG_PATH);
|
||||
InputStream sourceDatStream = new FileInputStream(SOURCE_DAT_PATH);
|
||||
InputStream targetCfgStream = new FileInputStream(TARGET_CFG_PATH);
|
||||
InputStream targetDatStream = new FileInputStream(TARGET_DAT_PATH)) {
|
||||
|
||||
System.out.println("成功创建文件输入流");
|
||||
System.out.println("源CFG文件: " + SOURCE_CFG_PATH);
|
||||
System.out.println("源DAT文件: " + SOURCE_DAT_PATH);
|
||||
System.out.println("目标CFG文件: " + TARGET_CFG_PATH);
|
||||
System.out.println("目标DAT文件: " + TARGET_DAT_PATH);
|
||||
System.out.println("输出路径: " + OUTPUT_PATH);
|
||||
|
||||
// 创建输出目录
|
||||
File outputDir = new File(OUTPUT_PATH);
|
||||
if (!outputDir.exists()) {
|
||||
outputDir.mkdirs();
|
||||
System.out.println("创建输出目录: " + outputDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
// 执行分析,使用星型接线方式(0)
|
||||
System.out.println("\n开始执行电能质量分析(星型接线)...");
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
CompareWaveDTO result = compareWaveServiceImpl.analyzeAndCompareWithStreams(
|
||||
sourceCfgStream,
|
||||
sourceDatStream,
|
||||
targetCfgStream,
|
||||
targetDatStream,
|
||||
// 接线方式: 0=星型接线, 1=V型接线
|
||||
0
|
||||
);
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
long duration = endTime - startTime;
|
||||
|
||||
// 输出分析结果
|
||||
System.out.println("========================================");
|
||||
System.out.println("分析完成!");
|
||||
System.out.println("总耗时: " + duration + " ms (" + String.format("%.2f", duration / 1000.0) + " 秒)");
|
||||
|
||||
|
||||
|
||||
|
||||
System.out.println("========================================");
|
||||
System.out.println("流式文件分析测试完成!");
|
||||
System.out.println("========================================");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试段信息保留模式的波形分析(新方法)
|
||||
* <p>不进行跨段的统一降采样,保留每个段的原始采样率(超过512才降到256)</p>
|
||||
* <p>跨段的窗口会被丢弃,只计算不跨段的窗口</p>
|
||||
*/
|
||||
@Test
|
||||
public void testAnalyzeWithSegmentPreservation() throws Exception {
|
||||
System.out.println("========================================");
|
||||
System.out.println("开始执行电能质量分析(段信息保留模式)...");
|
||||
System.out.println("========================================");
|
||||
|
||||
// 检查文件是否存在
|
||||
checkFileExists(SOURCE_CFG_PATH, "源CFG文件");
|
||||
checkFileExists(SOURCE_DAT_PATH, "源DAT文件");
|
||||
checkFileExists(TARGET_CFG_PATH, "目标CFG文件");
|
||||
checkFileExists(TARGET_DAT_PATH, "目标DAT文件");
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try (InputStream sourceCfgStream = new FileInputStream(SOURCE_CFG_PATH);
|
||||
InputStream sourceDatStream = new FileInputStream(SOURCE_DAT_PATH);
|
||||
InputStream targetCfgStream = new FileInputStream(TARGET_CFG_PATH);
|
||||
InputStream targetDatStream = new FileInputStream(TARGET_DAT_PATH)) {
|
||||
|
||||
CompareWaveDTO result = compareWaveServiceImpl.analyzeWithSegmentPreservation(
|
||||
sourceCfgStream,
|
||||
sourceDatStream,
|
||||
targetCfgStream,
|
||||
targetDatStream,
|
||||
0 // 接线方式: 0=星型接线, 1=V型接线
|
||||
);
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
long duration = endTime - startTime;
|
||||
|
||||
// 输出分析结果
|
||||
System.out.println("========================================");
|
||||
System.out.println("分析完成!");
|
||||
System.out.println("总耗时: " + duration + " ms (" + String.format("%.2f", duration / 1000.0) + " 秒)");
|
||||
System.out.println("源文件有效窗口数: " + (result.getSourceResults() != null ? result.getSourceResults().size() : 0));
|
||||
System.out.println("目标文件有效窗口数: " + (result.getTargetResults() != null ? result.getTargetResults().size() : 0));
|
||||
System.out.println("========================================");
|
||||
System.out.println("段信息保留模式测试完成!");
|
||||
System.out.println("========================================");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否存在
|
||||
*/
|
||||
private void checkFileExists(String filePath, String description) {
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
System.err.println("警告: " + description + " 不存在: " + filePath);
|
||||
System.err.println("请确保文件路径正确,或修改测试中的文件路径");
|
||||
} else {
|
||||
System.out.println(description + " 存在: " + filePath);
|
||||
System.out.println(" 文件大小: " + file.length() + " bytes");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.njcn;
|
||||
|
||||
import com.njcn.gather.EntranceApplication;
|
||||
import com.njcn.gather.report.service.IPqReportService;
|
||||
import com.njcn.http.util.RestTemplateUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月10日 15:05
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebAppConfiguration
|
||||
@SpringBootTest(classes = EntranceApplication.class)
|
||||
public class BaseJunitTest {
|
||||
|
||||
@Autowired
|
||||
private IPqReportService pqReportService;
|
||||
|
||||
@Autowired
|
||||
private RestTemplateUtil restTemplateUtil;
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
File file = new File("D:\\report\\PQS_882B4\\5555.docx");
|
||||
|
||||
try{
|
||||
ResponseEntity<String> stringResponseEntity = restTemplateUtil.uploadFile("http://localhost:18082/api/file/upload",file);
|
||||
}catch (Exception runtimeException){
|
||||
System.out.println(runtimeException.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
package com.njcn;
|
||||
|
||||
import com.njcn.gather.tools.report.util.Docx4jUtil;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
|
||||
import org.docx4j.wml.ObjectFactory;
|
||||
import org.docx4j.wml.P;
|
||||
import org.docx4j.wml.Tbl;
|
||||
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 动态表格生成测试
|
||||
*
|
||||
* @author hongawen
|
||||
* @version 1.0
|
||||
* @date 2025/9/21
|
||||
*/
|
||||
public class DynamicTableTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
// 测试场景1:2个回路,7个检测项目(与result.png一致)
|
||||
testScenario1();
|
||||
|
||||
// 测试场景2:1个回路,只检测电压和频率
|
||||
testScenario2();
|
||||
|
||||
// 测试场景3:4个回路,多个检测项目
|
||||
testScenario3();
|
||||
|
||||
System.out.println("所有测试场景执行完成!");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试场景1:2个回路,7个检测项目(模拟result.png的数据)
|
||||
*/
|
||||
public static void testScenario1() throws Exception {
|
||||
System.out.println("=== 测试场景1:2个回路,7个检测项目 ===");
|
||||
|
||||
// 创建Word文档
|
||||
WordprocessingMLPackage wordPackage = WordprocessingMLPackage.createPackage();
|
||||
MainDocumentPart mainDocumentPart = wordPackage.getMainDocumentPart();
|
||||
ObjectFactory factory = new ObjectFactory();
|
||||
|
||||
// 1. 添加标题
|
||||
P titleP = factory.createP();
|
||||
Docx4jUtil.createTitle(factory, titleP, "检测结果(场景1:2回路7项目)", 32, true);
|
||||
mainDocumentPart.getContent().add(titleP);
|
||||
|
||||
// 2. 检测项目配置
|
||||
List<String> testItems = Arrays.asList(
|
||||
"电压",
|
||||
"电压不平衡度",
|
||||
"电流不平衡度",
|
||||
"谐波电压",
|
||||
"谐波电流",
|
||||
"间谐波电压",
|
||||
"短时间闪变"
|
||||
);
|
||||
|
||||
// 3. 检测结果数据(模拟result.png中的数据)
|
||||
String[][] testResults = {
|
||||
{"不合格", "不合格"}, // 电压
|
||||
{"无法比较", "无法比较"}, // 电压不平衡度
|
||||
{"合格", "合格"}, // 电流不平衡度
|
||||
{"合格", "合格"}, // 谐波电压
|
||||
{"合格", "合格"}, // 谐波电流
|
||||
{"不合格", "不合格"}, // 间谐波电压
|
||||
{"无法比较", "无法比较"} // 短时间闪变
|
||||
};
|
||||
|
||||
// 4. 定义回路名称
|
||||
List<String> circuitNames = Arrays.asList("测量回路 1", "测量回路 2");
|
||||
|
||||
// 5. 生成动态表格(包含说明内容)
|
||||
JAXBElement<Tbl> table = Docx4jUtil.createDynamicTestResultTable(
|
||||
factory, testItems, circuitNames, testResults, "不合格",
|
||||
"部分值", "200", "去除最大最小值");
|
||||
mainDocumentPart.getContent().add(table);
|
||||
|
||||
// 6. 保存文档
|
||||
File outputFile = new File("检测结果_场景1_2回路7项目.docx");
|
||||
wordPackage.save(outputFile);
|
||||
System.out.println("文档已保存:" + outputFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试场景2:1个回路,只检测电压和频率
|
||||
*/
|
||||
public static void testScenario2() throws Exception {
|
||||
System.out.println("=== 测试场景2:1个回路,2个检测项目 ===");
|
||||
|
||||
WordprocessingMLPackage wordPackage = WordprocessingMLPackage.createPackage();
|
||||
MainDocumentPart mainDocumentPart = wordPackage.getMainDocumentPart();
|
||||
ObjectFactory factory = new ObjectFactory();
|
||||
|
||||
// 标题
|
||||
P titleP = factory.createP();
|
||||
Docx4jUtil.createTitle(factory, titleP, "检测结果(场景2:1回路2项目)", 32, true);
|
||||
mainDocumentPart.getContent().add(titleP);
|
||||
|
||||
// 简单的检测项目
|
||||
List<String> testItems = Arrays.asList("电压", "频率");
|
||||
|
||||
// 1个回路的检测结果
|
||||
String[][] testResults = {
|
||||
{"不合格"}, // 电压
|
||||
{"合格"} // 频率
|
||||
};
|
||||
|
||||
// 定义回路名称
|
||||
List<String> circuitNames = Arrays.asList("#1母线");
|
||||
|
||||
// 生成表格(包含说明内容)
|
||||
JAXBElement<Tbl> table = Docx4jUtil.createDynamicTestResultTable(
|
||||
factory, testItems, circuitNames, testResults, "不合格",
|
||||
"任意值", "100", "取第一个满足条件的数据");
|
||||
mainDocumentPart.getContent().add(table);
|
||||
|
||||
File outputFile = new File("检测结果_场景2_1回路2项目.docx");
|
||||
wordPackage.save(outputFile);
|
||||
System.out.println("文档已保存:" + outputFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试场景3:4个回路,多个检测项目
|
||||
*/
|
||||
public static void testScenario3() throws Exception {
|
||||
System.out.println("=== 测试场景3:4个回路,5个检测项目 ===");
|
||||
|
||||
WordprocessingMLPackage wordPackage = WordprocessingMLPackage.createPackage();
|
||||
MainDocumentPart mainDocumentPart = wordPackage.getMainDocumentPart();
|
||||
ObjectFactory factory = new ObjectFactory();
|
||||
|
||||
// 标题
|
||||
P titleP = factory.createP();
|
||||
Docx4jUtil.createTitle(factory, titleP, "检测结果(场景3:4回路5项目)", 32, true);
|
||||
mainDocumentPart.getContent().add(titleP);
|
||||
|
||||
// 检测项目
|
||||
List<String> testItems = Arrays.asList(
|
||||
"电压", "频率", "电压不平衡度", "谐波电压", "间谐波电压"
|
||||
);
|
||||
|
||||
// 4个回路的检测结果
|
||||
String[][] testResults = {
|
||||
{"不合格", "合格", "合格", "不合格"}, // 电压
|
||||
{"合格", "合格", "合格", "合格"}, // 频率
|
||||
{"无法比较", "无法比较", "合格", "合格"}, // 电压不平衡度
|
||||
{"合格", "不合格", "合格", "合格"}, // 谐波电压
|
||||
{"不合格", "不合格", "不合格", "合格"} // 间谐波电压
|
||||
};
|
||||
|
||||
// 定义回路名称(自定义名称示例)
|
||||
List<String> circuitNames = Arrays.asList("主变高压侧", "主变低压侧", "备用线路1", "备用线路2");
|
||||
|
||||
// 生成表格(包含说明内容)
|
||||
JAXBElement<Tbl> table = Docx4jUtil.createDynamicTestResultTable(
|
||||
factory, testItems, circuitNames, testResults, "不合格",
|
||||
"平均值", "300", "取算术平均值");
|
||||
mainDocumentPart.getContent().add(table);
|
||||
|
||||
File outputFile = new File("检测结果_场景3_4回路5项目.docx");
|
||||
wordPackage.save(outputFile);
|
||||
System.out.println("文档已保存:" + outputFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package com.njcn;
|
||||
|
||||
import com.njcn.gather.device.pojo.po.PqDevSub;
|
||||
import com.njcn.gather.device.service.IPqDevSubService;
|
||||
import com.njcn.gather.monitor.pojo.po.PqMonitor;
|
||||
import com.njcn.gather.monitor.service.IPqMonitorService;
|
||||
import com.njcn.gather.result.pojo.param.DataCheckRequest;
|
||||
import com.njcn.gather.result.service.impl.ResultServiceImpl;
|
||||
import com.njcn.http.util.RestTemplateUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ResultChecksquareCreateTest {
|
||||
|
||||
@Mock
|
||||
private IPqMonitorService pqMonitorService;
|
||||
@Mock
|
||||
private IPqDevSubService pqDevSubService;
|
||||
@Mock
|
||||
private RestTemplateUtil restTemplateUtil;
|
||||
|
||||
@Test
|
||||
public void createChecksquareTaskByDevIdBuildsRequestAndReturnsThirdPartyResponse() {
|
||||
String devId = "dev-1";
|
||||
PqMonitor monitor1 = new PqMonitor();
|
||||
monitor1.setId("line-1");
|
||||
PqMonitor monitor2 = new PqMonitor();
|
||||
monitor2.setId("line-2");
|
||||
PqDevSub devSub = new PqDevSub();
|
||||
devSub.setCheckStartTime(LocalDateTime.of(2026, 6, 22, 10, 1, 2));
|
||||
devSub.setCheckEndTime(LocalDateTime.of(2026, 6, 22, 11, 3, 4));
|
||||
|
||||
when(pqMonitorService.listPqMonitorByDevIds(Collections.singletonList(devId))).thenReturn(Arrays.asList(monitor1, monitor2));
|
||||
when(pqDevSubService.getOne(any(), eq(false))).thenReturn(devSub);
|
||||
ArgumentCaptor<DataCheckRequest> requestCaptor = ArgumentCaptor.forClass(DataCheckRequest.class);
|
||||
when(restTemplateUtil.postJson(eq(ResultServiceImpl.CHECKSQUARE_CREATE_URL), requestCaptor.capture(), eq(String.class)))
|
||||
.thenReturn("{\"code\":0}");
|
||||
|
||||
ResultServiceImpl resultService = new ResultServiceImpl(null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, pqMonitorService, null, null,
|
||||
pqDevSubService, null, restTemplateUtil);
|
||||
|
||||
String response = resultService.createChecksquareTaskByDevId(devId);
|
||||
|
||||
DataCheckRequest request = requestCaptor.getValue();
|
||||
assertEquals("{\"code\":0}", response);
|
||||
assertEquals(Arrays.asList("line-1", "line-2"), request.getLineIds());
|
||||
assertTrue(request.getIndicatorCodes().isEmpty());
|
||||
assertEquals("2026-06-22 10:01:02", request.getTimeStart());
|
||||
assertEquals("2026-06-22 11:03:04", request.getTimeEnd());
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.njcn;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.njcn.gather.detection.pojo.vo.DetectionData;
|
||||
import com.njcn.gather.device.pojo.vo.PqDevVO;
|
||||
import com.njcn.gather.device.service.IPqDevService;
|
||||
import com.njcn.gather.device.service.impl.PqDevServiceImpl;
|
||||
import com.njcn.gather.report.pojo.DevReportParam;
|
||||
import com.njcn.gather.report.pojo.result.ContrastTestResult;
|
||||
import com.njcn.gather.report.service.IPqReportService;
|
||||
import com.njcn.gather.result.pojo.vo.MonitorResultVO;
|
||||
import com.njcn.gather.result.service.impl.ResultServiceImpl;
|
||||
import com.njcn.gather.storage.pojo.po.ContrastHarmonicResult;
|
||||
import com.njcn.gather.system.dictionary.pojo.po.DictTree;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* ResultServiceImpl 测试类
|
||||
* 专门测试 getContrastResultHarm 方法
|
||||
*
|
||||
* @author test
|
||||
* @date 2025-01-18
|
||||
*/
|
||||
@Slf4j
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = com.njcn.gather.EntranceApplication.class)
|
||||
public class ResultServiceImplTest extends BaseJunitTest {
|
||||
|
||||
@Autowired
|
||||
private ResultServiceImpl resultService;
|
||||
|
||||
@Autowired
|
||||
private IPqDevService pqDevService;
|
||||
|
||||
@Autowired
|
||||
private IPqReportService pqReportService;
|
||||
|
||||
/**
|
||||
* 测试 getContrastResultHarm 方法 - 正常情况,所有数据合格
|
||||
*/
|
||||
@Test
|
||||
public void testGetContrastResultHarm_AllQualified() throws Exception {
|
||||
log.info("==================== 开始测试:所有数据合格场景 ====================");
|
||||
|
||||
// 准备测试数据
|
||||
DevReportParam devReportParam = new DevReportParam();
|
||||
devReportParam.setPlanId("307a4b57abe84746acec5fd62f58e789");
|
||||
devReportParam.setPlanCode("1");
|
||||
devReportParam.setDevId("11b1a3cadafd4d51986d5c88815c2ece");
|
||||
devReportParam.setDevIdList(Collections.singletonList(devReportParam.getDevId()));
|
||||
// PqDevVO pqDevVO = pqDevService.getPqDevById(devReportParam.getDevId());
|
||||
// Map<Integer, List<ContrastTestResult>> contrastResultHarm = resultService.getContrastResultForReport(devReportParam, pqDevVO);
|
||||
|
||||
|
||||
pqReportService.generateReport(devReportParam);
|
||||
System.out.println(1);
|
||||
System.out.println(1);
|
||||
System.out.println(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
package com.njcn.gather.detection.lock;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class DetectionLockManagerTest {
|
||||
|
||||
private DetectionLockManager manager;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
manager = DetectionLockManager.getInstance();
|
||||
// 通过反射把 current 清零,避免不同测试方法间状态污染
|
||||
Field f = DetectionLockManager.class.getDeclaredField("current");
|
||||
f.setAccessible(true);
|
||||
((AtomicReference<?>) f.get(manager)).set(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tryAcquire_whenEmpty_returnsOk() {
|
||||
DetectionLockManager.AcquireResult r = manager.tryAcquire("u1", "alice", "page-1");
|
||||
assertTrue(r.isOk());
|
||||
assertNull(r.getHolder());
|
||||
assertEquals("u1", manager.getCurrent().getUserId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tryAcquire_whenHeldByOther_returnsBusyWithHolder() {
|
||||
manager.tryAcquire("u1", "alice", "page-1");
|
||||
DetectionLockManager.AcquireResult r = manager.tryAcquire("u2", "bob", "page-2");
|
||||
assertFalse(r.isOk());
|
||||
assertNotNull(r.getHolder());
|
||||
assertEquals("u1", r.getHolder().getHolderUserId());
|
||||
assertEquals("alice", r.getHolder().getHolderUserName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tryAcquire_reentrantSameUser_refreshesPageAndExpireAt() throws Exception {
|
||||
manager.tryAcquire("u1", "alice", "page-1");
|
||||
long oldAcquire = manager.getCurrent().getAcquireTime();
|
||||
long oldExpire = manager.getCurrent().getExpireAt();
|
||||
// sleep 50ms(远超 Windows 系统时钟 ~15ms 精度),保证时间戳推进
|
||||
Thread.sleep(50);
|
||||
DetectionLockManager.AcquireResult r = manager.tryAcquire("u1", "alice", "page-2");
|
||||
assertTrue(r.isOk());
|
||||
assertEquals("page-2", manager.getCurrent().getUserPageId());
|
||||
assertTrue("acquireTime 应推进", manager.getCurrent().getAcquireTime() > oldAcquire);
|
||||
assertTrue("expireAt 应推进", manager.getCurrent().getExpireAt() > oldExpire);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tryAcquire_whenExpired_anyUserCanAcquire() throws Exception {
|
||||
// 直接构造一个 expireAt 在过去的 lock 写进去
|
||||
Field f = DetectionLockManager.class.getDeclaredField("current");
|
||||
f.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
AtomicReference<DetectionLock> ref = (AtomicReference<DetectionLock>) f.get(manager);
|
||||
long past = System.currentTimeMillis() - 1000;
|
||||
ref.set(new DetectionLock("u1", "alice", "page-1", past - 1000, past));
|
||||
|
||||
DetectionLockManager.AcquireResult r = manager.tryAcquire("u2", "bob", "page-2");
|
||||
assertTrue(r.isOk());
|
||||
assertEquals("u2", manager.getCurrent().getUserId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void releaseIfHeldBy_matchingUser_clears() {
|
||||
manager.tryAcquire("u1", "alice", "page-1");
|
||||
manager.releaseIfHeldBy("u1", "TEST");
|
||||
assertNull(manager.getCurrent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void releaseIfHeldBy_nonMatchingUser_isNoOp() {
|
||||
manager.tryAcquire("u1", "alice", "page-1");
|
||||
manager.releaseIfHeldBy("u2", "TEST");
|
||||
assertNotNull(manager.getCurrent());
|
||||
assertEquals("u1", manager.getCurrent().getUserId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void releaseIfHeldBy_whenEmpty_isNoOp() {
|
||||
manager.releaseIfHeldBy("u1", "TEST");
|
||||
assertNull(manager.getCurrent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void releaseIfMatchPage_matchingPage_clears() {
|
||||
manager.tryAcquire("u1", "alice", "page-1");
|
||||
manager.releaseIfMatchPage("page-1", "TEST");
|
||||
assertNull(manager.getCurrent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void releaseIfMatchPage_nonMatchingPage_isNoOp() {
|
||||
manager.tryAcquire("u1", "alice", "page-1");
|
||||
manager.releaseIfMatchPage("page-2", "TEST");
|
||||
assertNotNull(manager.getCurrent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forceRelease_alwaysClears() {
|
||||
manager.tryAcquire("u1", "alice", "page-1");
|
||||
manager.forceRelease("admin", "TEST");
|
||||
assertNull(manager.getCurrent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void concurrentTryAcquire_onlyOneWins() throws Exception {
|
||||
int n = 100;
|
||||
ExecutorService pool = Executors.newFixedThreadPool(16);
|
||||
CountDownLatch start = new CountDownLatch(1);
|
||||
CountDownLatch done = new CountDownLatch(n);
|
||||
AtomicInteger okCount = new AtomicInteger(0);
|
||||
// 记下胜出线程的 userId,便于断言 holder 身份与胜出者一致
|
||||
AtomicReference<String> winnerUserId = new AtomicReference<>(null);
|
||||
for (int i = 0; i < n; i++) {
|
||||
final String uid = "u" + i;
|
||||
pool.submit(() -> {
|
||||
try {
|
||||
start.await();
|
||||
DetectionLockManager.AcquireResult r = manager.tryAcquire(uid, uid, "page-" + uid);
|
||||
if (r.isOk()) {
|
||||
okCount.incrementAndGet();
|
||||
winnerUserId.set(uid);
|
||||
}
|
||||
} catch (InterruptedException ignored) {
|
||||
} finally {
|
||||
done.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
start.countDown();
|
||||
done.await(5, TimeUnit.SECONDS);
|
||||
pool.shutdownNow();
|
||||
assertEquals("100 个不同账号并发只能有 1 个抢到锁", 1, okCount.get());
|
||||
assertNotNull(manager.getCurrent());
|
||||
// 持锁者必须就是宣称 ok 的那个线程,不能是别人
|
||||
assertEquals("holder 身份必须等于胜出线程的 userId", winnerUserId.get(), manager.getCurrent().getUserId());
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="20 seconds" debug="false">
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
||||
|
||||
<!-- 测试环境下明确指定日志配置,避免IS_UNDEFINED问题 -->
|
||||
<property name="log.projectName" value="entrance"/>
|
||||
<property name="logHomeDir" value="D:\logs"/>
|
||||
<property name="logCommonLevel" value="info"/>
|
||||
|
||||
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
|
||||
<conversionRule conversionWord="wex"
|
||||
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
|
||||
<conversionRule conversionWord="ec"
|
||||
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
|
||||
|
||||
|
||||
<!--日志输出格式-->
|
||||
<property name="log.pattern"
|
||||
value="|-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%level} ${log.projectName} -- %t %logger{100}.%M ==> %m%n${Log_EXCEPTION_CONVERSION_WORD:-%ec}}}"/>
|
||||
<property name="log.maxHistory" value="30"/>
|
||||
|
||||
<!--客户端输出日志-->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!--系统中常规的debug日志-->
|
||||
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender -->
|
||||
<appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>
|
||||
${logHomeDir}/${log.projectName}/debug/debug.log
|
||||
</file>
|
||||
<!-- 如果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 设置过滤级别 -->
|
||||
<level>DEBUG</level>
|
||||
<!-- 用于配置符合过滤条件的操作 -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 用于配置不符合过滤条件的操作 -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责触发滚动 SizeAndTimeBasedRollingPolicy-->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!--日志输出位置 可相对、和绝对路径 -->
|
||||
<fileNamePattern>
|
||||
${logHomeDir}/${log.projectName}/debug/debug.log.%d{yyyy-MM-dd}.%i.log
|
||||
</fileNamePattern>
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件,假设设置每个月滚动,且<maxHistory>是6,
|
||||
则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除 -->
|
||||
<maxHistory>${log.maxHistory:-30}</maxHistory>
|
||||
<!--重启清理日志文件-->
|
||||
<!-- <cleanHistoryOnStart>true</cleanHistoryOnStart>-->
|
||||
<!--每个文件最多100MB,保留N天的历史记录,但最多20GB-->
|
||||
<!--<totalSizeCap>20GB</totalSizeCap>-->
|
||||
<!--日志文件最大的大小-->
|
||||
<!--<MaxFileSize>${log.maxSize}</MaxFileSize>-->
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>
|
||||
${log.pattern}
|
||||
</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!--系统中常规的info日志-->
|
||||
<appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>INFO</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<file>
|
||||
${logHomeDir}/${log.projectName}/info/info.log
|
||||
</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>
|
||||
${logHomeDir}/${log.projectName}/info/info.log.%d{yyyy-MM-dd}.%i.log
|
||||
</fileNamePattern>
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<maxHistory>${log.maxHistory:-30}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>
|
||||
${log.pattern}
|
||||
</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<!--系统中常规的error日志-->
|
||||
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>
|
||||
${logHomeDir}/${log.projectName}/error/error.log
|
||||
</file>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>ERROR</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>
|
||||
${logHomeDir}/${log.projectName}/error/error.log.%d{yyyy-MM-dd}.%i.log
|
||||
</fileNamePattern>
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<maxHistory>${log.maxHistory:-30}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>
|
||||
${log.pattern}
|
||||
</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
|
||||
<logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>
|
||||
<logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
|
||||
|
||||
|
||||
|
||||
<logger name="com.njcn" level="INFO" additivity="false">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="DEBUG"/>
|
||||
<appender-ref ref="INFO"/>
|
||||
<appender-ref ref="ERROR"/>
|
||||
</logger>
|
||||
|
||||
<root level="${logCommonLevel}">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="DEBUG"/>
|
||||
<appender-ref ref="INFO"/>
|
||||
<appender-ref ref="ERROR"/>
|
||||
</root>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user