Fix uncaught test failures
Prior to this commit, if you run `yarn unit cli/load`, you would see a lot of unhandled promise rejection warnings related to the fact that load calls a `saveTimestamps` function which expects the SourceCred directory to contain the results of really loading SourceCred plugins. However, when testing, these functions have been mocked, and so saveTimestamps rejects. This rejection was not caught, and polluted the test output without actually failing the tests. This commit updates the tests so that saveTimestamps can be mocked (via dependency injection) and we can both verify that it is invoked correctly, and not pollute the test output with spurious warnings. Test plan: - `yarn test --full` passes - `yarn unit cli/load` produces far fewer UnhandledPromiseRejectionWarnings (there is still one unrelated one) - loading sourcecred/research still works (as a canary) Note: the PR which introduced this issue is #1162.
This commit is contained in:
parent
1d32141f76
commit
7c4ff66907
|
@ -172,7 +172,20 @@ export function makeLoadCommand(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadDefaultPlugins = async (options: LoadOptions) => {
|
export type SaveTimestamps = (
|
||||||
|
$ReadOnlyArray<IBackendAdapterLoader>,
|
||||||
|
RepoId
|
||||||
|
) => Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around the default plugin loader.
|
||||||
|
*
|
||||||
|
* We wrap so that we can dependency inject saveTimestamps for testability.
|
||||||
|
* (saveTimestamps depends on the directory state that's generated by running
|
||||||
|
* load.)
|
||||||
|
*/
|
||||||
|
export const makeLoadDefaultPlugins = (saveTimestamps: SaveTimestamps) => {
|
||||||
|
return async (options: LoadOptions) => {
|
||||||
const sourcecredCommand = (args) => [
|
const sourcecredCommand = (args) => [
|
||||||
process.execPath,
|
process.execPath,
|
||||||
"--max_old_space_size=8192",
|
"--max_old_space_size=8192",
|
||||||
|
@ -201,7 +214,7 @@ export const loadDefaultPlugins = async (options: LoadOptions) => {
|
||||||
throw new Error("Load tasks failed.");
|
throw new Error("Load tasks failed.");
|
||||||
}
|
}
|
||||||
addToRepoIdRegistry(options.output);
|
addToRepoIdRegistry(options.output);
|
||||||
saveTimestamps(defaultAdapterLoaders(), options.output);
|
await saveTimestamps(defaultAdapterLoaders(), options.output);
|
||||||
// HACK: Logically, we should have the PagerankTask be included in the
|
// HACK: Logically, we should have the PagerankTask be included in the
|
||||||
// first execDependencyGraph run, depending on the other tasks completing.
|
// first execDependencyGraph run, depending on the other tasks completing.
|
||||||
//
|
//
|
||||||
|
@ -219,13 +232,17 @@ export const loadDefaultPlugins = async (options: LoadOptions) => {
|
||||||
cmd: sourcecredCommand(["pagerank", repoIdToString(options.output)]),
|
cmd: sourcecredCommand(["pagerank", repoIdToString(options.output)]),
|
||||||
deps: [],
|
deps: [],
|
||||||
};
|
};
|
||||||
const {success: pagerankSuccess} = await execDependencyGraph([pagerankTask], {
|
const {success: pagerankSuccess} = await execDependencyGraph(
|
||||||
|
[pagerankTask],
|
||||||
|
{
|
||||||
taskPassLabel: "DONE",
|
taskPassLabel: "DONE",
|
||||||
});
|
}
|
||||||
|
);
|
||||||
if (!pagerankSuccess) {
|
if (!pagerankSuccess) {
|
||||||
throw new Error("Pagerank task failed.");
|
throw new Error("Pagerank task failed.");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadIndividualPlugin = async (
|
export const loadIndividualPlugin = async (
|
||||||
|
@ -270,7 +287,15 @@ function addToRepoIdRegistry(repoId) {
|
||||||
RepoIdRegistry.writeRegistry(newRegistry, Common.sourcecredDirectory());
|
RepoIdRegistry.writeRegistry(newRegistry, Common.sourcecredDirectory());
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveTimestamps(
|
/**
|
||||||
|
* Load timestamp data for every node in the serialized graph,
|
||||||
|
* then write the timestamps to disk.
|
||||||
|
*
|
||||||
|
* Note: This function calls well-tested code, but is not itself tested, except
|
||||||
|
* by the sharness load snapshot test.
|
||||||
|
* Modify with caution.
|
||||||
|
*/
|
||||||
|
export async function saveTimestamps(
|
||||||
adapterLoaders: $ReadOnlyArray<IBackendAdapterLoader>,
|
adapterLoaders: $ReadOnlyArray<IBackendAdapterLoader>,
|
||||||
repoId: RepoId
|
repoId: RepoId
|
||||||
) {
|
) {
|
||||||
|
@ -302,6 +327,7 @@ export const help: Command = async (args, std) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadDefaultPlugins = makeLoadDefaultPlugins(saveTimestamps);
|
||||||
const load = makeLoadCommand(loadIndividualPlugin, loadDefaultPlugins);
|
const load = makeLoadCommand(loadIndividualPlugin, loadDefaultPlugins);
|
||||||
|
|
||||||
export default load;
|
export default load;
|
||||||
|
|
|
@ -6,13 +6,14 @@ import tmp from "tmp";
|
||||||
import {run} from "./testUtil";
|
import {run} from "./testUtil";
|
||||||
import {
|
import {
|
||||||
makeLoadCommand,
|
makeLoadCommand,
|
||||||
loadDefaultPlugins,
|
makeLoadDefaultPlugins,
|
||||||
loadIndividualPlugin,
|
loadIndividualPlugin,
|
||||||
help,
|
help,
|
||||||
} from "./load";
|
} from "./load";
|
||||||
|
|
||||||
import * as RepoIdRegistry from "../core/repoIdRegistry";
|
import * as RepoIdRegistry from "../core/repoIdRegistry";
|
||||||
import {makeRepoId} from "../core/repoId";
|
import {makeRepoId} from "../core/repoId";
|
||||||
|
import {defaultAdapterLoaders} from "./pagerank";
|
||||||
|
|
||||||
jest.mock("../tools/execDependencyGraph", () => jest.fn());
|
jest.mock("../tools/execDependencyGraph", () => jest.fn());
|
||||||
jest.mock("../plugins/github/loadGithubData", () => ({
|
jest.mock("../plugins/github/loadGithubData", () => ({
|
||||||
|
@ -462,6 +463,7 @@ describe("cli/load", () => {
|
||||||
const fooCombined = makeRepoId("foo", "combined");
|
const fooCombined = makeRepoId("foo", "combined");
|
||||||
const fooBar = makeRepoId("foo", "bar");
|
const fooBar = makeRepoId("foo", "bar");
|
||||||
const fooBaz = makeRepoId("foo", "baz");
|
const fooBaz = makeRepoId("foo", "baz");
|
||||||
|
const loadDefaultPlugins = makeLoadDefaultPlugins(jest.fn());
|
||||||
|
|
||||||
it("creates a load sub-task per plugin", async () => {
|
it("creates a load sub-task per plugin", async () => {
|
||||||
execDependencyGraph.mockResolvedValue({success: true});
|
execDependencyGraph.mockResolvedValue({success: true});
|
||||||
|
@ -533,6 +535,21 @@ describe("cli/load", () => {
|
||||||
expect(RepoIdRegistry.getRegistry(directory)).toEqual(expectedRegistry);
|
expect(RepoIdRegistry.getRegistry(directory)).toEqual(expectedRegistry);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("calls saveTimestamps on success", async () => {
|
||||||
|
const saveTimestamps = jest.fn();
|
||||||
|
const loadDefaultPlugins = makeLoadDefaultPlugins(saveTimestamps);
|
||||||
|
execDependencyGraph.mockResolvedValue({success: true});
|
||||||
|
await loadDefaultPlugins({
|
||||||
|
output: fooCombined,
|
||||||
|
repoIds: [fooBar, fooBaz],
|
||||||
|
});
|
||||||
|
expect(saveTimestamps).toHaveBeenCalledTimes(1);
|
||||||
|
expect(saveTimestamps).toHaveBeenCalledWith(
|
||||||
|
defaultAdapterLoaders(),
|
||||||
|
fooCombined
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("throws an load error on first execDependencyGraph failure", async () => {
|
it("throws an load error on first execDependencyGraph failure", async () => {
|
||||||
execDependencyGraph.mockResolvedValueOnce({success: false});
|
execDependencyGraph.mockResolvedValueOnce({success: false});
|
||||||
const result = loadDefaultPlugins({
|
const result = loadDefaultPlugins({
|
||||||
|
|
Loading…
Reference in New Issue