Files
factorio-clusterio/test/lib/rce_ops.js
T
bbassieandClaude Fable 5.1 7ff2092547 Add update all for the controller, hosts and plugins
Updating a single plugin can leave the installation with multiple
versions of @clusterio/lib. Passing the core package and every npm
installed plugin to a single npm update call lets npm resolve them
together.

UpdateAllRequest targets the controller or a host, requires both the
core update permission and core.plugin.update, and is gated by both
allow_remote_updates and allow_plugin_updates. The web UI Updates modal
gets an Update All action and ctl gets --all on the update commands.

Closes #910

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 22:40:32 +00:00

91 lines
2.6 KiB
JavaScript

"use strict";
const assert = require("assert").strict;
const lib = require("@clusterio/lib");
describe("rce_ops", function() {
describe("updatePackage", function() {
it("runs", async function() {
// In dev env no side effects occur, so best we can do is check it doesn't error
await lib.updatePackage("foo");
});
});
describe("installPackage", function() {
it("runs", async function() {
// In dev env no side effects occur, so best we can do is check it doesn't error
await lib.installPackage("foo");
});
});
describe("handlePluginUpdate", function() {
it("runs", async function() {
await lib.handlePluginUpdate("foo", [{ npmPackage: "foo" }]);
});
it("rejects when plugin not installed", async function() {
await assert.rejects(
lib.handlePluginUpdate("foo", []),
/Plugin foo is not installed on this machine/
);
});
});
describe("handleUpdateAll", function() {
it("updates the core package and all npm plugins in one command", async function() {
const _audit = lib.logger.audit;
const messages = [];
lib.logger.audit = (msg) => { messages.push(msg); };
try {
await lib.handleUpdateAll("core", [{ npmPackage: "foo" }, { name: "local" }, { npmPackage: "bar" }]);
} finally {
lib.logger.audit = _audit;
}
assert.deepEqual(messages, ["RCE | npm update --save core foo bar"]);
});
});
describe("handlePluginInstall", function() {
const _fetch = global.fetch;
before(function() {
global.fetch = function() { return { ok: false }; };
});
after(function() {
global.fetch = _fetch;
});
it("runs", async function() {
let calledWith = "";
global.fetch = function(url) {
calledWith = url;
return { ok: true };
};
await lib.handlePluginInstall("foo");
assert.equal(calledWith, "https://registry.npmjs.com/foo");
});
it("rejects when name too long", async function() {
const pluginName = "a".repeat(215);
await assert.rejects(
lib.handlePluginInstall(pluginName),
{ message: `Invalid plugin name: ${pluginName}` }
);
});
it("rejects when invalid symbol present", async function() {
const pluginName = "?";
await assert.rejects(
lib.handlePluginInstall(pluginName),
{ message: `Invalid plugin name: ${pluginName}` },
);
});
it("rejects unregistered packages", async function() {
let calledWith = "";
global.fetch = function(url) {
calledWith = url;
return { ok: false };
};
await assert.rejects(lib.handlePluginInstall("foo"), /Unknown plugin: foo/);
assert.equal(calledWith, "https://registry.npmjs.com/foo");
});
});
});