Files
anonymous_github/test/download-progress-fences.test.js

79 lines
4.0 KiB
JavaScript

const { expect } = require("chai");
const { setImmediate } = require("timers");
require("ts-node/register/transpile-only");
const db = require("../src/server/database");
const Model = require("../src/core/model/anonymizedRepositories/anonymizedRepositories.model").default;
const Repository = require("../src/core/Repository").default;
const gh = require("../src/core/GitHubUtils");
const sift = require("sift").default;
describe("download progress publication fences", function () {
const restores = [];
function stub(object, key, value) { const before = object[key]; restores.push(() => { object[key] = before; }); object[key] = value; }
afterEach(() => { while (restores.length) restores.pop()(); });
function setup() {
const model = new Model({ repoId: "progress-test", status: "download", statusDate: new Date(1000),
owner: "507f1f77bcf86cd799439011", anonymizeDate: new Date(500),
source: { repositoryName: "owner/repo", commit: "abc", branch: "main" }, options: { terms: [], expirationMode: "never" } });
const repo = new Repository(model); repo.protectLifecycle = true;
const stored = model.toObject();
stub(db, "isConnected", true);
stub(Model, "updateOne", (filter, update) => ({ exec: async () => {
if (!sift(filter)(stored)) return { matchedCount: 0 };
Object.assign(stored, update.$set); return { matchedCount: 1 };
} }));
return { repo, stored };
}
it("keeps a captured publication fence valid when a queue progress tick runs", async function () {
const { repo, stored } = setup(); let tick;
stub(global, "setInterval", callback => { tick = callback; return 1; });
stub(global, "clearInterval", () => {});
stub(db, "connect", async () => {});
stub(db, "getRepository", async () => repo);
stub(gh, "getToken", async () => "test-token");
stub(gh, "getRedisGateResetAt", async () => 0);
stub(repo, "resetSate", async () => {});
stub(repo, "anonymize", async progress => {
const fence = { status: stored.status, statusDate: stored.statusDate };
progress("Writing files"); tick();
await new Promise(resolve => setImmediate(resolve));
expect(sift(fence)(stored), "progress invalidated the publication fence").to.equal(true);
expect(stored.statusMessage).to.equal("Writing files");
});
await require("../src/queue/processes/downloadRepository").default({ data: { repoId: repo.repoId }, updateProgress: async () => {} });
expect(stored.status).to.equal("ready");
});
it("keeps fresh long-running downloads busy without changing statusDate", async function () {
const { repo, stored } = setup(); const before = repo.model.statusDate;
await repo.updateProgressMessage("Writing files");
expect(stored.statusDate).to.deep.equal(before);
expect(repo.model.statusDate).to.deep.equal(before);
expect(repo.statusActivityDate.getTime()).to.be.greaterThan(Date.now() - 1000);
try { await repo.check(); throw new Error("expected not ready"); }
catch (error) { expect(error.message).to.equal("repository_not_ready"); }
});
for (const replacement of ["ready", "removed", "download"]) {
it(`does not overwrite progress for a newer ${replacement} state`, async function () {
const { repo, stored } = setup();
stored.status = replacement; stored.statusDate = new Date(2000); stored.statusMessage = "new operation";
await repo.updateProgressMessage("old progress");
expect(stored.statusMessage).to.equal("new operation");
expect(repo.model.statusMessage).not.to.equal("old progress");
expect(stored).not.to.have.property("progressDate");
});
}
it("does not apply a completed progress write to a locally advanced status", async function () {
const { repo } = setup();
stub(Model, "updateOne", () => ({ exec: async () => {
repo.model.status = "ready"; repo.model.statusDate = new Date(2000); repo.model.statusMessage = "done";
return { matchedCount: 1 };
} }));
await repo.updateProgressMessage("old progress");
expect(repo.model.statusMessage).to.equal("done");
});
});