@mablhq/mabl-cli 1.55.4 → 1.56.6
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.
- package/api/featureSet.js +4 -0
- package/api/mablApiClient.js +33 -42
- package/browserLauncher/playwrightBrowserLauncher/chromium/chromiumPageDelegate.js +6 -0
- package/browserLauncher/playwrightBrowserLauncher/nonChromium/nonChromiumAbstractPageDelegate.js +3 -0
- package/browserLauncher/playwrightBrowserLauncher/playwrightFrame.js +16 -9
- package/browserLauncher/playwrightBrowserLauncher/playwrightPage.js +5 -2
- package/browserTestMonitoring/cloudMonitoringPerformanceMetrics.js +277 -0
- package/browserTestMonitoring/distributions.js +44 -0
- package/browserTestMonitoring/metricsRecorder.js +112 -0
- package/browserTestMonitoring/types.js +8 -0
- package/commands/tests/tests_cmds/import.js +1 -1
- package/core/execution/ApiTestUtils.js +2 -2
- package/coreWebVitals/index.js +0 -8
- package/domUtil/index.js +1 -1
- package/execution/index.js +1 -1
- package/execution/index.js.LICENSE.txt +18 -0
- package/mablApi/index.js +1 -1
- package/mablscriptFind/index.js +1 -1
- package/package.json +11 -5
- package/resources/coreWebVitals.js +1 -1
- package/resources/mablFind.js +1 -1
- package/util/CloudStorageWriter.js +45 -0
- package/util/IdentifierUtil.js +57 -0
- package/util/TestOutputWriter.js +67 -0
- package/util/analytics.js +10 -0
package/api/featureSet.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.FeatureSet = exports.FindImplementationVersion = void 0;
|
|
4
4
|
const types_1 = require("../browserLauncher/types");
|
|
5
5
|
const ACCESSIBILITY_CHECK_FEATURE_FLAG = 'accessibility_checks';
|
|
6
|
+
const PERFORMANCE_TESTING_BROWSER_RUNS_FEATURE_FLAG = 'performance_testing_browser_runs';
|
|
6
7
|
const SMARTER_WAIT_FEATURE_FLAG = 'smarter_wait';
|
|
7
8
|
var FindImplementationVersion;
|
|
8
9
|
(function (FindImplementationVersion) {
|
|
@@ -24,5 +25,8 @@ class FeatureSet {
|
|
|
24
25
|
hasAccessibilityChecksEnabled() {
|
|
25
26
|
return this.featureFlags.has(ACCESSIBILITY_CHECK_FEATURE_FLAG);
|
|
26
27
|
}
|
|
28
|
+
hasPerformanceTestingBrowserRunsFeatureEnabled() {
|
|
29
|
+
return this.featureFlags.has(PERFORMANCE_TESTING_BROWSER_RUNS_FEATURE_FLAG);
|
|
30
|
+
}
|
|
27
31
|
}
|
|
28
32
|
exports.FeatureSet = FeatureSet;
|
package/api/mablApiClient.js
CHANGED
|
@@ -1,26 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
4
|
};
|
|
25
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
6
|
exports.MablApiClient = void 0;
|
|
@@ -29,7 +9,7 @@ const env_1 = require("../env/env");
|
|
|
29
9
|
const mablApi_1 = require("../mablApi");
|
|
30
10
|
const cliConfigProvider_1 = require("../providers/cliConfigProvider");
|
|
31
11
|
const basicApiClient_1 = require("./basicApiClient");
|
|
32
|
-
const
|
|
12
|
+
const query_string_1 = __importDefault(require("query-string"));
|
|
33
13
|
const featureSet_1 = require("./featureSet");
|
|
34
14
|
class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
35
15
|
constructor(options) {
|
|
@@ -48,7 +28,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
48
28
|
async getPlans(options) {
|
|
49
29
|
var _a, _b;
|
|
50
30
|
try {
|
|
51
|
-
const queryArg =
|
|
31
|
+
const queryArg = query_string_1.default.stringify(options);
|
|
52
32
|
const plans = await this.makeGetRequest(`${this.baseApiUrl}/schedule/runPolicy/?${queryArg}`);
|
|
53
33
|
sortTemporallyAscending((_a = plans.run_policies) !== null && _a !== void 0 ? _a : []);
|
|
54
34
|
return (_b = plans.run_policies) !== null && _b !== void 0 ? _b : [];
|
|
@@ -67,7 +47,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
67
47
|
}
|
|
68
48
|
async getApplications(workspaceId, limit) {
|
|
69
49
|
try {
|
|
70
|
-
const applicationQueryString =
|
|
50
|
+
const applicationQueryString = query_string_1.default.stringify({
|
|
71
51
|
organization_id: workspaceId,
|
|
72
52
|
limit,
|
|
73
53
|
});
|
|
@@ -84,7 +64,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
84
64
|
const queryStringArgs = {
|
|
85
65
|
decrypt: decryptVariables,
|
|
86
66
|
};
|
|
87
|
-
const envQueryString =
|
|
67
|
+
const envQueryString = query_string_1.default.stringify(queryStringArgs);
|
|
88
68
|
return await this.makeGetRequest(`${this.baseApiUrl}/v1/environments/${environmentId}?${envQueryString}`);
|
|
89
69
|
}
|
|
90
70
|
catch (error) {
|
|
@@ -117,7 +97,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
117
97
|
}
|
|
118
98
|
async getEnvironments(workspaceId, limit) {
|
|
119
99
|
try {
|
|
120
|
-
const environmentQueryString =
|
|
100
|
+
const environmentQueryString = query_string_1.default.stringify({
|
|
121
101
|
organization_id: workspaceId,
|
|
122
102
|
limit,
|
|
123
103
|
});
|
|
@@ -139,7 +119,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
139
119
|
}
|
|
140
120
|
async selectLinkServer(workspaceId, label) {
|
|
141
121
|
try {
|
|
142
|
-
const queryParams =
|
|
122
|
+
const queryParams = query_string_1.default.stringify({
|
|
143
123
|
workspace_id: workspaceId,
|
|
144
124
|
label,
|
|
145
125
|
});
|
|
@@ -187,7 +167,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
187
167
|
}
|
|
188
168
|
async getCredentials(workspaceId, limit) {
|
|
189
169
|
try {
|
|
190
|
-
const credentialsQueryString =
|
|
170
|
+
const credentialsQueryString = query_string_1.default.stringify({
|
|
191
171
|
organization_id: workspaceId,
|
|
192
172
|
limit,
|
|
193
173
|
});
|
|
@@ -198,7 +178,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
198
178
|
}
|
|
199
179
|
}
|
|
200
180
|
async getCredential(credentialId, withSecrets, withComputedTotpCount) {
|
|
201
|
-
const queryStringParams =
|
|
181
|
+
const queryStringParams = query_string_1.default.stringify({
|
|
202
182
|
with_secrets: withSecrets,
|
|
203
183
|
with_computed_totp_count: withComputedTotpCount,
|
|
204
184
|
});
|
|
@@ -211,7 +191,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
211
191
|
}
|
|
212
192
|
async getDeploymentEvents(workspaceId, limit) {
|
|
213
193
|
try {
|
|
214
|
-
const deploymentQueryString =
|
|
194
|
+
const deploymentQueryString = query_string_1.default.stringify({
|
|
215
195
|
workspace_id: workspaceId,
|
|
216
196
|
limit,
|
|
217
197
|
});
|
|
@@ -239,7 +219,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
239
219
|
}
|
|
240
220
|
async queryDeploymentEntities(workspaceId, environmentId, applicationId, limit = 50) {
|
|
241
221
|
try {
|
|
242
|
-
const queryStringParams =
|
|
222
|
+
const queryStringParams = query_string_1.default.stringify({
|
|
243
223
|
organization_id: workspaceId,
|
|
244
224
|
environment_id: environmentId,
|
|
245
225
|
application_id: applicationId,
|
|
@@ -370,7 +350,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
370
350
|
cliExport: forExportFormat,
|
|
371
351
|
sourceControlTag: branchName,
|
|
372
352
|
};
|
|
373
|
-
const journeyQueryString =
|
|
353
|
+
const journeyQueryString = query_string_1.default.stringify(queryStringArgs);
|
|
374
354
|
return await this.makeGetRequest(`${this.baseApiUrl}/test/journey/${journeyId}?${journeyQueryString}`);
|
|
375
355
|
}
|
|
376
356
|
catch (error) {
|
|
@@ -380,7 +360,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
380
360
|
async getJourneys(options) {
|
|
381
361
|
var _a;
|
|
382
362
|
try {
|
|
383
|
-
const queryArg =
|
|
363
|
+
const queryArg = query_string_1.default.stringify(options);
|
|
384
364
|
const journeys = (_a = (await this.makeGetRequest(`${this.baseApiUrl}/test/journeys?${queryArg}`)).journeys) !== null && _a !== void 0 ? _a : [];
|
|
385
365
|
sortTemporallyAscending(journeys);
|
|
386
366
|
return journeys;
|
|
@@ -394,7 +374,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
394
374
|
const queryStringArgs = {
|
|
395
375
|
sourceControlTag: branchName,
|
|
396
376
|
};
|
|
397
|
-
const flowQueryString =
|
|
377
|
+
const flowQueryString = query_string_1.default.stringify(queryStringArgs);
|
|
398
378
|
return await this.makeGetRequest(`${this.baseApiUrl}/flows/${flowId}?${flowQueryString}`);
|
|
399
379
|
}
|
|
400
380
|
catch (error) {
|
|
@@ -404,7 +384,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
404
384
|
async getFlows(options) {
|
|
405
385
|
var _a;
|
|
406
386
|
try {
|
|
407
|
-
const queryArg =
|
|
387
|
+
const queryArg = query_string_1.default.stringify(options);
|
|
408
388
|
const flows = (_a = (await this.makeGetRequest(`${this.baseApiUrl}/flows?${queryArg}`)).flows) !== null && _a !== void 0 ? _a : [];
|
|
409
389
|
sortTemporallyAscending(flows);
|
|
410
390
|
return flows;
|
|
@@ -442,7 +422,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
442
422
|
}
|
|
443
423
|
async getBranches(workspaceId, limit, statusFilter) {
|
|
444
424
|
try {
|
|
445
|
-
const branchQueryString =
|
|
425
|
+
const branchQueryString = query_string_1.default.stringify({
|
|
446
426
|
workspace_id: workspaceId,
|
|
447
427
|
limit,
|
|
448
428
|
status: statusFilter,
|
|
@@ -463,7 +443,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
463
443
|
}
|
|
464
444
|
async queryDataTables(workspaceId, limit, cursor) {
|
|
465
445
|
try {
|
|
466
|
-
const dataTablesQueryString =
|
|
446
|
+
const dataTablesQueryString = query_string_1.default.stringify({
|
|
467
447
|
workspace_id: workspaceId,
|
|
468
448
|
limit,
|
|
469
449
|
cursor,
|
|
@@ -492,7 +472,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
492
472
|
}
|
|
493
473
|
async queryScenarios(dataTableId, limit, cursor) {
|
|
494
474
|
try {
|
|
495
|
-
const scenariosQueryString =
|
|
475
|
+
const scenariosQueryString = query_string_1.default.stringify({
|
|
496
476
|
data_table_id: dataTableId,
|
|
497
477
|
limit,
|
|
498
478
|
cursor,
|
|
@@ -559,7 +539,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
559
539
|
from: fromBranchName,
|
|
560
540
|
to: toBranchName,
|
|
561
541
|
};
|
|
562
|
-
const mergeQueryString =
|
|
542
|
+
const mergeQueryString = query_string_1.default.stringify(queryStringArgs);
|
|
563
543
|
const url = `${this.baseApiUrl}/branch/${workspaceId}/merge?${mergeQueryString}`;
|
|
564
544
|
return await this.makePostRequest(url, {});
|
|
565
545
|
}
|
|
@@ -777,7 +757,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
777
757
|
}
|
|
778
758
|
}
|
|
779
759
|
async terminateJourneyRun(journeyRunId, terminationReason) {
|
|
780
|
-
const terminateParams =
|
|
760
|
+
const terminateParams = query_string_1.default.stringify({
|
|
781
761
|
terminationReason: terminationReason.toString(),
|
|
782
762
|
});
|
|
783
763
|
try {
|
|
@@ -807,7 +787,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
807
787
|
}
|
|
808
788
|
async getUsers(workspaceId, limit) {
|
|
809
789
|
try {
|
|
810
|
-
const userQueryString =
|
|
790
|
+
const userQueryString = query_string_1.default.stringify({
|
|
811
791
|
organization_id: workspaceId,
|
|
812
792
|
limit,
|
|
813
793
|
});
|
|
@@ -819,6 +799,17 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
|
|
|
819
799
|
throw toApiError(`Failed to get users`, error);
|
|
820
800
|
}
|
|
821
801
|
}
|
|
802
|
+
async getStepIdsInJourneyByFlow(journeyInvariantId, flowIds) {
|
|
803
|
+
try {
|
|
804
|
+
const stepIdsQueryString = query_string_1.default.stringify({
|
|
805
|
+
flow_variant_ids: [flowIds],
|
|
806
|
+
});
|
|
807
|
+
return await this.makeGetRequest(`${this.baseApiUrl}/test/journey/${journeyInvariantId}/stepIdsByFlow?${stepIdsQueryString}`).then((result) => result !== null && result !== void 0 ? result : []);
|
|
808
|
+
}
|
|
809
|
+
catch (error) {
|
|
810
|
+
throw toApiError(`Failed to get step ids in journey by flow`, error);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
822
813
|
async recordTimeSeriesMetricMeasurement(type, value, options) {
|
|
823
814
|
try {
|
|
824
815
|
return this.makePostRequest(`${this.baseApiUrl}/metrics/timeSeries`, createTimeSeriesMetricMeasurement(type, value, options));
|
|
@@ -132,5 +132,11 @@ class ChromiumPageDelegate {
|
|
|
132
132
|
(0, logUtils_1.logInternal)(`Unable to enable screencast mode. No CDP session found. Error: ${e}`);
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
+
async getContentAsMhtml() {
|
|
136
|
+
const document = await this.getCDPSession().send('Page.captureSnapshot', {
|
|
137
|
+
format: 'mhtml',
|
|
138
|
+
});
|
|
139
|
+
return Promise.resolve(document.data);
|
|
140
|
+
}
|
|
135
141
|
}
|
|
136
142
|
exports.ChromiumPageDelegate = ChromiumPageDelegate;
|
|
@@ -76,19 +76,26 @@ class PlaywrightFrame extends browserLauncher_1.Frame {
|
|
|
76
76
|
}
|
|
77
77
|
return { world: forcedWorld, value: arg };
|
|
78
78
|
};
|
|
79
|
-
const originalEvaluateExpressionFunction = serverFrame.
|
|
80
|
-
const functionOverride = async function (expression,
|
|
79
|
+
const originalEvaluateExpressionFunction = serverFrame.evaluateExpression.bind(serverFrame);
|
|
80
|
+
const functionOverride = async function (expression, options = {}, arg) {
|
|
81
81
|
const { world, value } = await this.checkWorldFunction(arg);
|
|
82
|
-
return originalEvaluateExpressionFunction(expression,
|
|
82
|
+
return originalEvaluateExpressionFunction(expression, {
|
|
83
|
+
isFunction: options.isFunction,
|
|
84
|
+
exposeUtilityScript: options.exposeUtilityScript,
|
|
85
|
+
world,
|
|
86
|
+
}, value);
|
|
83
87
|
};
|
|
84
|
-
serverFrame.
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
const functionHandleOverride = async function (expression, isFunction, arg, _world) {
|
|
88
|
+
serverFrame.evaluateExpression = functionOverride.bind(serverFrame);
|
|
89
|
+
const originalEvaluateExpressionHandleFunction = serverFrame.evaluateExpressionHandle.bind(serverFrame);
|
|
90
|
+
const functionHandleOverride = async function (expression, options = {}, arg) {
|
|
88
91
|
const { world, value } = await this.checkWorldFunction(arg);
|
|
89
|
-
return originalEvaluateExpressionHandleFunction(expression,
|
|
92
|
+
return originalEvaluateExpressionHandleFunction(expression, {
|
|
93
|
+
isFunction: options.isFunction,
|
|
94
|
+
exposeUtilityScript: options.exposeUtilityScript,
|
|
95
|
+
world,
|
|
96
|
+
}, value);
|
|
90
97
|
};
|
|
91
|
-
serverFrame.
|
|
98
|
+
serverFrame.evaluateExpressionHandle =
|
|
92
99
|
functionHandleOverride.bind(serverFrame);
|
|
93
100
|
}
|
|
94
101
|
async $(selector) {
|
|
@@ -159,8 +159,8 @@ class PlaywrightPage extends events_1.default {
|
|
|
159
159
|
(0, logUtils_1.logInternal)(`Unable to register event ${event.toString()}. Error: ${error}`);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
-
async screenshot(
|
|
163
|
-
return
|
|
162
|
+
async screenshot(options) {
|
|
163
|
+
return this.page.screenshot(options);
|
|
164
164
|
}
|
|
165
165
|
sendCharacter(key) {
|
|
166
166
|
return this.page.keyboard.insertText(key);
|
|
@@ -358,5 +358,8 @@ class PlaywrightPage extends events_1.default {
|
|
|
358
358
|
}
|
|
359
359
|
return this.playwrightFrames.get(frameId);
|
|
360
360
|
}
|
|
361
|
+
async getContentAsMhtml() {
|
|
362
|
+
return this.delegate.getContentAsMhtml();
|
|
363
|
+
}
|
|
361
364
|
}
|
|
362
365
|
exports.PlaywrightPage = PlaywrightPage;
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.CloudMonitoringPerformanceMetrics = exports.DEFAULT_CLOUD_MONITORING_METRICS_EXPORT_PERIOD_MS = void 0;
|
|
27
|
+
const api_1 = __importStar(require("@opentelemetry/api"));
|
|
28
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
29
|
+
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
|
|
30
|
+
const opentelemetry_cloud_monitoring_exporter_1 = require("@google-cloud/opentelemetry-cloud-monitoring-exporter");
|
|
31
|
+
const distributions_1 = require("./distributions");
|
|
32
|
+
const DEBUG = false;
|
|
33
|
+
const METRIC_NAME_PREFIX = 'mabl/tests/performance';
|
|
34
|
+
exports.DEFAULT_CLOUD_MONITORING_METRICS_EXPORT_PERIOD_MS = 8000;
|
|
35
|
+
const DEFAULT_METER_PROVIDER_SHUTDOWN_TIMEOUT_MS = 3 * exports.DEFAULT_CLOUD_MONITORING_METRICS_EXPORT_PERIOD_MS + 1000;
|
|
36
|
+
class CloudMonitoringPerformanceMetrics {
|
|
37
|
+
constructor(projectId, runnerId, cloudMonitoringMetricsExportPeriodMs = exports.DEFAULT_CLOUD_MONITORING_METRICS_EXPORT_PERIOD_MS, meterProviderShutdownTimeoutMs = DEFAULT_METER_PROVIDER_SHUTDOWN_TIMEOUT_MS) {
|
|
38
|
+
this.projectId = projectId;
|
|
39
|
+
this.runnerId = runnerId;
|
|
40
|
+
this.cloudMonitoringMetricsExportPeriodMs = cloudMonitoringMetricsExportPeriodMs;
|
|
41
|
+
this.meterProviderShutdownTimeoutMs = meterProviderShutdownTimeoutMs;
|
|
42
|
+
if (DEBUG) {
|
|
43
|
+
api_1.diag.setLogger(new api_1.DiagConsoleLogger(), api_1.DiagLogLevel.ALL);
|
|
44
|
+
}
|
|
45
|
+
this.stepMetricsInstrumentNames = this.generateStepMetricsInstrumentNames();
|
|
46
|
+
this.testMetricsInstrumentNames = this.generateTestMetricsInstrumentNames();
|
|
47
|
+
this.meterProvider = this.initializeOpenTelemetry();
|
|
48
|
+
this.meter = this.meterProvider.getMeter(runnerId);
|
|
49
|
+
this.step = this.initializeStepMetrics();
|
|
50
|
+
this.test = this.initializeTestMetrics();
|
|
51
|
+
}
|
|
52
|
+
async shutdown() {
|
|
53
|
+
await this.meterProvider.shutdown({
|
|
54
|
+
timeoutMillis: this.meterProviderShutdownTimeoutMs,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
generateStepMetricsInstrumentNames() {
|
|
58
|
+
return {
|
|
59
|
+
...this.generateCommonInstrumentNames('step'),
|
|
60
|
+
firstContentfulPaint: this.generateInstrumentName('step', 'firstContentfulPaint'),
|
|
61
|
+
largestContentfulPaint: this.generateInstrumentName('step', 'largestContentfulPaint'),
|
|
62
|
+
cumulativeLayoutShift: this.generateInstrumentName('step', 'cumulativeLayoutShift'),
|
|
63
|
+
timeToFirstByte: this.generateInstrumentName('step', 'timeToFirstByte'),
|
|
64
|
+
domContentLoaded: this.generateInstrumentName('step', 'domContentLoaded'),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
generateTestMetricsInstrumentNames() {
|
|
68
|
+
return {
|
|
69
|
+
...this.generateCommonInstrumentNames('test'),
|
|
70
|
+
executionTime: this.generateInstrumentName('test', 'execution', 'time'),
|
|
71
|
+
runnerCount: this.generateCountInstrumentName('test', 'runner'),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
initializeOpenTelemetry() {
|
|
75
|
+
const StepMetricsViews = {
|
|
76
|
+
executionCount: new sdk_metrics_1.View({
|
|
77
|
+
aggregation: new sdk_metrics_1.SumAggregation(),
|
|
78
|
+
instrumentName: this.stepMetricsInstrumentNames.executionCount,
|
|
79
|
+
}),
|
|
80
|
+
failCount: new sdk_metrics_1.View({
|
|
81
|
+
aggregation: new sdk_metrics_1.SumAggregation(),
|
|
82
|
+
instrumentName: this.stepMetricsInstrumentNames.failCount,
|
|
83
|
+
}),
|
|
84
|
+
passCount: new sdk_metrics_1.View({
|
|
85
|
+
aggregation: new sdk_metrics_1.SumAggregation(),
|
|
86
|
+
instrumentName: this.stepMetricsInstrumentNames.passCount,
|
|
87
|
+
}),
|
|
88
|
+
firstContentfulPaint: new sdk_metrics_1.View({
|
|
89
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.FCPBucketBoundaries, true),
|
|
90
|
+
instrumentName: this.stepMetricsInstrumentNames.firstContentfulPaint,
|
|
91
|
+
}),
|
|
92
|
+
largestContentfulPaint: new sdk_metrics_1.View({
|
|
93
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.LCPBucketBoundaries, true),
|
|
94
|
+
instrumentName: this.stepMetricsInstrumentNames.largestContentfulPaint,
|
|
95
|
+
}),
|
|
96
|
+
cumulativeLayoutShift: new sdk_metrics_1.View({
|
|
97
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.CLSBucketBoundaries, true),
|
|
98
|
+
instrumentName: this.stepMetricsInstrumentNames.cumulativeLayoutShift,
|
|
99
|
+
}),
|
|
100
|
+
timeToFirstByte: new sdk_metrics_1.View({
|
|
101
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.TTFBBucketBoundaries, true),
|
|
102
|
+
instrumentName: this.stepMetricsInstrumentNames.timeToFirstByte,
|
|
103
|
+
}),
|
|
104
|
+
domContentLoaded: new sdk_metrics_1.View({
|
|
105
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.DCLBucketBoundaries, true),
|
|
106
|
+
instrumentName: this.stepMetricsInstrumentNames.domContentLoaded,
|
|
107
|
+
}),
|
|
108
|
+
firstContentfulPaintCategory: new sdk_metrics_1.View({
|
|
109
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.FCPCategoryBucketBoundaries, false),
|
|
110
|
+
instrumentName: this.stepMetricsInstrumentNames.firstContentfulPaintCategory,
|
|
111
|
+
}),
|
|
112
|
+
largestContentfulPaintCategory: new sdk_metrics_1.View({
|
|
113
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.LCPCategoryBucketBoundaries, false),
|
|
114
|
+
instrumentName: this.stepMetricsInstrumentNames.largestContentfulPaintCategory,
|
|
115
|
+
}),
|
|
116
|
+
cumulativeLayoutShiftCategory: new sdk_metrics_1.View({
|
|
117
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.CLSCategoryBucketBoundaries, false),
|
|
118
|
+
instrumentName: this.stepMetricsInstrumentNames.cumulativeLayoutShiftCategory,
|
|
119
|
+
}),
|
|
120
|
+
timeToFirstByteCategory: new sdk_metrics_1.View({
|
|
121
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.TTFBCategoryBucketBoundaries, false),
|
|
122
|
+
instrumentName: this.stepMetricsInstrumentNames.timeToFirstByteCategory,
|
|
123
|
+
}),
|
|
124
|
+
domContentLoadedCategory: new sdk_metrics_1.View({
|
|
125
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.DCLCategoryBucketBoundaries, false),
|
|
126
|
+
instrumentName: this.stepMetricsInstrumentNames.domContentLoadedCategory,
|
|
127
|
+
}),
|
|
128
|
+
};
|
|
129
|
+
const TestMetricsViews = {
|
|
130
|
+
executionCount: new sdk_metrics_1.View({
|
|
131
|
+
aggregation: new sdk_metrics_1.SumAggregation(),
|
|
132
|
+
instrumentName: this.testMetricsInstrumentNames.executionCount,
|
|
133
|
+
}),
|
|
134
|
+
executionTime: new sdk_metrics_1.View({
|
|
135
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.ElapsedExecutionTimeBucketBoundaries, true),
|
|
136
|
+
instrumentName: this.testMetricsInstrumentNames.executionTime,
|
|
137
|
+
}),
|
|
138
|
+
failCount: new sdk_metrics_1.View({
|
|
139
|
+
aggregation: new sdk_metrics_1.SumAggregation(),
|
|
140
|
+
instrumentName: this.testMetricsInstrumentNames.failCount,
|
|
141
|
+
}),
|
|
142
|
+
passCount: new sdk_metrics_1.View({
|
|
143
|
+
aggregation: new sdk_metrics_1.SumAggregation(),
|
|
144
|
+
instrumentName: this.testMetricsInstrumentNames.passCount,
|
|
145
|
+
}),
|
|
146
|
+
runnerCount: new sdk_metrics_1.View({
|
|
147
|
+
aggregation: new sdk_metrics_1.LastValueAggregation(),
|
|
148
|
+
instrumentName: this.testMetricsInstrumentNames.runnerCount,
|
|
149
|
+
}),
|
|
150
|
+
firstContentfulPaintCategory: new sdk_metrics_1.View({
|
|
151
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.FCPCategoryBucketBoundaries, false),
|
|
152
|
+
instrumentName: this.stepMetricsInstrumentNames.firstContentfulPaintCategory,
|
|
153
|
+
}),
|
|
154
|
+
largestContentfulPaintCategory: new sdk_metrics_1.View({
|
|
155
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.LCPCategoryBucketBoundaries, false),
|
|
156
|
+
instrumentName: this.stepMetricsInstrumentNames.largestContentfulPaintCategory,
|
|
157
|
+
}),
|
|
158
|
+
cumulativeLayoutShiftCategory: new sdk_metrics_1.View({
|
|
159
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.CLSCategoryBucketBoundaries, false),
|
|
160
|
+
instrumentName: this.stepMetricsInstrumentNames.cumulativeLayoutShiftCategory,
|
|
161
|
+
}),
|
|
162
|
+
timeToFirstByteCategory: new sdk_metrics_1.View({
|
|
163
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.TTFBCategoryBucketBoundaries, false),
|
|
164
|
+
instrumentName: this.stepMetricsInstrumentNames.timeToFirstByteCategory,
|
|
165
|
+
}),
|
|
166
|
+
domContentLoadedCategory: new sdk_metrics_1.View({
|
|
167
|
+
aggregation: new sdk_metrics_1.ExplicitBucketHistogramAggregation(distributions_1.DCLCategoryBucketBoundaries, false),
|
|
168
|
+
instrumentName: this.stepMetricsInstrumentNames.domContentLoadedCategory,
|
|
169
|
+
}),
|
|
170
|
+
};
|
|
171
|
+
const meterProvider = new sdk_metrics_1.MeterProvider({
|
|
172
|
+
resource: new resources_1.Resource({
|
|
173
|
+
'service.namespace': 'execution',
|
|
174
|
+
'service.name': 'performance-test-runner',
|
|
175
|
+
'host.id': this.runnerId,
|
|
176
|
+
}),
|
|
177
|
+
views: [
|
|
178
|
+
...Object.values(StepMetricsViews),
|
|
179
|
+
...Object.values(TestMetricsViews),
|
|
180
|
+
],
|
|
181
|
+
});
|
|
182
|
+
const exporter = new opentelemetry_cloud_monitoring_exporter_1.MetricExporter({
|
|
183
|
+
prefix: 'custom.googleapis.com',
|
|
184
|
+
projectId: this.projectId,
|
|
185
|
+
});
|
|
186
|
+
meterProvider.addMetricReader(new sdk_metrics_1.PeriodicExportingMetricReader({
|
|
187
|
+
exportIntervalMillis: this.cloudMonitoringMetricsExportPeriodMs,
|
|
188
|
+
exporter,
|
|
189
|
+
}));
|
|
190
|
+
api_1.default.metrics.setGlobalMeterProvider(this.meterProvider);
|
|
191
|
+
return meterProvider;
|
|
192
|
+
}
|
|
193
|
+
initializeStepMetrics() {
|
|
194
|
+
return {
|
|
195
|
+
executionCount: this.initializeStepCount('executionCount'),
|
|
196
|
+
failCount: this.initializeStepCount('failCount'),
|
|
197
|
+
passCount: this.initializeStepCount('passCount'),
|
|
198
|
+
firstContentfulPaint: this.initializeStepTimeHistogram('firstContentfulPaint'),
|
|
199
|
+
largestContentfulPaint: this.initializeStepTimeHistogram('largestContentfulPaint'),
|
|
200
|
+
cumulativeLayoutShift: this.initializeStepTimeHistogram('cumulativeLayoutShift'),
|
|
201
|
+
timeToFirstByte: this.initializeStepTimeHistogram('timeToFirstByte'),
|
|
202
|
+
domContentLoaded: this.initializeStepTimeHistogram('domContentLoaded'),
|
|
203
|
+
firstContentfulPaintCategory: this.initializeStepTimeHistogram('firstContentfulPaintCategory'),
|
|
204
|
+
largestContentfulPaintCategory: this.initializeStepTimeHistogram('largestContentfulPaintCategory'),
|
|
205
|
+
cumulativeLayoutShiftCategory: this.initializeStepTimeHistogram('cumulativeLayoutShiftCategory'),
|
|
206
|
+
timeToFirstByteCategory: this.initializeStepTimeHistogram('timeToFirstByteCategory'),
|
|
207
|
+
domContentLoadedCategory: this.initializeStepTimeHistogram('domContentLoadedCategory'),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
initializeTestMetrics() {
|
|
211
|
+
return {
|
|
212
|
+
executionCount: this.initializeTestCount('executionCount'),
|
|
213
|
+
executionTime: this.initializeTestTimeHistogram('executionTime'),
|
|
214
|
+
failCount: this.initializeTestCount('failCount'),
|
|
215
|
+
passCount: this.initializeTestCount('passCount'),
|
|
216
|
+
runnerCount: this.initializeTestCount('runnerCount'),
|
|
217
|
+
firstContentfulPaintCategory: this.initializeTestTimeHistogram('firstContentfulPaintCategory'),
|
|
218
|
+
largestContentfulPaintCategory: this.initializeTestTimeHistogram('largestContentfulPaintCategory'),
|
|
219
|
+
cumulativeLayoutShiftCategory: this.initializeTestTimeHistogram('cumulativeLayoutShiftCategory'),
|
|
220
|
+
timeToFirstByteCategory: this.initializeTestTimeHistogram('timeToFirstByteCategory'),
|
|
221
|
+
domContentLoadedCategory: this.initializeTestTimeHistogram('domContentLoadedCategory'),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
initializeStepCount(instrumentName) {
|
|
225
|
+
return this.initializeCounter(this.stepMetricsInstrumentNames[instrumentName]);
|
|
226
|
+
}
|
|
227
|
+
initializeTestCount(instrumentName) {
|
|
228
|
+
return this.initializeCounter(this.testMetricsInstrumentNames[instrumentName]);
|
|
229
|
+
}
|
|
230
|
+
initializeCounter(instrumentName) {
|
|
231
|
+
return this.meter.createCounter(instrumentName, {
|
|
232
|
+
valueType: api_1.ValueType.INT,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
initializeStepTimeHistogram(instrumentName) {
|
|
236
|
+
return this.initializeTimeHistogram(this.stepMetricsInstrumentNames[instrumentName]);
|
|
237
|
+
}
|
|
238
|
+
initializeTestTimeHistogram(instrumentName) {
|
|
239
|
+
return this.initializeTimeHistogram(this.testMetricsInstrumentNames[instrumentName]);
|
|
240
|
+
}
|
|
241
|
+
initializeTimeHistogram(instrumentName) {
|
|
242
|
+
const histogram = this.meter.createHistogram(instrumentName, {
|
|
243
|
+
unit: instrumentName ===
|
|
244
|
+
this.stepMetricsInstrumentNames.cumulativeLayoutShift ||
|
|
245
|
+
instrumentName ===
|
|
246
|
+
this.stepMetricsInstrumentNames.cumulativeLayoutShiftCategory
|
|
247
|
+
? undefined
|
|
248
|
+
: 'ms',
|
|
249
|
+
});
|
|
250
|
+
return histogram;
|
|
251
|
+
}
|
|
252
|
+
generateCommonInstrumentNames(granularity) {
|
|
253
|
+
return {
|
|
254
|
+
executionCount: this.generateCountInstrumentName(granularity, 'execution'),
|
|
255
|
+
failCount: this.generateResultInstrumentName(granularity, 'fail'),
|
|
256
|
+
passCount: this.generateResultInstrumentName(granularity, 'pass'),
|
|
257
|
+
firstContentfulPaintCategory: this.generateCWVCategoryInstrumentName(granularity, 'firstContentfulPaint'),
|
|
258
|
+
largestContentfulPaintCategory: this.generateCWVCategoryInstrumentName(granularity, 'largestContentfulPaint'),
|
|
259
|
+
cumulativeLayoutShiftCategory: this.generateCWVCategoryInstrumentName(granularity, 'cumulativeLayoutShift'),
|
|
260
|
+
timeToFirstByteCategory: this.generateCWVCategoryInstrumentName(granularity, 'timeToFirstByte'),
|
|
261
|
+
domContentLoadedCategory: this.generateCWVCategoryInstrumentName(granularity, 'domContentLoaded'),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
generateCountInstrumentName(granularity, type) {
|
|
265
|
+
return this.generateInstrumentName(granularity, type, 'count');
|
|
266
|
+
}
|
|
267
|
+
generateResultInstrumentName(granularity, type) {
|
|
268
|
+
return this.generateInstrumentName(granularity, 'result', type);
|
|
269
|
+
}
|
|
270
|
+
generateCWVCategoryInstrumentName(granularity, type) {
|
|
271
|
+
return this.generateInstrumentName(granularity, type, 'category');
|
|
272
|
+
}
|
|
273
|
+
generateInstrumentName(granularity, ...path) {
|
|
274
|
+
return `${METRIC_NAME_PREFIX}/${granularity}/${path.join('/')}`;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
exports.CloudMonitoringPerformanceMetrics = CloudMonitoringPerformanceMetrics;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateBucketBoundaries = exports.DCLCategoryBucketBoundaries = exports.DCLBucketBoundaries = exports.TTFBCategoryBucketBoundaries = exports.TTFBBucketBoundaries = exports.CLSCategoryBucketBoundaries = exports.CLSBucketBoundaries = exports.LCPCategoryBucketBoundaries = exports.LCPBucketBoundaries = exports.FCPCategoryBucketBoundaries = exports.FCPBucketBoundaries = exports.ElapsedExecutionTimeBucketBoundaries = void 0;
|
|
4
|
+
exports.ElapsedExecutionTimeBucketBoundaries = generateBucketBoundaries({ limit: 60000, width: 1000 }, { limit: 300000, width: 5000 }, { limit: 3600000, width: 60000 });
|
|
5
|
+
exports.FCPBucketBoundaries = generateBucketBoundaries({ limit: 1800, width: 25 }, { limit: 3000, width: 50 }, { limit: 6000, width: 100 }, { limit: 30000, width: 500 }, { limit: 50000, width: 1000 });
|
|
6
|
+
exports.FCPCategoryBucketBoundaries = [1800.01, 3000.01];
|
|
7
|
+
exports.LCPBucketBoundaries = generateBucketBoundaries({ limit: 1500, width: 25 }, { limit: 2500, width: 50 }, { limit: 4000, width: 75 }, { limit: 8000, width: 250 }, { limit: 30000, width: 500 }, { limit: 60000, width: 1000 });
|
|
8
|
+
exports.LCPCategoryBucketBoundaries = [2500.01, 4000.01];
|
|
9
|
+
exports.CLSBucketBoundaries = generateBucketBoundaries({ limit: 0.1, width: 0.001 }, { limit: 0.25, width: 0.0025 }, { limit: 0.5, width: 0.01 }, { limit: 1, width: 0.05 });
|
|
10
|
+
exports.CLSCategoryBucketBoundaries = [0.1001, 0.2501];
|
|
11
|
+
exports.TTFBBucketBoundaries = generateBucketBoundaries({ limit: 1000, width: 25 }, { limit: 2000, width: 50 }, { limit: 5000, width: 75 }, { limit: 10000, width: 250 }, { limit: 30000, width: 500 }, { limit: 60000, width: 1000 });
|
|
12
|
+
exports.TTFBCategoryBucketBoundaries = [800.01, 1800.01];
|
|
13
|
+
exports.DCLBucketBoundaries = generateBucketBoundaries({ limit: 1000, width: 25 }, { limit: 2000, width: 50 }, { limit: 5000, width: 75 }, { limit: 10000, width: 250 }, { limit: 30000, width: 500 }, { limit: 60000, width: 1000 });
|
|
14
|
+
exports.DCLCategoryBucketBoundaries = [1000.01, 2000.01];
|
|
15
|
+
function generateBucketBoundaries(...rules) {
|
|
16
|
+
if (!rules.length) {
|
|
17
|
+
throw new Error('At least one rule must be specified');
|
|
18
|
+
}
|
|
19
|
+
return rules
|
|
20
|
+
.reduce((boundaries, rule, index) => {
|
|
21
|
+
const { limit, width } = rule;
|
|
22
|
+
const previousLimit = boundaries[index][boundaries[index].length - 1];
|
|
23
|
+
if (width <= 0) {
|
|
24
|
+
throw new Error(`Invalid rule specification at index ${index}: width must be positive but was ${width}`);
|
|
25
|
+
}
|
|
26
|
+
if (limit <= previousLimit) {
|
|
27
|
+
throw new Error(`Invalid rule specification at index ${index}: limit ${limit} must be strictly greater than previous limit ${previousLimit}`);
|
|
28
|
+
}
|
|
29
|
+
if (previousLimit + width > limit) {
|
|
30
|
+
throw new Error(`Invalid rule specification at index ${index}: previous limit ${previousLimit} + width ${width} must not exceed limit ${limit}`);
|
|
31
|
+
}
|
|
32
|
+
const correctionFactor = 10000;
|
|
33
|
+
const bucketCount = Math.floor((limit * correctionFactor - previousLimit * correctionFactor) /
|
|
34
|
+
(width * correctionFactor));
|
|
35
|
+
const buckets = [...Array(bucketCount)].map((_value, index) => (previousLimit * correctionFactor +
|
|
36
|
+
width * correctionFactor * (index + 1)) /
|
|
37
|
+
correctionFactor);
|
|
38
|
+
boundaries.push(buckets);
|
|
39
|
+
return boundaries;
|
|
40
|
+
}, [[0]])
|
|
41
|
+
.flat()
|
|
42
|
+
.slice(1);
|
|
43
|
+
}
|
|
44
|
+
exports.generateBucketBoundaries = generateBucketBoundaries;
|