Files
factorio-clusterio/test/controller/ControlConnection.test.js
T
bbassieandClaude Fable 5 5e6b06f009 Filter dependency resolution by the mod pack's Factorio version
The dependency resolver picked the newest release satisfying the version
range regardless of which Factorio version it targeted, so a 2.0 mod pack
could end up with 2.1 dependencies. Only consider portal releases and
local mods whose factorio_version matches the mod pack.

Fixes #965

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 14:30:32 +00:00

116 lines
4.0 KiB
JavaScript

"use strict";
const assert = require("assert").strict;
const lib = require("@clusterio/lib");
const { ControlConnection } = require("@clusterio/controller");
describe("controller/src/ControlConnection", function() {
describe(".handleControllerRestartRequest()", function() {
let mockController;
beforeEach(function() {
mockController = {
canRestart: true,
shouldRestart: false,
stopped: false,
async checkRestartDowngrade() { return null; },
stop() { this.stopped = true; },
};
});
async function restart() {
await ControlConnection.prototype.handleControllerRestartRequest.call({
_controller: mockController,
});
}
it("restarts when the installed version is not older", async function() {
await restart();
assert.equal(mockController.shouldRestart, true);
assert.equal(mockController.stopped, true);
});
it("rejects a downgrade without stopping the controller", async function() {
mockController.checkRestartDowngrade = async () => ({
installedVersion: "1.0.0",
runningVersion: "2.0.0",
});
await assert.rejects(restart, /Stop the controller before starting the older version manually/);
assert.equal(mockController.shouldRestart, false);
assert.equal(mockController.stopped, false);
});
});
describe(".handleModDependencyResolveRequest()", function() {
const originalFetchModReleases = lib.ModStore.fetchModReleases;
const portal = new Map();
let localMods;
function release(version, factorioVersion, dependencies = []) {
return {
version, sha1: "0".repeat(40),
info_json: { factorio_version: factorioVersion, dependencies },
};
}
before(function() {
lib.ModStore.fetchModReleases = async (name) => {
const releases = portal.get(name);
if (!releases) {
throw new Error("Fetch: returned 404 Not Found");
}
return { name, owner: "owner", title: name, releases };
};
});
after(function() {
lib.ModStore.fetchModReleases = originalFetchModReleases;
});
beforeEach(function() {
portal.clear();
localMods = [];
});
async function resolve(mods, factorioVersion, checkForUpdates = false) {
const response = await ControlConnection.prototype.handleModDependencyResolveRequest.call(
{ _controller: { modStore: { mods: () => localMods } } },
new lib.ModDependencyResolveRequest(
mods.map(mod => new lib.ModDependency(mod)), factorioVersion, checkForUpdates,
),
);
return new Map(response.dependencies.map(mod => [mod.name, mod]));
}
it("only selects portal releases matching the mod pack's Factorio version", async function() {
portal.set("root", [release("1.0.0", "2.0", ["dep"]), release("1.1.0", "2.1", ["dep"])]);
portal.set("dep", [
release("1.0.0", "1.1"),
release("2.0.0", "2.0"),
release("3.0.0", "2.1"),
]);
assert.equal((await resolve(["root = 1.0.0"], "2.0")).get("dep").version, "2.0.0");
assert.equal((await resolve(["root = 1.1.0"], "2.1")).get("dep").version, "3.0.0");
});
it("only selects local mods matching the mod pack's Factorio version", async function() {
portal.set("root", [release("1.0.0", "2.0", ["dep"])]);
portal.set("dep", [release("2.0.0", "2.0")]);
localMods = [
lib.ModInfo.fromJSON({ name: "dep", version: "3.0.0", factorio_version: "2.1" }),
lib.ModInfo.fromJSON({ name: "dep", version: "1.0.0", factorio_version: "2.0" }),
];
assert.equal((await resolve(["root = 1.0.0"], "2.0")).get("dep").version, "1.0.0");
assert.equal((await resolve(["root = 1.0.0"], "2.0", true)).get("dep").version, "2.0.0");
});
it("reports dependencies without a matching Factorio version as not found", async function() {
portal.set("root", [release("1.0.0", "2.0", ["dep"])]);
portal.set("dep", [release("3.0.0", "2.1")]);
const response = await ControlConnection.prototype.handleModDependencyResolveRequest.call(
{ _controller: { modStore: { mods: () => localMods } } },
new lib.ModDependencyResolveRequest([new lib.ModDependency("root = 1.0.0")], "2.0", false),
);
assert.equal(response.errors.get("dep"), "notFound");
});
});
});