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

Add unit tests and fix handling empty runAfter array

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-12-14 09:34:44 -05:00
parent 7b8e97ba08
commit fcddf442a0
2 changed files with 316 additions and 2 deletions

View File

@ -8,6 +8,8 @@ import { createContainer, getInjectable, getInjectionToken } from "@ogre-tools/i
import type { Runnable } from "./run-many-for"; import type { Runnable } from "./run-many-for";
import { runManyFor } from "./run-many-for"; import { runManyFor } from "./run-many-for";
import { getPromiseStatus } from "../test-utils/get-promise-status"; import { getPromiseStatus } from "../test-utils/get-promise-status";
import { runInAction } from "mobx";
import { flushPromises } from "../test-utils/flush-promises";
describe("runManyFor", () => { describe("runManyFor", () => {
describe("given no hierarchy, when running many", () => { describe("given no hierarchy, when running many", () => {
@ -340,4 +342,315 @@ describe("runManyFor", () => {
]); ]);
}); });
}); });
describe("given multiple runAfters", () => {
let runMock: AsyncFnMock<(...args: unknown[]) => void>;
let finishingPromise: Promise<void>;
beforeEach(async () => {
const rootDi = createContainer("irrelevant");
runMock = asyncFn<(...args: unknown[]) => void>();
const someInjectionToken = getInjectionToken<Runnable>({
id: "some-injection-token",
});
const runnableOneInjectable = getInjectable({
id: "runnable-1",
instantiate: () => ({
id: "runnable-1",
run: () => runMock("runnable-1"),
}),
injectionToken: someInjectionToken,
});
const runnableTwoInjectable = getInjectable({
id: "runnable-2",
instantiate: () => ({
id: "runnable-2",
run: () => runMock("runnable-2"),
runAfter: [], // shouldn't block being called
}),
injectionToken: someInjectionToken,
});
const runnableThreeInjectable = getInjectable({
id: "runnable-3",
instantiate: (di) => ({
id: "runnable-3",
run: () => runMock("runnable-3"),
runAfter: di.inject(runnableOneInjectable),
}),
injectionToken: someInjectionToken,
});
const runnableFourInjectable = getInjectable({
id: "runnable-4",
instantiate: (di) => ({
id: "runnable-4",
run: () => runMock("runnable-4"),
runAfter: [di.inject(runnableThreeInjectable)], // should be the same as an single item
}),
injectionToken: someInjectionToken,
});
const runnableFiveInjectable = getInjectable({
id: "runnable-5",
instantiate: (di) => ({
id: "runnable-5",
run: () => runMock("runnable-5"),
runAfter: di.inject(runnableThreeInjectable),
}),
injectionToken: someInjectionToken,
});
const runnableSixInjectable = getInjectable({
id: "runnable-6",
instantiate: (di) => ({
id: "runnable-6",
run: () => runMock("runnable-6"),
runAfter: [
di.inject(runnableFourInjectable),
di.inject(runnableFiveInjectable),
],
}),
injectionToken: someInjectionToken,
});
const runnableSevenInjectable = getInjectable({
id: "runnable-7",
instantiate: (di) => ({
id: "runnable-7",
run: () => runMock("runnable-7"),
runAfter: [
di.inject(runnableFiveInjectable),
di.inject(runnableSixInjectable),
],
}),
injectionToken: someInjectionToken,
});
runInAction(() => {
rootDi.register(
runnableOneInjectable,
runnableTwoInjectable,
runnableThreeInjectable,
runnableFourInjectable,
runnableFiveInjectable,
runnableSixInjectable,
runnableSevenInjectable,
);
});
const runMany = runManyFor(rootDi);
const runSome = runMany(someInjectionToken);
finishingPromise = runSome();
await flushPromises();
});
it("should run 'runnable-1'", () => {
expect(runMock).toBeCalledWith("runnable-1");
});
it("should run 'runnable-2'", () => {
expect(runMock).toBeCalledWith("runnable-2");
});
describe("when 'runnable-1' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-1"]);
});
it("should run 'runnable-3'", () => {
expect(runMock).toBeCalledWith("runnable-3");
});
describe("when 'runnable-2' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-2"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(3);
});
});
describe("when 'runnable-3' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-3"]);
});
it("should run 'runnable-4'", () => {
expect(runMock).toBeCalledWith("runnable-4");
});
it("should run 'runnable-5'", () => {
expect(runMock).toBeCalledWith("runnable-5");
});
describe("when 'runnable-2' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-2"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(5);
});
});
describe("when 'runnable-4' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-4"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(5);
});
describe("when 'runnable-2' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-2"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(5);
});
});
describe("when 'runnable-5' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-5"]);
});
it("should run 'runnable-6'", () => {
expect(runMock).toBeCalledWith("runnable-6");
});
describe("when 'runnable-2' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-2"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(6);
});
});
describe("when 'runnable-6' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-6"]);
});
it("should run 'runnable-7'", () => {
expect(runMock).toBeCalledWith("runnable-7");
});
describe("when 'runnable-2' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-2"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(7);
});
describe("when 'runnable-7' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-7"]);
});
it("should resolve the runMany promise call", async () => {
await finishingPromise;
});
});
});
});
});
});
describe("when 'runnable-5' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-5"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(5);
});
describe("when 'runnable-2' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-2"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(5);
});
});
describe("when 'runnable-4' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-4"]);
});
it("should run 'runnable-6'", () => {
expect(runMock).toBeCalledWith("runnable-6");
});
describe("when 'runnable-2' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-2"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(6);
});
});
describe("when 'runnable-6' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-6"]);
});
it("should run 'runnable-7'", () => {
expect(runMock).toBeCalledWith("runnable-7");
});
describe("when 'runnable-2' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-2"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(7);
});
describe("when 'runnable-7' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-7"]);
});
it("should resolve the runMany promise call", async () => {
await finishingPromise;
});
});
});
});
});
});
});
});
describe("when 'runnable-2' resolves", () => {
beforeEach(async () => {
await runMock.resolveSpecific(["runnable-2"]);
});
it("shouldn't call any more runnables", () => {
expect(runMock).toBeCalledTimes(2);
});
});
});
}); });

View File

@ -8,6 +8,7 @@ import { getOrInsertSetFor, isDefined } from "../utils";
import { observable, when } from "mobx"; import { observable, when } from "mobx";
import * as uuid from "uuid"; import * as uuid from "uuid";
import assert from "assert"; import assert from "assert";
import type { Asyncify } from "type-fest";
export interface Runnable<TParameter = void> { export interface Runnable<TParameter = void> {
id: string; id: string;
@ -17,7 +18,7 @@ export interface Runnable<TParameter = void> {
type Run<Param> = (parameter: Param) => Promise<void> | void; type Run<Param> = (parameter: Param) => Promise<void> | void;
export type RunMany = <Param>(injectionToken: InjectionToken<Runnable<Param>, void>) => Run<Param>; export type RunMany = <Param>(injectionToken: InjectionToken<Runnable<Param>, void>) => Asyncify<Run<Param>>;
const computedNextEdge = (traversed: string[], graph: Map<string, Set<string>>, currentId: string, seenIds: Set<string>) => { const computedNextEdge = (traversed: string[], graph: Map<string, Set<string>>, currentId: string, seenIds: Set<string>) => {
seenIds.add(currentId); seenIds.add(currentId);
@ -44,7 +45,7 @@ const verifyRunnablesAreDAG = <Param>(injectionToken: InjectionToken<Runnable<Pa
for (const runnable of runnables) { for (const runnable of runnables) {
addRunnableId(runnable.id); addRunnableId(runnable.id);
if (!runnable.runAfter) { if (!runnable.runAfter || (Array.isArray(runnable.runAfter) && runnable.runAfter.length === 0)) {
addRunnableId(rootId).add(runnable.id); addRunnableId(rootId).add(runnable.id);
} else if (Array.isArray(runnable.runAfter)) { } else if (Array.isArray(runnable.runAfter)) {
for (const parentRunnable of runnable.runAfter) { for (const parentRunnable of runnable.runAfter) {