Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: modify large queries use query more to fetch all needed records #338

Merged
merged 12 commits into from
Dec 8, 2023
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
"bugs": "https://github.com/forcedotcom/salesforcedx-apex/issues",
"main": "lib/src/index.js",
"dependencies": {
"@salesforce/core": "^5.3.18",
"@salesforce/core": "^5.3.20",
"@salesforce/kit": "^3.0.15",
"@types/istanbul-reports": "^3.0.4",
"faye": "1.4.0",
"glob": "^10.3.10",
"istanbul-lib-coverage": "^3.2.2",
"istanbul-lib-report": "^3.0.1",
"istanbul-reports": "^3.1.6",
"jsforce": "^2.0.0-beta.28"
"jsforce": "^2.0.0-beta.29"
},
"devDependencies": {
"@commitlint/config-conventional": "^18.1.0",
Expand Down Expand Up @@ -86,4 +86,4 @@
"path": "./node_modules/cz-conventional-changelog"
}
}
}
}
7 changes: 2 additions & 5 deletions src/tests/asyncTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
ApexTestResult,
ApexTestResultData,
ApexTestResultOutcome,
ApexTestResultRecord,
ApexTestRunResult,
ApexTestRunResultRecord,
ApexTestRunResultStatus,
Expand All @@ -28,7 +27,7 @@ import {
TestResult,
TestRunIdResult
} from './types';
import { calculatePercentage, isValidTestRunID } from './utils';
import { calculatePercentage, isValidTestRunID, queryAll } from './utils';
import * as util from 'util';
import { QUERY_RECORD_LIMIT } from './constants';
import { CodeCoverage } from './codeCoverage';
Expand Down Expand Up @@ -307,9 +306,7 @@ export class AsyncTests {
}

const queryPromises = queries.map((query) => {
return this.connection.tooling.query<ApexTestResultRecord>(query, {
autoFetch: true
});
return queryAll(this.connection, query, true);
});
const apexTestResults = await Promise.all(queryPromises);
return apexTestResults as ApexTestResult[];
Expand Down
10 changes: 2 additions & 8 deletions src/tests/codeCoverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ import { Connection } from '@salesforce/core';
import {
ApexCodeCoverage,
ApexCodeCoverageAggregate,
ApexCodeCoverageAggregateRecord,
ApexCodeCoverageRecord,
ApexOrgWideCoverage,
CodeCoverageResult,
PerClassCoverage
} from './types';
import * as util from 'util';
import { calculatePercentage } from './utils';
import { calculatePercentage, queryAll } from './utils';
import { QUERY_RECORD_LIMIT } from './constants';

export class CodeCoverage {
Expand Down Expand Up @@ -176,11 +174,7 @@ export class CodeCoverage {
// that has takes a type that extends the jsforce Record.
// ApexCodeCoverageRecord and ApexCodeCoverageAggregateRecord
// are the Records compatible types defined in this project.
return this.connection.tooling.query<
ApexCodeCoverageRecord | ApexCodeCoverageAggregateRecord
>(query, {
autoFetch: true
});
return queryAll(this.connection, query, true);
});

// Note here the result of the .all call is of type QueryResult<ApexCodeCoverageAggregateRecord | ApexCodeCoverageRecord>[]
Expand Down
22 changes: 22 additions & 0 deletions src/tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { Connection } from '@salesforce/core';
import { CLASS_ID_PREFIX, TEST_RUN_ID_PREFIX } from './constants';
import { NamespaceInfo } from './types';
import { QueryResult } from 'jsforce';

export function isValidTestRunID(testRunId: string): boolean {
return (
Expand Down Expand Up @@ -54,3 +55,24 @@ export async function queryNamespaces(

return [...orgNamespaces, ...installedNamespaces];
}

export const queryAll = async <T>(
connection: Connection,
query: string,
tooling = false
): Promise<QueryResult<T>> => {
const conn = tooling ? connection.tooling : connection;
const allRecords: T[] = [];
let result = await conn.query<T>(query);
allRecords.push(...result.records);
while (!result.done) {
result = (await conn.queryMore(result.nextRecordsUrl)) as QueryResult<T>;
allRecords.push(...result.records);
}

return {
done: true,
totalSize: allRecords.length,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we log these details (totalSize) during the run?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@diyer do you mean so they can be seen in telemetry or just in the typical local log files for the user?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log files for the user

records: allRecords
} as QueryResult<T>;
};
35 changes: 15 additions & 20 deletions test/tests/asyncTests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -710,10 +710,9 @@ describe('Run Apex tests asynchronously', () => {
};

it('should split into multiple queries if query is longer than char limit', async () => {
const mockToolingQuery = sandboxStub.stub(
mockConnection.tooling,
'query'
);
const mockToolingQuery = sandboxStub
.stub(mockConnection.tooling, 'query')
.resolves({ done: true, totalSize: 1, records: [] });

const asyncTestSrv = new AsyncTests(mockConnection);
const result = await asyncTestSrv.getAsyncTestResults(testQueueItems);
Expand All @@ -723,10 +722,9 @@ describe('Run Apex tests asynchronously', () => {
});

it('should make a single api call if query is under char limit', async () => {
const mockToolingQuery = sandboxStub.stub(
mockConnection.tooling,
'query'
);
const mockToolingQuery = sandboxStub
.stub(mockConnection.tooling, 'query')
.resolves({ done: true, totalSize: 1, records: [] });

const asyncTestSrv = new AsyncTests(mockConnection);
const result = await asyncTestSrv.getAsyncTestResults(pollResponse);
Expand All @@ -747,10 +745,9 @@ describe('Run Apex tests asynchronously', () => {
records: queueItemRecords
};

const mockToolingQuery = sandboxStub.stub(
mockConnection.tooling,
'query'
);
const mockToolingQuery = sandboxStub
.stub(mockConnection.tooling, 'query')
.resolves({ done: true, totalSize: 1, records: [] });

const asyncTestSrv = new AsyncTests(mockConnection);
const result = await asyncTestSrv.getAsyncTestResults(testQueueItems);
Expand All @@ -771,10 +768,9 @@ describe('Run Apex tests asynchronously', () => {
records: queueItemRecords
};

const mockToolingQuery = sandboxStub.stub(
mockConnection.tooling,
'query'
);
const mockToolingQuery = sandboxStub
.stub(mockConnection.tooling, 'query')
.resolves({ done: true, totalSize: 1, records: [] });

const asyncTestSrv = new AsyncTests(mockConnection);
const result = await asyncTestSrv.getAsyncTestResults(testQueueItems);
Expand All @@ -792,10 +788,9 @@ describe('Run Apex tests asynchronously', () => {
'SELECT Id, QueueItemId, StackTrace, Message, RunTime, TestTimestamp, AsyncApexJobId, MethodName, Outcome, ApexLogId, ApexClass.Id, ApexClass.Name, ApexClass.NamespacePrefix FROM ApexTestResult WHERE QueueItemId IN ';
const queryStartSeparatorCount = queryStart.split(',').length - 1;

const mockToolingQuery = sandboxStub.stub(
mockConnection.tooling,
'query'
);
const mockToolingQuery = sandboxStub
.stub(mockConnection.tooling, 'query')
.resolves({ done: true, totalSize: 1, records: [] });

const queueItemRecord: ApexTestQueueItemRecord[] = [];

Expand Down
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"lib": ["es6", "dom"],
"target": "ES2020",
"lib": ["ES2020", "dom"],
"sourceMap": true,
"declaration": true,
"moduleResolution": "node",
Expand Down
Loading