Skip to content

Commit d0f2e72

Browse files
chore: address system test flakiness (#275)
* The timeout used for waiting for the API to report an error event has been increased. * The system tests only poll for error events for a specific service and version. * The page size has been increased when requesting reported errors. * Increase polling timeout to avoid using the API too much to hit quota exceeded errors. * Error items are not deleted after the test. This is needed to avoid conflicting with concurrent runs of the system test because it is not possible to delete error items only associated with a particular test.
1 parent 6badea3 commit d0f2e72

3 files changed

Lines changed: 33 additions & 30 deletions

File tree

handwritten/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
"boom": "^7.2.0",
7878
"codecov": "^3.0.2",
7979
"cpy-cli": "^2.0.0",
80+
"delay": "^4.1.0",
8081
"eslint": "^5.0.0",
8182
"eslint-config-prettier": "^3.0.0",
8283
"eslint-plugin-node": "^8.0.0",

handwritten/system-test/error-reporting.ts

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
import * as assert from 'assert';
18+
import delay from 'delay';
1819
import * as is from 'is';
1920
import * as nock from 'nock';
2021

@@ -34,7 +35,7 @@ import * as util from 'util';
3435
import * as path from 'path';
3536

3637
const ERR_TOKEN = '_@google_STACKDRIVER_INTEGRATION_TEST_ERROR__';
37-
const TIMEOUT = 120000;
38+
const TIMEOUT = 10 * 60 * 1000;
3839

3940
const envKeys = [
4041
'GOOGLE_APPLICATION_CREDENTIALS',
@@ -140,12 +141,6 @@ if (!shouldRun()) {
140141
process.exit(1);
141142
}
142143

143-
function sleep(timeout: number) {
144-
return new Promise((resolve) => {
145-
setTimeout(resolve, timeout);
146-
});
147-
}
148-
149144
describe('Request/Response lifecycle mocking', () => {
150145
const sampleError = new Error(ERR_TOKEN);
151146
const errorMessage = new ErrorMessage().setMessage(sampleError.message);
@@ -445,6 +440,7 @@ describe('error-reporting', () => {
445440

446441
const SERVICE = buildName('service-name');
447442
const VERSION = buildName('service-version');
443+
const PAGE_SIZE = 100;
448444

449445
let errors: ErrorReporting;
450446
let transport: ErrorsApiTransport;
@@ -465,7 +461,6 @@ describe('error-reporting', () => {
465461
logOutput += text;
466462
};
467463
reinitialize();
468-
await transport.deleteAllEvents();
469464
});
470465

471466
function reinitialize(extraConfig?: {}) {
@@ -487,12 +482,6 @@ describe('error-reporting', () => {
487482
transport = new ErrorsApiTransport(configuration, logger);
488483
}
489484

490-
after(async () => {
491-
if (transport) {
492-
await transport.deleteAllEvents();
493-
}
494-
});
495-
496485
afterEach(() => {
497486
logOutput = '';
498487
});
@@ -503,7 +492,8 @@ describe('error-reporting', () => {
503492
const start = Date.now();
504493
let groups: ErrorGroupStats[] = [];
505494
while (groups.length < maxCount && (Date.now() - start) <= timeout) {
506-
const allGroups = await transport.getAllGroups();
495+
const allGroups =
496+
await transport.getAllGroups(SERVICE, VERSION, PAGE_SIZE);
507497
assert.ok(allGroups, 'Failed to get groups from the Error Reporting API');
508498

509499
const filteredGroups = allGroups!.filter(errItem => {
@@ -515,7 +505,7 @@ describe('error-reporting', () => {
515505
messageTest(errItem.representative.message));
516506
});
517507
groups = groups.concat(filteredGroups);
518-
await sleep(1000);
508+
await delay(5000);
519509
}
520510

521511
return groups;
@@ -684,9 +674,9 @@ describe('error-reporting', () => {
684674
});
685675

686676
it('Should report unhandledRejections if enabled', async function(this) {
687-
this.timeout(TIMEOUT * 4);
677+
this.timeout(TIMEOUT * 5);
688678
reinitialize({reportUnhandledRejections: true});
689-
const rejectValue = buildName('promise-rejection');
679+
const rejectValue = buildName('report-promise-rejection');
690680
function expectedTopOfStack() {
691681
// An Error is used for the rejection value so that it's stack
692682
// contains the stack trace at the point the rejection occured and is
@@ -718,11 +708,13 @@ describe('error-reporting', () => {
718708
it('Should not report unhandledRejections if disabled', async function(this) {
719709
this.timeout(TIMEOUT * 2);
720710
reinitialize({reportUnhandledRejections: false});
721-
const rejectValue = buildName('promise-rejection');
711+
const rejectValue = buildName('do-not-report-promise-rejection');
712+
const canaryValue = buildName('canary-value');
722713
function expectedTopOfStack() {
723714
Promise.reject(rejectValue);
724715
}
725716
expectedTopOfStack();
717+
errors.report(new Error(canaryValue));
726718
await new Promise((resolve, reject) => {
727719
setImmediate(async () => {
728720
try {
@@ -734,11 +726,21 @@ describe('error-reporting', () => {
734726
// all of the groups corresponding to the above rejection (Since the
735727
// buildName() creates a string unique enough to single out only the
736728
// above rejection.) and verify that there are no such groups
737-
// reported.
729+
// reported. This is done by looking for the canary value. If the
730+
// canary value is found, but the rejection value has not, then the
731+
// rejection was not reported to the API.
732+
const rejectPrefix = `Error: ${rejectValue}`;
733+
const canaryPrefix = `Error: ${canaryValue}`;
738734
const matchedErrors = await verifyAllGroups(message => {
739-
return message.startsWith(rejectValue);
735+
return message.startsWith(rejectPrefix) ||
736+
message.startsWith(canaryPrefix);
740737
}, 1, TIMEOUT);
741-
assert.strictEqual(matchedErrors.length, 0);
738+
assert.strictEqual(matchedErrors.length, 1);
739+
const message = matchedErrors[0].representative.message;
740+
assert(
741+
message.startsWith(canaryPrefix),
742+
`Expected the error message to start with ${
743+
canaryPrefix} but found ${message}`);
742744
resolve();
743745
} catch (err) {
744746
reject(err);

handwritten/utils/errors-api-transport.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,16 @@ export class ErrorsApiTransport extends AuthClient {
5252
super(config, logger);
5353
}
5454

55-
async deleteAllEvents() {
56-
const id = await this.getProjectId();
57-
const options = {uri: [API, id, 'events'].join('/'), method: 'DELETE'};
58-
return this.request_(options);
59-
}
60-
61-
async getAllGroups(): Promise<ErrorGroupStats[]> {
55+
async getAllGroups(service: string, version: string, pageSize: number):
56+
Promise<ErrorGroupStats[]> {
6257
const id = await this.getProjectId();
6358
const options = {
64-
uri: [API, id, 'groupStats?' + ONE_HOUR_API].join('/'),
59+
uri: [
60+
API, id,
61+
'groupStats?' + ONE_HOUR_API +
62+
`&serviceFilter.service=${service}&serviceFilter.version=${
63+
version}&pageSize=${pageSize}`
64+
].join('/'),
6565
method: 'GET'
6666
};
6767
const r = await this.request_(options);

0 commit comments

Comments
 (0)