Skip to content

Commit 00175bd

Browse files
cortinicofacebook-github-bot
authored andcommitted
Compare nightly results up to 7 days in the back (#53065)
Summary: Pull Request resolved: #53065 Instead of checking results from the previous day, allow to go back up to 7 days in the past to check for previous runs. Changelog: [Internal] [Changed] - Reviewed By: cipolleschi Differential Revision: D79568067 fbshipit-source-id: 5d6fac6a06b4e26e52de6fbf6187ec8f8e44e10e
1 parent f806851 commit 00175bd

3 files changed

Lines changed: 343 additions & 9 deletions

File tree

.github/workflow-scripts/__tests__/firebaseUtils-test.js

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,286 @@ describe('FirebaseClient', () => {
362362
);
363363
});
364364
});
365+
366+
describe('getLatestResults', () => {
367+
it('should authenticate before making requests if no token exists', async () => {
368+
const authResponse = {idToken: 'new-token'};
369+
const mockResults = [{library: 'test', status: 'success'}];
370+
371+
global.fetch
372+
.mockResolvedValueOnce({
373+
ok: true,
374+
text: jest.fn().mockResolvedValueOnce(JSON.stringify(authResponse)),
375+
})
376+
.mockResolvedValueOnce({
377+
ok: true,
378+
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
379+
});
380+
381+
const client = new FirebaseClient();
382+
const result = await client.getLatestResults('2023-12-15', 1);
383+
384+
expect(result).toEqual({
385+
results: mockResults,
386+
date: '2023-12-14',
387+
});
388+
expect(client.idToken).toBe('new-token');
389+
expect(console.log).toHaveBeenCalledWith(
390+
'Checking for results on 2023-12-14 (1 days back)...',
391+
);
392+
expect(console.log).toHaveBeenCalledWith(
393+
'Found results from 2023-12-14 (1 days back)',
394+
);
395+
});
396+
397+
it('should find results from the previous day', async () => {
398+
const mockResults = [{library: 'test', status: 'success'}];
399+
global.fetch.mockResolvedValueOnce({
400+
ok: true,
401+
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
402+
});
403+
404+
const client = new FirebaseClient();
405+
client.idToken = 'existing-token';
406+
407+
const result = await client.getLatestResults('2023-12-15', 7);
408+
409+
expect(result).toEqual({
410+
results: mockResults,
411+
date: '2023-12-14',
412+
});
413+
expect(console.log).toHaveBeenCalledWith(
414+
'Checking for results on 2023-12-14 (1 days back)...',
415+
);
416+
expect(console.log).toHaveBeenCalledWith(
417+
'Found results from 2023-12-14 (1 days back)',
418+
);
419+
});
420+
421+
it('should find results from several days back', async () => {
422+
const mockResults = [{library: 'test', status: 'success'}];
423+
424+
// Mock 404 responses for first 2 days, then success on 3rd day
425+
global.fetch
426+
.mockResolvedValueOnce({
427+
ok: false,
428+
status: 404,
429+
text: jest.fn().mockResolvedValueOnce('Not Found'),
430+
})
431+
.mockResolvedValueOnce({
432+
ok: false,
433+
status: 404,
434+
text: jest.fn().mockResolvedValueOnce('Not Found'),
435+
})
436+
.mockResolvedValueOnce({
437+
ok: true,
438+
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
439+
});
440+
441+
const client = new FirebaseClient();
442+
client.idToken = 'existing-token';
443+
444+
const result = await client.getLatestResults('2023-12-15', 7);
445+
446+
expect(result).toEqual({
447+
results: mockResults,
448+
date: '2023-12-12',
449+
});
450+
expect(console.log).toHaveBeenCalledWith(
451+
'Checking for results on 2023-12-14 (1 days back)...',
452+
);
453+
expect(console.log).toHaveBeenCalledWith(
454+
'Checking for results on 2023-12-13 (2 days back)...',
455+
);
456+
expect(console.log).toHaveBeenCalledWith(
457+
'Checking for results on 2023-12-12 (3 days back)...',
458+
);
459+
expect(console.log).toHaveBeenCalledWith(
460+
'Found results from 2023-12-12 (3 days back)',
461+
);
462+
});
463+
464+
it('should skip empty results and continue searching', async () => {
465+
const mockResults = [{library: 'test', status: 'success'}];
466+
467+
// Mock empty array for first day, then valid results on second day
468+
global.fetch
469+
.mockResolvedValueOnce({
470+
ok: true,
471+
text: jest.fn().mockResolvedValueOnce(JSON.stringify([])),
472+
})
473+
.mockResolvedValueOnce({
474+
ok: true,
475+
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
476+
});
477+
478+
const client = new FirebaseClient();
479+
client.idToken = 'existing-token';
480+
481+
const result = await client.getLatestResults('2023-12-15', 7);
482+
483+
expect(result).toEqual({
484+
results: mockResults,
485+
date: '2023-12-13',
486+
});
487+
expect(console.log).toHaveBeenCalledWith(
488+
'Checking for results on 2023-12-14 (1 days back)...',
489+
);
490+
expect(console.log).toHaveBeenCalledWith(
491+
'Checking for results on 2023-12-13 (2 days back)...',
492+
);
493+
expect(console.log).toHaveBeenCalledWith(
494+
'Found results from 2023-12-13 (2 days back)',
495+
);
496+
});
497+
498+
it('should return null when no results found within maxDaysBack', async () => {
499+
// Mock 404 responses for all days
500+
global.fetch.mockResolvedValue({
501+
ok: false,
502+
status: 404,
503+
text: jest.fn().mockResolvedValue('Not Found'),
504+
});
505+
506+
const client = new FirebaseClient();
507+
client.idToken = 'existing-token';
508+
509+
const result = await client.getLatestResults('2023-12-15', 3);
510+
511+
expect(result).toEqual({
512+
results: null,
513+
date: null,
514+
});
515+
expect(console.log).toHaveBeenCalledWith(
516+
'No previous results found within the last 3 days',
517+
);
518+
expect(global.fetch).toHaveBeenCalledTimes(3);
519+
});
520+
521+
it('should use default maxDaysBack of 7 when not specified', async () => {
522+
// Mock 404 responses for all days
523+
global.fetch.mockResolvedValue({
524+
ok: false,
525+
status: 404,
526+
text: jest.fn().mockResolvedValue('Not Found'),
527+
});
528+
529+
const client = new FirebaseClient();
530+
client.idToken = 'existing-token';
531+
532+
const result = await client.getLatestResults('2023-12-15');
533+
534+
expect(result).toEqual({
535+
results: null,
536+
date: null,
537+
});
538+
expect(console.log).toHaveBeenCalledWith(
539+
'No previous results found within the last 7 days',
540+
);
541+
expect(global.fetch).toHaveBeenCalledTimes(7);
542+
});
543+
544+
it('should handle non-404 errors and continue searching', async () => {
545+
const mockResults = [{library: 'test', status: 'success'}];
546+
547+
// Mock 500 error for first day, then success on second day
548+
global.fetch
549+
.mockResolvedValueOnce({
550+
ok: false,
551+
status: 500,
552+
text: jest.fn().mockResolvedValueOnce('Internal Server Error'),
553+
})
554+
.mockResolvedValueOnce({
555+
ok: true,
556+
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
557+
});
558+
559+
const client = new FirebaseClient();
560+
client.idToken = 'existing-token';
561+
562+
const result = await client.getLatestResults('2023-12-15', 7);
563+
564+
expect(result).toEqual({
565+
results: mockResults,
566+
date: '2023-12-13',
567+
});
568+
expect(console.log).toHaveBeenCalledWith(
569+
'No results found for 2023-12-14: HTTP 500: Internal Server Error',
570+
);
571+
expect(console.log).toHaveBeenCalledWith(
572+
'Found results from 2023-12-13 (2 days back)',
573+
);
574+
});
575+
576+
it('should handle date boundaries correctly', async () => {
577+
const mockResults = [{library: 'test', status: 'success'}];
578+
global.fetch.mockResolvedValueOnce({
579+
ok: true,
580+
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
581+
});
582+
583+
const client = new FirebaseClient();
584+
client.idToken = 'existing-token';
585+
586+
// Test month boundary
587+
const result = await client.getLatestResults('2023-12-01', 1);
588+
589+
expect(result).toEqual({
590+
results: mockResults,
591+
date: '2023-11-30',
592+
});
593+
expect(console.log).toHaveBeenCalledWith(
594+
'Checking for results on 2023-11-30 (1 days back)...',
595+
);
596+
});
597+
598+
it('should handle year boundary correctly', async () => {
599+
const mockResults = [{library: 'test', status: 'success'}];
600+
global.fetch.mockResolvedValueOnce({
601+
ok: true,
602+
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
603+
});
604+
605+
const client = new FirebaseClient();
606+
client.idToken = 'existing-token';
607+
608+
// Test year boundary
609+
const result = await client.getLatestResults('2024-01-01', 1);
610+
611+
expect(result).toEqual({
612+
results: mockResults,
613+
date: '2023-12-31',
614+
});
615+
expect(console.log).toHaveBeenCalledWith(
616+
'Checking for results on 2023-12-31 (1 days back)...',
617+
);
618+
});
619+
620+
it('should handle null results and continue searching', async () => {
621+
const mockResults = [{library: 'test', status: 'success'}];
622+
623+
// Mock null for first day, then valid results on second day
624+
global.fetch
625+
.mockResolvedValueOnce({
626+
ok: true,
627+
text: jest.fn().mockResolvedValueOnce('null'),
628+
})
629+
.mockResolvedValueOnce({
630+
ok: true,
631+
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
632+
});
633+
634+
const client = new FirebaseClient();
635+
client.idToken = 'existing-token';
636+
637+
const result = await client.getLatestResults('2023-12-15', 7);
638+
639+
expect(result).toEqual({
640+
results: mockResults,
641+
date: '2023-12-13',
642+
});
643+
});
644+
});
365645
});
366646

367647
describe('compareResults', () => {

.github/workflow-scripts/collectNightlyOutcomes.js

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,23 +124,35 @@ async function collectResults(discordWebHook) {
124124
// Initialize Firebase client
125125
const firebaseClient = new FirebaseClient();
126126
const today = getTodayDate();
127-
const yesterday = getYesterdayDate();
128127

129128
try {
130129
// Store today's results in Firebase
131130
console.log(`Storing results for ${today} in Firebase...`);
132131
await firebaseClient.storeResults(today, outcomes);
133132

134-
// Get yesterday's results for comparison
135-
console.log(`Retrieving results for ${yesterday} from Firebase...`);
136-
const yesterdayResults = await firebaseClient.getResults(yesterday);
133+
// Get the most recent previous results for comparison
134+
console.log(`Looking for most recent previous results before ${today}...`);
135+
const {results: previousResults, date: previousDate} =
136+
await firebaseClient.getLatestResults(today);
137137

138-
// Compare results and identify broken/recovered tests
139-
const {broken, recovered} = compareResults(outcomes, yesterdayResults);
138+
let broken = [];
139+
let recovered = [];
140140

141-
console.log(
142-
`Found ${broken.length} newly broken tests and ${recovered.length} recovered tests`,
143-
);
141+
if (previousResults) {
142+
console.log(`Comparing with results from ${previousDate}`);
143+
// Compare results and identify broken/recovered jobs
144+
const comparison = compareResults(outcomes, previousResults);
145+
broken = comparison.broken;
146+
recovered = comparison.recovered;
147+
148+
console.log(
149+
`Found ${broken.length} newly broken jobs and ${recovered.length} recovered jobs compared to ${previousDate}`,
150+
);
151+
} else {
152+
console.log(
153+
'No previous results found for comparison - this might be the first run or no recent data available',
154+
);
155+
}
144156

145157
// Send comparison message to Discord if there are changes
146158
if (discordWebHook && (broken.length > 0 || recovered.length > 0)) {

.github/workflow-scripts/firebaseUtils.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,48 @@ class FirebaseClient {
8686
}
8787
}
8888

89+
/**
90+
* Find the most recent available job results before the given date
91+
* @param {string} currentDate - Current date in YYYY-MM-DD format
92+
* @param {number} maxDaysBack - Maximum number of days to look back (default: 7)
93+
* @returns {Promise<{results: Array<Object>|null, date: string|null}>} - Most recent results and their date
94+
*/
95+
async getLatestResults(currentDate, maxDaysBack = 7) {
96+
if (!this.idToken) {
97+
await this.authenticate();
98+
}
99+
100+
const currentDateObj = new Date(currentDate);
101+
102+
for (let daysBack = 1; daysBack <= maxDaysBack; daysBack++) {
103+
const checkDate = new Date(currentDateObj);
104+
checkDate.setDate(checkDate.getDate() - daysBack);
105+
const checkDateStr = checkDate.toISOString().split('T')[0];
106+
107+
console.log(
108+
`Checking for results on ${checkDateStr} (${daysBack} days back)...`,
109+
);
110+
111+
try {
112+
const results = await this.getResults(checkDateStr);
113+
if (results && results.length > 0) {
114+
console.log(
115+
`Found results from ${checkDateStr} (${daysBack} days back)`,
116+
);
117+
return {results, date: checkDateStr};
118+
}
119+
} catch (error) {
120+
console.log(`No results found for ${checkDateStr}: ${error.message}`);
121+
continue;
122+
}
123+
}
124+
125+
console.log(
126+
`No previous results found within the last ${maxDaysBack} days`,
127+
);
128+
return {results: null, date: null};
129+
}
130+
89131
async makeRequest(hostname, path, method, data = null) {
90132
const url = `https://${hostname}${path}`;
91133
const options = {

0 commit comments

Comments
 (0)