@oneuptime/common 11.5.12 → 11.6.0

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 (193) hide show
  1. package/Models/DatabaseModels/AIInsight.ts +30 -0
  2. package/Models/DatabaseModels/EnterpriseLicense.ts +21 -0
  3. package/Models/DatabaseModels/EnterpriseLicenseInstance.ts +25 -0
  4. package/Models/DatabaseModels/GlobalConfig.ts +76 -0
  5. package/Models/DatabaseModels/Project.ts +30 -0
  6. package/Models/DatabaseModels/TelemetryException.ts +128 -0
  7. package/Server/API/AIAgentDataAPI.ts +129 -5
  8. package/Server/API/AIInvestigationAPI.ts +87 -0
  9. package/Server/API/EnterpriseLicenseAPI.ts +57 -0
  10. package/Server/API/GlobalConfigAPI.ts +62 -1
  11. package/Server/EnvironmentConfig.ts +22 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1784640000000-AddExceptionTriageAndPrivacyColumns.ts +56 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.ts +38 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.ts +25 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  16. package/Server/Services/AIRunService.ts +8 -0
  17. package/Server/Services/AnalyticsDatabaseService.ts +48 -45
  18. package/Server/Services/DatabaseService.ts +66 -1
  19. package/Server/Services/TelemetryExceptionService.ts +320 -24
  20. package/Server/Services/WorkflowService.ts +100 -39
  21. package/Server/Types/Workflow/Components/Schedule.ts +57 -32
  22. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +15 -4
  23. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +15 -4
  24. package/Server/Utils/AI/SRE/Insights/InsightScanner.ts +222 -24
  25. package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +225 -9
  26. package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +39 -0
  27. package/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.ts +114 -0
  28. package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +59 -0
  29. package/Server/Utils/Express.ts +13 -0
  30. package/Server/Utils/Telemetry/ExceptionSanitizer.ts +222 -0
  31. package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +799 -0
  32. package/Server/Utils/Telemetry/TelemetryWriterClient.ts +263 -0
  33. package/Server/Utils/Telemetry/TelemetryWriterServer.ts +240 -0
  34. package/Server/Utils/Telemetry/TelemetryWriterShedMetrics.ts +93 -0
  35. package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +232 -0
  36. package/Tests/Server/Services/TelemetryExceptionCodeFixRun.test.ts +205 -1
  37. package/Tests/Server/Services/UpdateOneByIdKeepsRowId.test.ts +107 -0
  38. package/Tests/Server/Services/WorkflowService.test.ts +308 -0
  39. package/Tests/Server/Utils/AI/Insights/InsightScanner.test.ts +150 -141
  40. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +277 -1
  41. package/Tests/Server/Utils/Attribution.test.ts +203 -0
  42. package/Tests/Server/Utils/ExceptionSanitizer.test.ts +70 -0
  43. package/Tests/Server/Utils/InsightTriageClassification.test.ts +57 -0
  44. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +183 -0
  45. package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +340 -0
  46. package/Tests/Server/Utils/Monitor/Criteria/ExceptionMonitorCriteria.test.ts +87 -0
  47. package/Tests/Server/Utils/Monitor/Criteria/LogMonitorCriteria.test.ts +165 -0
  48. package/Tests/Server/Utils/Monitor/Criteria/TraceMonitorCriteria.test.ts +86 -0
  49. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +1565 -0
  50. package/Tests/Server/Utils/Telemetry/TelemetryWriterClient.test.ts +313 -0
  51. package/Tests/Server/Utils/Telemetry/TelemetryWriterServer.test.ts +270 -0
  52. package/Tests/Server/Utils/Telemetry/TelemetryWriterShedMetrics.test.ts +127 -0
  53. package/Tests/Server/Utils/TelemetryImprovementTaskTrigger.test.ts +141 -0
  54. package/Tests/Types/AI/CodeFixTaskType.test.ts +3 -0
  55. package/Tests/Types/Monitor/MonitorCriteriaMetricVariables.test.ts +228 -0
  56. package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +169 -0
  57. package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +289 -0
  58. package/Tests/Types/Monitor/MonitorStepLogMonitor.test.ts +231 -0
  59. package/Tests/Types/Monitor/MonitorStepMetricViewConfigUtil.test.ts +245 -0
  60. package/Tests/Types/Monitor/MonitorStepNetworkDeviceMonitor.test.ts +155 -0
  61. package/Tests/Types/Monitor/MonitorStepTelemetrySerialization.test.ts +141 -0
  62. package/Tests/Types/Monitor/MonitorStepTraceMonitor.test.ts +137 -0
  63. package/Tests/Types/Workspace/NotificationRules/NotificationRuleCondition.test.ts +311 -0
  64. package/Tests/UI/Components/ModelTableSelectFromColumns.test.ts +259 -0
  65. package/Tests/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.test.ts +461 -0
  66. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +2852 -0
  67. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +758 -0
  68. package/Tests/UI/Utils/NotificationMethodUtil.test.ts +564 -0
  69. package/Tests/Utils/Array.test.ts +156 -0
  70. package/Tests/Utils/CronTab.test.ts +199 -0
  71. package/Tests/Utils/ModelImportExport.test.ts +101 -0
  72. package/Tests/Utils/Number.test.ts +179 -0
  73. package/Tests/Utils/VersionUtil.test.ts +348 -0
  74. package/Tests/jest.setup.ts +1 -0
  75. package/Types/AI/CodeFixTaskContext.ts +6 -0
  76. package/Types/AI/CodeFixTaskType.ts +38 -1
  77. package/Types/AI/ExceptionAIClassification.ts +27 -0
  78. package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +6 -0
  79. package/Types/Log/LogScrubPatternType.ts +7 -0
  80. package/Types/Monitor/MonitorStep.ts +24 -4
  81. package/Types/Monitor/MonitorStepMetricViewConfigUtil.ts +105 -0
  82. package/Types/Trace/TraceScrubPatternType.ts +7 -0
  83. package/UI/Components/EditionLabel/EditionLabel.tsx +445 -12
  84. package/UI/Components/ModelTable/BaseModelTable.tsx +15 -46
  85. package/UI/Components/ModelTable/SelectFromColumns.ts +129 -0
  86. package/UI/Components/Workflow/ArgumentsForm.tsx +68 -30
  87. package/UI/Components/Workflow/CronScheduleField.tsx +411 -0
  88. package/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.ts +176 -0
  89. package/UI/Utils/NotificationMethodUtil.ts +310 -0
  90. package/Utils/CronTab.ts +823 -0
  91. package/Utils/ModelImportExport.ts +21 -6
  92. package/Utils/VersionUtil.ts +260 -0
  93. package/build/dist/Models/DatabaseModels/AIInsight.js +31 -0
  94. package/build/dist/Models/DatabaseModels/AIInsight.js.map +1 -1
  95. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +22 -0
  96. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  97. package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js +26 -0
  98. package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js.map +1 -1
  99. package/build/dist/Models/DatabaseModels/GlobalConfig.js +81 -0
  100. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  101. package/build/dist/Models/DatabaseModels/Project.js +31 -0
  102. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  103. package/build/dist/Models/DatabaseModels/TelemetryException.js +134 -0
  104. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  105. package/build/dist/Server/API/AIAgentDataAPI.js +97 -8
  106. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  107. package/build/dist/Server/API/AIInvestigationAPI.js +55 -0
  108. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  109. package/build/dist/Server/API/EnterpriseLicenseAPI.js +47 -0
  110. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  111. package/build/dist/Server/API/GlobalConfigAPI.js +52 -1
  112. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  113. package/build/dist/Server/EnvironmentConfig.js +17 -0
  114. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  115. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784640000000-AddExceptionTriageAndPrivacyColumns.js +33 -0
  116. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784640000000-AddExceptionTriageAndPrivacyColumns.js.map +1 -0
  117. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.js +18 -0
  118. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784659816363-AddInstanceVersionAndLatestReleaseColumns.js.map +1 -0
  119. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.js +14 -0
  120. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784705487674-AddEnterpriseLicenseEvaluationColumns.js.map +1 -0
  121. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  122. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  123. package/build/dist/Server/Services/AIRunService.js +9 -2
  124. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  125. package/build/dist/Server/Services/AnalyticsDatabaseService.js +44 -16
  126. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  127. package/build/dist/Server/Services/DatabaseService.js +53 -1
  128. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  129. package/build/dist/Server/Services/TelemetryExceptionService.js +263 -22
  130. package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
  131. package/build/dist/Server/Services/WorkflowService.js +80 -30
  132. package/build/dist/Server/Services/WorkflowService.js.map +1 -1
  133. package/build/dist/Server/Types/Workflow/Components/Schedule.js +44 -19
  134. package/build/dist/Server/Types/Workflow/Components/Schedule.js.map +1 -1
  135. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +12 -4
  136. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  137. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +12 -4
  138. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  139. package/build/dist/Server/Utils/AI/SRE/Insights/InsightScanner.js +193 -22
  140. package/build/dist/Server/Utils/AI/SRE/Insights/InsightScanner.js.map +1 -1
  141. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +178 -9
  142. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
  143. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +37 -0
  144. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
  145. package/build/dist/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.js +98 -0
  146. package/build/dist/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.js.map +1 -0
  147. package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js +24 -0
  148. package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -0
  149. package/build/dist/Server/Utils/Express.js +12 -0
  150. package/build/dist/Server/Utils/Express.js.map +1 -1
  151. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +149 -0
  152. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -0
  153. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +496 -0
  154. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -0
  155. package/build/dist/Server/Utils/Telemetry/TelemetryWriterClient.js +165 -0
  156. package/build/dist/Server/Utils/Telemetry/TelemetryWriterClient.js.map +1 -0
  157. package/build/dist/Server/Utils/Telemetry/TelemetryWriterServer.js +136 -0
  158. package/build/dist/Server/Utils/Telemetry/TelemetryWriterServer.js.map +1 -0
  159. package/build/dist/Server/Utils/Telemetry/TelemetryWriterShedMetrics.js +76 -0
  160. package/build/dist/Server/Utils/Telemetry/TelemetryWriterShedMetrics.js.map +1 -0
  161. package/build/dist/Types/AI/CodeFixTaskType.js +38 -1
  162. package/build/dist/Types/AI/CodeFixTaskType.js.map +1 -1
  163. package/build/dist/Types/AI/ExceptionAIClassification.js +28 -0
  164. package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -0
  165. package/build/dist/Types/Log/LogScrubPatternType.js +7 -0
  166. package/build/dist/Types/Log/LogScrubPatternType.js.map +1 -1
  167. package/build/dist/Types/Monitor/MonitorStep.js +20 -4
  168. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  169. package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js +73 -0
  170. package/build/dist/Types/Monitor/MonitorStepMetricViewConfigUtil.js.map +1 -0
  171. package/build/dist/Types/Trace/TraceScrubPatternType.js +7 -0
  172. package/build/dist/Types/Trace/TraceScrubPatternType.js.map +1 -1
  173. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +261 -13
  174. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  175. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +12 -37
  176. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  177. package/build/dist/UI/Components/ModelTable/SelectFromColumns.js +82 -0
  178. package/build/dist/UI/Components/ModelTable/SelectFromColumns.js.map +1 -0
  179. package/build/dist/UI/Components/Workflow/ArgumentsForm.js +30 -6
  180. package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
  181. package/build/dist/UI/Components/Workflow/CronScheduleField.js +209 -0
  182. package/build/dist/UI/Components/Workflow/CronScheduleField.js.map +1 -0
  183. package/build/dist/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.js +129 -0
  184. package/build/dist/UI/Utils/Breadcrumb/BreadcrumbTrailResolver.js.map +1 -0
  185. package/build/dist/UI/Utils/NotificationMethodUtil.js +189 -0
  186. package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -0
  187. package/build/dist/Utils/CronTab.js +609 -0
  188. package/build/dist/Utils/CronTab.js.map +1 -0
  189. package/build/dist/Utils/ModelImportExport.js +20 -6
  190. package/build/dist/Utils/ModelImportExport.js.map +1 -1
  191. package/build/dist/Utils/VersionUtil.js +193 -0
  192. package/build/dist/Utils/VersionUtil.js.map +1 -0
  193. package/package.json +1 -1
@@ -0,0 +1,141 @@
1
+ import TelemetryImprovementTaskTrigger from "../../../Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger";
2
+ import SubjectCodeFixRun from "../../../Server/Utils/AI/SRE/SubjectCodeFixRun";
3
+ import ServiceService from "../../../Server/Services/ServiceService";
4
+ import Service from "../../../Models/DatabaseModels/Service";
5
+ import AIRun from "../../../Models/DatabaseModels/AIRun";
6
+ import CodeFixTaskType from "../../../Types/AI/CodeFixTaskType";
7
+ import ObjectID from "../../../Types/ObjectID";
8
+ import { describe, expect, test, afterEach, beforeEach } from "@jest/globals";
9
+
10
+ /*
11
+ * The service-scoped instrumentation-improvement triggers (ImproveLogging /
12
+ * ImproveTracing): human-triggered, so every unmet gate fails EARLY with a
13
+ * clear message — unsupported recipe, missing/foreign service, no
14
+ * GitHub-App repository, or a duplicate active run for the same service.
15
+ */
16
+
17
+ const projectId: ObjectID = ObjectID.generate();
18
+ const telemetryServiceId: ObjectID = ObjectID.generate();
19
+ const userId: ObjectID = ObjectID.generate();
20
+
21
+ function mockService(overrides: Partial<Service> = {}): void {
22
+ jest.spyOn(ServiceService, "findOneById").mockResolvedValue({
23
+ id: telemetryServiceId,
24
+ name: "checkout",
25
+ projectId: projectId,
26
+ ...overrides,
27
+ } as unknown as Service);
28
+ }
29
+
30
+ describe("TelemetryImprovementTaskTrigger.createTelemetryImprovementTask", () => {
31
+ beforeEach(() => {
32
+ jest
33
+ .spyOn(SubjectCodeFixRun, "hasGitHubAppConnectedRepository")
34
+ .mockResolvedValue(true);
35
+ jest
36
+ .spyOn(SubjectCodeFixRun, "findNonTerminalRunForTelemetryService")
37
+ .mockResolvedValue(null);
38
+ });
39
+
40
+ afterEach(() => {
41
+ jest.restoreAllMocks();
42
+ });
43
+
44
+ test("rejects non-improvement recipes before touching anything", async () => {
45
+ const findService: jest.SpyInstance = jest.spyOn(
46
+ ServiceService,
47
+ "findOneById",
48
+ );
49
+
50
+ await expect(
51
+ TelemetryImprovementTaskTrigger.createTelemetryImprovementTask({
52
+ projectId,
53
+ telemetryServiceId,
54
+ taskType: CodeFixTaskType.FixException,
55
+ userId,
56
+ }),
57
+ ).rejects.toThrow(/not a telemetry-improvement recipe/);
58
+
59
+ expect(findService).not.toHaveBeenCalled();
60
+ });
61
+
62
+ test("rejects a service from another project (root read, explicit tenant check)", async () => {
63
+ mockService({ projectId: ObjectID.generate() });
64
+
65
+ await expect(
66
+ TelemetryImprovementTaskTrigger.createTelemetryImprovementTask({
67
+ projectId,
68
+ telemetryServiceId,
69
+ taskType: CodeFixTaskType.ImproveLogging,
70
+ userId,
71
+ }),
72
+ ).rejects.toThrow(/not found/);
73
+ });
74
+
75
+ test("rejects when no GitHub-App-connected repository exists", async () => {
76
+ mockService();
77
+ jest
78
+ .spyOn(SubjectCodeFixRun, "hasGitHubAppConnectedRepository")
79
+ .mockResolvedValue(false);
80
+
81
+ await expect(
82
+ TelemetryImprovementTaskTrigger.createTelemetryImprovementTask({
83
+ projectId,
84
+ telemetryServiceId,
85
+ taskType: CodeFixTaskType.ImproveLogging,
86
+ userId,
87
+ }),
88
+ ).rejects.toThrow(/GitHub-App-connected repository/);
89
+ });
90
+
91
+ test("per-(service, recipe) dedupe: an active run for the service blocks a second one", async () => {
92
+ mockService();
93
+ jest
94
+ .spyOn(SubjectCodeFixRun, "findNonTerminalRunForTelemetryService")
95
+ .mockResolvedValue({ id: ObjectID.generate() } as unknown as AIRun);
96
+ const enqueue: jest.SpyInstance = jest.spyOn(
97
+ SubjectCodeFixRun,
98
+ "enqueueSubjectCodeFixRun",
99
+ );
100
+
101
+ await expect(
102
+ TelemetryImprovementTaskTrigger.createTelemetryImprovementTask({
103
+ projectId,
104
+ telemetryServiceId,
105
+ taskType: CodeFixTaskType.ImproveTracing,
106
+ userId,
107
+ }),
108
+ ).rejects.toThrow(/already queued or running/);
109
+
110
+ expect(enqueue).not.toHaveBeenCalled();
111
+ });
112
+
113
+ test("happy path: enqueues with the service captured in taskContext and the user attributed", async () => {
114
+ mockService();
115
+ const createdRun: AIRun = { id: ObjectID.generate() } as unknown as AIRun;
116
+ const enqueue: jest.SpyInstance = jest
117
+ .spyOn(SubjectCodeFixRun, "enqueueSubjectCodeFixRun")
118
+ .mockResolvedValue(createdRun);
119
+
120
+ const run: AIRun =
121
+ await TelemetryImprovementTaskTrigger.createTelemetryImprovementTask({
122
+ projectId,
123
+ telemetryServiceId,
124
+ taskType: CodeFixTaskType.ImproveLogging,
125
+ userId,
126
+ });
127
+
128
+ expect(run).toBe(createdRun);
129
+ expect(enqueue).toHaveBeenCalledWith(
130
+ expect.objectContaining({
131
+ projectId,
132
+ taskType: CodeFixTaskType.ImproveLogging,
133
+ userId,
134
+ taskContext: expect.objectContaining({
135
+ telemetryServiceId: telemetryServiceId.toString(),
136
+ serviceName: "checkout",
137
+ }),
138
+ }),
139
+ );
140
+ });
141
+ });
@@ -9,6 +9,7 @@ describe("CodeFixTaskTypeHelper", () => {
9
9
  expect(CodeFixTaskTypeHelper.getUserTriggerableTaskTypes()).toEqual([
10
10
  CodeFixTaskType.FixException,
11
11
  CodeFixTaskType.WriteRegressionTest,
12
+ CodeFixTaskType.ImproveExceptionHandling,
12
13
  ]);
13
14
  });
14
15
  });
@@ -17,6 +18,7 @@ describe("CodeFixTaskTypeHelper", () => {
17
18
  test.each([
18
19
  CodeFixTaskType.FixException,
19
20
  CodeFixTaskType.WriteRegressionTest,
21
+ CodeFixTaskType.ImproveExceptionHandling,
20
22
  ])("returns true for %s", (taskType: CodeFixTaskType) => {
21
23
  expect(CodeFixTaskTypeHelper.isUserTriggerable(taskType)).toBe(true);
22
24
  });
@@ -69,6 +71,7 @@ describe("CodeFixTaskTypeHelper", () => {
69
71
  test.each([
70
72
  CodeFixTaskType.FixException,
71
73
  CodeFixTaskType.WriteRegressionTest,
74
+ CodeFixTaskType.ImproveExceptionHandling,
72
75
  ])("returns true for %s", (taskType: CodeFixTaskType) => {
73
76
  expect(CodeFixTaskTypeHelper.requiresTelemetryException(taskType)).toBe(
74
77
  true,
@@ -0,0 +1,228 @@
1
+ import MetricsAggregationType from "../../../Types/Metrics/MetricsAggregationType";
2
+ import { CheckOn, CriteriaFilter } from "../../../Types/Monitor/CriteriaFilter";
3
+ import { getAllCephAlertTemplates } from "../../../Types/Monitor/CephAlertTemplates";
4
+ import { getAllDockerAlertTemplates } from "../../../Types/Monitor/DockerAlertTemplates";
5
+ import { getAllDockerSwarmAlertTemplates } from "../../../Types/Monitor/DockerSwarmAlertTemplates";
6
+ import {
7
+ buildHostMonitorConfig,
8
+ getAllHostAlertTemplates,
9
+ } from "../../../Types/Monitor/HostAlertTemplates";
10
+ import { getAllIoTAlertTemplates } from "../../../Types/Monitor/IotAlertTemplates";
11
+ import { getAllKubernetesAlertTemplates } from "../../../Types/Monitor/KubernetesAlertTemplates";
12
+ import { getAllPodmanAlertTemplates } from "../../../Types/Monitor/PodmanAlertTemplates";
13
+ import { getAllProxmoxAlertTemplates } from "../../../Types/Monitor/ProxmoxAlertTemplates";
14
+ import MonitorCriteriaInstance from "../../../Types/Monitor/MonitorCriteriaInstance";
15
+ import MonitorStep, {
16
+ MonitorStepType,
17
+ } from "../../../Types/Monitor/MonitorStep";
18
+ import MonitorStepHostMonitor from "../../../Types/Monitor/MonitorStepHostMonitor";
19
+ import MonitorStepMetricViewConfigUtil from "../../../Types/Monitor/MonitorStepMetricViewConfigUtil";
20
+ import RollingTime from "../../../Types/RollingTime/RollingTime";
21
+ import ObjectID from "../../../Types/ObjectID";
22
+
23
+ /*
24
+ * End-to-end regression guard for the blank "METRIC" dropdown (Issues 1 & 2).
25
+ *
26
+ * For EVERY metric-shaped monitor type, a Quick Setup alert template must
27
+ * produce a monitor step whose metric variables are discoverable through
28
+ * MonitorStepMetricViewConfigUtil — the same resolver the criteria UI uses to
29
+ * fill the "Which metric query should this alert rule check?" dropdown. And
30
+ * every MetricValue criteria the template emits must reference a variable that
31
+ * the dropdown actually offers, otherwise the alert rule points at a metric the
32
+ * user can never (re)select.
33
+ *
34
+ * Before the fix, Host / Podman / DockerSwarm / IoT would all fail the
35
+ * "surfaces at least one metric variable" assertion because the criteria UI
36
+ * never read their metricViewConfig.
37
+ */
38
+
39
+ // Superset of every template's Args — excess fields are ignored per type.
40
+ interface UniversalTemplateArgs {
41
+ hostIdentifier: string;
42
+ clusterIdentifier: string;
43
+ fleetIdentifier: string;
44
+ onlineMonitorStatusId: ObjectID;
45
+ offlineMonitorStatusId: ObjectID;
46
+ defaultIncidentSeverityId: ObjectID;
47
+ defaultAlertSeverityId: ObjectID;
48
+ monitorName: string;
49
+ }
50
+
51
+ interface AnyAlertTemplate {
52
+ id: string;
53
+ name: string;
54
+ getMonitorStep: (args: UniversalTemplateArgs) => MonitorStep;
55
+ }
56
+
57
+ interface ResourceDescriptor {
58
+ name: string;
59
+ subConfigKey: keyof MonitorStepType;
60
+ templates: Array<AnyAlertTemplate>;
61
+ }
62
+
63
+ function buildArgs(): UniversalTemplateArgs {
64
+ return {
65
+ hostIdentifier: "host-identifier-1",
66
+ clusterIdentifier: "cluster-identifier-1",
67
+ fleetIdentifier: "fleet-identifier-1",
68
+ onlineMonitorStatusId: ObjectID.generate(),
69
+ offlineMonitorStatusId: ObjectID.generate(),
70
+ defaultIncidentSeverityId: ObjectID.generate(),
71
+ defaultAlertSeverityId: ObjectID.generate(),
72
+ monitorName: "Test Monitor",
73
+ };
74
+ }
75
+
76
+ const RESOURCES: Array<ResourceDescriptor> = [
77
+ {
78
+ name: "Host",
79
+ subConfigKey: "hostMonitor",
80
+ templates: getAllHostAlertTemplates() as unknown as Array<AnyAlertTemplate>,
81
+ },
82
+ {
83
+ name: "Kubernetes",
84
+ subConfigKey: "kubernetesMonitor",
85
+ templates:
86
+ getAllKubernetesAlertTemplates() as unknown as Array<AnyAlertTemplate>,
87
+ },
88
+ {
89
+ name: "Docker",
90
+ subConfigKey: "dockerMonitor",
91
+ templates:
92
+ getAllDockerAlertTemplates() as unknown as Array<AnyAlertTemplate>,
93
+ },
94
+ {
95
+ name: "DockerSwarm",
96
+ subConfigKey: "dockerSwarmMonitor",
97
+ templates:
98
+ getAllDockerSwarmAlertTemplates() as unknown as Array<AnyAlertTemplate>,
99
+ },
100
+ {
101
+ name: "Podman",
102
+ subConfigKey: "podmanMonitor",
103
+ templates:
104
+ getAllPodmanAlertTemplates() as unknown as Array<AnyAlertTemplate>,
105
+ },
106
+ {
107
+ name: "Proxmox",
108
+ subConfigKey: "proxmoxMonitor",
109
+ templates:
110
+ getAllProxmoxAlertTemplates() as unknown as Array<AnyAlertTemplate>,
111
+ },
112
+ {
113
+ name: "Ceph",
114
+ subConfigKey: "cephMonitor",
115
+ templates: getAllCephAlertTemplates() as unknown as Array<AnyAlertTemplate>,
116
+ },
117
+ {
118
+ name: "IoT",
119
+ subConfigKey: "iotMonitor",
120
+ templates: getAllIoTAlertTemplates() as unknown as Array<AnyAlertTemplate>,
121
+ },
122
+ ];
123
+
124
+ function getCriteriaInstances(
125
+ step: MonitorStep,
126
+ ): Array<MonitorCriteriaInstance> {
127
+ return step.data?.monitorCriteria?.data?.monitorCriteriaInstanceArray || [];
128
+ }
129
+
130
+ describe("Monitor criteria metric-variable resolution (all resource types)", () => {
131
+ test("every resource type exposes at least one alert template", () => {
132
+ for (const resource of RESOURCES) {
133
+ expect(resource.templates.length).toBeGreaterThan(0);
134
+ }
135
+ });
136
+
137
+ describe.each(RESOURCES)(
138
+ "$name alert templates",
139
+ (resource: ResourceDescriptor) => {
140
+ test("the resolver reads this resource's metricViewConfig", () => {
141
+ const step: MonitorStep =
142
+ resource.templates[0]!.getMonitorStep(buildArgs());
143
+
144
+ const stepRecord: Record<
145
+ string,
146
+ { metricViewConfig?: unknown } | undefined
147
+ > = step.data as unknown as Record<
148
+ string,
149
+ { metricViewConfig?: unknown } | undefined
150
+ >;
151
+
152
+ const expectedConfig: unknown =
153
+ stepRecord[resource.subConfigKey as string]?.metricViewConfig;
154
+
155
+ expect(expectedConfig).toBeDefined();
156
+ expect(
157
+ MonitorStepMetricViewConfigUtil.getMetricViewConfig(step.data),
158
+ ).toBe(expectedConfig);
159
+ });
160
+
161
+ test.each(
162
+ resource.templates.map(
163
+ (t: AnyAlertTemplate): [string, AnyAlertTemplate] => {
164
+ return [t.id, t];
165
+ },
166
+ ),
167
+ )(
168
+ "%s surfaces metric variables and resolves its criteria aliases",
169
+ (_id: string, template: AnyAlertTemplate) => {
170
+ const step: MonitorStep = template.getMonitorStep(buildArgs());
171
+
172
+ // 1. The dropdown would offer at least one option (the actual bug).
173
+ const variables: Array<string> =
174
+ MonitorStepMetricViewConfigUtil.getMetricVariables(step.data);
175
+ expect(variables.length).toBeGreaterThan(0);
176
+ // No blank options leak through.
177
+ expect(variables).not.toContain("");
178
+
179
+ // 2. Every MetricValue criteria references an offered variable.
180
+ const referencedAliases: Set<string> = new Set<string>();
181
+ for (const instance of getCriteriaInstances(step)) {
182
+ for (const filter of (instance.data?.filters ||
183
+ []) as Array<CriteriaFilter>) {
184
+ if (
185
+ filter.checkOn === CheckOn.MetricValue &&
186
+ filter.metricMonitorOptions?.metricAlias
187
+ ) {
188
+ referencedAliases.add(filter.metricMonitorOptions.metricAlias);
189
+ }
190
+ }
191
+ }
192
+
193
+ // These templates must produce at least one metric criteria.
194
+ expect(referencedAliases.size).toBeGreaterThan(0);
195
+
196
+ for (const alias of referencedAliases) {
197
+ expect(variables).toContain(alias);
198
+ }
199
+ },
200
+ );
201
+ },
202
+ );
203
+ });
204
+
205
+ describe("Custom Metric flow (buildHostMonitorConfig)", () => {
206
+ test("a long descriptive alias is surfaced by the resolver", () => {
207
+ const config: MonitorStepHostMonitor = buildHostMonitorConfig({
208
+ hostIdentifier: "host-1",
209
+ metricName: "process.cpu.utilization",
210
+ metricAlias: "process_cpu_utilization",
211
+ rollingTime: RollingTime.Past5Minutes,
212
+ aggregationType: MetricsAggregationType.Max,
213
+ });
214
+
215
+ const stepData: MonitorStepType = {
216
+ hostMonitor: config,
217
+ } as unknown as MonitorStepType;
218
+
219
+ expect(
220
+ MonitorStepMetricViewConfigUtil.getMetricVariables(stepData),
221
+ ).toEqual(["process_cpu_utilization"]);
222
+
223
+ // The alias also lands on the query config so the criteria join key holds.
224
+ expect(
225
+ config.metricViewConfig.queryConfigs[0]?.metricAliasData?.metricVariable,
226
+ ).toBe("process_cpu_utilization");
227
+ });
228
+ });
@@ -0,0 +1,169 @@
1
+ import MonitorStep from "../../../Types/Monitor/MonitorStep";
2
+ import MonitorType from "../../../Types/Monitor/MonitorType";
3
+ import ObjectID from "../../../Types/ObjectID";
4
+ import { MonitorStepLogMonitorUtil } from "../../../Types/Monitor/MonitorStepLogMonitor";
5
+ import { MonitorStepTraceMonitorUtil } from "../../../Types/Monitor/MonitorStepTraceMonitor";
6
+ import { MonitorStepMetricMonitorUtil } from "../../../Types/Monitor/MonitorStepMetricMonitor";
7
+ import { MonitorStepExceptionMonitorUtil } from "../../../Types/Monitor/MonitorStepExceptionMonitor";
8
+
9
+ /*
10
+ * Regression coverage for the "log monitors do not work" bug: a telemetry
11
+ * monitor step created on defaults must persist its own type's sub-config
12
+ * (logMonitor / traceMonitor / metricMonitor / exceptionMonitor) rather than
13
+ * leaving it undefined. When it was left undefined, the worker's
14
+ * monitorLogs()/monitorTrace()/... threw "<type> query/config is missing" on
15
+ * every evaluation, so the monitor never ran and its criteria never applied.
16
+ */
17
+ describe("MonitorStep.getDefaultMonitorStep telemetry sub-config seeding", () => {
18
+ const buildArgs: (
19
+ monitorType: MonitorType,
20
+ ) => Parameters<typeof MonitorStep.getDefaultMonitorStep>[0] = (
21
+ monitorType: MonitorType,
22
+ ) => {
23
+ const id: ObjectID = ObjectID.generate();
24
+ return {
25
+ monitorName: `${monitorType} monitor`,
26
+ monitorType,
27
+ onlineMonitorStatusId: id,
28
+ offlineMonitorStatusId: id,
29
+ defaultIncidentSeverityId: id,
30
+ defaultAlertSeverityId: id,
31
+ };
32
+ };
33
+
34
+ describe("seeds exactly the matching type's sub-config", () => {
35
+ test("Logs monitor seeds logMonitor equal to its util default", () => {
36
+ const step: MonitorStep = MonitorStep.getDefaultMonitorStep(
37
+ buildArgs(MonitorType.Logs),
38
+ );
39
+
40
+ expect(step.data?.logMonitor).toBeDefined();
41
+ expect(step.data?.logMonitor).toEqual(
42
+ MonitorStepLogMonitorUtil.getDefault(),
43
+ );
44
+ // The default query config must be usable (positive time window).
45
+ expect(step.data?.logMonitor?.lastXSecondsOfLogs).toBeGreaterThan(0);
46
+ expect(step.data?.traceMonitor).toBeUndefined();
47
+ expect(step.data?.metricMonitor).toBeUndefined();
48
+ expect(step.data?.exceptionMonitor).toBeUndefined();
49
+ });
50
+
51
+ test("Traces monitor seeds traceMonitor equal to its util default", () => {
52
+ const step: MonitorStep = MonitorStep.getDefaultMonitorStep(
53
+ buildArgs(MonitorType.Traces),
54
+ );
55
+
56
+ expect(step.data?.traceMonitor).toBeDefined();
57
+ expect(step.data?.traceMonitor).toEqual(
58
+ MonitorStepTraceMonitorUtil.getDefault(),
59
+ );
60
+ expect(step.data?.traceMonitor?.lastXSecondsOfSpans).toBeGreaterThan(0);
61
+ expect(step.data?.logMonitor).toBeUndefined();
62
+ expect(step.data?.metricMonitor).toBeUndefined();
63
+ expect(step.data?.exceptionMonitor).toBeUndefined();
64
+ });
65
+
66
+ test("Metrics monitor seeds metricMonitor equal to its util default", () => {
67
+ const step: MonitorStep = MonitorStep.getDefaultMonitorStep(
68
+ buildArgs(MonitorType.Metrics),
69
+ );
70
+
71
+ expect(step.data?.metricMonitor).toBeDefined();
72
+ expect(step.data?.metricMonitor).toEqual(
73
+ MonitorStepMetricMonitorUtil.getDefault(),
74
+ );
75
+ expect(step.data?.metricMonitor?.metricViewConfig).toBeDefined();
76
+ expect(step.data?.logMonitor).toBeUndefined();
77
+ expect(step.data?.traceMonitor).toBeUndefined();
78
+ expect(step.data?.exceptionMonitor).toBeUndefined();
79
+ });
80
+
81
+ test("Exceptions monitor seeds exceptionMonitor equal to its util default", () => {
82
+ const step: MonitorStep = MonitorStep.getDefaultMonitorStep(
83
+ buildArgs(MonitorType.Exceptions),
84
+ );
85
+
86
+ expect(step.data?.exceptionMonitor).toBeDefined();
87
+ expect(step.data?.exceptionMonitor).toEqual(
88
+ MonitorStepExceptionMonitorUtil.getDefault(),
89
+ );
90
+ expect(step.data?.logMonitor).toBeUndefined();
91
+ expect(step.data?.traceMonitor).toBeUndefined();
92
+ expect(step.data?.metricMonitor).toBeUndefined();
93
+ });
94
+ });
95
+
96
+ describe("does not seed a telemetry sub-config for other types", () => {
97
+ /*
98
+ * Only the four telemetry types offered by the Telemetry picker are
99
+ * seeded here. Infra metric monitors (Kubernetes/Docker/Host/...) carry
100
+ * their own sub-config from templates, and non-telemetry monitors have
101
+ * no telemetry sub-config at all — none must get a logMonitor/traceMonitor
102
+ * /metricMonitor/exceptionMonitor from the generic default step.
103
+ */
104
+ const nonSeededTypes: Array<MonitorType> = [
105
+ MonitorType.Ping,
106
+ MonitorType.IP,
107
+ MonitorType.Port,
108
+ MonitorType.Website,
109
+ MonitorType.API,
110
+ MonitorType.Server,
111
+ MonitorType.SSLCertificate,
112
+ MonitorType.IncomingRequest,
113
+ MonitorType.SyntheticMonitor,
114
+ MonitorType.CustomJavaScriptCode,
115
+ MonitorType.SQLQuery,
116
+ MonitorType.Manual,
117
+ MonitorType.Profiles,
118
+ MonitorType.Kubernetes,
119
+ MonitorType.Docker,
120
+ MonitorType.Host,
121
+ MonitorType.Podman,
122
+ MonitorType.DockerSwarm,
123
+ MonitorType.Proxmox,
124
+ MonitorType.Ceph,
125
+ MonitorType.IoTDevice,
126
+ ];
127
+
128
+ test.each(nonSeededTypes)(
129
+ "%s seeds no telemetry sub-config",
130
+ (monitorType: MonitorType) => {
131
+ const step: MonitorStep = MonitorStep.getDefaultMonitorStep(
132
+ buildArgs(monitorType),
133
+ );
134
+
135
+ expect(step.data?.logMonitor).toBeUndefined();
136
+ expect(step.data?.traceMonitor).toBeUndefined();
137
+ expect(step.data?.metricMonitor).toBeUndefined();
138
+ expect(step.data?.exceptionMonitor).toBeUndefined();
139
+ },
140
+ );
141
+ });
142
+
143
+ test("still seeds the default criteria and a step id", () => {
144
+ const step: MonitorStep = MonitorStep.getDefaultMonitorStep(
145
+ buildArgs(MonitorType.Logs),
146
+ );
147
+
148
+ expect(step.data?.id).toBeDefined();
149
+ expect(step.data?.monitorCriteria).toBeDefined();
150
+ expect(
151
+ step.data?.monitorCriteria.data?.monitorCriteriaInstanceArray.length,
152
+ ).toBeGreaterThan(0);
153
+ });
154
+
155
+ test("seeds a fresh sub-config object per call (no shared mutable state)", () => {
156
+ const a: MonitorStep = MonitorStep.getDefaultMonitorStep(
157
+ buildArgs(MonitorType.Logs),
158
+ );
159
+ const b: MonitorStep = MonitorStep.getDefaultMonitorStep(
160
+ buildArgs(MonitorType.Logs),
161
+ );
162
+
163
+ expect(a.data?.logMonitor).not.toBe(b.data?.logMonitor);
164
+
165
+ // Mutating one must not bleed into the other.
166
+ a.data!.logMonitor!.lastXSecondsOfLogs = 999;
167
+ expect(b.data?.logMonitor?.lastXSecondsOfLogs).not.toBe(999);
168
+ });
169
+ });