@oneuptime/common 12.0.12 → 12.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +32 -5
  2. package/Models/DatabaseModels/NetworkDevice.ts +64 -0
  3. package/Models/DatabaseModels/StatusPage.ts +59 -0
  4. package/Models/DatabaseModels/StatusPageOidc.ts +2 -0
  5. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -2
  6. package/Server/API/AIChatAPI.ts +55 -56
  7. package/Server/API/CommonAPI.ts +89 -0
  8. package/Server/API/MicrosoftTeamsAPI.ts +20 -9
  9. package/Server/API/SlackAPI.ts +13 -10
  10. package/Server/API/StatusPageAPI.ts +2197 -2128
  11. package/Server/API/TelemetryAPI.ts +72 -3
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.ts +30 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.ts +47 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  15. package/Server/Middleware/UserAuthorization.ts +11 -2
  16. package/Server/Services/ApiKeyPermissionService.ts +116 -2
  17. package/Server/Services/DatabaseService.ts +17 -6
  18. package/Server/Services/LogAggregationService.ts +34 -0
  19. package/Server/Services/LogService.ts +21 -0
  20. package/Server/Services/NetworkSiteService.ts +12 -0
  21. package/Server/Services/SpanService.ts +21 -0
  22. package/Server/Services/TraceAggregationService.ts +15 -0
  23. package/Server/Services/WorkspaceNotificationRuleService.ts +172 -220
  24. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
  25. package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -16
  26. package/Server/Utils/APIKey/AccessPermission.ts +16 -40
  27. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +144 -0
  28. package/Server/Utils/LogRedaction.ts +576 -0
  29. package/Server/Utils/Logger.ts +123 -46
  30. package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +94 -23
  31. package/Server/Utils/Monitor/MonitorResource.ts +29 -9
  32. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +28 -7
  33. package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +56 -10
  34. package/Server/Utils/StartServer.ts +30 -9
  35. package/Server/Utils/StatusPageSearchEngineIndexing.ts +33 -0
  36. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +441 -0
  37. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +488 -46
  38. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +300 -0
  39. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +130 -0
  40. package/Tests/Models/DatabaseModels/DatabaseBaseModelToJSONObjectCache.test.ts +180 -0
  41. package/Tests/Models/StatusPageEnableSearchEngineIndexing.test.ts +157 -0
  42. package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +23 -1
  43. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +785 -0
  44. package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +21 -8
  45. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +290 -0
  46. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +7 -1
  47. package/Tests/Server/API/StatusPageOverviewCache.test.ts +474 -0
  48. package/Tests/Server/API/StatusPageSeoSearchEngineIndexing.test.ts +189 -0
  49. package/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts +158 -0
  50. package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +9 -60
  51. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +24 -15
  52. package/Tests/Server/Middleware/UserAuthorization.test.ts +79 -0
  53. package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +332 -0
  54. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +347 -0
  55. package/Tests/Server/Services/DatabaseServiceUpdateDebugLogging.test.ts +282 -0
  56. package/Tests/Server/Services/NetworkSiteService.test.ts +56 -2
  57. package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +267 -0
  58. package/Tests/Server/Services/WorkspaceNotificationRuleTestRuleChannels.test.ts +702 -0
  59. package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +165 -0
  60. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +48 -36
  61. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +213 -0
  62. package/Tests/Server/Utils/LogRedaction.test.ts +415 -0
  63. package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +245 -0
  64. package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +374 -4
  65. package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +455 -0
  66. package/Tests/Server/Utils/Monitor/NetworkDeviceReachabilityRoundTrip.test.ts +369 -0
  67. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +86 -8
  68. package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +64 -0
  69. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCacheStore.test.ts +207 -0
  70. package/Tests/Server/Utils/StartServerBodyVerify.test.ts +335 -0
  71. package/Tests/Server/Utils/StatusPageSearchEngineIndexing.test.ts +60 -0
  72. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +435 -0
  73. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +607 -62
  74. package/Tests/Server/Utils/Workspace/MicrosoftTeamsInstalledTeamIdSpace.test.ts +778 -0
  75. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +44 -10
  76. package/Tests/Types/API/HostnameFromAuthority.test.ts +164 -0
  77. package/Tests/Types/Database/AccessControl/ColumnAccessControlCache.test.ts +344 -0
  78. package/Tests/Types/Database/DatabasePropertyFindOperator.test.ts +518 -0
  79. package/Tests/Types/Database/TableColumnMetadataCache.test.ts +286 -0
  80. package/Tests/Types/Monitor/MonitorStep.test.ts +100 -0
  81. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +360 -0
  82. package/Tests/Types/StatusPage/SearchEngineIndexing.test.ts +86 -0
  83. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +254 -0
  84. package/Tests/UI/Components/CardSelect.test.tsx +1021 -0
  85. package/Tests/UI/Components/MasterPage.test.tsx +36 -1
  86. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +66 -1
  87. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +115 -6
  88. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +610 -0
  89. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +114 -45
  90. package/Types/API/Hostname.ts +79 -0
  91. package/Types/Database/AccessControl/ColumnAccessControl.ts +33 -11
  92. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +33 -11
  93. package/Types/Database/DatabaseProperty.ts +38 -0
  94. package/Types/Database/TableColumn.ts +34 -7
  95. package/Types/Events/Recurring.ts +16 -1
  96. package/Types/Monitor/MonitorStep.ts +13 -1
  97. package/Types/Monitor/MonitorType.ts +345 -40
  98. package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +43 -0
  99. package/Types/StatusPage/SearchEngineIndexing.ts +61 -0
  100. package/Types/Telemetry/ResourceEntityFacet.ts +211 -0
  101. package/UI/Components/CardSelect/CardSelect.tsx +714 -105
  102. package/UI/Components/EmptyState/EmptyState.tsx +8 -1
  103. package/UI/Components/Footer/Footer.tsx +32 -6
  104. package/UI/Components/Forms/Fields/FormField.tsx +3 -0
  105. package/UI/Components/Forms/Types/Field.ts +8 -0
  106. package/UI/Components/Loader/PageLoader.tsx +29 -8
  107. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +26 -4
  108. package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +17 -1
  109. package/UI/Components/MasterPage/MasterPage.tsx +24 -11
  110. package/Utils/Monitor/MonitorMetricType.ts +16 -1
  111. package/Utils/Monitor/NetworkTopologyUtil.ts +60 -8
  112. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +262 -0
  113. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +41 -24
  114. package/Utils/Telemetry/CrossSignalScope.ts +75 -4
  115. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +20 -4
  116. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  117. package/build/dist/Models/DatabaseModels/NetworkDevice.js +66 -0
  118. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  119. package/build/dist/Models/DatabaseModels/StatusPage.js +60 -0
  120. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  121. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +2 -0
  122. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  123. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  124. package/build/dist/Server/API/AIChatAPI.js +48 -35
  125. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  126. package/build/dist/Server/API/CommonAPI.js +59 -0
  127. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  128. package/build/dist/Server/API/MicrosoftTeamsAPI.js +20 -6
  129. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  130. package/build/dist/Server/API/SlackAPI.js +13 -10
  131. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  132. package/build/dist/Server/API/StatusPageAPI.js +745 -673
  133. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  134. package/build/dist/Server/API/TelemetryAPI.js +34 -3
  135. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  136. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js +23 -0
  137. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js.map +1 -0
  138. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js +34 -0
  139. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js.map +1 -0
  140. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  141. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  142. package/build/dist/Server/Middleware/UserAuthorization.js +6 -2
  143. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  144. package/build/dist/Server/Services/ApiKeyPermissionService.js +90 -1
  145. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  146. package/build/dist/Server/Services/DatabaseService.js +15 -6
  147. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  148. package/build/dist/Server/Services/LogAggregationService.js +2 -0
  149. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  150. package/build/dist/Server/Services/LogService.js +16 -0
  151. package/build/dist/Server/Services/LogService.js.map +1 -1
  152. package/build/dist/Server/Services/NetworkSiteService.js +12 -0
  153. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  154. package/build/dist/Server/Services/SpanService.js +16 -0
  155. package/build/dist/Server/Services/SpanService.js.map +1 -1
  156. package/build/dist/Server/Services/TraceAggregationService.js +2 -0
  157. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  158. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +137 -164
  159. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  160. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
  161. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  162. package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +21 -13
  163. package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
  164. package/build/dist/Server/Utils/APIKey/AccessPermission.js +9 -32
  165. package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
  166. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +87 -0
  167. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  168. package/build/dist/Server/Utils/LogRedaction.js +449 -0
  169. package/build/dist/Server/Utils/LogRedaction.js.map +1 -0
  170. package/build/dist/Server/Utils/Logger.js +98 -45
  171. package/build/dist/Server/Utils/Logger.js.map +1 -1
  172. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +65 -13
  173. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
  174. package/build/dist/Server/Utils/Monitor/MonitorResource.js +20 -3
  175. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  176. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +27 -7
  177. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  178. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +29 -10
  179. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -1
  180. package/build/dist/Server/Utils/StartServer.js +10 -7
  181. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  182. package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js +24 -0
  183. package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js.map +1 -0
  184. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +311 -0
  185. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -0
  186. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +366 -37
  187. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  188. package/build/dist/Types/API/Hostname.js +63 -0
  189. package/build/dist/Types/API/Hostname.js.map +1 -1
  190. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +20 -6
  191. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  192. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +20 -6
  193. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  194. package/build/dist/Types/Database/DatabaseProperty.js +38 -0
  195. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  196. package/build/dist/Types/Database/TableColumn.js +24 -6
  197. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  198. package/build/dist/Types/Events/Recurring.js +13 -1
  199. package/build/dist/Types/Events/Recurring.js.map +1 -1
  200. package/build/dist/Types/Monitor/MonitorStep.js +9 -1
  201. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  202. package/build/dist/Types/Monitor/MonitorType.js +330 -31
  203. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  204. package/build/dist/Types/StatusPage/SearchEngineIndexing.js +55 -0
  205. package/build/dist/Types/StatusPage/SearchEngineIndexing.js.map +1 -0
  206. package/build/dist/Types/Telemetry/ResourceEntityFacet.js +156 -0
  207. package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -0
  208. package/build/dist/UI/Components/CardSelect/CardSelect.js +360 -40
  209. package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
  210. package/build/dist/UI/Components/EmptyState/EmptyState.js +1 -1
  211. package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
  212. package/build/dist/UI/Components/Footer/Footer.js +7 -4
  213. package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
  214. package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
  215. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  216. package/build/dist/UI/Components/Loader/PageLoader.js +15 -5
  217. package/build/dist/UI/Components/Loader/PageLoader.js.map +1 -1
  218. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +16 -3
  219. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  220. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js +13 -1
  221. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
  222. package/build/dist/UI/Components/MasterPage/MasterPage.js +10 -2
  223. package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
  224. package/build/dist/Utils/Monitor/MonitorMetricType.js +13 -1
  225. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  226. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +34 -7
  227. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  228. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +177 -0
  229. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -0
  230. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +23 -27
  231. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  232. package/build/dist/Utils/Telemetry/CrossSignalScope.js +44 -4
  233. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  234. package/package.json +1 -1
@@ -0,0 +1,455 @@
1
+ /*
2
+ * Which monitor step a result is evaluated against.
3
+ *
4
+ * A monitor can have several steps and EACH step carries its own criteria. A
5
+ * probe result names the step it actually ran in `monitorStepId`, so that step
6
+ * — not whichever step happens to sit first in the array — decides which
7
+ * criteria may match. Five outputs hang off that choice:
8
+ *
9
+ * - `criteriaMetId`, matched against the ingested step's criteria only;
10
+ * - `ingestedMonitorStepId`, echoed back to the probe;
11
+ * - `nextMonitorStepId`, which walks the chain from the ingested step;
12
+ * - the step handed to MonitorCriteriaEvaluator.processMonitorStep;
13
+ * - the step handed to checkProbeAgreement, which keys every other probe's
14
+ * lastMonitoringLog by step id — the wrong id compares this result against
15
+ * other probes' state for a different step.
16
+ *
17
+ * MonitorResource used to run the `.find()` for the ingested step and DISCARD
18
+ * its result, leaving `monitorStep` pinned to `monitorStepsInstanceArray[0]`.
19
+ * Single-step monitors (the overwhelming majority, including every SSL
20
+ * monitor) could not notice; multi-step monitors silently evaluated every
21
+ * step's results against step 0's criteria.
22
+ *
23
+ * A `monitorStepId` that matches NO step is stale — the step was deleted after
24
+ * the probe was scheduled — and still falls back to step 0 rather than
25
+ * dropping the result. That fallback is pinned here too, because it is the one
26
+ * case where "use step 0" is deliberate rather than a bug.
27
+ *
28
+ * Everything heavy is mocked BEFORE importing MonitorResource: the criteria
29
+ * evaluator (pulls native isolated-vm via VMAPI/VMRunner), the monitor and
30
+ * probe services (Postgres), the per-monitor semaphore (Redis), the metric and
31
+ * log utils (ClickHouse) and the logger. checkProbeAgreement is spied on so
32
+ * this suite pins only the step it is HANDED — its internals are covered by
33
+ * MonitorResourceProbeAgreementReuse.test.ts. Pure in-memory model instances.
34
+ */
35
+
36
+ jest.mock("../../../../Server/Utils/Monitor/MonitorCriteriaEvaluator", () => {
37
+ return {
38
+ __esModule: true,
39
+ default: {
40
+ processMonitorStep: jest.fn(),
41
+ },
42
+ };
43
+ });
44
+
45
+ jest.mock("../../../../Server/Services/MonitorService", () => {
46
+ return {
47
+ __esModule: true,
48
+ default: {
49
+ findOneById: jest.fn(),
50
+ updateColumnsByIdWithoutHooks: jest.fn(),
51
+ },
52
+ };
53
+ });
54
+
55
+ jest.mock("../../../../Server/Services/MonitorProbeService", () => {
56
+ return {
57
+ __esModule: true,
58
+ default: {
59
+ findBy: jest.fn(),
60
+ updateColumnsByIdWithoutHooks: jest.fn(),
61
+ },
62
+ };
63
+ });
64
+
65
+ jest.mock("../../../../Server/Infrastructure/Semaphore", () => {
66
+ return {
67
+ __esModule: true,
68
+ default: {
69
+ lock: jest.fn(),
70
+ release: jest.fn(),
71
+ },
72
+ };
73
+ });
74
+
75
+ jest.mock("../../../../Server/Utils/Monitor/MonitorMetricUtil", () => {
76
+ return {
77
+ __esModule: true,
78
+ default: {
79
+ saveMonitorMetrics: jest.fn(),
80
+ },
81
+ };
82
+ });
83
+
84
+ jest.mock("../../../../Server/Utils/Monitor/MonitorLogUtil", () => {
85
+ return {
86
+ __esModule: true,
87
+ default: {
88
+ saveMonitorLog: jest.fn(),
89
+ },
90
+ };
91
+ });
92
+
93
+ jest.mock("../../../../Server/Utils/Logger", () => {
94
+ return {
95
+ __esModule: true,
96
+ default: {
97
+ debug: jest.fn(),
98
+ info: jest.fn(),
99
+ warn: jest.fn(),
100
+ error: jest.fn(),
101
+ trace: jest.fn(),
102
+ },
103
+ };
104
+ });
105
+
106
+ import MonitorResourceUtil from "../../../../Server/Utils/Monitor/MonitorResource";
107
+ import MonitorCriteriaEvaluator from "../../../../Server/Utils/Monitor/MonitorCriteriaEvaluator";
108
+ import MonitorService from "../../../../Server/Services/MonitorService";
109
+ import MonitorProbeService from "../../../../Server/Services/MonitorProbeService";
110
+ import Semaphore from "../../../../Server/Infrastructure/Semaphore";
111
+ import DataToProcess from "../../../../Server/Utils/Monitor/DataToProcess";
112
+ import Monitor from "../../../../Models/DatabaseModels/Monitor";
113
+ import MonitorProbe from "../../../../Models/DatabaseModels/MonitorProbe";
114
+ import MonitorCriteria from "../../../../Types/Monitor/MonitorCriteria";
115
+ import MonitorCriteriaInstance from "../../../../Types/Monitor/MonitorCriteriaInstance";
116
+ import MonitorStep from "../../../../Types/Monitor/MonitorStep";
117
+ import MonitorSteps from "../../../../Types/Monitor/MonitorSteps";
118
+ import MonitorType from "../../../../Types/Monitor/MonitorType";
119
+ import ServerMonitorResponse from "../../../../Types/Monitor/ServerMonitor/ServerMonitorResponse";
120
+ import ObjectID from "../../../../Types/ObjectID";
121
+ import OneUptimeDate from "../../../../Types/Date";
122
+ import ProbeApiIngestResponse from "../../../../Types/Probe/ProbeApiIngestResponse";
123
+ import ProbeMonitorResponse from "../../../../Types/Probe/ProbeMonitorResponse";
124
+ import { describe, expect, test, beforeEach, afterEach } from "@jest/globals";
125
+
126
+ const processMonitorStepMock: jest.Mock =
127
+ MonitorCriteriaEvaluator.processMonitorStep as unknown as jest.Mock;
128
+
129
+ const findOneByIdMock: jest.Mock =
130
+ MonitorService.findOneById as unknown as jest.Mock;
131
+
132
+ const findByMock: jest.Mock =
133
+ MonitorProbeService.findBy as unknown as jest.Mock;
134
+
135
+ const lockMock: jest.Mock = Semaphore.lock as unknown as jest.Mock;
136
+
137
+ /*
138
+ * One criteria per step, so the criteria id that comes back on the response
139
+ * names the step it was read off — exactly the coupling the discarded lookup
140
+ * broke.
141
+ */
142
+ type MakeStep = (criteriaName: string) => MonitorStep;
143
+
144
+ const makeStep: MakeStep = (criteriaName: string): MonitorStep => {
145
+ const criteriaInstance: MonitorCriteriaInstance =
146
+ new MonitorCriteriaInstance();
147
+ criteriaInstance.data!.name = criteriaName;
148
+
149
+ const monitorCriteria: MonitorCriteria = new MonitorCriteria();
150
+ monitorCriteria.data = {
151
+ monitorCriteriaInstanceArray: [criteriaInstance],
152
+ };
153
+
154
+ const step: MonitorStep = new MonitorStep();
155
+ step.data!.monitorCriteria = monitorCriteria;
156
+
157
+ return step;
158
+ };
159
+
160
+ type CriteriaIdOfStep = (step: MonitorStep) => string;
161
+
162
+ const criteriaIdOfStep: CriteriaIdOfStep = (step: MonitorStep): string => {
163
+ return step.data!.monitorCriteria.data!.monitorCriteriaInstanceArray[0]!.data!
164
+ .id;
165
+ };
166
+
167
+ type MakeMonitor = (input: {
168
+ monitorType: MonitorType;
169
+ steps: Array<MonitorStep>;
170
+ }) => Monitor;
171
+
172
+ const makeMonitor: MakeMonitor = (input: {
173
+ monitorType: MonitorType;
174
+ steps: Array<MonitorStep>;
175
+ }): Monitor => {
176
+ const monitorSteps: MonitorSteps = new MonitorSteps();
177
+ monitorSteps.data = {
178
+ monitorStepsInstanceArray: input.steps,
179
+ /*
180
+ * Left undefined on purpose: a set default status sends the
181
+ * no-criteria-met path into MonitorStatusTimelineService, which this
182
+ * suite has no reason to reach.
183
+ */
184
+ defaultMonitorStatusId: undefined,
185
+ };
186
+
187
+ const monitor: Monitor = new Monitor();
188
+ monitor.id = ObjectID.generate();
189
+ monitor.projectId = ObjectID.generate();
190
+ monitor.monitorType = input.monitorType;
191
+ monitor.monitorSteps = monitorSteps;
192
+
193
+ return monitor;
194
+ };
195
+
196
+ type MakeProbeResult = (input: {
197
+ monitor: Monitor;
198
+ probeId: ObjectID;
199
+ monitorStepId: ObjectID;
200
+ }) => DataToProcess;
201
+
202
+ const makeProbeResult: MakeProbeResult = (input: {
203
+ monitor: Monitor;
204
+ probeId: ObjectID;
205
+ monitorStepId: ObjectID;
206
+ }): DataToProcess => {
207
+ return {
208
+ projectId: input.monitor.projectId!,
209
+ monitorId: input.monitor.id!,
210
+ probeId: input.probeId,
211
+ monitorStepId: input.monitorStepId,
212
+ isOnline: true,
213
+ failureCause: "",
214
+ } as ProbeMonitorResponse;
215
+ };
216
+
217
+ type StepPassedToEvaluator = () => MonitorStep;
218
+
219
+ const stepPassedToEvaluator: StepPassedToEvaluator = (): MonitorStep => {
220
+ return processMonitorStepMock.mock.calls[0]![0].monitorStep;
221
+ };
222
+
223
+ describe("MonitorResourceUtil.monitorResource ingested monitor step selection", () => {
224
+ let checkProbeAgreementSpy: jest.SpyInstance;
225
+
226
+ beforeEach(() => {
227
+ jest.clearAllMocks();
228
+
229
+ lockMock.mockResolvedValue({});
230
+
231
+ /*
232
+ * Stands in for the real evaluator in the one respect this suite is
233
+ * about: the criteria it can match are exactly the ones hanging off the
234
+ * step it was handed. rootCause stays null so the criteria-met branch
235
+ * (incidents, alerts, status timeline) never runs.
236
+ */
237
+ processMonitorStepMock.mockImplementation(
238
+ (input: {
239
+ monitorStep: MonitorStep;
240
+ probeApiIngestResponse: ProbeApiIngestResponse;
241
+ }): Promise<ProbeApiIngestResponse> => {
242
+ return Promise.resolve({
243
+ ...input.probeApiIngestResponse,
244
+ criteriaMetId: criteriaIdOfStep(input.monitorStep),
245
+ rootCause: null,
246
+ });
247
+ },
248
+ );
249
+
250
+ /*
251
+ * Agreement itself is covered elsewhere; here it only has to pass the
252
+ * evaluated criteria through so the response still reports it, while
253
+ * recording the step it was given.
254
+ */
255
+ checkProbeAgreementSpy = jest
256
+ .spyOn(MonitorResourceUtil as any, "checkProbeAgreement")
257
+ .mockImplementation((input: any) => {
258
+ return Promise.resolve({
259
+ hasAgreement: true,
260
+ agreementCount: 1,
261
+ requiredCount: 1,
262
+ totalActiveProbes: 1,
263
+ agreedCriteriaId: input.currentCriteriaMetId,
264
+ agreedRootCause: input.currentRootCause,
265
+ agreedProbeNames: [],
266
+ });
267
+ });
268
+ });
269
+
270
+ afterEach(() => {
271
+ jest.restoreAllMocks();
272
+ });
273
+
274
+ describe("probe result naming a step (multi-step monitor)", () => {
275
+ let stepOne: MonitorStep;
276
+ let stepTwo: MonitorStep;
277
+ let stepThree: MonitorStep;
278
+ let monitor: Monitor;
279
+ let probeId: ObjectID;
280
+
281
+ beforeEach(() => {
282
+ stepOne = makeStep("Step one criteria");
283
+ stepTwo = makeStep("Step two criteria");
284
+ stepThree = makeStep("Step three criteria");
285
+
286
+ monitor = makeMonitor({
287
+ monitorType: MonitorType.Website,
288
+ steps: [stepOne, stepTwo, stepThree],
289
+ });
290
+
291
+ probeId = ObjectID.generate();
292
+
293
+ const monitorProbe: MonitorProbe = new MonitorProbe();
294
+ monitorProbe.id = ObjectID.generate();
295
+ monitorProbe.probeId = probeId;
296
+ monitorProbe.isEnabled = true;
297
+
298
+ findOneByIdMock.mockResolvedValue(monitor);
299
+ findByMock.mockResolvedValue([monitorProbe]);
300
+ });
301
+
302
+ test("evaluates the named step's criteria, not step 0's", async () => {
303
+ const response: ProbeApiIngestResponse =
304
+ await MonitorResourceUtil.monitorResource(
305
+ makeProbeResult({
306
+ monitor: monitor,
307
+ probeId: probeId,
308
+ monitorStepId: stepTwo.id,
309
+ }),
310
+ );
311
+
312
+ expect(stepPassedToEvaluator().id.toString()).toBe(stepTwo.id.toString());
313
+ expect(response.criteriaMetId).toBe(criteriaIdOfStep(stepTwo));
314
+ expect(response.criteriaMetId).not.toBe(criteriaIdOfStep(stepOne));
315
+ });
316
+
317
+ test("reports the named step as the ingested step", async () => {
318
+ const response: ProbeApiIngestResponse =
319
+ await MonitorResourceUtil.monitorResource(
320
+ makeProbeResult({
321
+ monitor: monitor,
322
+ probeId: probeId,
323
+ monitorStepId: stepTwo.id,
324
+ }),
325
+ );
326
+
327
+ expect(response.ingestedMonitorStepId?.toString()).toBe(
328
+ stepTwo.id.toString(),
329
+ );
330
+ });
331
+
332
+ test("walks the step chain on from the named step", async () => {
333
+ const response: ProbeApiIngestResponse =
334
+ await MonitorResourceUtil.monitorResource(
335
+ makeProbeResult({
336
+ monitor: monitor,
337
+ probeId: probeId,
338
+ monitorStepId: stepTwo.id,
339
+ }),
340
+ );
341
+
342
+ // Step three follows step two — not step two, which follows step one.
343
+ expect(response.nextMonitorStepId?.toString()).toBe(
344
+ stepThree.id.toString(),
345
+ );
346
+ });
347
+
348
+ test("the last step has no next step", async () => {
349
+ const response: ProbeApiIngestResponse =
350
+ await MonitorResourceUtil.monitorResource(
351
+ makeProbeResult({
352
+ monitor: monitor,
353
+ probeId: probeId,
354
+ monitorStepId: stepThree.id,
355
+ }),
356
+ );
357
+
358
+ expect(response.nextMonitorStepId).toBeUndefined();
359
+ });
360
+
361
+ test("hands probe agreement the named step, so it reads the right step's probe logs", async () => {
362
+ await MonitorResourceUtil.monitorResource(
363
+ makeProbeResult({
364
+ monitor: monitor,
365
+ probeId: probeId,
366
+ monitorStepId: stepTwo.id,
367
+ }),
368
+ );
369
+
370
+ expect(checkProbeAgreementSpy).toHaveBeenCalledTimes(1);
371
+
372
+ const agreementInput: { monitorStep: MonitorStep } =
373
+ checkProbeAgreementSpy.mock.calls[0]![0] as {
374
+ monitorStep: MonitorStep;
375
+ };
376
+
377
+ expect(agreementInput.monitorStep.id.toString()).toBe(
378
+ stepTwo.id.toString(),
379
+ );
380
+ });
381
+
382
+ test("step 0 is still selected when the result names step 0", async () => {
383
+ const response: ProbeApiIngestResponse =
384
+ await MonitorResourceUtil.monitorResource(
385
+ makeProbeResult({
386
+ monitor: monitor,
387
+ probeId: probeId,
388
+ monitorStepId: stepOne.id,
389
+ }),
390
+ );
391
+
392
+ expect(stepPassedToEvaluator().id.toString()).toBe(stepOne.id.toString());
393
+ expect(response.criteriaMetId).toBe(criteriaIdOfStep(stepOne));
394
+ expect(response.ingestedMonitorStepId?.toString()).toBe(
395
+ stepOne.id.toString(),
396
+ );
397
+ });
398
+
399
+ test("an unknown step id falls back to step 0 rather than dropping the result", async () => {
400
+ // The step was deleted after this probe was scheduled.
401
+ const response: ProbeApiIngestResponse =
402
+ await MonitorResourceUtil.monitorResource(
403
+ makeProbeResult({
404
+ monitor: monitor,
405
+ probeId: probeId,
406
+ monitorStepId: ObjectID.generate(),
407
+ }),
408
+ );
409
+
410
+ expect(stepPassedToEvaluator().id.toString()).toBe(stepOne.id.toString());
411
+ expect(response.criteriaMetId).toBe(criteriaIdOfStep(stepOne));
412
+ expect(response.ingestedMonitorStepId?.toString()).toBe(
413
+ stepOne.id.toString(),
414
+ );
415
+ expect(response.nextMonitorStepId?.toString()).toBe(
416
+ stepTwo.id.toString(),
417
+ );
418
+ });
419
+ });
420
+
421
+ describe("result carrying no step id", () => {
422
+ test("uses step 0", async () => {
423
+ /*
424
+ * Server monitors heartbeat in without a monitorStepId at all — the
425
+ * whole lookup is skipped and step 0 is the intended step.
426
+ */
427
+ const stepOne: MonitorStep = makeStep("Step one criteria");
428
+ const stepTwo: MonitorStep = makeStep("Step two criteria");
429
+
430
+ const monitor: Monitor = makeMonitor({
431
+ monitorType: MonitorType.Server,
432
+ steps: [stepOne, stepTwo],
433
+ });
434
+
435
+ findOneByIdMock.mockResolvedValue(monitor);
436
+
437
+ const serverMonitorResponse: ServerMonitorResponse = {
438
+ projectId: monitor.projectId!,
439
+ monitorId: monitor.id!,
440
+ hostname: "test-host",
441
+ requestReceivedAt: OneUptimeDate.getCurrentDate(),
442
+ onlyCheckRequestReceivedAt: false,
443
+ };
444
+
445
+ const response: ProbeApiIngestResponse =
446
+ await MonitorResourceUtil.monitorResource(serverMonitorResponse);
447
+
448
+ expect(stepPassedToEvaluator().id.toString()).toBe(stepOne.id.toString());
449
+ expect(response.criteriaMetId).toBe(criteriaIdOfStep(stepOne));
450
+ expect(response.ingestedMonitorStepId?.toString()).toBe(
451
+ stepOne.id.toString(),
452
+ );
453
+ });
454
+ });
455
+ });