CEC-4854 Trunk-based deploy pipeline (#412)
* CEC-4855: fix manifest deselect (#410) * fix manifest deselect * adjusted blackduck pipeline to run the latest detect version * added blackduck_rapid pipeline to run synopsys detect rapid scans * adjusted deploy pipeline to trun-based model, adjusted test pipeline to use main branch * test image builds * clean up * CEC-4563: add cancel and include results in promise (#411) * splited build and deploy order according to each environment, test builds * clean up * clean up * CEC-4635: prevent false 0 calculation (#413) * prevent false 0 calculation * refactor switch statement --------- Co-authored-by: Tristan Timblin <ttimblin@fiskerinc.com>
This commit is contained in:
@@ -127,8 +127,16 @@ export const CarUpdatesProvider = ({ children }) => {
|
||||
};
|
||||
|
||||
const getDownloadProgress = (status) => {
|
||||
if (status.package_total > 0)
|
||||
const disabled = status.status === "install_succeeded";
|
||||
if (disabled) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const calculated = status.package_total > 0;
|
||||
if (calculated) {
|
||||
return Math.floor((100 * status.package_current) / status.package_total);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -274,12 +274,10 @@ const MainForm = () => {
|
||||
|
||||
const handleSelect = (event, manifest) => {
|
||||
setUpdateManifestIds((selected) => {
|
||||
if (event.target.checked && selected.find((id) => id === manifest.id)) {
|
||||
return selected;
|
||||
} else if (event.target.checked) {
|
||||
if (event.target.checked) {
|
||||
return [...selected, manifest.id];
|
||||
}
|
||||
return selected.filter(({ id }) => id !== manifest.id);
|
||||
return selected.filter(id => id !== manifest.id);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ jest.mock("../../Contexts/UserContext");
|
||||
|
||||
import React from "react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
|
||||
import { UserProvider, setToken } from "../../Contexts/UserContext";
|
||||
@@ -32,4 +33,14 @@ describe("Manifest List Component", () => {
|
||||
fireEvent.click(screen.getByText("Archived"));
|
||||
expect(archiveActionEl.innerHTML).toBe("Activate");
|
||||
});
|
||||
|
||||
it("properly selects and deselects a manifest", () => {
|
||||
const { queryAllByRole } = render(Page);
|
||||
const checkbox = queryAllByRole("checkbox")[0];
|
||||
expect(checkbox).not.toBeChecked();
|
||||
userEvent.click(checkbox);
|
||||
expect(checkbox).toBeChecked();
|
||||
userEvent.click(checkbox);
|
||||
expect(checkbox).not.toBeChecked();
|
||||
})
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ export default class TaskRunner {
|
||||
|
||||
if (total) {
|
||||
this._total = total;
|
||||
this._responses = new Array(total);
|
||||
this._responses = new Array(total).fill(undefined);
|
||||
}
|
||||
|
||||
this._onComplete = new Promise((resolve, reject) => {
|
||||
@@ -18,7 +18,8 @@ export default class TaskRunner {
|
||||
}
|
||||
|
||||
execute() {
|
||||
if (this._running >= this._concurrencyLimit || this._queue.length === 0) {
|
||||
const isBusy = this._running >= this._concurrencyLimit || this._queue.length === 0;
|
||||
if (isBusy || this._paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -38,10 +39,16 @@ export default class TaskRunner {
|
||||
}
|
||||
resolve(response);
|
||||
} catch (error) {
|
||||
if (this._responses) {
|
||||
this._responses[index] = new Error(`Task was rejected: ${error}`);
|
||||
}
|
||||
reject(error);
|
||||
} finally {
|
||||
this._running -= 1;
|
||||
this.#progress();
|
||||
this._complete += 1;
|
||||
if (this._complete === this._total) {
|
||||
this._onCompleteResolve(this._responses);
|
||||
}
|
||||
this.execute();
|
||||
}
|
||||
}
|
||||
@@ -51,17 +58,15 @@ export default class TaskRunner {
|
||||
});
|
||||
}
|
||||
|
||||
#progress() {
|
||||
this._complete += 1;
|
||||
if (this._complete === this._total) {
|
||||
this._onCompleteResolve(this._responses);
|
||||
}
|
||||
}
|
||||
|
||||
async onComplete() {
|
||||
if (!this._total) {
|
||||
this._onCompleteReject(new Error("Total is required to determine onComplete."));
|
||||
}
|
||||
return this._onComplete;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this._concurrencyLimit = 0;
|
||||
this._onCompleteReject(this._responses);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,9 @@ const mockPromise = async (id, ms) => {
|
||||
await new Promise(resolve => setTimeout(resolve, ms));
|
||||
return id;
|
||||
}
|
||||
const mockPromiseReject = async (id, ms) => {
|
||||
return new Promise((_, reject) => setTimeout(reject(id), ms));
|
||||
}
|
||||
const mockPromiseError = async (id, ms) => {
|
||||
await new Promise(resolve => setTimeout(resolve, ms));
|
||||
return new Error(`Task ${id} had an error`);
|
||||
@@ -44,19 +47,10 @@ describe("TaskRunner", () => {
|
||||
it("runs tasks in order", async () => {
|
||||
const actual = [];
|
||||
const taskRunner = new TaskRunner(2);
|
||||
taskRunner.push(asyncFn1)
|
||||
.then((id) => {
|
||||
actual.push(id);
|
||||
});
|
||||
taskRunner.push(asyncFn2)
|
||||
.then((id) => {
|
||||
actual.push(id);
|
||||
});
|
||||
taskRunner.push(asyncFn3)
|
||||
.then((id) => {
|
||||
actual.push(id);
|
||||
});
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
taskRunner.push(asyncFn1).then(id => actual.push(id));
|
||||
taskRunner.push(asyncFn2).then(id => actual.push(id));
|
||||
taskRunner.push(asyncFn3).then(id => actual.push(id));
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
expect(actual).toEqual([2, 3, 1]);
|
||||
});
|
||||
|
||||
@@ -72,6 +66,20 @@ describe("TaskRunner", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves a promise when all tasks are complete, even if some are rejected", async () => {
|
||||
const error = new Error(`Task was rejected: 3`);
|
||||
const taskRunner = new TaskRunner(2, 5);
|
||||
taskRunner.push(() => mockPromise(1, 600));
|
||||
taskRunner.push(() => mockPromise(2, 300));
|
||||
taskRunner.push(() => mockPromiseReject(3, 200)).catch(payload => expect(payload).toBe(3));
|
||||
taskRunner.push(() => mockPromise(4, 600));
|
||||
taskRunner.push(() => mockPromise(5, 100));
|
||||
|
||||
await taskRunner.onComplete().then((response) => {
|
||||
expect(response).toStrictEqual([1, 2, error, 4, 5]);
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves a promise when all tasks are complete, even if some fail", async () => {
|
||||
const error = new Error(`Task 3 had an error`);
|
||||
const taskRunner = new TaskRunner(2, 5);
|
||||
@@ -85,7 +93,7 @@ describe("TaskRunner", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects a promise when the total number of tasks is unknown", async () => {
|
||||
it("immediately rejects onComplete when the total number of tasks is unknown", async () => {
|
||||
const taskRunner = new TaskRunner(2);
|
||||
taskRunner.push(() => mockPromise(1, 600));
|
||||
taskRunner.push(() => mockPromise(2, 300));
|
||||
@@ -96,4 +104,21 @@ describe("TaskRunner", () => {
|
||||
expect(error.message).toBe("Total is required to determine onComplete.");
|
||||
});
|
||||
});
|
||||
|
||||
it("cancels a task runner and returns progress", async () => {
|
||||
const taskRunner = new TaskRunner(2, 5);
|
||||
taskRunner.push(() => mockPromise(1, 600));
|
||||
taskRunner.push(() => mockPromise(2, 300));
|
||||
taskRunner.push(() => mockPromise(3, 200));
|
||||
taskRunner.push(() => mockPromise(4, 600));
|
||||
taskRunner.push(() => mockPromise(5, 100));
|
||||
|
||||
setTimeout(() => {
|
||||
taskRunner.cancel();
|
||||
}, 550);
|
||||
|
||||
await taskRunner.onComplete().catch((response) => {
|
||||
expect(response).toStrictEqual([undefined, 2, 3, undefined, undefined]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user