CockpitWorkOrderListContractTest.java 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package com.zksy.web.controller.cockpit;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
  4. import com.zksy.base.alarm.domain.AlarmData;
  5. import com.zksy.base.alarm.service.AlarmDataService;
  6. import com.zksy.base.domain.EquipmentBase;
  7. import com.zksy.base.mapper.EquipmentBaseMapper;
  8. import com.zksy.base.warning.mapper.AlarmWarningRelMapper;
  9. import com.zksy.base.warning.service.EarlyWarningService;
  10. import com.zksy.cockpit.workorder.BusinessCockpitWorkOrderReadAdapter;
  11. import com.zksy.cockpit.workorder.CockpitWorkOrderReadService;
  12. import com.zksy.ops.domain.WorkOrder;
  13. import com.zksy.ops.service.WorkOrderService;
  14. import org.apache.ibatis.builder.MapperBuilderAssistant;
  15. import org.apache.ibatis.session.Configuration;
  16. import org.junit.jupiter.api.BeforeEach;
  17. import org.junit.jupiter.api.Test;
  18. import org.springframework.test.web.servlet.MockMvc;
  19. import org.springframework.test.web.servlet.setup.MockMvcBuilders;
  20. import java.time.Clock;
  21. import java.time.Instant;
  22. import java.time.ZoneOffset;
  23. import java.util.Arrays;
  24. import java.util.Collections;
  25. import java.util.Date;
  26. import static org.mockito.ArgumentMatchers.any;
  27. import static org.mockito.ArgumentMatchers.anyInt;
  28. import static org.mockito.ArgumentMatchers.eq;
  29. import static org.mockito.ArgumentMatchers.isNull;
  30. import static org.mockito.Mockito.mock;
  31. import static org.mockito.Mockito.verify;
  32. import static org.mockito.Mockito.when;
  33. import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
  34. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
  35. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  36. /**
  37. * 全量工单列表端点(票 65):报警效率面板的「当前工单列表」。
  38. *
  39. * <p>锁四件事,都是**会真的画错界面**的那几件:
  40. * <ol>
  41. * <li>不按设备/事件筛——全量口径(查询条件里不得出现 device_id);</li>
  42. * <li>总数取独立 count,不由本页条数反推(票 61 纪律);</li>
  43. * <li>非法 page/pageSize/stateCode 被夹到合法区间并**回显实际生效值**;</li>
  44. * <li>状态字典与每张工单的关联标记照常给出(卡片要按同一份词表上色)。</li>
  45. * </ol>
  46. */
  47. class CockpitWorkOrderListContractTest {
  48. private static final String BASE = "/api/cockpit/v1";
  49. private static final String ORDER_CODE = "WO202610101511303516";
  50. private static final String DEVICE_CODE = "21119740";
  51. private static final String ALARM_ID = "cd57be18d02f7d3390fb98539b93";
  52. private static final String CREATE_TIME = "2026-10-10T15:11:30+08:00";
  53. private WorkOrderService workOrderService;
  54. private AlarmDataService alarmDataService;
  55. private MockMvc mockMvc;
  56. @BeforeEach
  57. void setUp() {
  58. for (Class<?> entity : Arrays.asList(EquipmentBase.class, WorkOrder.class, AlarmData.class)) {
  59. TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new Configuration(), ""), entity);
  60. }
  61. workOrderService = mock(WorkOrderService.class);
  62. alarmDataService = mock(AlarmDataService.class);
  63. EquipmentBaseMapper equipmentMapper = mock(EquipmentBaseMapper.class);
  64. EquipmentBase equipment = new EquipmentBase();
  65. equipment.setEquipmentId("equipment-id");
  66. equipment.setEquipmentCode(DEVICE_CODE);
  67. when(equipmentMapper.selectById("equipment-id")).thenReturn(equipment);
  68. WorkOrder order = new WorkOrder();
  69. order.setOrderId(279L);
  70. order.setOrderNo(ORDER_CODE);
  71. order.setDeviceId("equipment-id");
  72. order.setOrderLevel(2);
  73. order.setOrderDesc("监测报警,请现场核实处理");
  74. order.setOrderStatus(0);
  75. order.setCreateTime(Date.from(Instant.parse("2026-10-10T07:11:30Z")));
  76. order.setUpdateTime(Date.from(Instant.parse("2026-10-10T07:11:30Z")));
  77. when(workOrderService.count(any(LambdaQueryWrapper.class))).thenReturn(7L);
  78. when(workOrderService.list(any(LambdaQueryWrapper.class)))
  79. .thenReturn(Collections.singletonList(order));
  80. AlarmData alarm = new AlarmData();
  81. alarm.setId(ALARM_ID);
  82. alarm.setWorkOrderId(279L);
  83. when(alarmDataService.list(any(LambdaQueryWrapper.class)))
  84. .thenReturn(Collections.singletonList(alarm));
  85. BusinessCockpitWorkOrderReadAdapter adapter = new BusinessCockpitWorkOrderReadAdapter(
  86. workOrderService, mock(EarlyWarningService.class), mock(AlarmWarningRelMapper.class),
  87. alarmDataService, equipmentMapper);
  88. CockpitWorkOrderReadService service = new CockpitWorkOrderReadService(
  89. adapter, Clock.fixed(Instant.parse("2026-10-10T07:11:30Z"), ZoneOffset.UTC));
  90. mockMvc = MockMvcBuilders.standaloneSetup(new CockpitWorkOrderReadController(service)).build();
  91. }
  92. @Test
  93. void listIsGlobalNotScopedToDeviceOrEvent() throws Exception {
  94. mockMvc.perform(get(BASE + "/work-orders"))
  95. .andExpect(status().isOk())
  96. .andExpect(jsonPath("$.data.state").value("READY"))
  97. .andExpect(jsonPath("$.data.workOrders[0].workOrderCode").value(ORDER_CODE))
  98. // 总数是 count 的结果(7),不是本页 1 条
  99. .andExpect(jsonPath("$.data.pagination.total").value(7))
  100. .andExpect(jsonPath("$.data.pagination.page").value(1))
  101. .andExpect(jsonPath("$.data.pagination.pageSize").value(10))
  102. .andExpect(jsonPath("$.data.pagination.totalPages").value(1))
  103. // 状态字典必须给(卡片按同一词表上色)
  104. .andExpect(jsonPath("$.data.stateDictionary[0].code").value(0));
  105. }
  106. @Test
  107. void pageAndSizeAreClampedAndEchoedBack() throws Exception {
  108. mockMvc.perform(get(BASE + "/work-orders").param("page", "0").param("pageSize", "9999"))
  109. .andExpect(status().isOk())
  110. .andExpect(jsonPath("$.data.pagination.page").value(1))
  111. .andExpect(jsonPath("$.data.pagination.pageSize").value(100));
  112. // 夹取后才下到适配器:offset 必须由生效值算出,不能让非法值进 SQL
  113. verify(workOrderService, org.mockito.Mockito.atLeastOnce())
  114. .list(any(LambdaQueryWrapper.class));
  115. }
  116. @Test
  117. void invalidStateCodeFallsBackToNoFilter() throws Exception {
  118. mockMvc.perform(get(BASE + "/work-orders").param("stateCode", "99"))
  119. .andExpect(status().isOk());
  120. // 越界状态码当成"不筛",仍然返回数据(而不是空列表假读数)
  121. verify(workOrderService, org.mockito.Mockito.atLeastOnce()).count(any(LambdaQueryWrapper.class));
  122. }
  123. @Test
  124. void validStateCodeIsApplied() throws Exception {
  125. mockMvc.perform(get(BASE + "/work-orders").param("stateCode", "3"))
  126. .andExpect(status().isOk());
  127. verify(workOrderService).count(any(LambdaQueryWrapper.class));
  128. }
  129. }