package com.ruoyi.system.service.impl;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.isNull;
|
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.times;
|
|
import java.math.BigDecimal;
|
import java.util.Collections;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.time.Instant;
|
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.mockito.InjectMocks;
|
import org.mockito.Mock;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.springframework.dao.DuplicateKeyException;
|
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.system.domain.TTest;
|
import com.ruoyi.system.domain.TTestBattery;
|
import com.ruoyi.system.domain.TTestChannelBinding;
|
import com.ruoyi.system.domain.TTestCollectorChannel;
|
import com.ruoyi.system.domain.TTestFieldSnapshot;
|
import com.ruoyi.system.domain.TTestPlanStep;
|
import com.ruoyi.system.domain.TTestWarningThreshold;
|
import com.ruoyi.system.domain.TDetectionChannel;
|
import com.ruoyi.system.mapper.TTestMapper;
|
import com.ruoyi.system.service.ISharedFieldSnapshotService;
|
|
/** 测试配置服务的业务契约测试。 */
|
@ExtendWith(MockitoExtension.class)
|
class TTestServiceImplTest
|
{
|
@Mock
|
private TTestMapper testMapper;
|
|
@Mock
|
private ISharedFieldSnapshotService sharedFieldSnapshotService;
|
|
@InjectMocks
|
private TTestServiceImpl testService;
|
|
@Test
|
void createShouldReturnIdentifierAndInitializeIndependentStatuses()
|
{
|
TTest test = validTest();
|
mockEnabledOptions();
|
mockGroupSnapshot();
|
when(testMapper.insertTest(any(TTest.class))).thenAnswer(invocation -> {
|
invocation.<TTest>getArgument(0).setTestId(10L);
|
return 1;
|
});
|
doAnswer(invocation -> {
|
invocation.<TTestBattery>getArgument(0).setRelationId(20L);
|
return 1;
|
}).when(testMapper).insertTestBattery(any(TTestBattery.class));
|
|
assertEquals(10L, testService.createTest(test));
|
assertEquals("WAITING", test.getTestStatus());
|
assertEquals("NOT_STARTED", test.getReceptionStatus());
|
assertEquals(7L, test.getCreatorId());
|
verify(testMapper).insertTestPlanStep(any(TTestPlanStep.class));
|
verify(testMapper).insertTestChannelBinding(any(TTestChannelBinding.class));
|
verify(testMapper, times(3)).insertTestCollectorChannel(any(TTestCollectorChannel.class));
|
verify(sharedFieldSnapshotService).saveForTest(eq(10L), any());
|
verify(testMapper).insertTestThreshold(any(TTestWarningThreshold.class));
|
verify(testMapper).insertTestAudit(anyLong(), any(), anyLong(), any(), isNull(), any());
|
}
|
|
@Test
|
void listShouldAggregateBatteryNumbersOutsideDatabaseQuery()
|
{
|
TTest first = new TTest();
|
first.setTestId(10L);
|
TTest second = new TTest();
|
second.setTestId(11L);
|
TTestBattery firstBattery = new TTestBattery();
|
firstBattery.setTestId(10L);
|
firstBattery.setBatteryNo("BAT-001");
|
TTestBattery secondBattery = new TTestBattery();
|
secondBattery.setTestId(10L);
|
secondBattery.setBatteryNo("BAT-002");
|
when(testMapper.selectTestList(any(TTest.class))).thenReturn(java.util.List.of(first, second));
|
when(testMapper.selectBatteryNosByTestIds(java.util.List.of(10L, 11L)))
|
.thenReturn(java.util.List.of(firstBattery, secondBattery));
|
|
java.util.List<TTest> result = testService.selectTestList(new TTest());
|
|
assertEquals("BAT-001、BAT-002", result.get(0).getBatteryNo());
|
assertEquals("", result.get(1).getBatteryNo());
|
}
|
|
@Test
|
void createShouldRejectMissingCollector()
|
{
|
TTest test = validTest();
|
test.getBatteries().get(0).setCollectorId(null);
|
mockEnabledPeopleAndType();
|
when(testMapper.countBatteryInEnabledGroup(1L, "BAT-001")).thenReturn(1);
|
when(testMapper.countRegisteredChannel(100L)).thenReturn(1);
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("采集器不能为空", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void createShouldRejectMissingRequiredCollectorChannel()
|
{
|
TTest test = validTest();
|
test.getBatteries().get(0).getCollectorChannels().remove(0);
|
mockEnabledOptions();
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("每个电池号必须绑定主温度、正电位主通道和负电位主通道", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void createShouldAllowPlanStepsToBeConfiguredLater()
|
{
|
TTest test = validTest();
|
test.setPlanSteps(Collections.emptyList());
|
mockEnabledOptions();
|
mockGroupSnapshot();
|
when(testMapper.insertTest(any(TTest.class))).thenAnswer(invocation -> {
|
invocation.<TTest>getArgument(0).setTestId(10L);
|
return 1;
|
});
|
doAnswer(invocation -> {
|
invocation.<TTestBattery>getArgument(0).setRelationId(20L);
|
return 1;
|
}).when(testMapper).insertTestBattery(any(TTestBattery.class));
|
|
assertEquals(10L, testService.createTest(test));
|
|
verify(testMapper, never()).insertTestPlanStep(any(TTestPlanStep.class));
|
}
|
|
@Test
|
void createShouldRejectBatteryOutsideSelectedGroup()
|
{
|
TTest test = validTest();
|
mockEnabledPeopleAndType();
|
when(testMapper.countBatteryInEnabledGroup(1L, "BAT-001")).thenReturn(0);
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("电池号不属于所选启用电池组", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void createShouldRejectDisabledCreator()
|
{
|
TTest test = validTest();
|
when(testMapper.countUserEnabled(7L)).thenReturn(0);
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("创建人不存在或已停用", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void createShouldRejectDisabledPrincipal()
|
{
|
TTest test = validTest();
|
when(testMapper.countUserEnabled(7L)).thenReturn(1);
|
when(testMapper.countUserEnabled(9L)).thenReturn(0);
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("测试负责人不存在或已停用", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void createShouldRejectDuplicatePrimaryChannelBinding()
|
{
|
TTest test = validTest();
|
TTestBattery duplicate = validBattery("BAT-002", 2L, 100L);
|
test.setBatteries(java.util.List.of(test.getBatteries().get(0), duplicate));
|
mockEnabledPeopleAndType();
|
when(testMapper.countBatteryInEnabledGroup(1L, "BAT-001")).thenReturn(1);
|
when(testMapper.countBatteryInEnabledGroup(1L, "BAT-002")).thenReturn(1);
|
when(testMapper.countRegisteredChannel(100L)).thenReturn(1);
|
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
|
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("同一检测柜通道不可重复绑定", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void createShouldRejectDuplicateCollectorChannelMapping()
|
{
|
TTest test = validTest();
|
TTestBattery second = validBattery("BAT-002", 2L, 101L);
|
test.setBatteries(java.util.List.of(test.getBatteries().get(0), second));
|
mockEnabledPeopleAndType();
|
when(testMapper.countBatteryInEnabledGroup(1L, "BAT-001")).thenReturn(1);
|
when(testMapper.countBatteryInEnabledGroup(1L, "BAT-002")).thenReturn(1);
|
when(testMapper.countRegisteredChannel(100L)).thenReturn(1);
|
when(testMapper.countRegisteredChannel(101L)).thenReturn(1);
|
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
|
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("同一采集器通道不可重复映射", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void createShouldRejectCaseInsensitiveDuplicateCollectorMeasurement()
|
{
|
TTest test = validTest();
|
test.getBatteries().get(0).getCollectorChannels()
|
.add(collectorChannel("primary_temperature", "主温度重复", "S-04"));
|
mockEnabledOptions();
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("同一电池号的采集器测量项不可重复", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void createShouldRejectBatteriesFromDifferentGroups()
|
{
|
TTest test = validTest();
|
TTestBattery otherGroup = validBattery("BAT-002", 2L, 101L);
|
otherGroup.setGroupId(2L);
|
test.setBatteries(java.util.List.of(test.getBatteries().get(0), otherGroup));
|
mockEnabledPeopleAndType();
|
when(testMapper.countBatteryInEnabledGroup(1L, "BAT-001")).thenReturn(1);
|
when(testMapper.countRegisteredChannel(100L)).thenReturn(1);
|
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
|
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("同一测试只能选择一个电池组", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void updateShouldRejectConfigurationAfterReceptionStarted()
|
{
|
TTest request = validTest();
|
request.setTestId(10L);
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("RECEIVING");
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.updateTest(request));
|
|
assertEquals("开始接收后不能修改测试配置", exception.getMessage());
|
verify(testMapper, never()).updateTest(any(TTest.class));
|
}
|
|
@Test
|
void createShouldRejectCollectorChannelOutsideRegisteredRange()
|
{
|
TTest test = validTest();
|
test.getBatteries().get(0).getCollectorChannels().get(2).setChannelCode("S-05");
|
mockEnabledPeopleAndType();
|
when(testMapper.countBatteryInEnabledGroup(1L, "BAT-001")).thenReturn(1);
|
when(testMapper.countRegisteredChannel(100L)).thenReturn(1);
|
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
|
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
|
|
ServiceException exception = assertThrows(ServiceException.class, () -> testService.createTest(test));
|
|
assertEquals("采集器通道不存在或超出登记范围", exception.getMessage());
|
verify(testMapper, never()).insertTest(any(TTest.class));
|
}
|
|
@Test
|
void updateShouldReplaceConfigurationBeforeMonitoringAndAppendAudit()
|
{
|
TTest request = validTest();
|
request.setTestId(10L);
|
request.setMonitorTimeoutMinutes(45);
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setCreatorId(7L);
|
current.setReceptionStatus("NOT_STARTED");
|
current.setMonitorTimeoutMinutes(30);
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
when(testMapper.selectTestBatteries(10L)).thenReturn(current.getBatteries());
|
when(sharedFieldSnapshotService.selectByTestId(10L)).thenReturn(java.util.List.of());
|
when(sharedFieldSnapshotService.resolveForUpdate(1L, 1L, java.util.List.of()))
|
.thenReturn(java.util.List.of());
|
mockEnabledOptions();
|
when(testMapper.updateTest(request)).thenReturn(1);
|
doAnswer(invocation -> {
|
invocation.<TTestBattery>getArgument(0).setRelationId(21L);
|
return 1;
|
}).when(testMapper).insertTestBattery(any(TTestBattery.class));
|
|
assertEquals(1, testService.updateTest(request));
|
assertEquals(45, request.getMonitorTimeoutMinutes());
|
verify(testMapper).deleteTestBindingsByTestId(10L);
|
verify(testMapper).deleteTestPlanStepsByTestId(10L);
|
verify(testMapper).insertTestAudit(anyLong(), any(), anyLong(), any(), any(), any());
|
}
|
|
@Test
|
void updateSameGroupShouldPreserveOriginalFieldSnapshot()
|
{
|
TTest request = validTest();
|
request.setTestId(10L);
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setCreatorId(7L);
|
current.setReceptionStatus("NOT_STARTED");
|
TTestFieldSnapshot originalSnapshot = new TTestFieldSnapshot();
|
originalSnapshot.setFieldDefinitionId(11L);
|
originalSnapshot.setFieldName("额定容量");
|
originalSnapshot.setFieldType("number");
|
originalSnapshot.setFieldValue("72");
|
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
when(testMapper.selectTestBatteries(10L)).thenReturn(current.getBatteries());
|
when(sharedFieldSnapshotService.selectByTestId(10L)).thenReturn(java.util.List.of(originalSnapshot));
|
when(sharedFieldSnapshotService.resolveForUpdate(1L, 1L, java.util.List.of(originalSnapshot)))
|
.thenReturn(java.util.List.of(originalSnapshot));
|
mockEnabledOptions();
|
when(testMapper.updateTest(request)).thenReturn(1);
|
doAnswer(invocation -> {
|
invocation.<TTestBattery>getArgument(0).setRelationId(21L);
|
return 1;
|
}).when(testMapper).insertTestBattery(any(TTestBattery.class));
|
|
assertEquals(1, testService.updateTest(request));
|
|
verify(sharedFieldSnapshotService).resolveForUpdate(1L, 1L, java.util.List.of(originalSnapshot));
|
verify(sharedFieldSnapshotService).saveForTest(eq(10L), org.mockito.ArgumentMatchers.argThat(snapshots ->
|
snapshots.size() == 1 && "72".equals(snapshots.get(0).getFieldValue())));
|
}
|
|
@Test
|
void deleteBeforeMonitoringShouldAppendAudit()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("NOT_STARTED");
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
when(testMapper.deleteTestById(10L, "operator")).thenReturn(1);
|
|
assertEquals(1, testService.deleteTestByIds(new Long[] { 10L }, 7L, "operator"));
|
|
verify(testMapper).insertTestAudit(eq(10L), eq("TEST_DELETED"), eq(7L), eq("operator"), any(), isNull());
|
}
|
|
@Test
|
void startReceptionShouldOpenAllSourceIntervalsAtomically()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("NOT_STARTED");
|
current.getBatteries().get(0).getBinding().setBindingId(30L);
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
TDetectionChannel channel = new TDetectionChannel();
|
channel.setChannelId(100L);
|
channel.setOnlineStatus("ONLINE");
|
channel.setLastSeenAtUtc(Instant.parse("2026-08-29T12:00:00Z"));
|
when(testMapper.selectReceptionChannelForUpdate(100L)).thenReturn(channel);
|
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
|
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
|
when(testMapper.collectorOnline(8L)).thenReturn(true);
|
when(testMapper.updateReceptionStarted(eq(10L), any(), anyBoolean(), eq("operator"))).thenReturn(1);
|
|
assertEquals(1, testService.startReception(10L, 7L, "operator"));
|
verify(testMapper).insertChannelLease(eq(100L), eq(10L), eq(30L), eq(7L), any());
|
verify(testMapper).insertReceptionInterval(eq(10L), eq(30L), eq("CABINET_CHANNEL"), eq(100L), isNull(), any(), eq("RECEPTION_STARTED"));
|
verify(testMapper, times(3)).insertCollectorChannelLease(eq(8L), any(), eq(10L), eq(30L), eq(7L), any());
|
verify(testMapper, times(3)).insertReceptionInterval(eq(10L), eq(30L), eq("COLLECTOR_CHANNEL"), eq(8L), any(), any(), eq("RECEPTION_STARTED"));
|
verify(testMapper).insertTestAudit(eq(10L), eq("RECEPTION_STARTED"), eq(7L), eq("operator"), isNull(), any());
|
}
|
|
@Test
|
void startReceptionShouldMarkRunningCabinetAttachmentWithoutControlCommand()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("NOT_STARTED");
|
current.getBatteries().get(0).getBinding().setBindingId(30L);
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
TDetectionChannel channel = new TDetectionChannel();
|
channel.setChannelId(100L);
|
channel.setOnlineStatus("ONLINE");
|
channel.setWorkStatus("WORKING");
|
channel.setLastSeenAtUtc(Instant.parse("2026-08-29T12:00:00Z"));
|
when(testMapper.selectReceptionChannelForUpdate(100L)).thenReturn(channel);
|
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
|
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
|
when(testMapper.collectorOnline(8L)).thenReturn(true);
|
when(testMapper.updateReceptionStarted(eq(10L), any(), anyBoolean(), eq("operator"))).thenReturn(1);
|
|
assertEquals(1, testService.startReception(10L, 7L, "operator"));
|
verify(testMapper).insertTestAudit(eq(10L), eq("RECEPTION_STARTED"), eq(7L), eq("operator"), isNull(),
|
org.mockito.ArgumentMatchers.argThat(value -> value != null && value.contains("runtimeAttach")
|
&& value.contains("true")));
|
}
|
|
@Test
|
void startReceptionShouldRollbackWhenDatabaseLeaseIsTaken()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("NOT_STARTED");
|
current.getBatteries().get(0).getBinding().setBindingId(30L);
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
TDetectionChannel channel = new TDetectionChannel();
|
channel.setChannelId(100L);
|
channel.setOnlineStatus("ONLINE");
|
channel.setLastSeenAtUtc(Instant.parse("2026-08-29T12:00:00Z"));
|
when(testMapper.selectReceptionChannelForUpdate(100L)).thenReturn(channel);
|
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
|
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
|
when(testMapper.collectorOnline(8L)).thenReturn(true);
|
when(testMapper.insertChannelLease(any(), any(), any(), any(), any()))
|
.thenThrow(new DuplicateKeyException("lease already exists"));
|
|
ServiceException exception = assertThrows(ServiceException.class,
|
() -> testService.startReception(10L, 7L, "operator"));
|
|
assertEquals("数据来源已被其他测试占用,请刷新后重试", exception.getMessage());
|
verify(testMapper, never()).updateReceptionStarted(any(), any(), anyBoolean(), any());
|
verify(testMapper, never()).insertTestAudit(anyLong(), any(), anyLong(), any(), any(), any());
|
}
|
|
@Test
|
void startReceptionShouldRejectOfflineSourceWithoutWritingAnything()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("NOT_STARTED");
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
TDetectionChannel channel = new TDetectionChannel();
|
channel.setChannelId(100L);
|
channel.setOnlineStatus("OFFLINE");
|
when(testMapper.selectReceptionChannelForUpdate(100L)).thenReturn(channel);
|
|
ServiceException exception = assertThrows(ServiceException.class,
|
() -> testService.startReception(10L, 7L, "operator"));
|
|
assertEquals("检测柜通道 100 当前离线或不可观测", exception.getMessage());
|
verify(testMapper, never()).insertChannelLease(any(), any(), any(), any(), any());
|
verify(testMapper, never()).updateReceptionStarted(any(), any(), anyBoolean(), any());
|
}
|
|
@Test
|
void startReceptionShouldRejectIncompleteCollectorMappingsBeforeWriting()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("NOT_STARTED");
|
current.getBatteries().get(0).getBinding().setBindingId(30L);
|
current.getBatteries().get(0).setCollectorChannels(Collections.emptyList());
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
TDetectionChannel channel = new TDetectionChannel();
|
channel.setChannelId(100L);
|
channel.setOnlineStatus("ONLINE");
|
channel.setLastSeenAtUtc(Instant.parse("2026-08-29T12:00:00Z"));
|
when(testMapper.selectReceptionChannelForUpdate(100L)).thenReturn(channel);
|
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
|
when(testMapper.collectorOnline(8L)).thenReturn(true);
|
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
|
|
ServiceException exception = assertThrows(ServiceException.class,
|
() -> testService.startReception(10L, 7L, "operator"));
|
|
assertEquals("每个电池号必须绑定主温度、正电位主通道和负电位主通道", exception.getMessage());
|
verify(testMapper, never()).insertChannelLease(any(), any(), any(), any(), any());
|
verify(testMapper, never()).updateReceptionStarted(any(), any(), anyBoolean(), any());
|
}
|
|
@Test
|
void startReceptionShouldRejectMissingOperatorExplicitly()
|
{
|
ServiceException exception = assertThrows(ServiceException.class,
|
() -> testService.startReception(10L, null, "operator"));
|
|
assertEquals("操作人不能为空", exception.getMessage());
|
verify(testMapper, never()).selectTestByIdForUpdate(anyLong());
|
}
|
|
@Test
|
void pauseReceptionShouldStopPollingAndAppendAudit()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("RECEIVING");
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
when(testMapper.updateReceptionPaused(eq(10L), eq("operator"), any())).thenReturn(1);
|
|
assertEquals(1, testService.pauseReception(10L, 7L, "operator"));
|
verify(testMapper).updateReceptionPaused(eq(10L), eq("operator"), any());
|
verify(testMapper).insertTestAudit(eq(10L), eq("RECEPTION_PAUSED"), eq(7L), eq("operator"), isNull(),
|
org.mockito.ArgumentMatchers.argThat(value -> value != null && value.contains("STOPPED")));
|
}
|
|
@Test
|
void resumeReceptionShouldRestartPollingAndAppendAudit()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("PAUSED");
|
List<TTestBattery> configuredBatteries = current.getBatteries();
|
current.setBatteries(null);
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
when(testMapper.selectTestBatteries(10L)).thenReturn(configuredBatteries);
|
when(testMapper.updateReceptionResumed(eq(10L), eq("operator"), any())).thenReturn(1);
|
|
assertEquals(1, testService.resumeReception(10L, 7L, "operator"));
|
verify(testMapper).updateReceptionResumed(eq(10L), eq("operator"), any());
|
verify(testMapper).insertTestAudit(eq(10L), eq("RECEPTION_RESUMED"), eq(7L), eq("operator"), isNull(),
|
org.mockito.ArgumentMatchers.argThat(value -> value != null && value.contains("RESUMED")));
|
}
|
|
@Test
|
void stopTestShouldCompleteAndReleaseLeases()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("PAUSED");
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
when(testMapper.updateReceptionStopped(eq(10L), eq("operator"), any())).thenReturn(1);
|
|
assertEquals(1, testService.stopTest(10L, 7L, "operator"));
|
verify(testMapper).updateReceptionStopped(eq(10L), eq("operator"), any());
|
verify(testMapper).closeOpenReceptionIntervals(eq(10L), any(), eq("MANUAL_END"));
|
verify(testMapper).deleteChannelLeasesByTestId(10L);
|
verify(testMapper).deleteCollectorChannelLeasesByTestId(10L);
|
verify(testMapper).insertTestAudit(eq(10L), eq("TEST_STOPPED"), eq(7L), eq("operator"), isNull(),
|
org.mockito.ArgumentMatchers.argThat(value -> value != null && value.contains("COMPLETED")));
|
}
|
|
@Test
|
void stopTestShouldAuditImmediateReleaseAndClosedIntervals()
|
{
|
TTest current = validTest();
|
current.setTestId(10L);
|
current.setReceptionStatus("RECEIVING");
|
when(testMapper.selectTestByIdForUpdate(10L)).thenReturn(current);
|
when(testMapper.updateReceptionStopped(eq(10L), eq("operator"), any())).thenReturn(1);
|
when(testMapper.closeOpenReceptionIntervals(eq(10L), any(), eq("MANUAL_END"))).thenReturn(4);
|
|
testService.stopTest(10L, 7L, "operator");
|
|
verify(testMapper).insertTestAudit(eq(10L), eq("TEST_STOPPED"), eq(7L), eq("operator"), isNull(),
|
org.mockito.ArgumentMatchers.argThat(value -> value != null
|
&& value.contains("closedIntervals") && value.contains("IMMEDIATE")));
|
}
|
|
private void mockEnabledOptions()
|
{
|
mockEnabledPeopleAndType();
|
when(testMapper.countBatteryInEnabledGroup(1L, "BAT-001")).thenReturn(1);
|
when(testMapper.countRegisteredChannel(100L)).thenReturn(1);
|
when(testMapper.countCollectorEnabled(8L)).thenReturn(1);
|
when(testMapper.selectCollectorChannelCount(8L)).thenReturn(4);
|
}
|
|
private void mockEnabledPeopleAndType()
|
{
|
when(testMapper.countUserEnabled(7L)).thenReturn(1);
|
when(testMapper.countUserEnabled(9L)).thenReturn(1);
|
when(testMapper.countTestTypeEnabled(3L)).thenReturn(1);
|
}
|
|
private void mockGroupSnapshot()
|
{
|
TTestFieldSnapshot snapshot = new TTestFieldSnapshot();
|
snapshot.setFieldDefinitionId(11L);
|
snapshot.setFieldName("额定容量");
|
snapshot.setFieldType("number");
|
snapshot.setFieldValue("72");
|
when(sharedFieldSnapshotService.createForBatteryGroup(1L)).thenReturn(java.util.List.of(snapshot));
|
}
|
|
private TTest validTest()
|
{
|
TTestPlanStep step = new TTestPlanStep();
|
step.setCycleNo(1);
|
step.setStepNo(1);
|
step.setStepType("CONSTANT_CURRENT_CHARGE");
|
step.setStepName("恒流充电");
|
step.setSortOrder(1);
|
LinkedHashMap<String, Object> parameters = new LinkedHashMap<>();
|
parameters.put("currentA", new BigDecimal("1.5"));
|
step.setParameters(parameters);
|
|
TTestWarningThreshold threshold = new TTestWarningThreshold();
|
threshold.setMetricCode("VOLTAGE");
|
threshold.setMinValue(new BigDecimal("2.5"));
|
threshold.setMaxValue(new BigDecimal("4.2"));
|
threshold.setUnit("V");
|
threshold.setSeverity("WARNING");
|
|
TTest test = new TTest();
|
test.setTestName("低温循环测试");
|
test.setCreatorId(7L);
|
test.setOperatorId(7L);
|
test.setCreateBy("creator");
|
test.setUpdateBy("creator");
|
test.setPrincipalId(9L);
|
test.setTestTypeId(3L);
|
test.setTestPurpose("验证低温循环性能");
|
test.setMonitorTimeoutMinutes(30);
|
test.setBatteries(Collections.singletonList(validBattery("BAT-001", 1L, 100L)));
|
test.setPlanSteps(Collections.singletonList(step));
|
test.setThresholds(Collections.singletonList(threshold));
|
return test;
|
}
|
|
private TTestBattery validBattery(String batteryNo, Long relationId, Long channelId)
|
{
|
TTestChannelBinding binding = new TTestChannelBinding();
|
binding.setChannelId(channelId);
|
binding.setExpectedBarcode("CODE-" + batteryNo);
|
|
TTestBattery battery = new TTestBattery();
|
battery.setRelationId(relationId);
|
battery.setGroupId(1L);
|
battery.setBatteryNo(batteryNo);
|
battery.setCollectorId(8L);
|
battery.setBinding(binding);
|
battery.setCollectorChannels(new java.util.ArrayList<>(java.util.List.of(
|
collectorChannel("PRIMARY_TEMPERATURE", "主温度", "S-01"),
|
collectorChannel("PRIMARY_POSITIVE_POTENTIAL", "正电位主通道", "S-02"),
|
collectorChannel("PRIMARY_NEGATIVE_POTENTIAL", "负电位主通道", "S-03"))));
|
battery.setFields(Collections.emptyList());
|
return battery;
|
}
|
|
private TTestCollectorChannel collectorChannel(String measurementCode, String measurementName, String channelCode)
|
{
|
TTestCollectorChannel mapping = new TTestCollectorChannel();
|
mapping.setMeasurementCode(measurementCode);
|
mapping.setMeasurementName(measurementName);
|
mapping.setChannelCode(channelCode);
|
return mapping;
|
}
|
}
|