@wdio/browserstack-service 8.48.0 → 8.48.3
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/build/accessibility-handler.d.ts.map +1 -1
- package/build/accessibility-handler.js +13 -11
- package/build/ai-handler.d.ts.map +1 -1
- package/build/ai-handler.js +11 -0
- package/build/cli/cliLogger.d.ts +1 -0
- package/build/cli/cliLogger.d.ts.map +1 -1
- package/build/cli/cliLogger.js +23 -12
- package/build/cli/cliUtils.d.ts +18 -0
- package/build/cli/cliUtils.d.ts.map +1 -1
- package/build/cli/cliUtils.js +29 -0
- package/build/cli/frameworks/wdioMochaTestFramework.d.ts.map +1 -1
- package/build/cli/frameworks/wdioMochaTestFramework.js +4 -2
- package/build/cli/grpcClient.d.ts +19 -3
- package/build/cli/grpcClient.d.ts.map +1 -1
- package/build/cli/grpcClient.js +133 -21
- package/build/cli/index.d.ts +2 -0
- package/build/cli/index.d.ts.map +1 -1
- package/build/cli/index.js +52 -4
- package/build/cli/modules/accessibilityModule.d.ts +3 -0
- package/build/cli/modules/accessibilityModule.d.ts.map +1 -1
- package/build/cli/modules/accessibilityModule.js +75 -10
- package/build/constants.d.ts +28 -0
- package/build/constants.d.ts.map +1 -1
- package/build/constants.js +37 -1
- package/build/exitHandler.d.ts +1 -1
- package/build/exitHandler.d.ts.map +1 -1
- package/build/exitHandler.js +6 -5
- package/build/insights-handler.d.ts.map +1 -1
- package/build/insights-handler.js +33 -7
- package/build/instrumentation/funnelInstrumentation.d.ts +2 -2
- package/build/instrumentation/funnelInstrumentation.d.ts.map +1 -1
- package/build/instrumentation/funnelInstrumentation.js +30 -8
- package/build/instrumentation/performance/constants.d.ts +64 -0
- package/build/instrumentation/performance/constants.d.ts.map +1 -1
- package/build/instrumentation/performance/constants.js +73 -2
- package/build/instrumentation/performance/performance-tester.d.ts +11 -0
- package/build/instrumentation/performance/performance-tester.d.ts.map +1 -1
- package/build/instrumentation/performance/performance-tester.js +115 -12
- package/build/launcher.d.ts +1 -0
- package/build/launcher.d.ts.map +1 -1
- package/build/launcher.js +151 -6
- package/build/service.d.ts.map +1 -1
- package/build/service.js +77 -5
- package/build/testorchestration/apply-orchestration.d.ts +7 -0
- package/build/testorchestration/apply-orchestration.d.ts.map +1 -0
- package/build/testorchestration/apply-orchestration.js +42 -0
- package/build/testorchestration/helpers.d.ts +20 -0
- package/build/testorchestration/helpers.d.ts.map +1 -0
- package/build/testorchestration/helpers.js +412 -0
- package/build/testorchestration/request-utils.d.ts +23 -0
- package/build/testorchestration/request-utils.d.ts.map +1 -0
- package/build/testorchestration/request-utils.js +81 -0
- package/build/testorchestration/test-ordering-server.d.ts +33 -0
- package/build/testorchestration/test-ordering-server.d.ts.map +1 -0
- package/build/testorchestration/test-ordering-server.js +168 -0
- package/build/testorchestration/testorcherstrationhandler.d.ts +50 -0
- package/build/testorchestration/testorcherstrationhandler.d.ts.map +1 -0
- package/build/testorchestration/testorcherstrationhandler.js +133 -0
- package/build/testorchestration/testorcherstrationutils.d.ts +86 -0
- package/build/testorchestration/testorcherstrationutils.d.ts.map +1 -0
- package/build/testorchestration/testorcherstrationutils.js +379 -0
- package/build/types.d.ts +21 -0
- package/build/types.d.ts.map +1 -1
- package/build/util.d.ts +33 -4
- package/build/util.d.ts.map +1 -1
- package/build/util.js +112 -18
- package/package.json +3 -2
- package/tsconfig.prod.tsbuildinfo +1 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility class for making API requests to the BrowserStack orchestration API
|
|
3
|
+
*/
|
|
4
|
+
export declare class RequestUtils {
|
|
5
|
+
/**
|
|
6
|
+
* Makes a request to the test orchestration split tests endpoint
|
|
7
|
+
*/
|
|
8
|
+
static testOrchestrationSplitTests(reqEndpoint: string, data: any): Promise<any>;
|
|
9
|
+
/**
|
|
10
|
+
* Gets ordered tests from the test orchestration
|
|
11
|
+
*/
|
|
12
|
+
static getTestOrchestrationOrderedTests(reqEndpoint: string): Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* Makes an orchestration request with the given method and data
|
|
15
|
+
*/
|
|
16
|
+
static makeOrchestrationRequest(method: 'GET' | 'POST' | 'PUT', reqEndpoint: string, options: {
|
|
17
|
+
data?: any;
|
|
18
|
+
params?: Record<string, any>;
|
|
19
|
+
extraHeaders?: Record<string, string>;
|
|
20
|
+
}): Promise<any>;
|
|
21
|
+
}
|
|
22
|
+
export default RequestUtils;
|
|
23
|
+
//# sourceMappingURL=request-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-utils.d.ts","sourceRoot":"","sources":["../../src/testorchestration/request-utils.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,qBAAa,YAAY;IACrB;;OAEG;WACU,2BAA2B,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG;IAKvE;;OAEG;WACU,gCAAgC,CAAC,WAAW,EAAE,MAAM;IAKjE;;OAEG;WACU,wBAAwB,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE;QAChG,IAAI,CAAC,EAAE,GAAG,CAAC;QACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KACxC;CA4DJ;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import got from 'got';
|
|
2
|
+
import { BStackLogger } from '../bstackLogger.js';
|
|
3
|
+
import APIUtils from '../cli/apiUtils.js';
|
|
4
|
+
/**
|
|
5
|
+
* Utility class for making API requests to the BrowserStack orchestration API
|
|
6
|
+
*/
|
|
7
|
+
export class RequestUtils {
|
|
8
|
+
/**
|
|
9
|
+
* Makes a request to the test orchestration split tests endpoint
|
|
10
|
+
*/
|
|
11
|
+
static async testOrchestrationSplitTests(reqEndpoint, data) {
|
|
12
|
+
BStackLogger.debug('Processing Request for testOrchestrationSplitTests');
|
|
13
|
+
return RequestUtils.makeOrchestrationRequest('POST', reqEndpoint, { data });
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Gets ordered tests from the test orchestration
|
|
17
|
+
*/
|
|
18
|
+
static async getTestOrchestrationOrderedTests(reqEndpoint) {
|
|
19
|
+
BStackLogger.debug('Processing Request for getTestOrchestrationOrderedTests');
|
|
20
|
+
return RequestUtils.makeOrchestrationRequest('GET', reqEndpoint, {});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Makes an orchestration request with the given method and data
|
|
24
|
+
*/
|
|
25
|
+
static async makeOrchestrationRequest(method, reqEndpoint, options) {
|
|
26
|
+
const jwtToken = process.env.BROWSERSTACK_TESTHUB_JWT || '';
|
|
27
|
+
const headers = {
|
|
28
|
+
'authorization': `Bearer ${jwtToken}`,
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
|
+
'Accept': 'application/json'
|
|
31
|
+
};
|
|
32
|
+
if (options.extraHeaders) {
|
|
33
|
+
Object.assign(headers, options.extraHeaders);
|
|
34
|
+
}
|
|
35
|
+
const url = `${APIUtils.DATA_ENDPOINT}/${reqEndpoint.replace(/^\//, '')}`;
|
|
36
|
+
try {
|
|
37
|
+
let response;
|
|
38
|
+
const requestOptions = {
|
|
39
|
+
headers,
|
|
40
|
+
responseType: 'json'
|
|
41
|
+
};
|
|
42
|
+
if (options.data) {
|
|
43
|
+
requestOptions.json = options.data;
|
|
44
|
+
}
|
|
45
|
+
if (options.params) {
|
|
46
|
+
requestOptions.searchParams = options.params;
|
|
47
|
+
}
|
|
48
|
+
if (method === 'GET') {
|
|
49
|
+
response = await got.get(url, requestOptions);
|
|
50
|
+
}
|
|
51
|
+
else if (method === 'POST') {
|
|
52
|
+
response = await got.post(url, requestOptions);
|
|
53
|
+
}
|
|
54
|
+
else if (method === 'PUT') {
|
|
55
|
+
response = await got.put(url, requestOptions);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
59
|
+
}
|
|
60
|
+
BStackLogger.debug(`Orchestration request made to URL: ${url} with method: ${method}`);
|
|
61
|
+
let responseObj = {};
|
|
62
|
+
try {
|
|
63
|
+
responseObj = response.body;
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
BStackLogger.debug(`Failed to parse JSON response: ${e} - ${response.body}`);
|
|
67
|
+
}
|
|
68
|
+
if (responseObj) {
|
|
69
|
+
responseObj.next_poll_time = response.headers.next_poll_time ||
|
|
70
|
+
String(Date.now());
|
|
71
|
+
responseObj.status = response.statusCode;
|
|
72
|
+
}
|
|
73
|
+
return responseObj;
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
BStackLogger.error(`Orchestration request failed: ${e} - ${url}`);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export default RequestUtils;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles test ordering orchestration with the BrowserStack server.
|
|
3
|
+
*/
|
|
4
|
+
export declare class TestOrderingServer {
|
|
5
|
+
private config;
|
|
6
|
+
private ORDERING_ENDPOINT;
|
|
7
|
+
private requestData;
|
|
8
|
+
private defaultTimeout;
|
|
9
|
+
private defaultTimeoutInterval;
|
|
10
|
+
private splitTestsApiCallCount;
|
|
11
|
+
/**
|
|
12
|
+
* @param config Test orchestration config
|
|
13
|
+
*/
|
|
14
|
+
constructor(config: Record<string, any>);
|
|
15
|
+
/**
|
|
16
|
+
* Initiates the split tests request and stores the response data for polling.
|
|
17
|
+
*/
|
|
18
|
+
splitTests(testFiles: string[], orchestrationStrategy: string, orchestrationMetadata?: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Processes the split tests API response and extracts relevant fields.
|
|
21
|
+
*/
|
|
22
|
+
private _processSplitTestsResponse;
|
|
23
|
+
/**
|
|
24
|
+
* Retrieves the ordered test files from the orchestration server
|
|
25
|
+
*/
|
|
26
|
+
getOrderedTestFiles(): Promise<any[] | null>;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the count of split tests API calls made.
|
|
29
|
+
*/
|
|
30
|
+
getSplitTestsApiCallCount(): number;
|
|
31
|
+
}
|
|
32
|
+
export default TestOrderingServer;
|
|
33
|
+
//# sourceMappingURL=test-ordering-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-ordering-server.d.ts","sourceRoot":"","sources":["../../src/testorchestration/test-ordering-server.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,iBAAiB,CAAQ;IACjC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,sBAAsB,CAAQ;IACtC,OAAO,CAAC,sBAAsB,CAAQ;IAEtC;;OAEG;gBACS,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IASvC;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,qBAAqB,EAAE,MAAM,EAAE,qBAAqB,GAAE,MAAa;IAsCzG;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAoClC;;OAEG;IACG,mBAAmB;IAgEzB;;OAEG;IACH,yBAAyB;CAG5B;AAED,eAAe,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { getHostInfo, getGitMetadataForAISelection } from './helpers.js';
|
|
3
|
+
import { RequestUtils } from './request-utils.js';
|
|
4
|
+
import APIUtils from '../cli/apiUtils.js';
|
|
5
|
+
import { BStackLogger } from '../bstackLogger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Handles test ordering orchestration with the BrowserStack server.
|
|
8
|
+
*/
|
|
9
|
+
export class TestOrderingServer {
|
|
10
|
+
config;
|
|
11
|
+
ORDERING_ENDPOINT;
|
|
12
|
+
requestData;
|
|
13
|
+
defaultTimeout;
|
|
14
|
+
defaultTimeoutInterval;
|
|
15
|
+
splitTestsApiCallCount;
|
|
16
|
+
/**
|
|
17
|
+
* @param config Test orchestration config
|
|
18
|
+
*/
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.ORDERING_ENDPOINT = 'testorchestration/api/v1/split-tests';
|
|
22
|
+
this.requestData = null;
|
|
23
|
+
this.defaultTimeout = 60;
|
|
24
|
+
this.defaultTimeoutInterval = 5;
|
|
25
|
+
this.splitTestsApiCallCount = 0;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Initiates the split tests request and stores the response data for polling.
|
|
29
|
+
*/
|
|
30
|
+
async splitTests(testFiles, orchestrationStrategy, orchestrationMetadata = '{}') {
|
|
31
|
+
BStackLogger.debug(`[splitTests] Initiating split tests with strategy: ${orchestrationStrategy}`);
|
|
32
|
+
try {
|
|
33
|
+
let prDetails = [];
|
|
34
|
+
const parsedMetadata = JSON.parse(orchestrationMetadata);
|
|
35
|
+
const source = parsedMetadata.run_smart_selection?.source;
|
|
36
|
+
const isGithubAppApproach = Array.isArray(source) && source.length > 0 && source.every(src => src && typeof src === 'object' && !Array.isArray(src));
|
|
37
|
+
if (parsedMetadata.run_smart_selection?.enabled && !isGithubAppApproach) {
|
|
38
|
+
const multiRepoSource = parsedMetadata.run_smart_selection?.source;
|
|
39
|
+
prDetails = getGitMetadataForAISelection(multiRepoSource);
|
|
40
|
+
}
|
|
41
|
+
BStackLogger.info(`PR Details for AI Selection: ${JSON.stringify(prDetails)}`);
|
|
42
|
+
const payload = {
|
|
43
|
+
tests: testFiles.map(f => ({ filePath: f })),
|
|
44
|
+
orchestrationStrategy,
|
|
45
|
+
orchestrationMetadata: parsedMetadata,
|
|
46
|
+
nodeIndex: parseInt(process.env.BROWSERSTACK_NODE_INDEX || '0'),
|
|
47
|
+
totalNodes: parseInt(process.env.BROWSERSTACK_TOTAL_NODE_COUNT || '1'),
|
|
48
|
+
projectName: this.config.testObservabilityOptions.projectName || '',
|
|
49
|
+
buildName: this.config.testObservabilityOptions.buildName || path.basename(process.cwd()),
|
|
50
|
+
buildRunIdentifier: process.env.BROWSERSTACK_BUILD_RUN_IDENTIFIER || '',
|
|
51
|
+
hostInfo: getHostInfo(),
|
|
52
|
+
prDetails
|
|
53
|
+
};
|
|
54
|
+
const response = await RequestUtils.testOrchestrationSplitTests(this.ORDERING_ENDPOINT, payload);
|
|
55
|
+
if (response) {
|
|
56
|
+
this.requestData = this._processSplitTestsResponse(response);
|
|
57
|
+
BStackLogger.debug(`[splitTests] Split tests response: ${JSON.stringify(this.requestData)}`);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
BStackLogger.error('[splitTests] Failed to get split tests response.');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
BStackLogger.error(`[splitTests] Exception in sending test files:: ${e}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Processes the split tests API response and extracts relevant fields.
|
|
69
|
+
*/
|
|
70
|
+
_processSplitTestsResponse(response) {
|
|
71
|
+
const responseData = {};
|
|
72
|
+
responseData.timeout = response.timeout !== undefined ? response.timeout : this.defaultTimeout;
|
|
73
|
+
responseData.timeoutInterval = response.timeoutInterval !== undefined ? response.timeoutInterval : this.defaultTimeoutInterval;
|
|
74
|
+
const resultUrl = response.resultUrl;
|
|
75
|
+
const timeoutUrl = response.timeoutUrl;
|
|
76
|
+
// Remove the API prefix if present
|
|
77
|
+
if (resultUrl) {
|
|
78
|
+
responseData.resultUrl = resultUrl.includes(`${APIUtils.DATA_ENDPOINT}/`)
|
|
79
|
+
? resultUrl.split(`${APIUtils.DATA_ENDPOINT}/`)[1]
|
|
80
|
+
: resultUrl;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
responseData.resultUrl = null;
|
|
84
|
+
}
|
|
85
|
+
if (timeoutUrl) {
|
|
86
|
+
responseData.timeoutUrl = timeoutUrl.includes(`${APIUtils.DATA_ENDPOINT}/`)
|
|
87
|
+
? timeoutUrl.split(`${APIUtils.DATA_ENDPOINT}/`)[1]
|
|
88
|
+
: timeoutUrl;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
responseData.timeoutUrl = null;
|
|
92
|
+
}
|
|
93
|
+
if (response.timeout === undefined ||
|
|
94
|
+
response.timeoutInterval === undefined ||
|
|
95
|
+
response.timeoutUrl === undefined ||
|
|
96
|
+
response.resultUrl === undefined) {
|
|
97
|
+
BStackLogger.debug('[process_split_tests_response] Received null value(s) for some attributes in split tests API response');
|
|
98
|
+
}
|
|
99
|
+
return responseData;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Retrieves the ordered test files from the orchestration server
|
|
103
|
+
*/
|
|
104
|
+
async getOrderedTestFiles() {
|
|
105
|
+
if (!this.requestData) {
|
|
106
|
+
BStackLogger.error('[getOrderedTestFiles] No request data available to fetch ordered test files.');
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
let testFilesJsonList = null;
|
|
110
|
+
const testFiles = [];
|
|
111
|
+
const startTimeMillis = Date.now();
|
|
112
|
+
const timeoutInterval = parseInt(String(this.requestData.timeoutInterval || this.defaultTimeoutInterval), 10);
|
|
113
|
+
const timeoutMillis = parseInt(String(this.requestData.timeout || this.defaultTimeout), 10) * 1000;
|
|
114
|
+
const timeoutUrl = this.requestData.timeoutUrl;
|
|
115
|
+
const resultUrl = this.requestData.resultUrl;
|
|
116
|
+
if (resultUrl === null && timeoutUrl === null) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
// Poll resultUrl until timeout or until tests are available
|
|
121
|
+
while (resultUrl && (Date.now() - startTimeMillis) < timeoutMillis) {
|
|
122
|
+
const response = await RequestUtils.getTestOrchestrationOrderedTests(resultUrl);
|
|
123
|
+
if (response && response.tests) {
|
|
124
|
+
testFilesJsonList = response.tests;
|
|
125
|
+
}
|
|
126
|
+
this.splitTestsApiCallCount++;
|
|
127
|
+
if (testFilesJsonList) {
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
await new Promise(resolve => setTimeout(resolve, timeoutInterval * 1000));
|
|
131
|
+
BStackLogger.debug(`[getOrderedTestFiles] Fetching ordered tests from result URL after waiting for ${timeoutInterval} seconds.`);
|
|
132
|
+
}
|
|
133
|
+
// If still not available, try timeoutUrl
|
|
134
|
+
if (timeoutUrl && !testFilesJsonList) {
|
|
135
|
+
BStackLogger.debug('[getOrderedTestFiles] Fetching ordered tests from timeout URL');
|
|
136
|
+
const response = await RequestUtils.getTestOrchestrationOrderedTests(timeoutUrl);
|
|
137
|
+
if (response && response.tests) {
|
|
138
|
+
testFilesJsonList = response.tests;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Extract file paths
|
|
142
|
+
if (testFilesJsonList && testFilesJsonList.length > 0) {
|
|
143
|
+
for (const testData of testFilesJsonList) {
|
|
144
|
+
const filePath = testData.filePath;
|
|
145
|
+
if (filePath) {
|
|
146
|
+
testFiles.push(filePath);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (!testFilesJsonList) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
BStackLogger.debug(`[getOrderedTestFiles] Ordered test files received: ${JSON.stringify(testFiles)}`);
|
|
154
|
+
return testFiles;
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
BStackLogger.error(`[getOrderedTestFiles] Exception in fetching ordered test files: ${e}`);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Returns the count of split tests API calls made.
|
|
163
|
+
*/
|
|
164
|
+
getSplitTestsApiCallCount() {
|
|
165
|
+
return this.splitTestsApiCallCount;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export default TestOrderingServer;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles test orchestration operations
|
|
3
|
+
*/
|
|
4
|
+
export declare class TestOrchestrationHandler {
|
|
5
|
+
private static _instance;
|
|
6
|
+
private config;
|
|
7
|
+
private testOrderingServerHandler;
|
|
8
|
+
private orchestrationUtils;
|
|
9
|
+
private orderingInstrumentationData;
|
|
10
|
+
private testOrderingApplied;
|
|
11
|
+
private isTestOrderingEnabled;
|
|
12
|
+
/**
|
|
13
|
+
* @param config Service configuration
|
|
14
|
+
*/
|
|
15
|
+
constructor(config: Record<string, any>);
|
|
16
|
+
/**
|
|
17
|
+
* Get or create an instance of TestOrchestrationHandler
|
|
18
|
+
*/
|
|
19
|
+
static getInstance(config: Record<string, any>): TestOrchestrationHandler;
|
|
20
|
+
/**
|
|
21
|
+
* Checks if observability is enabled
|
|
22
|
+
*/
|
|
23
|
+
private _isObservabilityEnabled;
|
|
24
|
+
/**
|
|
25
|
+
* Logs test ordering checks
|
|
26
|
+
*/
|
|
27
|
+
logTestOrderingChecks(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Checks if test ordering is applied
|
|
30
|
+
*/
|
|
31
|
+
isTestOrderingApplied(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Sets whether test ordering is applied
|
|
34
|
+
*/
|
|
35
|
+
setTestOrderingApplied(orderingApplied: boolean): void;
|
|
36
|
+
/**
|
|
37
|
+
* Reorders test files based on the orchestration strategy
|
|
38
|
+
*/
|
|
39
|
+
reorderTestFiles(testFiles: string[]): Promise<string[] | null>;
|
|
40
|
+
/**
|
|
41
|
+
* Adds data to the ordering instrumentation data
|
|
42
|
+
*/
|
|
43
|
+
addToOrderingInstrumentationData(key: string, value: any): void;
|
|
44
|
+
/**
|
|
45
|
+
* Gets the ordering instrumentation data
|
|
46
|
+
*/
|
|
47
|
+
getOrderingInstrumentationData(): Record<string, any>;
|
|
48
|
+
}
|
|
49
|
+
export default TestOrchestrationHandler;
|
|
50
|
+
//# sourceMappingURL=testorcherstrationhandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testorcherstrationhandler.d.ts","sourceRoot":"","sources":["../../src/testorchestration/testorcherstrationhandler.ts"],"names":[],"mappings":"AAmBA;;GAEG;AACH,qBAAa,wBAAwB;IACjC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAwC;IAChE,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,yBAAyB,CAAoB;IACrD,OAAO,CAAC,kBAAkB,CAA2B;IACrD,OAAO,CAAC,2BAA2B,CAAqB;IACxD,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,qBAAqB,CAAS;IAEtC;;OAEG;gBACS,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IASvC;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,wBAAwB;IAOzE;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAI/B;;OAEG;IACH,qBAAqB,IAAI,IAAI;IAU7B;;OAEG;IACH,qBAAqB,IAAI,OAAO;IAIhC;;OAEG;IACH,sBAAsB,CAAC,eAAe,EAAE,OAAO,GAAG,IAAI;IAKtD;;OAEG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IA2CrE;;OAEG;IACH,gCAAgC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAI/D;;OAEG;IACH,8BAA8B,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;CAGxD;AAED,eAAe,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { TestOrderingServer } from './test-ordering-server.js';
|
|
2
|
+
import { OrchestrationUtils } from './testorcherstrationutils.js';
|
|
3
|
+
import { GrpcClient } from '../cli/grpcClient.js';
|
|
4
|
+
import { BrowserstackCLI } from '../cli/index.js';
|
|
5
|
+
import { BStackLogger } from '../bstackLogger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Checks if a value is true
|
|
8
|
+
*/
|
|
9
|
+
function isTrue(value) {
|
|
10
|
+
if (typeof value === 'boolean') {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
if (typeof value === 'string') {
|
|
14
|
+
return value.toLowerCase() === 'true';
|
|
15
|
+
}
|
|
16
|
+
return !!value;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Handles test orchestration operations
|
|
20
|
+
*/
|
|
21
|
+
export class TestOrchestrationHandler {
|
|
22
|
+
static _instance = null;
|
|
23
|
+
config;
|
|
24
|
+
testOrderingServerHandler;
|
|
25
|
+
orchestrationUtils;
|
|
26
|
+
orderingInstrumentationData;
|
|
27
|
+
testOrderingApplied;
|
|
28
|
+
isTestOrderingEnabled;
|
|
29
|
+
/**
|
|
30
|
+
* @param config Service configuration
|
|
31
|
+
*/
|
|
32
|
+
constructor(config) {
|
|
33
|
+
this.config = config;
|
|
34
|
+
this.testOrderingServerHandler = new TestOrderingServer(this.config);
|
|
35
|
+
this.orchestrationUtils = OrchestrationUtils.getInstance(config);
|
|
36
|
+
this.orderingInstrumentationData = {};
|
|
37
|
+
this.testOrderingApplied = false;
|
|
38
|
+
this.isTestOrderingEnabled = config.testOrchestration?.enabled || false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get or create an instance of TestOrchestrationHandler
|
|
42
|
+
*/
|
|
43
|
+
static getInstance(config) {
|
|
44
|
+
if (TestOrchestrationHandler._instance === null && config !== null) {
|
|
45
|
+
TestOrchestrationHandler._instance = new TestOrchestrationHandler(config);
|
|
46
|
+
}
|
|
47
|
+
return TestOrchestrationHandler._instance;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Checks if observability is enabled
|
|
51
|
+
*/
|
|
52
|
+
_isObservabilityEnabled() {
|
|
53
|
+
return isTrue(this.config.testObservability);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Logs test ordering checks
|
|
57
|
+
*/
|
|
58
|
+
logTestOrderingChecks() {
|
|
59
|
+
if (this.config.projectName === undefined || this.config.buildName === undefined) {
|
|
60
|
+
BStackLogger.info("Test Reordering can't work as buildName or projectName is null. Please set a non-null value.");
|
|
61
|
+
}
|
|
62
|
+
if (!this._isObservabilityEnabled()) {
|
|
63
|
+
BStackLogger.info("Test Reordering can't work as testReporting is disabled. Please enable it from browserstack.yml file.");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Checks if test ordering is applied
|
|
68
|
+
*/
|
|
69
|
+
isTestOrderingApplied() {
|
|
70
|
+
return this.testOrderingApplied;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Sets whether test ordering is applied
|
|
74
|
+
*/
|
|
75
|
+
setTestOrderingApplied(orderingApplied) {
|
|
76
|
+
this.testOrderingApplied = orderingApplied;
|
|
77
|
+
this.addToOrderingInstrumentationData('applied', orderingApplied);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Reorders test files based on the orchestration strategy
|
|
81
|
+
*/
|
|
82
|
+
async reorderTestFiles(testFiles) {
|
|
83
|
+
try {
|
|
84
|
+
if (!testFiles || testFiles.length === 0) {
|
|
85
|
+
BStackLogger.debug('[reorderTestFiles] No test files provided for ordering.');
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
let orchestrationStrategy = null;
|
|
89
|
+
const orchestrationMetadata = this.orchestrationUtils?.getTestOrchestrationMetadata() || {};
|
|
90
|
+
if (this.orchestrationUtils !== null) {
|
|
91
|
+
orchestrationStrategy = this.orchestrationUtils.getTestOrderingName();
|
|
92
|
+
}
|
|
93
|
+
if (orchestrationStrategy === null) {
|
|
94
|
+
BStackLogger.error('Orchestration strategy is None. Cannot proceed with test orchestration session.');
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
BStackLogger.info(`Reordering test files with orchestration strategy: ${orchestrationStrategy}`);
|
|
98
|
+
let orderedTestFiles = [];
|
|
99
|
+
if (BrowserstackCLI.getInstance().isRunning()) {
|
|
100
|
+
BStackLogger.info('Using CLI flow for test files orchestration.');
|
|
101
|
+
orderedTestFiles = await GrpcClient.getInstance().testOrchestrationSession(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata)) || [];
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
BStackLogger.info('Using SDK flow for test files orchestration.');
|
|
105
|
+
await this.testOrderingServerHandler.splitTests(testFiles, orchestrationStrategy, JSON.stringify(orchestrationMetadata));
|
|
106
|
+
orderedTestFiles = await this.testOrderingServerHandler.getOrderedTestFiles() || [];
|
|
107
|
+
}
|
|
108
|
+
this.addToOrderingInstrumentationData('uploadedTestFilesCount', testFiles.length);
|
|
109
|
+
this.addToOrderingInstrumentationData('nodeIndex', parseInt(process.env.BROWSERSTACK_NODE_INDEX || '0'));
|
|
110
|
+
this.addToOrderingInstrumentationData('totalNodes', parseInt(process.env.BROWSERSTACK_NODE_COUNT || '1'));
|
|
111
|
+
this.addToOrderingInstrumentationData('downloadedTestFilesCount', orderedTestFiles.length);
|
|
112
|
+
this.addToOrderingInstrumentationData('splitTestsAPICallCount', this.testOrderingServerHandler.getSplitTestsApiCallCount());
|
|
113
|
+
return orderedTestFiles;
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
BStackLogger.debug(`[reorderTestFiles] Error in ordering test classes: ${e}`);
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Adds data to the ordering instrumentation data
|
|
122
|
+
*/
|
|
123
|
+
addToOrderingInstrumentationData(key, value) {
|
|
124
|
+
this.orderingInstrumentationData[key] = value;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Gets the ordering instrumentation data
|
|
128
|
+
*/
|
|
129
|
+
getOrderingInstrumentationData() {
|
|
130
|
+
return this.orderingInstrumentationData;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export default TestOrchestrationHandler;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility class for test orchestration
|
|
3
|
+
*/
|
|
4
|
+
export declare class OrchestrationUtils {
|
|
5
|
+
private static _instance;
|
|
6
|
+
private runSmartSelection;
|
|
7
|
+
private smartSelectionMode;
|
|
8
|
+
private testOrdering;
|
|
9
|
+
private smartSelectionSource;
|
|
10
|
+
private projectName?;
|
|
11
|
+
private buildName?;
|
|
12
|
+
private buildIdentifier?;
|
|
13
|
+
/**
|
|
14
|
+
* @param config Configuration object
|
|
15
|
+
*/
|
|
16
|
+
constructor(config: Record<string, any>);
|
|
17
|
+
/**
|
|
18
|
+
* Extract build details from capabilities
|
|
19
|
+
*/
|
|
20
|
+
private _extractBuildDetails;
|
|
21
|
+
/**
|
|
22
|
+
* Get or create an instance of OrchestrationUtils
|
|
23
|
+
*/
|
|
24
|
+
static getInstance(config?: Record<string, any>): OrchestrationUtils | null;
|
|
25
|
+
/**
|
|
26
|
+
* Get orchestration data from config
|
|
27
|
+
*/
|
|
28
|
+
static getOrchestrationData(config: Record<string, any>): Record<string, any>;
|
|
29
|
+
/**
|
|
30
|
+
* Get run smart selection setting
|
|
31
|
+
*/
|
|
32
|
+
getRunSmartSelection(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Get smart selection mode
|
|
35
|
+
*/
|
|
36
|
+
getSmartSelectionMode(): string;
|
|
37
|
+
/**
|
|
38
|
+
* Get smart selection source
|
|
39
|
+
*/
|
|
40
|
+
getSmartSelectionSource(): string[] | Array<Record<string, any>> | null;
|
|
41
|
+
/**
|
|
42
|
+
* Get project name
|
|
43
|
+
*/
|
|
44
|
+
getProjectName(): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Get build name
|
|
47
|
+
*/
|
|
48
|
+
getBuildName(): string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Get build identifier
|
|
51
|
+
*/
|
|
52
|
+
getBuildIdentifier(): string | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Set build details
|
|
55
|
+
*/
|
|
56
|
+
setBuildDetails(projectName?: string, buildName?: string, buildIdentifier?: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Set run smart selection
|
|
59
|
+
*/
|
|
60
|
+
private _setRunSmartSelection;
|
|
61
|
+
/**
|
|
62
|
+
* Parse JSON source configuration file and format it for smart selection.
|
|
63
|
+
*
|
|
64
|
+
* @param filePath - Path to the JSON configuration file
|
|
65
|
+
* @returns Formatted list of repository configurations
|
|
66
|
+
*/
|
|
67
|
+
private _loadSourceFromFile;
|
|
68
|
+
/**
|
|
69
|
+
* Set test ordering based on priorities
|
|
70
|
+
*/
|
|
71
|
+
private _setTestOrdering;
|
|
72
|
+
/**
|
|
73
|
+
* Get test ordering name
|
|
74
|
+
*/
|
|
75
|
+
getTestOrderingName(): string | null;
|
|
76
|
+
/**
|
|
77
|
+
* Get test orchestration metadata
|
|
78
|
+
*/
|
|
79
|
+
getTestOrchestrationMetadata(): Record<string, any>;
|
|
80
|
+
/**
|
|
81
|
+
* Get build start data
|
|
82
|
+
*/
|
|
83
|
+
getBuildStartData(): Record<string, any>;
|
|
84
|
+
}
|
|
85
|
+
export default OrchestrationUtils;
|
|
86
|
+
//# sourceMappingURL=testorcherstrationutils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testorcherstrationutils.d.ts","sourceRoot":"","sources":["../../src/testorchestration/testorcherstrationutils.ts"],"names":[],"mappings":"AA0CA;;GAEG;AACH,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAkC;IAC1D,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,oBAAoB,CAA8C;IAC1E,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,eAAe,CAAC,CAAQ;IAEhC;;OAEG;gBACS,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAiCvC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAuC5B;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,kBAAkB,GAAG,IAAI;IAO3E;;OAEG;IACH,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAa7E;;OAEG;IACH,oBAAoB,IAAI,OAAO;IAI/B;;OAEG;IACH,qBAAqB,IAAI,MAAM;IAI/B;;OAEG;IACH,uBAAuB,IAAI,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI;IAIvE;;OAEG;IACH,cAAc,IAAI,MAAM,GAAG,SAAS;IAIpC;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,SAAS;IAIlC;;OAEG;IACH,kBAAkB,IAAI,MAAM,GAAG,SAAS;IAIxC;;OAEG;IACH,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI;IAOzF;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiC7B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAmI3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAQxB;;OAEG;IACH,mBAAmB,IAAI,MAAM,GAAG,IAAI;IAOpC;;OAEG;IACH,4BAA4B,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAWnD;;OAEG;IACH,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;CAW3C;AAED,eAAe,kBAAkB,CAAA"}
|