1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Implement downloading of Electron specific updates as responsibility

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen 2022-05-16 13:26:51 +03:00
parent 243f39b17f
commit bb2e8fbf65
No known key found for this signature in database
GPG Key ID: 8C6CFB2FFFE8F68A
5 changed files with 195 additions and 17 deletions

View File

@ -14,7 +14,7 @@ import type { AsyncFnMock } from "@async-fn/jest";
import asyncFn from "@async-fn/jest"; import asyncFn from "@async-fn/jest";
import type { UpdateChannel, UpdateChannelId } from "../../main/update-app/update-channels"; import type { UpdateChannel, UpdateChannelId } from "../../main/update-app/update-channels";
import { updateChannels } from "../../main/update-app/update-channels"; import { updateChannels } from "../../main/update-app/update-channels";
import downloadPlatformUpdateInjectable from "../../main/update-app/download-platform-update.injectable"; import downloadPlatformUpdateInjectable from "../../main/update-app/download-platform-update/download-platform-update.injectable";
import selectedUpdateChannelInjectable from "../../main/update-app/selected-update-channel.injectable"; import selectedUpdateChannelInjectable from "../../main/update-app/selected-update-channel.injectable";
import progressOfUpdateDownloadInjectable from "../../main/update-app/progress-of-update-download.injectable"; import progressOfUpdateDownloadInjectable from "../../main/update-app/progress-of-update-download.injectable";
import type { IComputedValue } from "mobx"; import type { IComputedValue } from "mobx";

View File

@ -1,15 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
const downloadPlatformUpdateInjectable = getInjectable({
id: "download-platform-update",
instantiate: () => {
return async () => {};
},
});
export default downloadPlatformUpdateInjectable;

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import type { ProgressInfo } from "electron-updater";
import electronUpdaterInjectable from "../../electron-app/features/electron-updater.injectable";
import progressOfUpdateDownloadInjectable from "../progress-of-update-download.injectable";
import loggerInjectable from "../../../common/logger.injectable";
const downloadPlatformUpdateInjectable = getInjectable({
id: "download-platform-update",
instantiate: (di) => {
const electronUpdater = di.inject(electronUpdaterInjectable);
const progressOfUpdateDownload = di.inject(progressOfUpdateDownloadInjectable);
const logger = di.inject(loggerInjectable);
const updateDownloadProgress = ({ percent }: ProgressInfo) => {
progressOfUpdateDownload.setValue(percent);
};
return async () => {
progressOfUpdateDownload.setValue(0);
electronUpdater.on("download-progress", updateDownloadProgress);
try {
await electronUpdater.downloadUpdate();
} catch(error) {
logger.error("[UPDATE-APP/DOWNLOAD]", error);
return { downloadWasSuccessful: false };
} finally {
electronUpdater.off("download-progress", updateDownloadProgress);
}
return { downloadWasSuccessful: true };
};
},
});
export default downloadPlatformUpdateInjectable;

View File

@ -0,0 +1,150 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
import electronUpdaterInjectable from "../../electron-app/features/electron-updater.injectable";
import downloadPlatformUpdateInjectable from "./download-platform-update.injectable";
import type { AppUpdater } from "electron-updater";
import type { AsyncFnMock } from "@async-fn/jest";
import asyncFn from "@async-fn/jest";
import { getPromiseStatus } from "../../../common/test-utils/get-promise-status";
import progressOfUpdateDownloadInjectable from "../progress-of-update-download.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import loggerInjectable from "../../../common/logger.injectable";
import type { Logger } from "../../../common/logger";
describe("download-platform-update", () => {
let downloadPlatformUpdate: () => Promise<{ downloadWasSuccessful: boolean }>;
let downloadUpdateMock: AsyncFnMock<() => void>;
let electronUpdaterFake: AppUpdater;
let electronUpdaterOnMock: jest.Mock;
let electronUpdaterOffMock: jest.Mock;
let di: DiContainer;
let progressOfUpdateDownload: { value: { get: () => number }};
let logErrorMock: jest.Mock;
beforeEach(() => {
di = getDiForUnitTesting();
downloadUpdateMock = asyncFn();
electronUpdaterOnMock = jest.fn();
electronUpdaterOffMock = jest.fn();
electronUpdaterFake = {
channel: undefined,
autoDownload: undefined,
on: electronUpdaterOnMock,
off: electronUpdaterOffMock,
downloadUpdate: downloadUpdateMock,
} as unknown as AppUpdater;
di.override(electronUpdaterInjectable, () => electronUpdaterFake);
logErrorMock = jest.fn();
di.override(loggerInjectable, () => ({ error: logErrorMock }) as unknown as Logger);
downloadPlatformUpdate = di.inject(downloadPlatformUpdateInjectable);
progressOfUpdateDownload = di.inject(progressOfUpdateDownloadInjectable);
});
describe("when called", () => {
let actualPromise: Promise<{ downloadWasSuccessful: boolean }>;
beforeEach(() => {
actualPromise = downloadPlatformUpdate();
});
it("calls for downloading of update", () => {
expect(downloadUpdateMock).toHaveBeenCalled();
});
it("does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(actualPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
it("starts progress of download from 0", () => {
expect(progressOfUpdateDownload.value.get()).toBe(0);
});
describe("when downloading progresses", () => {
beforeEach(() => {
const [, callback] = electronUpdaterOnMock.mock.calls.find(
([event]) => event === "download-progress",
);
callback({
percent: 42,
total: 0,
delta: 0,
transferred: 0,
bytesPerSecond: 0,
});
});
it("updates progress of the download", () => {
expect(progressOfUpdateDownload.value.get()).toBe(42);
});
describe("when downloading resolves", () => {
beforeEach(async () => {
await downloadUpdateMock.resolve();
});
it("resolves with success", async () => {
const actual = await actualPromise;
expect(actual).toEqual({ downloadWasSuccessful: true });
});
it("does not reset progress of download yet", () => {
expect(progressOfUpdateDownload.value.get()).toBe(42);
});
it("stops watching for download progress", () => {
expect(electronUpdaterOffMock).toHaveBeenCalledWith(
"download-progress",
expect.any(Function),
);
});
it("when starting download again, resets progress of download", () => {
downloadPlatformUpdate();
expect(progressOfUpdateDownload.value.get()).toBe(0);
});
});
describe("when downloading rejects", () => {
let errorStub: Error;
beforeEach(() => {
errorStub = new Error("Some error");
downloadUpdateMock.reject(errorStub);
});
it("logs error", () => {
expect(logErrorMock).toHaveBeenCalledWith("[UPDATE-APP/DOWNLOAD]", errorStub);
});
it("stops watching for download progress", () => {
expect(electronUpdaterOffMock).toHaveBeenCalledWith(
"download-progress",
expect.any(Function),
);
});
it("resolves with failure", async () => {
const actual = await actualPromise;
expect(actual).toEqual({ downloadWasSuccessful: false });
});
});
});
});
});

View File

@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import type { IComputedValue, IObservableValue } from "mobx"; import type { IComputedValue, IObservableValue } from "mobx";
import { computed, observable, runInAction } from "mobx"; import { computed, observable, runInAction } from "mobx";
import selectedUpdateChannelInjectable from "./selected-update-channel.injectable"; import selectedUpdateChannelInjectable from "./selected-update-channel.injectable";
import downloadPlatformUpdateInjectable from "./download-platform-update.injectable"; import downloadPlatformUpdateInjectable from "./download-platform-update/download-platform-update.injectable";
import type { CheckForPlatformUpdates } from "./check-for-platform-updates/check-for-platform-updates.injectable"; import type { CheckForPlatformUpdates } from "./check-for-platform-updates/check-for-platform-updates.injectable";
import checkForPlatformUpdatesInjectable from "./check-for-platform-updates/check-for-platform-updates.injectable"; import checkForPlatformUpdatesInjectable from "./check-for-platform-updates/check-for-platform-updates.injectable";
import type { UpdateChannel } from "./update-channels"; import type { UpdateChannel } from "./update-channels";