Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -275,19 +275,14 @@ describe('CronjobController', () => {
},
);

const secondCronjobController = new CronjobController({
messenger: controllerMessenger,
state: cronjobController.state,
stateManager: getMockStateManager(),
});
expect(handleRequest).toHaveBeenCalledTimes(1);

secondCronjobController.init();
jest.advanceTimersByTime(inMilliseconds(26, Duration.Hour));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test did not seem to do what the title says, I re-used it to ensure that both of the fixes in this PR work


await new Promise((resolve) => originalProcessNextTick(resolve));
expect(handleRequest).toHaveBeenCalledTimes(1);
expect(handleRequest).toHaveBeenCalledTimes(2);

cronjobController.destroy();
secondCronjobController.destroy();
});

it('does not schedule cronjob that is too far in the future', () => {
Expand Down Expand Up @@ -473,55 +468,6 @@ describe('CronjobController', () => {
cronjobController.destroy();
});

it('handles scheduled event close to current time gracefully', () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find a good way to test this anymore since I eliminated the state update I relied on to replicate the race condition

const rootMessenger = getRootCronjobControllerMessenger();
const controllerMessenger =
getRestrictedCronjobControllerMessenger(rootMessenger);

const cronjobController = new CronjobController({
messenger: controllerMessenger,
stateManager: getMockStateManager(),
state: {
events: {
foo: {
id: 'foo',
recurring: false,
date: '2022-01-01T00:00:01.000Z',
schedule: '2022-01-01T00:00:01.000Z',
scheduledAt: new Date().toISOString(),
snapId: MOCK_SNAP_ID,
request: {
method: 'handleEvent',
params: ['p1'],
},
},
},
},
});

rootMessenger.subscribe('CronjobController:stateChange', () => {
jest.advanceTimersByTime(inMilliseconds(2, Duration.Second));
});

cronjobController.init();

expect(rootMessenger.call).toHaveBeenNthCalledWith(
1,
'SnapController:handleRequest',
{
snapId: MOCK_SNAP_ID,
origin: METAMASK_ORIGIN,
handler: HandlerType.OnCronjob,
request: {
method: 'handleEvent',
params: ['p1'],
},
},
);

cronjobController.destroy();
});

it('handles the `snapInstalled` event', () => {
const rootMessenger = getRootCronjobControllerMessenger();
const controllerMessenger =
Expand Down Expand Up @@ -663,7 +609,7 @@ describe('CronjobController', () => {
foo: {
id: 'foo',
recurring: false,
date: '2022-01-01T01:00:00Z',
date: '2022-01-01T01:00Z',
schedule: '2022-01-01T01:00Z',
scheduledAt: new Date().toISOString(),
snapId: MOCK_SNAP_ID,
Expand Down
12 changes: 10 additions & 2 deletions packages/snaps-controllers/src/cronjob/CronjobController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,15 @@ export class CronjobController extends BaseController<
* Get the next execution date for a given event and start a timer for it.
*
* @param event - The event to schedule.
* @param next - Whether to schedule to the next date, otherwise will
* schedule for existing date.
*/
#schedule(event: InternalBackgroundEvent) {
#schedule(event: InternalBackgroundEvent, next = true) {
if (!next) {
this.#startTimer(event);
return;
}

const date = getExecutionDate(event.schedule);
const { nextState } = this.update((state) => {
state.events[event.id].date = date;
Expand Down Expand Up @@ -621,9 +628,10 @@ export class CronjobController extends BaseController<
// immediately.
if (event.recurring && eventDate <= now) {
this.#execute(event);
continue;
}

this.#schedule(event);
this.#schedule(event, false);
}
}

Expand Down
Loading