perf: streamline repository and deployment awareness
ForgeFlow quality gate / quality (push) Canceled after 0s
ForgeFlow quality gate / quality (push) Canceled after 0s
This commit is contained in:
@@ -172,3 +172,22 @@ test('rollback refuses a stale target that is no longer the server-reported prev
|
||||
assert.equal(dispatched, false);
|
||||
});
|
||||
|
||||
test('active deployment refreshes run concurrently with a bounded worker pool', async () => {
|
||||
const operations = Array.from({ length: 9 }, (_, index) => ({ id: `operation-${index}`, type: 'deployment', status: 'running' }));
|
||||
const service = new DeploymentService({ data: { operations } }, {}, {});
|
||||
let running = 0;
|
||||
let peak = 0;
|
||||
service.refreshOperation = async (id) => {
|
||||
running += 1;
|
||||
peak = Math.max(peak, running);
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
running -= 1;
|
||||
return { id };
|
||||
};
|
||||
|
||||
const refreshed = await service.refreshActiveOperations();
|
||||
assert.equal(refreshed.length, operations.length);
|
||||
assert.ok(peak > 1);
|
||||
assert.ok(peak <= 4);
|
||||
});
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ test('refresh uses last-known Gitea repositories after a transient remote failur
|
||||
|
||||
const fresh = await instance.refresh();
|
||||
remoteAvailable = false;
|
||||
const degraded = await instance.refresh();
|
||||
const degraded = await instance.refresh({ force: true });
|
||||
|
||||
assert.equal(fresh[0].remoteStale, false);
|
||||
assert.equal(degraded[0].fullName, remote.full_name);
|
||||
@@ -184,6 +184,26 @@ test('initial Gitea failure remains visible when no safe cache exists', async ()
|
||||
await assert.rejects(() => instance.refresh(), /Gitea unavailable/);
|
||||
});
|
||||
|
||||
test('refresh coalesces concurrent work and briefly reuses remote and discovery results', async () => {
|
||||
let remoteCalls = 0;
|
||||
let discoveryCalls = 0;
|
||||
const store = {
|
||||
data: { gitea: { baseUrl: 'https://gitea.example' }, workspaceRoots: [], repositoryMappings: {}, preferences: { preferredCloneProtocol: 'ssh' }, favorites: [] },
|
||||
getToken: () => 'token', getDeploymentProfiles: () => [], getDeploymentState: () => null
|
||||
};
|
||||
const instance = new RepositoryService(store, {}, { listRepositories: async () => { remoteCalls += 1; await new Promise((resolve) => setTimeout(resolve, 10)); return [remote]; } });
|
||||
instance.discoverAll = async () => { discoveryCalls += 1; return []; };
|
||||
|
||||
const [first, second] = await Promise.all([instance.refresh(), instance.refresh()]);
|
||||
assert.deepEqual(first, second);
|
||||
await instance.refresh();
|
||||
assert.equal(remoteCalls, 1);
|
||||
assert.equal(discoveryCalls, 1);
|
||||
await instance.refresh({ force: true });
|
||||
assert.equal(remoteCalls, 2);
|
||||
assert.equal(discoveryCalls, 2);
|
||||
});
|
||||
|
||||
test('decoration reports conflicts, behind branches, errors and remote-only repositories', () => {
|
||||
const instance = service();
|
||||
const conflicted = instance.decorate(remote, { localPath: 'repo', status: { ...status(), counts: { changed: 1, conflicts: 2 }, branch: { ...status().branch, behind: 3 } } }, []);
|
||||
|
||||
@@ -317,6 +317,7 @@ test("low-level inventory scan is read-only and user discovery auto-links exact
|
||||
assert.equal(profiles[0].containerName, "Portfolio");
|
||||
assert.equal(profiles[0].adoptedFromServer, true);
|
||||
assert.equal(states.get(profiles[0].id).matchesGitea, true);
|
||||
assert.deepEqual(discovery.refreshedProfileIds, [profiles[0].id]);
|
||||
});
|
||||
|
||||
|
||||
@@ -385,6 +386,18 @@ test("server inventory includes stopped DockerMan containers without Git and kee
|
||||
assert.match(workloads[0].candidates[0].reasons.join(" "), /manual confirmation/i);
|
||||
});
|
||||
|
||||
test("server inventory batches Docker inspect and retains a disappearing-container fallback", async () => {
|
||||
const source = await unraidSource();
|
||||
assert.match(source, /docker inspect "\\\$\{container_ids\[@\]\}"/);
|
||||
assert.match(source, /for container_id in "\\\$\{container_ids\[@\]\}"/);
|
||||
});
|
||||
|
||||
test("server inventory avoids a second Compose process for static image definitions", async () => {
|
||||
const source = await unraidSource();
|
||||
assert.match(source, /has_override=false/);
|
||||
assert.match(source, /\[ -z "\$images" \].*config --images/);
|
||||
});
|
||||
|
||||
test("server inventory groups multi-service Compose projects and preserves their identity", () => {
|
||||
const baseContainer = {
|
||||
image: "example/app:latest",
|
||||
@@ -477,6 +490,40 @@ test("manual workload linking does not claim Gitea parity for unrelated provenan
|
||||
assert.equal(savedState.giteaSha, null);
|
||||
});
|
||||
|
||||
test("inventory provenance alone never claims Gitea commit parity", async () => {
|
||||
let savedState = null;
|
||||
const service = new UnraidDeploymentService({
|
||||
store: { getDeploymentState: () => ({}), saveDeploymentState: async (_id, state) => { savedState = state; return state; } },
|
||||
});
|
||||
await service.saveWorkloadState(
|
||||
{ id: "profile", remoteFolder: "app", cloneUrl: "git@gitea.test:Owner/App.git" },
|
||||
{
|
||||
workloadId: "workload", observedAt: new Date().toISOString(),
|
||||
metadata: { sourceRepository: "git@gitea.test:Owner/App.git", liveRevision: "a".repeat(40) },
|
||||
runtime: { running: true, health: "healthy" }, containers: [{ name: "app", running: true, health: "healthy" }], compose: {},
|
||||
},
|
||||
{ basePath: "/mnt/user/appdata" },
|
||||
);
|
||||
assert.equal(savedState.matchesGitea, false);
|
||||
assert.equal(savedState.giteaSha, null);
|
||||
});
|
||||
|
||||
test("a stopped workload cannot become healthy through a reused healthcheck port", async () => {
|
||||
let savedState = null;
|
||||
const service = new UnraidDeploymentService({
|
||||
store: { getDeploymentState: () => ({}), saveDeploymentState: async (_id, state) => { savedState = state; return state; } },
|
||||
});
|
||||
await service.saveWorkloadState(
|
||||
{ id: "profile", remoteFolder: "app", healthcheckUrl: "http://server.test/health" },
|
||||
{ workloadId: "workload", metadata: {}, runtime: { running: false, health: "unverified" }, containers: [{ name: "app", running: false }], compose: {} },
|
||||
{ basePath: "/mnt/user/appdata" },
|
||||
{ health: { configured: true, healthy: true, status: 200 } },
|
||||
);
|
||||
assert.equal(savedState.containerRunning, false);
|
||||
assert.equal(savedState.healthy, false);
|
||||
assert.equal(savedState.runtimeVerification, "stopped");
|
||||
});
|
||||
|
||||
test("Docker ignore checks identify exact runtime and Git context exclusions", () => {
|
||||
const rules = "# build context\n.git\ndata/\nlogs/**\n!logs/keep.txt\n";
|
||||
assert.equal(dockerIgnoreHasPath(rules, ".git"), true);
|
||||
|
||||
Reference in New Issue
Block a user