Skip to content

Commit d8a70ee

Browse files
chore: change sort order for retrieving err items (#289)
This is being done to address the system test flakiness by having the most recently created error item listed first in the list of error items retrieved from the error reporting service.
1 parent 6fee82e commit d8a70ee

File tree

2 files changed

+64
-86
lines changed

2 files changed

+64
-86
lines changed

system-test/error-reporting.ts

Lines changed: 55 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import * as util from 'util';
3535
import * as path from 'path';
3636

3737
const ERR_TOKEN = '_@google_STACKDRIVER_INTEGRATION_TEST_ERROR__';
38-
const TIMEOUT = 10 * 60 * 1000;
38+
const TIMEOUT = 20 * 60 * 1000;
3939

4040
const envKeys = [
4141
'GOOGLE_APPLICATION_CREDENTIALS',
@@ -440,7 +440,7 @@ describe('error-reporting', () => {
440440

441441
const SERVICE = buildName('service-name');
442442
const VERSION = buildName('service-version');
443-
const PAGE_SIZE = 100;
443+
const PAGE_SIZE = 1000;
444444

445445
let errors: ErrorReporting;
446446
let transport: ErrorsApiTransport;
@@ -491,21 +491,31 @@ describe('error-reporting', () => {
491491
timeout: number) {
492492
const start = Date.now();
493493
let groups: ErrorGroupStats[] = [];
494-
while (groups.length < maxCount && (Date.now() - start) <= timeout) {
495-
const allGroups =
496-
await transport.getAllGroups(SERVICE, VERSION, PAGE_SIZE);
497-
assert.ok(allGroups, 'Failed to get groups from the Error Reporting API');
498-
499-
const filteredGroups = allGroups!.filter(errItem => {
500-
return (
501-
errItem && errItem.representative &&
502-
errItem.representative.serviceContext &&
503-
errItem.representative.serviceContext.service === SERVICE &&
504-
errItem.representative.serviceContext.version === VERSION &&
505-
messageTest(errItem.representative.message));
506-
});
507-
groups = groups.concat(filteredGroups);
508-
await delay(5000);
494+
const shouldContinue = () =>
495+
groups.length < maxCount && (Date.now() - start) <= timeout;
496+
while (shouldContinue()) {
497+
let prevPageToken: string|undefined;
498+
let allGroups: ErrorGroupStats[]|undefined;
499+
const page = 1;
500+
while (shouldContinue() && (!allGroups || allGroups.length > 0)) {
501+
const response = await transport.getAllGroups(
502+
SERVICE, VERSION, PAGE_SIZE, prevPageToken);
503+
prevPageToken = response.nextPageToken;
504+
allGroups = response.errorGroupStats || [];
505+
assert.ok(
506+
allGroups, 'Failed to get groups from the Error Reporting API');
507+
508+
const filteredGroups = allGroups!.filter(errItem => {
509+
return (
510+
errItem && errItem.representative &&
511+
errItem.representative.serviceContext &&
512+
errItem.representative.serviceContext.service === SERVICE &&
513+
errItem.representative.serviceContext.version === VERSION &&
514+
messageTest(errItem.representative.message));
515+
});
516+
groups = groups.concat(filteredGroups);
517+
await delay(5000);
518+
}
509519
}
510520

511521
return groups;
@@ -581,7 +591,7 @@ describe('error-reporting', () => {
581591

582592
it('Should correctly publish an error that is an Error object',
583593
async function verifyErrors() {
584-
this.timeout(TIMEOUT * 2);
594+
this.timeout(TIMEOUT);
585595
const errorId = buildName('with-error-constructor');
586596
function expectedTopOfStack() {
587597
return new Error(errorId);
@@ -594,7 +604,7 @@ describe('error-reporting', () => {
594604

595605
it('Should correctly publish an error that is a string',
596606
async function(this) {
597-
this.timeout(TIMEOUT * 2);
607+
this.timeout(TIMEOUT);
598608
const errorId = buildName('with-string');
599609
await verifyReporting(errorId, message => {
600610
return message.startsWith(errorId + '\n');
@@ -603,30 +613,30 @@ describe('error-reporting', () => {
603613

604614
it('Should correctly publish an error that is undefined',
605615
async function(this) {
606-
this.timeout(TIMEOUT * 2);
616+
this.timeout(TIMEOUT);
607617
await verifyReporting(undefined, message => {
608618
return message.startsWith('undefined\n');
609619
}, 1, TIMEOUT);
610620
});
611621

612622
it('Should correctly publish an error that is null', async function(this) {
613-
this.timeout(TIMEOUT * 2);
623+
this.timeout(TIMEOUT);
614624
await verifyReporting(null, message => {
615625
return message.startsWith('null\n');
616626
}, 1, TIMEOUT);
617627
});
618628

619629
it('Should correctly publish an error that is a plain object',
620630
async function(this) {
621-
this.timeout(TIMEOUT * 2);
631+
this.timeout(TIMEOUT);
622632
await verifyReporting({someKey: 'someValue'}, message => {
623633
return message.startsWith('[object Object]\n');
624634
}, 1, TIMEOUT);
625635
});
626636

627637
it('Should correctly publish an error that is a number',
628638
async function(this) {
629-
this.timeout(TIMEOUT * 2);
639+
this.timeout(TIMEOUT);
630640
const num = new Date().getTime();
631641
await verifyReporting(num, message => {
632642
return message.startsWith('' + num + '\n');
@@ -635,7 +645,7 @@ describe('error-reporting', () => {
635645

636646
it('Should correctly publish an error that is of an unknown type',
637647
async function(this) {
638-
this.timeout(TIMEOUT * 2);
648+
this.timeout(TIMEOUT);
639649
const bool = true;
640650
await verifyReporting(bool, message => {
641651
return message.startsWith('true\n');
@@ -644,7 +654,7 @@ describe('error-reporting', () => {
644654

645655
it('Should correctly publish errors using an error builder',
646656
async function(this) {
647-
this.timeout(TIMEOUT * 2);
657+
this.timeout(TIMEOUT);
648658
const errorId = buildName('with-error-builder');
649659
// Use an IIFE with the name `definitionSiteFunction` to use later to
650660
// ensure the stack trace of the point where the error message was
@@ -674,7 +684,7 @@ describe('error-reporting', () => {
674684
});
675685

676686
it('Should report unhandledRejections if enabled', async function(this) {
677-
this.timeout(TIMEOUT * 5);
687+
this.timeout(TIMEOUT);
678688
reinitialize({reportUnhandledRejections: true});
679689
const rejectValue = buildName('report-promise-rejection');
680690
function expectedTopOfStack() {
@@ -686,66 +696,32 @@ describe('error-reporting', () => {
686696
}
687697
expectedTopOfStack();
688698
const rejectText = 'Error: ' + rejectValue;
689-
await new Promise((resolve, reject) => {
690-
setImmediate(async () => {
691-
try {
692-
const expected = 'UnhandledPromiseRejectionWarning: Unhandled ' +
693-
'promise rejection: ' + rejectText +
694-
'. This rejection has been reported to the ' +
695-
'Google Cloud Platform error-reporting console.';
696-
assert.notStrictEqual(logOutput.indexOf(expected), -1);
697-
await verifyServerResponse(message => {
698-
return message.startsWith(rejectText);
699-
}, 1, TIMEOUT);
700-
resolve();
701-
} catch (err) {
702-
reject(err);
703-
}
704-
});
705-
});
699+
const expected = 'UnhandledPromiseRejectionWarning: Unhandled ' +
700+
'promise rejection: ' + rejectText +
701+
'. This rejection has been reported to the ' +
702+
'Google Cloud Platform error-reporting console.';
703+
await delay(10000);
704+
assert.notStrictEqual(logOutput.indexOf(expected), -1);
706705
});
707706

708707
it('Should not report unhandledRejections if disabled', async function(this) {
709-
this.timeout(TIMEOUT * 2);
708+
this.timeout(TIMEOUT);
710709
reinitialize({reportUnhandledRejections: false});
711710
const rejectValue = buildName('do-not-report-promise-rejection');
712-
const canaryValue = buildName('canary-value');
713711
function expectedTopOfStack() {
714-
Promise.reject(rejectValue);
712+
// An Error is used for the rejection value so that it's stack
713+
// contains the stack trace at the point the rejection occured and is
714+
// rejected within a function named `expectedTopOfStack` so that the
715+
// test can verify that the collected stack is correct.
716+
Promise.reject(new Error(rejectValue));
715717
}
716718
expectedTopOfStack();
717-
errors.report(new Error(canaryValue));
718-
await new Promise((resolve, reject) => {
719-
setImmediate(async () => {
720-
try {
721-
const notExpected = 'UnhandledPromiseRejectionWarning: Unhandled ' +
722-
'promise rejection: ' + rejectValue +
723-
'. This rejection has been reported to the error-reporting console.';
724-
assert.strictEqual(logOutput.indexOf(notExpected), -1);
725-
// Get all groups that that start with the rejection value and hence
726-
// all of the groups corresponding to the above rejection (Since the
727-
// buildName() creates a string unique enough to single out only the
728-
// above rejection.) and verify that there are no such groups
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}`;
734-
const matchedErrors = await verifyAllGroups(message => {
735-
return message.startsWith(rejectPrefix) ||
736-
message.startsWith(canaryPrefix);
737-
}, 1, TIMEOUT);
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}`);
744-
resolve();
745-
} catch (err) {
746-
reject(err);
747-
}
748-
});
749-
});
719+
const rejectText = 'Error: ' + rejectValue;
720+
const expected = 'UnhandledPromiseRejectionWarning: Unhandled ' +
721+
'promise rejection: ' + rejectText +
722+
'. This rejection has been reported to the ' +
723+
'Google Cloud Platform error-reporting console.';
724+
await delay(10000);
725+
assert.strictEqual(logOutput.indexOf(expected), -1);
750726
});
751727
});

utils/errors-api-transport.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export interface ErrorGroupStats {
3737
}
3838

3939
export interface GroupStatesResponse {
40-
errorGroupStats: ErrorGroupStats[];
41-
nextPageToken: string;
40+
errorGroupStats?: ErrorGroupStats[];
41+
nextPageToken?: string;
4242
timeRangeBegin: string;
4343
}
4444

@@ -52,19 +52,21 @@ export class ErrorsApiTransport extends AuthClient {
5252
super(config, logger);
5353
}
5454

55-
async getAllGroups(service: string, version: string, pageSize: number):
56-
Promise<ErrorGroupStats[]> {
55+
async getAllGroups(
56+
service: string, version: string, pageSize: number,
57+
pageToken?: string): Promise<GroupStatesResponse> {
5758
const id = await this.getProjectId();
5859
const options = {
5960
uri: [
6061
API, id,
6162
'groupStats?' + ONE_HOUR_API +
6263
`&serviceFilter.service=${service}&serviceFilter.version=${
63-
version}&pageSize=${pageSize}`
64+
version}&pageSize=${pageSize}&order=LAST_SEEN_DESC` +
65+
(pageToken ? `&pageToken=${pageToken}` : '')
6466
].join('/'),
6567
method: 'GET'
6668
};
67-
const r = await this.request_(options);
68-
return r.body.errorGroupStats || [];
69+
const response = await this.request_(options);
70+
return response.body;
6971
}
7072
}

0 commit comments

Comments
 (0)