1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-10-04 05:08:06 +02:00

[PM-6426] Working through jest tests

This commit is contained in:
Cesar Gonzalez 2024-05-01 16:43:24 -05:00
parent b34b2efa0c
commit 2891c2c8a6
No known key found for this signature in database
GPG Key ID: 3381A5457F8CCECF
7 changed files with 81 additions and 29 deletions

View File

@ -764,6 +764,7 @@ export default class MainBackground {
this.stateEventRunnerService,
lockedCallback,
logoutCallback,
this.taskSchedulerService,
);
this.containerService = new ContainerService(this.cryptoService, this.encryptService);

View File

@ -39,7 +39,7 @@ function setupGlobalBrowserMock(overrides: Partial<chrome.alarms.Alarm> = {}) {
}
const userUuid = "user-uuid" as UserId;
function getAlarmNameMock(taskName: string) {
return `${userUuid}__${taskName}`;
return `${taskName}__${userUuid}`;
}
describe("BrowserTaskSchedulerService", () => {
@ -252,9 +252,13 @@ describe("BrowserTaskSchedulerService", () => {
);
expect(globalThis.setInterval).toHaveBeenCalledWith(expect.any(Function), intervalInMs);
expect(chrome.alarms.create).not.toHaveBeenCalled();
});
it.todo(
"sets up stepped alarms that trigger behavior after the first minute of setInterval execution",
() => {},
);
it("creates an interval alarm", async () => {
const periodInMinutes = 2;
const initialDelayInMs = 1000;
@ -267,7 +271,7 @@ describe("BrowserTaskSchedulerService", () => {
expect(chrome.alarms.create).toHaveBeenCalledWith(
getAlarmNameMock(ScheduledTaskNames.loginStrategySessionTimeout),
{ periodInMinutes, delayInMinutes: initialDelayInMs / 1000 / 60 },
{ periodInMinutes, delayInMinutes: 0.5 },
expect.any(Function),
);
});

View File

@ -64,8 +64,8 @@ export class BrowserTaskSchedulerServiceImplementation
// The alarm previously scheduled will be used as a backup in case the setTimeout fails.
if (delayInMinutes < 1) {
return globalThis.setTimeout(async () => {
await this.triggerTask(alarmName);
await this.clearScheduledAlarm(alarmName);
await this.triggerTask(alarmName);
}, delayInMs);
}
}
@ -84,21 +84,56 @@ export class BrowserTaskSchedulerServiceImplementation
intervalInMs: number,
initialDelayInMs?: number,
): Promise<number | NodeJS.Timeout> {
const intervalInMinutes = intervalInMs / 1000 / 60;
if (intervalInMinutes < 1) {
return super.setInterval(taskName, intervalInMs);
}
this.validateRegisteredTask(taskName);
const intervalInMinutes = intervalInMs / 1000 / 60;
const alarmName = await this.getActiveUserAlarmName(taskName);
const initialDelayInMinutes = initialDelayInMs ? initialDelayInMs / 1000 / 60 : undefined;
const initialDelayInMinutes = initialDelayInMs
? initialDelayInMs / 1000 / 60
: intervalInMinutes;
if (intervalInMinutes < 1) {
return this.setupSteppedIntervalAlarms(taskName, alarmName, intervalInMinutes, intervalInMs);
}
await this.scheduleAlarm(alarmName, {
periodInMinutes: intervalInMinutes,
delayInMinutes: initialDelayInMinutes ?? intervalInMinutes,
periodInMinutes: this.getUpperBoundDelayInMinutes(intervalInMinutes),
delayInMinutes: this.getUpperBoundDelayInMinutes(initialDelayInMinutes),
});
}
private async setupSteppedIntervalAlarms(
taskName: ScheduledTaskName,
alarmName: string,
intervalInMinutes: number,
intervalInMs: number,
) {
let elapsedMs = 0;
const intervalId: number | NodeJS.Timeout = globalThis.setInterval(async () => {
elapsedMs += intervalInMs;
const elapsedMinutes = elapsedMs / 1000 / 60;
if (elapsedMinutes >= this.getAlarmMinDelayInMinutes()) {
globalThis.clearInterval(intervalId);
return;
}
await this.triggerTask(alarmName, intervalInMinutes);
}, intervalInMs);
const numberOfAlarmsToCreate = Math.ceil(1 / intervalInMinutes);
for (let i = 0; i < numberOfAlarmsToCreate; i++) {
const steppedAlarmName = `${alarmName}__${i}`;
const periodInMinutes = this.getAlarmMinDelayInMinutes() + i * intervalInMinutes;
await this.clearScheduledAlarm(steppedAlarmName);
await this.clearScheduledAlarm(`${taskName}__${i}`);
await this.scheduleAlarm(steppedAlarmName, {
periodInMinutes: this.getUpperBoundDelayInMinutes(periodInMinutes),
});
}
return intervalId;
}
/**
* Clears a scheduled task by its task identifier. If the task identifier
* contains a task name, it will clear the browser extension alarm with that
@ -308,7 +343,7 @@ export class BrowserTaskSchedulerServiceImplementation
return taskName;
}
return `${activeUserId}__${taskName}`;
return `${taskName}__${activeUserId}`;
}
/**
@ -318,7 +353,7 @@ export class BrowserTaskSchedulerServiceImplementation
* @param alarmName - The alarm name to parse.
*/
private getTaskFromAlarmName(alarmName: string): ScheduledTaskName {
const activeUserTask = alarmName.split("__")[1] as ScheduledTaskName;
const activeUserTask = alarmName.split("__")[0] as ScheduledTaskName;
if (activeUserTask) {
return activeUserTask;
}
@ -392,6 +427,10 @@ export class BrowserTaskSchedulerServiceImplementation
return typeof browser !== "undefined" && !!browser.alarms;
}
private getAlarmMinDelayInMinutes(): number {
return this.isNonChromeEnvironment() ? 1 : 0.5;
}
/**
* Gets the upper bound delay in minutes for a given delay in minutes. This is
* used to ensure that the delay is at least 1 minute in non-Chrome environments.
@ -400,7 +439,6 @@ export class BrowserTaskSchedulerServiceImplementation
* @param delayInMinutes - The delay in minutes.
*/
private getUpperBoundDelayInMinutes(delayInMinutes: number): number {
const minDelayInMinutes = this.isNonChromeEnvironment() ? 1 : 0.5;
return Math.max(minDelayInMinutes, delayInMinutes);
return Math.max(this.getAlarmMinDelayInMinutes(), delayInMinutes);
}
}

View File

@ -4,16 +4,13 @@ import { SafariApp } from "../../browser/safariApp";
export default class VaultTimeoutService extends BaseVaultTimeoutService {
startCheck() {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.checkVaultTimeout();
if (this.platformUtilsService.isSafari()) {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.checkSafari();
} else {
setInterval(() => this.checkVaultTimeout(), 10 * 1000); // check every 10 seconds
void this.checkVaultTimeout();
void this.checkSafari();
return;
}
super.startCheck();
}
// This is a work-around to safari adding an arbitrary delay to setTimeout and

View File

@ -668,6 +668,7 @@ const safeProviders: SafeProvider[] = [
StateEventRunnerService,
LOCKED_CALLBACK,
LOGOUT_CALLBACK,
TaskSchedulerService,
],
}),
safeProvider({

View File

@ -6,6 +6,7 @@ export const ScheduledTaskNames = {
fido2ClientAbortTimeout: "fido2ClientAbortTimeout",
scheduleNextSyncInterval: "scheduleNextSyncInterval",
eventUploadsInterval: "eventUploadsInterval",
vaultTimeoutCheckInterval: "vaultTimeoutCheckInterval",
} as const;
export type ScheduledTaskName = (typeof ScheduledTaskNames)[keyof typeof ScheduledTaskNames];

View File

@ -1,5 +1,8 @@
import { combineLatest, firstValueFrom, switchMap } from "rxjs";
import { TaskSchedulerService } from "@bitwarden/common/platform/abstractions/task-scheduler.service";
import { ScheduledTaskNames } from "@bitwarden/common/platform/enums/scheduled-task-name.enum";
import { SearchService } from "../../abstractions/search.service";
import { VaultTimeoutSettingsService } from "../../abstractions/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "../../abstractions/vault-timeout/vault-timeout.service";
@ -35,7 +38,13 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
private stateEventRunnerService: StateEventRunnerService,
private lockedCallback: (userId?: string) => Promise<void> = null,
private loggedOutCallback: (expired: boolean, userId?: string) => Promise<void> = null,
) {}
private taskSchedulerService?: TaskSchedulerService,
) {
void this.taskSchedulerService?.registerTaskHandler(
ScheduledTaskNames.vaultTimeoutCheckInterval,
() => this.checkVaultTimeout(),
);
}
async init(checkOnInterval: boolean) {
if (this.inited) {
@ -49,10 +58,11 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
}
startCheck() {
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.checkVaultTimeout();
setInterval(() => this.checkVaultTimeout(), 10 * 1000); // check every 10 seconds
void this.checkVaultTimeout();
void this.taskSchedulerService?.setInterval(
ScheduledTaskNames.vaultTimeoutCheckInterval,
10 * 1000, // check every 10 seconds
);
}
async checkVaultTimeout(): Promise<void> {