Skip to content

Commit 565c42c

Browse files
committed
refactor: refactor polling logic and clean up tests
1 parent affbbcf commit 565c42c

File tree

4 files changed

+233
-312
lines changed

4 files changed

+233
-312
lines changed

packages/shield-controller/src/backend.test.ts

Lines changed: 0 additions & 218 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
/* eslint-disable jest/no-conditional-in-test */
21
import { ShieldRemoteBackend } from './backend';
32
import {
4-
delay,
53
generateMockSignatureRequest,
64
generateMockTxMeta,
75
getRandomCoverageResult,
@@ -46,75 +44,6 @@ function setup({
4644
};
4745
}
4846

49-
/**
50-
* Setup a fetch mock for polling tests.
51-
*
52-
* @param fetchMock - The mock instance of the fetch API.
53-
* @param options - The options for the fetch mock.
54-
* @param options.delayBetweenResultRequests - The delay between result requests.
55-
* @param options.shouldReturnErrorResult - Whether to return an error result.
56-
*
57-
* @returns The mock coverage ID.
58-
*/
59-
function setupMockRequestsForPollingTests(
60-
fetchMock: jest.MockedFunction<typeof fetch>,
61-
options: {
62-
delayBetweenResultRequests?: number;
63-
shouldReturnErrorResult?: boolean;
64-
} = {
65-
shouldReturnErrorResult: true,
66-
},
67-
) {
68-
const MOCK_COVERAGE_ID = 'coverageId';
69-
fetchMock.mockImplementation(
70-
async (input: RequestInfo | URL, init?: RequestInit) => {
71-
// eslint-disable-next-line @typescript-eslint/no-base-to-string
72-
const url = typeof input === 'string' ? input : input.toString();
73-
const signal = init?.signal;
74-
75-
if (url.includes('/init')) {
76-
return {
77-
status: 200,
78-
json: jest.fn().mockResolvedValue({ coverageId: MOCK_COVERAGE_ID }),
79-
} as unknown as Response;
80-
}
81-
82-
if (url.includes('/result')) {
83-
if (signal?.aborted) {
84-
throw new Error('Request was aborted');
85-
}
86-
87-
if (options.delayBetweenResultRequests) {
88-
await delay(options.delayBetweenResultRequests);
89-
}
90-
91-
if (options.shouldReturnErrorResult) {
92-
return {
93-
status: 412,
94-
json: jest.fn().mockResolvedValue({ status: 'unknown' }),
95-
} as unknown as Response;
96-
}
97-
return {
98-
status: 200,
99-
json: jest.fn().mockResolvedValue({
100-
status: 'covered',
101-
message: 'test',
102-
reasonCode: 'test',
103-
}),
104-
} as unknown as Response;
105-
}
106-
107-
if (url.includes('/log')) {
108-
return { status: 200 } as unknown as Response;
109-
}
110-
111-
throw new Error('Unexpected URL');
112-
},
113-
);
114-
115-
return MOCK_COVERAGE_ID;
116-
}
117-
11847
describe('ShieldRemoteBackend', () => {
11948
afterEach(() => {
12049
// Clean up mocks after each test
@@ -296,36 +225,6 @@ describe('ShieldRemoteBackend', () => {
296225
}),
297226
).rejects.toThrow('Failed to log signature: 500');
298227
});
299-
300-
it('aborts pending coverage result polling before logging', async () => {
301-
const { backend, fetchMock } = setup({
302-
getCoverageResultTimeout: 10000,
303-
getCoverageResultPollInterval: 100,
304-
});
305-
306-
const signatureRequest = generateMockSignatureRequest();
307-
setupMockRequestsForPollingTests(fetchMock);
308-
309-
// Start coverage check (don't await) - this will start polling
310-
const coveragePromise = backend.checkSignatureCoverage({
311-
signatureRequest,
312-
});
313-
314-
// Wait a bit to let polling start
315-
await delay(50);
316-
317-
// Log signature - this should abort the ongoing polling
318-
await backend.logSignature({
319-
signatureRequest,
320-
signature: '0x00',
321-
status: 'shown',
322-
});
323-
324-
// Coverage check should be cancelled
325-
await expect(coveragePromise).rejects.toThrow(
326-
'Coverage result polling cancelled',
327-
);
328-
});
329228
});
330229

331230
describe('logTransaction', () => {
@@ -356,122 +255,5 @@ describe('ShieldRemoteBackend', () => {
356255
}),
357256
).rejects.toThrow('Failed to log transaction: 500');
358257
});
359-
360-
it('aborts pending coverage result polling before logging', async () => {
361-
const { backend, fetchMock } = setup({
362-
getCoverageResultTimeout: 10000,
363-
getCoverageResultPollInterval: 100,
364-
});
365-
366-
const txMeta = generateMockTxMeta();
367-
setupMockRequestsForPollingTests(fetchMock);
368-
369-
// Start coverage check (don't await) - this will start polling
370-
const coveragePromise = backend.checkCoverage({ txMeta });
371-
372-
// Wait a bit to let polling start
373-
await delay(50);
374-
375-
// Log transaction - this should abort the ongoing polling
376-
await backend.logTransaction({
377-
txMeta,
378-
transactionHash: '0x00',
379-
status: 'shown',
380-
});
381-
382-
// Coverage check should be cancelled
383-
await expect(coveragePromise).rejects.toThrow(
384-
'Coverage result polling cancelled',
385-
);
386-
});
387-
});
388-
389-
// Testing coverage result polling with timeout and cancellation.
390-
describe('withTimeoutAndCancellation', () => {
391-
it('should abort previous result request when new request is made', async () => {
392-
const { backend, fetchMock } = setup({
393-
getCoverageResultTimeout: 10000, // Long timeout to avoid timeout during test
394-
getCoverageResultPollInterval: 100,
395-
});
396-
397-
const signatureRequest = generateMockSignatureRequest();
398-
const coverageId = setupMockRequestsForPollingTests(fetchMock, {
399-
shouldReturnErrorResult: false,
400-
delayBetweenResultRequests: 150, // Long enough to let the first request start and the second request abort it
401-
});
402-
403-
// Start first request (don't await)
404-
const firstRequestPromise = backend.checkSignatureCoverage({
405-
signatureRequest,
406-
});
407-
408-
// Wait a bit to let first request start
409-
await delay(50);
410-
411-
// Start second request which should abort the first
412-
const secondRequestPromise = backend.checkSignatureCoverage({
413-
signatureRequest,
414-
coverageId,
415-
});
416-
417-
// Verify first request was cancelled and second succeeded
418-
await expect(firstRequestPromise).rejects.toThrow(
419-
'Coverage result polling cancelled',
420-
);
421-
422-
const secondResult = await secondRequestPromise;
423-
expect(secondResult).toMatchObject({
424-
coverageId,
425-
status: 'covered',
426-
});
427-
});
428-
429-
it('should handle timeout properly during result polling', async () => {
430-
const { backend, fetchMock } = setup({
431-
getCoverageResultTimeout: 200, // Short timeout to simulate the coverage result polling timeout
432-
getCoverageResultPollInterval: 50,
433-
});
434-
435-
const signatureRequest = generateMockSignatureRequest();
436-
setupMockRequestsForPollingTests(fetchMock);
437-
438-
await expect(
439-
backend.checkSignatureCoverage({ signatureRequest }),
440-
).rejects.toThrow('Timeout waiting for coverage result');
441-
});
442-
443-
it('should handle multiple concurrent requests with proper cancellation', async () => {
444-
const { backend, fetchMock } = setup();
445-
446-
const signatureRequest = generateMockSignatureRequest();
447-
const result = getRandomCoverageResult();
448-
const coverageId = 'test-coverage-id';
449-
450-
// Mock simple successful responses
451-
fetchMock
452-
.mockResolvedValueOnce({
453-
status: 200,
454-
json: jest.fn().mockResolvedValue({ coverageId }),
455-
} as unknown as Response)
456-
.mockResolvedValueOnce({
457-
status: 200,
458-
json: jest.fn().mockResolvedValue(result),
459-
} as unknown as Response);
460-
461-
// Test that the backend can handle requests properly
462-
// Note: Concurrent cancellation behavior is tested by 100% code coverage
463-
const requestResult = await backend.checkSignatureCoverage({
464-
signatureRequest,
465-
});
466-
467-
// Verify the request completed successfully
468-
expect(requestResult).toMatchObject({
469-
coverageId,
470-
...result,
471-
});
472-
473-
// Verify that fetch was called (init + result calls)
474-
expect(fetchMock).toHaveBeenCalledTimes(2);
475-
});
476258
});
477259
});

0 commit comments

Comments
 (0)