1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-08-27 23:31:41 +02:00

[PM-6426] Finalizing jest tests for BrowserTaskScheduler class

This commit is contained in:
Cesar Gonzalez 2024-04-02 09:36:17 -05:00
parent b9055cdc15
commit 2ee6d48585
No known key found for this signature in database
GPG Key ID: 3381A5457F8CCECF
2 changed files with 93 additions and 6 deletions

View File

@ -1,6 +1,7 @@
import { mock, MockProxy } from "jest-mock-extended";
import { Observable } from "rxjs";
import { TaskIdentifier } from "@bitwarden/common/platform/abstractions/task-scheduler.service";
import { ScheduledTaskNames } from "@bitwarden/common/platform/enums/scheduled-task-name.enum";
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
import { GlobalState, StateProvider } from "@bitwarden/common/platform/state";
@ -251,4 +252,70 @@ describe("BrowserTaskSchedulerService", () => {
);
});
});
describe("clearScheduledTask", () => {
afterEach(() => {
chrome.alarms.clear = jest.fn().mockImplementation((_name, callback) => callback(true));
});
it("skips clearing the alarm if the alarm name is not provided", async () => {
await browserTaskSchedulerService.clearScheduledTask({
timeoutId: 1,
intervalId: 2,
});
expect(chrome.alarms.clear).not.toHaveBeenCalled();
});
it("skips deleting the active alarm if the alarm was not cleared", async () => {
const taskIdentifier: TaskIdentifier = { taskName: ScheduledTaskNames.eventUploadsInterval };
chrome.alarms.clear = jest.fn().mockImplementation((_name, callback) => callback(false));
jest.spyOn(browserTaskSchedulerService as any, "deleteActiveAlarm");
await browserTaskSchedulerService.clearScheduledTask(taskIdentifier);
expect(browserTaskSchedulerService["deleteActiveAlarm"]).not.toHaveBeenCalled();
});
it("clears a named alarm", async () => {
const taskIdentifier: TaskIdentifier = { taskName: ScheduledTaskNames.eventUploadsInterval };
jest.spyOn(browserTaskSchedulerService as any, "deleteActiveAlarm");
await browserTaskSchedulerService.clearScheduledTask(taskIdentifier);
expect(chrome.alarms.clear).toHaveBeenCalledWith(
ScheduledTaskNames.eventUploadsInterval,
expect.any(Function),
);
expect(browserTaskSchedulerService["deleteActiveAlarm"]).toHaveBeenCalledWith(
ScheduledTaskNames.eventUploadsInterval,
);
});
});
describe("clearAllScheduledTasks", () => {
it("clears all scheduled tasks and extension alarms", async () => {
jest.spyOn(BrowserApi, "clearAllAlarms");
jest.spyOn(browserTaskSchedulerService as any, "updateActiveAlarms");
await browserTaskSchedulerService.clearAllScheduledTasks();
expect(BrowserApi.clearAllAlarms).toHaveBeenCalled();
expect(browserTaskSchedulerService["updateActiveAlarms"]).toHaveBeenCalledWith([]);
expect(browserTaskSchedulerService["onAlarmHandlers"]).toEqual({});
expect(browserTaskSchedulerService["recoveredAlarms"].size).toBe(0);
});
});
describe("handleOnAlarm", () => {
it("triggers the alarm", async () => {
const alarm = mock<chrome.alarms.Alarm>({ name: ScheduledTaskNames.eventUploadsInterval });
const callback = jest.fn();
browserTaskSchedulerService["onAlarmHandlers"][alarm.name] = callback;
await browserTaskSchedulerService["handleOnAlarm"](alarm);
expect(callback).toHaveBeenCalled();
});
});
});

View File

@ -129,6 +129,10 @@ export class BrowserTaskSchedulerService
}
}
/**
* Clears all scheduled tasks by clearing all browser extension
* alarms and resetting the active alarms state.
*/
async clearAllScheduledTasks(): Promise<void> {
await BrowserApi.clearAllAlarms();
await this.updateActiveAlarms([]);
@ -136,6 +140,12 @@ export class BrowserTaskSchedulerService
this.recoveredAlarms.clear();
}
/**
* Creates a browser extension alarm with the given name and create info.
*
* @param name - The name of the alarm.
* @param createInfo - The alarm create info.
*/
private async createAlarm(
name: ScheduledTaskName,
createInfo: chrome.alarms.AlarmCreateInfo,
@ -150,6 +160,12 @@ export class BrowserTaskSchedulerService
await this.setActiveAlarm({ name, startTime: Date.now(), createInfo });
}
/**
* Registers an alarm handler for the given name.
*
* @param name - The name of the alarm.
* @param handler - The alarm handler.
*/
private registerAlarmHandler(name: ScheduledTaskName, handler: CallableFunction): void {
if (this.onAlarmHandlers[name]) {
this.logService.warning(`Alarm handler for ${name} already exists. Overwriting.`);
@ -158,6 +174,10 @@ export class BrowserTaskSchedulerService
this.onAlarmHandlers[name] = () => handler();
}
/**
* Verifies the state of the active alarms by checking if
* any alarms have been missed or need to be created.
*/
private async verifyAlarmsState(): Promise<void> {
const currentTime = Date.now();
const activeAlarms = await firstValueFrom(this.activeAlarms$);
@ -169,12 +189,12 @@ export class BrowserTaskSchedulerService
continue;
}
if (
(createInfo.when && createInfo.when < currentTime) ||
(!createInfo.periodInMinutes &&
createInfo.delayInMinutes &&
startTime + createInfo.delayInMinutes * 60 * 1000 < currentTime)
) {
const shouldAlarmHaveBeenTriggered = createInfo.when && createInfo.when < currentTime;
const hasSetTimeoutAlarmExceededDelay =
!createInfo.periodInMinutes &&
createInfo.delayInMinutes &&
startTime + createInfo.delayInMinutes * 60 * 1000 < currentTime;
if (shouldAlarmHaveBeenTriggered || hasSetTimeoutAlarmExceededDelay) {
this.recoveredAlarms.add(name);
continue;
}