Compare nightly results up to 7 days in the back (#53065)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/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
This commit is contained in:
Nicola Corti
2025-08-06 03:04:02 -07:00
committed by Facebook GitHub Bot
parent f806851875
commit 00175bd096
3 changed files with 343 additions and 9 deletions
@@ -362,6 +362,286 @@ describe('FirebaseClient', () => {
);
});
});
describe('getLatestResults', () => {
it('should authenticate before making requests if no token exists', async () => {
const authResponse = {idToken: 'new-token'};
const mockResults = [{library: 'test', status: 'success'}];
global.fetch
.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify(authResponse)),
})
.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
});
const client = new FirebaseClient();
const result = await client.getLatestResults('2023-12-15', 1);
expect(result).toEqual({
results: mockResults,
date: '2023-12-14',
});
expect(client.idToken).toBe('new-token');
expect(console.log).toHaveBeenCalledWith(
'Checking for results on 2023-12-14 (1 days back)...',
);
expect(console.log).toHaveBeenCalledWith(
'Found results from 2023-12-14 (1 days back)',
);
});
it('should find results from the previous day', async () => {
const mockResults = [{library: 'test', status: 'success'}];
global.fetch.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
});
const client = new FirebaseClient();
client.idToken = 'existing-token';
const result = await client.getLatestResults('2023-12-15', 7);
expect(result).toEqual({
results: mockResults,
date: '2023-12-14',
});
expect(console.log).toHaveBeenCalledWith(
'Checking for results on 2023-12-14 (1 days back)...',
);
expect(console.log).toHaveBeenCalledWith(
'Found results from 2023-12-14 (1 days back)',
);
});
it('should find results from several days back', async () => {
const mockResults = [{library: 'test', status: 'success'}];
// Mock 404 responses for first 2 days, then success on 3rd day
global.fetch
.mockResolvedValueOnce({
ok: false,
status: 404,
text: jest.fn().mockResolvedValueOnce('Not Found'),
})
.mockResolvedValueOnce({
ok: false,
status: 404,
text: jest.fn().mockResolvedValueOnce('Not Found'),
})
.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
});
const client = new FirebaseClient();
client.idToken = 'existing-token';
const result = await client.getLatestResults('2023-12-15', 7);
expect(result).toEqual({
results: mockResults,
date: '2023-12-12',
});
expect(console.log).toHaveBeenCalledWith(
'Checking for results on 2023-12-14 (1 days back)...',
);
expect(console.log).toHaveBeenCalledWith(
'Checking for results on 2023-12-13 (2 days back)...',
);
expect(console.log).toHaveBeenCalledWith(
'Checking for results on 2023-12-12 (3 days back)...',
);
expect(console.log).toHaveBeenCalledWith(
'Found results from 2023-12-12 (3 days back)',
);
});
it('should skip empty results and continue searching', async () => {
const mockResults = [{library: 'test', status: 'success'}];
// Mock empty array for first day, then valid results on second day
global.fetch
.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify([])),
})
.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
});
const client = new FirebaseClient();
client.idToken = 'existing-token';
const result = await client.getLatestResults('2023-12-15', 7);
expect(result).toEqual({
results: mockResults,
date: '2023-12-13',
});
expect(console.log).toHaveBeenCalledWith(
'Checking for results on 2023-12-14 (1 days back)...',
);
expect(console.log).toHaveBeenCalledWith(
'Checking for results on 2023-12-13 (2 days back)...',
);
expect(console.log).toHaveBeenCalledWith(
'Found results from 2023-12-13 (2 days back)',
);
});
it('should return null when no results found within maxDaysBack', async () => {
// Mock 404 responses for all days
global.fetch.mockResolvedValue({
ok: false,
status: 404,
text: jest.fn().mockResolvedValue('Not Found'),
});
const client = new FirebaseClient();
client.idToken = 'existing-token';
const result = await client.getLatestResults('2023-12-15', 3);
expect(result).toEqual({
results: null,
date: null,
});
expect(console.log).toHaveBeenCalledWith(
'No previous results found within the last 3 days',
);
expect(global.fetch).toHaveBeenCalledTimes(3);
});
it('should use default maxDaysBack of 7 when not specified', async () => {
// Mock 404 responses for all days
global.fetch.mockResolvedValue({
ok: false,
status: 404,
text: jest.fn().mockResolvedValue('Not Found'),
});
const client = new FirebaseClient();
client.idToken = 'existing-token';
const result = await client.getLatestResults('2023-12-15');
expect(result).toEqual({
results: null,
date: null,
});
expect(console.log).toHaveBeenCalledWith(
'No previous results found within the last 7 days',
);
expect(global.fetch).toHaveBeenCalledTimes(7);
});
it('should handle non-404 errors and continue searching', async () => {
const mockResults = [{library: 'test', status: 'success'}];
// Mock 500 error for first day, then success on second day
global.fetch
.mockResolvedValueOnce({
ok: false,
status: 500,
text: jest.fn().mockResolvedValueOnce('Internal Server Error'),
})
.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
});
const client = new FirebaseClient();
client.idToken = 'existing-token';
const result = await client.getLatestResults('2023-12-15', 7);
expect(result).toEqual({
results: mockResults,
date: '2023-12-13',
});
expect(console.log).toHaveBeenCalledWith(
'No results found for 2023-12-14: HTTP 500: Internal Server Error',
);
expect(console.log).toHaveBeenCalledWith(
'Found results from 2023-12-13 (2 days back)',
);
});
it('should handle date boundaries correctly', async () => {
const mockResults = [{library: 'test', status: 'success'}];
global.fetch.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
});
const client = new FirebaseClient();
client.idToken = 'existing-token';
// Test month boundary
const result = await client.getLatestResults('2023-12-01', 1);
expect(result).toEqual({
results: mockResults,
date: '2023-11-30',
});
expect(console.log).toHaveBeenCalledWith(
'Checking for results on 2023-11-30 (1 days back)...',
);
});
it('should handle year boundary correctly', async () => {
const mockResults = [{library: 'test', status: 'success'}];
global.fetch.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
});
const client = new FirebaseClient();
client.idToken = 'existing-token';
// Test year boundary
const result = await client.getLatestResults('2024-01-01', 1);
expect(result).toEqual({
results: mockResults,
date: '2023-12-31',
});
expect(console.log).toHaveBeenCalledWith(
'Checking for results on 2023-12-31 (1 days back)...',
);
});
it('should handle null results and continue searching', async () => {
const mockResults = [{library: 'test', status: 'success'}];
// Mock null for first day, then valid results on second day
global.fetch
.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce('null'),
})
.mockResolvedValueOnce({
ok: true,
text: jest.fn().mockResolvedValueOnce(JSON.stringify(mockResults)),
});
const client = new FirebaseClient();
client.idToken = 'existing-token';
const result = await client.getLatestResults('2023-12-15', 7);
expect(result).toEqual({
results: mockResults,
date: '2023-12-13',
});
});
});
});
describe('compareResults', () => {
@@ -124,23 +124,35 @@ async function collectResults(discordWebHook) {
// Initialize Firebase client
const firebaseClient = new FirebaseClient();
const today = getTodayDate();
const yesterday = getYesterdayDate();
try {
// Store today's results in Firebase
console.log(`Storing results for ${today} in Firebase...`);
await firebaseClient.storeResults(today, outcomes);
// Get yesterday's results for comparison
console.log(`Retrieving results for ${yesterday} from Firebase...`);
const yesterdayResults = await firebaseClient.getResults(yesterday);
// Get the most recent previous results for comparison
console.log(`Looking for most recent previous results before ${today}...`);
const {results: previousResults, date: previousDate} =
await firebaseClient.getLatestResults(today);
// Compare results and identify broken/recovered tests
const {broken, recovered} = compareResults(outcomes, yesterdayResults);
let broken = [];
let recovered = [];
console.log(
`Found ${broken.length} newly broken tests and ${recovered.length} recovered tests`,
);
if (previousResults) {
console.log(`Comparing with results from ${previousDate}`);
// Compare results and identify broken/recovered jobs
const comparison = compareResults(outcomes, previousResults);
broken = comparison.broken;
recovered = comparison.recovered;
console.log(
`Found ${broken.length} newly broken jobs and ${recovered.length} recovered jobs compared to ${previousDate}`,
);
} else {
console.log(
'No previous results found for comparison - this might be the first run or no recent data available',
);
}
// Send comparison message to Discord if there are changes
if (discordWebHook && (broken.length > 0 || recovered.length > 0)) {
+42
View File
@@ -86,6 +86,48 @@ class FirebaseClient {
}
}
/**
* Find the most recent available job results before the given date
* @param {string} currentDate - Current date in YYYY-MM-DD format
* @param {number} maxDaysBack - Maximum number of days to look back (default: 7)
* @returns {Promise<{results: Array<Object>|null, date: string|null}>} - Most recent results and their date
*/
async getLatestResults(currentDate, maxDaysBack = 7) {
if (!this.idToken) {
await this.authenticate();
}
const currentDateObj = new Date(currentDate);
for (let daysBack = 1; daysBack <= maxDaysBack; daysBack++) {
const checkDate = new Date(currentDateObj);
checkDate.setDate(checkDate.getDate() - daysBack);
const checkDateStr = checkDate.toISOString().split('T')[0];
console.log(
`Checking for results on ${checkDateStr} (${daysBack} days back)...`,
);
try {
const results = await this.getResults(checkDateStr);
if (results && results.length > 0) {
console.log(
`Found results from ${checkDateStr} (${daysBack} days back)`,
);
return {results, date: checkDateStr};
}
} catch (error) {
console.log(`No results found for ${checkDateStr}: ${error.message}`);
continue;
}
}
console.log(
`No previous results found within the last ${maxDaysBack} days`,
);
return {results: null, date: null};
}
async makeRequest(hostname, path, method, data = null) {
const url = `https://${hostname}${path}`;
const options = {