Skip to content

Commit

Permalink
v0.0.15 improve timeout handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Anthony Heber committed Aug 1, 2024
1 parent eded02a commit 59cc214
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 10 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "sf-warp",
"description": "Warp your code and see if your tests notice",
"version": "0.0.14",
"version": "0.0.15",
"dependencies": {
"@oclif/core": "^3.15.1",
"@salesforce/core": "^6.4.2",
Expand Down
8 changes: 7 additions & 1 deletion src/lib/commands/apex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,13 @@ export default class ApexWarper {

if (error instanceof Error) {
errorMessage = error.message;
if (this.atLeastVerbosity(Verbosity.minimal)) {
if (error.message === 'Timeout polling action') {
if (this.config.verbosity === Verbosity.minimal) {
process.stdout.write('⏰');
} else if (this.atLeastVerbosity(Verbosity.details)) {
console.log('Test Timed Out ⏰');
}
} else if (this.atLeastVerbosity(Verbosity.minimal)) {
console.log('Failure:', error.message || error);
}
}
Expand Down
17 changes: 12 additions & 5 deletions src/lib/polling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ interface PollConfig {
timeout?: number;
actionName: string;
action(): unknown;
cancelAction?(): void;
cancelAction?(): void | Promise<void>;
}

const cancelledTimeouts: NodeJS.Timeout[] = [];
Expand All @@ -13,7 +13,17 @@ export function pollForResult<T>(pollConfig: PollConfig): Promise<T> {
let timeoutId: NodeJS.Timeout;
return new Promise((resolve, reject): void => {
timeoutId = setTimeout(() => {
reject('Timeout polling action');
let cancelPromise: Promise<void> | undefined;
if (pollConfig.cancelAction) {
cancelPromise = (pollConfig.cancelAction.call(null) as Promise<void>).catch(reject);
}
if (cancelPromise) {
void cancelPromise.finally(() => {
reject(new Error('Timeout polling action'));
});
} else {
reject(new Error('Timeout polling action'));
}
cancelledTimeouts.push(timeoutId);
}, pollConfig.timeout ?? 30000);
void executePollAction<T>(pollConfig, resolve, reject, timeoutId);
Expand All @@ -29,9 +39,6 @@ function executePollAction<T>(
pollTime?: number,
): void {
if (cancelledTimeouts.includes(timeoutId)) {
if (pollConfig.cancelAction) {
pollConfig.cancelAction.call(null);
}
return;
}
const waitTime = pollTime ?? pollConfig.initialWaitMs ?? 1000;
Expand Down
22 changes: 19 additions & 3 deletions src/lib/sf.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Connection } from '@salesforce/core';
// eslint-disable-next-line import/no-extraneous-dependencies
import { Record } from 'jsforce';
import type { Record, Schema, SObjectUpdateRecord } from 'jsforce';
import { pollForResult } from './polling';

interface ApexTestRunResultRecord extends Record {
Expand All @@ -13,6 +12,10 @@ interface ApexTestRunResultRecord extends Record {
MethodsFailed: number;
}

interface ApexTestQueueItem extends Record {
Status: string;
}

interface ContainerAsyncRequestRecord extends Record {
State: string;
ErrorMsg: string;
Expand All @@ -37,7 +40,7 @@ export async function executeTests(
testClasses: string[],
timeoutMs: number,
): Promise<ApexTestRunResultRecord> {
const asyncJobId = await conn.tooling.runTestsAsynchronous({ classNames: testClasses.join(',') });
const asyncJobId = await conn.tooling.runTestsAsynchronous({ classNames: testClasses.join(','), maxFailedTests: 0 });

return pollForResult({
timeout: timeoutMs,
Expand All @@ -50,6 +53,19 @@ export async function executeTests(
return request.records[0];
}
},
cancelAction: async () => {
const queryResults = await conn.query<ApexTestQueueItem>(
`SELECT Id, Status FROM ApexTestQueueItem WHERE ParentJobId = '${asyncJobId}'`,
);
queryResults.records.forEach((record) => (record.Status = 'Aborted'));
const saveResult = await conn.update(
'ApexTestQueueItem',
queryResults.records as Array<SObjectUpdateRecord<Schema, 'ApexTestQueueItem'>>,
);
if (saveResult.find((res) => res.success === false) === undefined) {
throw new Error('Failure to cancel tests:' + JSON.stringify(saveResult));
}
},
});
}

Expand Down

0 comments on commit 59cc214

Please sign in to comment.