prepare-tests.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. from pathlib import Path
  2. root = Path('.scratch/cockpit-real-data-wayfinding/t28-patch/work/pipe-network-service/zksy-admin/src/test/java/com/zksy/web/controller/cockpit')
  3. p = root / 'CockpitMonitoringDistributionControllerTest.java'
  4. s = p.read_text(encoding='utf-8')
  5. changes = [
  6. ('jsonPath("$.data.pagination.total").value(8)', 'jsonPath("$.data.pagination.total").value(9)', 3),
  7. ('jsonPath("$.data.unassociatedEquipment", hasSize(3))', 'jsonPath("$.data.unassociatedEquipment", hasSize(4))', 2),
  8. ('jsonPath("$.data.pointStatusDistribution[3].count").value(1)', 'jsonPath("$.data.pointStatusDistribution[3].count").value(2)', 2),
  9. ('.deviceCount").value(4)', '.deviceCount").value(5)', 3),
  10. ('jsonPath("$.data.mapFilter.deviceCodes", hasSize(8))', 'jsonPath("$.data.mapFilter.deviceCodes", hasSize(9))', 1),
  11. ('jsonPath("$.data.excluded.invalidCoordinateCount").value(1)', 'jsonPath("$.data.excluded.invalidCoordinateCount").value(0)', 1),
  12. ('get(ENDPOINT).param("industry", "GAS"))\n .andExpect(status().isOk())\n .andExpect(jsonPath("$.data.pagination.total").value(3))', 'get(ENDPOINT).param("industry", "GAS"))\n .andExpect(status().isOk())\n .andExpect(jsonPath("$.data.pagination.total").value(4))', 1),
  13. ('jsonPath("$.data.unassociatedEquipment", hasSize(1))', 'jsonPath("$.data.unassociatedEquipment", hasSize(2))', 1),
  14. ('get(ENDPOINT).param("deviceType", "GAS_SENSOR"))\n .andExpect(status().isOk())\n .andExpect(jsonPath("$.data.pagination.total").value(3))', 'get(ENDPOINT).param("deviceType", "GAS_SENSOR"))\n .andExpect(status().isOk())\n .andExpect(jsonPath("$.data.pagination.total").value(4))', 1),
  15. ('assertEquals(1, statusCount(initial, CockpitMonitoringPointStatus.NORMAL));', 'assertEquals(2, statusCount(initial, CockpitMonitoringPointStatus.NORMAL));', 1),
  16. ('assertEquals(2, statusCount(applied, CockpitMonitoringPointStatus.NORMAL));', 'assertEquals(3, statusCount(applied, CockpitMonitoringPointStatus.NORMAL));', 1),
  17. ('assertEquals(2, statusCount(ignoredOld, CockpitMonitoringPointStatus.NORMAL));', 'assertEquals(3, statusCount(ignoredOld, CockpitMonitoringPointStatus.NORMAL));', 1),
  18. ('assertEquals(2, statusCount(ignoredUnknown, CockpitMonitoringPointStatus.NORMAL));', 'assertEquals(3, statusCount(ignoredUnknown, CockpitMonitoringPointStatus.NORMAL));', 1),
  19. ]
  20. for old, new, count in changes:
  21. assert s.count(old) == count, (old, s.count(old), count)
  22. s = s.replace(old, new)
  23. anchor = ' private int statusCount(CockpitMonitoringDistributionResponse response,'
  24. assert s.count(anchor) == 1
  25. s = s.replace(anchor, ''' @Test
  26. void sixEmptyUntypedPointsRemainInLedgerAndStatusTotalsWithoutVerifiedCoordinates() throws Exception {
  27. List<CockpitMonitoringDistributionSnapshot.SourceMonitoringPoint> points = new java.util.ArrayList<>();
  28. for (String code : Arrays.asList("GS001", "GS002", "PS001", "PS002", "RQ001", "RQ002")) {
  29. points.add(new CockpitMonitoringDistributionSnapshot.SourceMonitoringPoint(
  30. code, code, null, null, new BigDecimal("110.399876"), new BigDecimal("28.458287"),
  31. false, Collections.emptyList()));
  32. }
  33. CockpitMonitoringDistributionSnapshot snapshot = new CockpitMonitoringDistributionSnapshot(
  34. SNAPSHOT_AT, SNAPSHOT_AT, Collections.emptyList(), points, Collections.emptyList());
  35. when(adapter.load(null)).thenReturn(snapshot);
  36. when(adapter.load(SNAPSHOT_AT)).thenReturn(snapshot);
  37. mockMvc.perform(get(ENDPOINT).param("pointStatus", "EMPTY").param("pageSize", "2"))
  38. .andExpect(status().isOk())
  39. .andExpect(jsonPath("$.data.pagination.total").value(6))
  40. .andExpect(jsonPath("$.data.pagination.totalPages").value(3))
  41. .andExpect(jsonPath("$.data.pagination.hasMore").value(true))
  42. .andExpect(jsonPath("$.data.monitoringPoints", hasSize(2)))
  43. .andExpect(jsonPath("$.data.monitoringPoints[0].pointCode").value("GS001"))
  44. .andExpect(jsonPath("$.data.monitoringPoints[0].pointStatus").value("EMPTY"))
  45. .andExpect(jsonPath("$.data.monitoringPoints[0].industry").value(nullValue()))
  46. .andExpect(jsonPath("$.data.monitoringPoints[0].deviceType.code").value(nullValue()))
  47. .andExpect(jsonPath("$.data.monitoringPoints[0].coordinateValidation.renderable").value(false))
  48. .andExpect(jsonPath("$.data.pointStatusDistribution[5].count").value(6))
  49. .andExpect(jsonPath("$.data.districtDistribution[0].districtName").value("未分区"))
  50. .andExpect(jsonPath("$.data.districtDistribution[0].pointCount").value(6))
  51. .andExpect(jsonPath("$.data.industryDistribution[0].industry").value(nullValue()))
  52. .andExpect(jsonPath("$.data.industryDistribution[0].pointCount").value(6))
  53. .andExpect(jsonPath("$.data.deviceTypeDistribution[0].deviceType.code").value(nullValue()))
  54. .andExpect(jsonPath("$.data.mapFilter.pointCodes", hasSize(6)))
  55. .andExpect(jsonPath("$.data.mapFilter.deviceCodes", hasSize(0)))
  56. .andExpect(jsonPath("$.data.excluded.unknownTypeCount").value(0))
  57. .andExpect(jsonPath("$.data.excluded.invalidCoordinateCount").value(0))
  58. .andExpect(jsonPath("$.data.freshness.status").value("CURRENT"))
  59. .andExpect(jsonPath("$.data.freshness.reason").value("READY"));
  60. mockMvc.perform(get(ENDPOINT).param("page", "3").param("pageSize", "2").param("snapshotAt", SNAPSHOT_AT))
  61. .andExpect(status().isOk())
  62. .andExpect(jsonPath("$.data.pagination.total").value(6))
  63. .andExpect(jsonPath("$.data.pagination.hasMore").value(false))
  64. .andExpect(jsonPath("$.data.monitoringPoints[0].pointCode").value("RQ001"));
  65. mockMvc.perform(get(ENDPOINT).param("district", "UNASSIGNED"))
  66. .andExpect(status().isOk()).andExpect(jsonPath("$.data.pagination.total").value(6));
  67. for (String[] filter : Arrays.asList(new String[]{"industry", "GAS"},
  68. new String[]{"deviceType", "GAS_SENSOR"}, new String[]{"district", "0"},
  69. new String[]{"pointStatus", "NORMAL"})) {
  70. mockMvc.perform(get(ENDPOINT).param(filter[0], filter[1]))
  71. .andExpect(status().isOk()).andExpect(jsonPath("$.data.pagination.total").value(0));
  72. }
  73. }
  74. @Test
  75. void coordinatesDoNotAffectStatisticsAndAssociatedDevicesNeverBecomeStandaloneMarkers() {
  76. CockpitMonitoringPointDeviceSnapshot bound = device(
  77. "BOUND", "关联设备", true, true, false, false, Collections.emptyList());
  78. CockpitMonitoringDistributionSnapshot snapshot = new CockpitMonitoringDistributionSnapshot(
  79. SNAPSHOT_AT, SNAPSHOT_AT, fixture().getTypes(),
  80. Collections.singletonList(new CockpitMonitoringDistributionSnapshot.SourceMonitoringPoint(
  81. "P", "点位", 0, "GAS_SENSOR", null, null, false, Collections.singletonList(bound))),
  82. Arrays.asList(smartDevice("BOUND", "关联设备", 1, "GAS_SENSOR", "110.4", "28.4", false,
  83. true, true, false, false, Collections.emptyList()),
  84. smartDevice("FREE", "独立设备", 1, "GAS_SENSOR", "181", "28.4", true,
  85. true, false, false, false, Collections.emptyList())));
  86. when(adapter.load(null)).thenReturn(snapshot);
  87. CockpitMonitoringDistributionResponse all = service.load("all", null, null, null, null, 1, 100, null);
  88. assertEquals(2, all.getPagination().getTotal());
  89. assertEquals(1, all.getUnassociatedEquipment().size());
  90. assertEquals("FREE", all.getUnassociatedEquipment().get(0).getDeviceCode());
  91. assertTrue(!all.getMonitoringPoints().get(0).getCoordinateValidation().isRenderable());
  92. assertTrue(!all.getUnassociatedEquipment().get(0).getCoordinateValidation().isRenderable());
  93. assertEquals(0, all.getExcluded().getInvalidCoordinateCount());
  94. assertEquals("READY", all.getFreshness().getReason());
  95. assertEquals(1, statusCount(all, CockpitMonitoringPointStatus.ALARM));
  96. assertEquals(1, statusCount(all, CockpitMonitoringPointStatus.NORMAL));
  97. CockpitMonitoringDistributionResponse normal = service.load("normal", null, null, "NORMAL", null, 1, 100, null);
  98. assertEquals(Collections.singletonList("FREE"), normal.getMapFilter().getDeviceCodes());
  99. assertTrue(normal.getMapFilter().getPointCodes().isEmpty());
  100. CockpitMonitoringDistributionResponse district = service.load("district", null, null, null, "1", 1, 100, null);
  101. assertEquals(1, district.getPagination().getTotal(), "被筛掉的点位不能让关联设备变成独立设备");
  102. assertEquals(Collections.singletonList("FREE"), district.getMapFilter().getDeviceCodes());
  103. }
  104. @Test
  105. void exclusionsCountEachRejectedObjectOnceRegardlessOfAssociatedDeviceCount() {
  106. CockpitMonitoringPointDeviceSnapshot d = device("D", "设备", true, false, false, false, Collections.emptyList());
  107. CockpitMonitoringDistributionSnapshot snapshot = new CockpitMonitoringDistributionSnapshot(
  108. SNAPSHOT_AT, SNAPSHOT_AT, fixture().getTypes(), Arrays.asList(
  109. point("EMPTY", "合法空点", null, null, "110.4", "28.4"),
  110. point("UNKNOWN", "未知类型", 0, "LEGACY", "110.4", "28.4", d, d, d),
  111. point("MISMATCH", "错种类", 0, "WATER_PLANT", "110.4", "28.4", d, d),
  112. point("NONFORMAL", "无行业", 0, "SMART_MANHOLE", "110.4", "28.4", d)), Arrays.asList(
  113. smartDevice("U", "未知", 0, "LEGACY", "110.4", "28.4", true, true, false, false, false, Collections.emptyList()),
  114. smartDevice("M", "错种类", 0, "WATER_PLANT", "110.4", "28.4", true, true, false, false, false, Collections.emptyList()),
  115. smartDevice("N", "无行业", 0, "SMART_MANHOLE", "110.4", "28.4", true, true, false, false, false, Collections.emptyList())));
  116. when(adapter.load(null)).thenReturn(snapshot);
  117. CockpitMonitoringDistributionResponse response = service.load("reconcile", null, null, null, null, 1, 100, null);
  118. assertEquals(1, response.getPagination().getTotal());
  119. assertEquals(1, statusCount(response, CockpitMonitoringPointStatus.EMPTY));
  120. assertEquals(2, response.getExcluded().getUnknownTypeCount());
  121. assertEquals(2, response.getExcluded().getTypeKindMismatchCount());
  122. assertEquals(2, response.getExcluded().getNonFormalIndustryCount());
  123. int excluded = response.getExcluded().getUnknownTypeCount() + response.getExcluded().getTypeKindMismatchCount()
  124. + response.getExcluded().getNonFormalIndustryCount() + response.getExcluded().getInvalidCoordinateCount();
  125. assertEquals(7, response.getPagination().getTotal() + excluded);
  126. }
  127. ''' + anchor)
  128. p.write_text(s, encoding='utf-8', newline='\n')
  129. p = root / 'CockpitMonitoringOverviewControllerTest.java'
  130. s = p.read_text(encoding='utf-8')
  131. anchor = ' private static CockpitMonitoringOverviewSnapshot fixture() {'
  132. assert s.count(anchor) == 1
  133. s = s.replace(anchor, ''' @Test
  134. void sixEmptyUntypedPointsAreCountedAndEchoedWithoutFabricatingDevicesOrIndustry() throws Exception {
  135. List<CockpitMonitoringOverviewSnapshot.SourceMonitoringPoint> points = new ArrayList<>();
  136. for (String code : Arrays.asList("GS001", "GS002", "PS001", "PS002", "RQ001", "RQ002")) {
  137. points.add(new CockpitMonitoringOverviewSnapshot.SourceMonitoringPoint(code, null, 0));
  138. }
  139. when(adapter.load()).thenReturn(new CockpitMonitoringOverviewSnapshot(
  140. "2026-09-02T09:59:50+08:00", Collections.emptyList(), Collections.emptyList(), points));
  141. mockMvc.perform(get(ENDPOINT))
  142. .andExpect(status().isOk())
  143. .andExpect(jsonPath("$.data.counts.monitoringPointCount").value(6))
  144. .andExpect(jsonPath("$.data.counts.equipmentCount").value(0))
  145. .andExpect(jsonPath("$.data.mapFilter.pointCodes", hasSize(6)))
  146. .andExpect(jsonPath("$.data.mapFilter.deviceCodes", hasSize(0)))
  147. .andExpect(jsonPath("$.data.status.denominator").value(0))
  148. .andExpect(jsonPath("$.data.onlineRate.state").value("EMPTY"))
  149. .andExpect(jsonPath("$.data.freshness.status").value("CURRENT"))
  150. .andExpect(jsonPath("$.data.freshness.reason").value("READY"));
  151. for (String[] filter : Arrays.asList(new String[]{"industry", "GAS"}, new String[]{"deviceType", "GAS_SENSOR"})) {
  152. mockMvc.perform(get(ENDPOINT).param(filter[0], filter[1]))
  153. .andExpect(status().isOk())
  154. .andExpect(jsonPath("$.data.counts.monitoringPointCount").value(0))
  155. .andExpect(jsonPath("$.data.mapFilter.pointCodes", hasSize(0)));
  156. }
  157. }
  158. @Test
  159. void unknownOrMixedTypeWithDevicesIsNotReinterpretedAsAnEmptyPoint() {
  160. when(adapter.load()).thenReturn(new CockpitMonitoringOverviewSnapshot(
  161. "2026-09-02T09:59:50+08:00", fixture().getTypes(), Collections.emptyList(), Arrays.asList(
  162. new CockpitMonitoringOverviewSnapshot.SourceMonitoringPoint("EMPTY", null, 0),
  163. new CockpitMonitoringOverviewSnapshot.SourceMonitoringPoint("MIXED", null, 2),
  164. new CockpitMonitoringOverviewSnapshot.SourceMonitoringPoint("LEGACY", null),
  165. new CockpitMonitoringOverviewSnapshot.SourceMonitoringPoint("FACILITY", "WATER_PLANT", 0))));
  166. CockpitMonitoringOverviewResponse response = service.load("points", null, null);
  167. assertEquals(1, response.getCounts().getMonitoringPointCount());
  168. assertEquals(Collections.singletonList("EMPTY"), response.getMapFilter().getPointCodes());
  169. }
  170. ''' + anchor)
  171. p.write_text(s, encoding='utf-8', newline='\n')
  172. p = root / 'BusinessCockpitMonitoringOverviewAdapterTest.java'
  173. s = p.read_text(encoding='utf-8')
  174. anchor = ' // ---- helpers ----'
  175. assert s.count(anchor) == 1
  176. s = s.replace(anchor, ''' @Test
  177. void realEmptyPointsAndMissingDeviceTypesPublishDistinctAssociationFacts() {
  178. stubPoints(Arrays.asList(point("P0", "EMPTY"), point("P1", "UNKNOWN")));
  179. stubTypes(Collections.emptyList());
  180. EquipmentBase bound = device("D", "BOUND", "99");
  181. when(equipmentBaseService.list()).thenReturn(Collections.singletonList(bound));
  182. when(equipmentBaseService.getEquipmentByPoint("P0")).thenReturn(Collections.emptyList());
  183. when(equipmentBaseService.getEquipmentByPoint("P1")).thenReturn(Arrays.asList(bound, bound));
  184. CockpitMonitoringOverviewSnapshot snapshot = adapter.load();
  185. assertNull(snapshot.getMonitoringPoints().get(0).getTypeCode());
  186. assertEquals(0, snapshot.getMonitoringPoints().get(0).getAssociatedDeviceCount());
  187. assertNull(snapshot.getMonitoringPoints().get(1).getTypeCode());
  188. assertEquals(1, snapshot.getMonitoringPoints().get(1).getAssociatedDeviceCount());
  189. CockpitMonitoringOverviewService service = new CockpitMonitoringOverviewService(
  190. () -> snapshot, Clock.fixed(Instant.parse("2026-09-02T02:00:00Z"), ZoneOffset.UTC));
  191. var response = service.load("empty-real", null, null);
  192. assertEquals(1, response.getCounts().getMonitoringPointCount());
  193. assertEquals(Collections.singletonList("EMPTY"), response.getMapFilter().getPointCodes());
  194. }
  195. ''' + anchor)
  196. p.write_text(s, encoding='utf-8', newline='\n')
  197. print('Updated existing coordinate expectations and added six contract regression tests; tests not executed.')