Merge pull request #778 from Cooldude2606/refactor/test-exec-ctl

Refactor execCtl and Ctl to speed up unit testing
This commit is contained in:
Daniel authored and GitHub committed 2025-07-10 13:09:27 +02:00
commit 02d14bd98d
12 files changed
+188 -143

No files matched your search

+61 -28
View File
@@ -143,7 +143,19 @@ interface CtlArguments {
pluginList: string,
}
async function startControl() {
interface InitializeParameters {
args: CtlArguments;
shouldRun: boolean;
ctlPlugins?: Map<string, BaseCtlPlugin>;
rootCommands?: lib.CommandTree;
controlConfig?: lib.ControlConfig;
}
export async function initialize(
argv: string | string[],
ctlPlugins?: Map<string, BaseCtlPlugin>,
noLoggerTransport?: boolean,
): Promise<InitializeParameters> {
yargs
.scriptName("clusterioctl")
.usage("$0 <command> [options]")
@@ -175,38 +187,41 @@ async function startControl() {
// Parse the args first to get the configured plugin list.
// eslint-disable-next-line node/no-sync
let args = yargs.parseSync() as CtlArguments;
let args = yargs.parseSync(argv) as CtlArguments;
// Log stream for the ctl session.
logger.add(
new ConsoleTransport({
errorLevels: Object.keys(levels),
level: args.logLevel,
format: new lib.TerminalFormat(),
})
);
lib.handleUnhandledErrors();
logger.verbose(`Loading available plugins from ${args.pluginList}`);
let pluginList = await lib.loadPluginList(args.pluginList);
// If the command is plugin management we don't try to load plugins
if (args._[0] === "plugin") {
await lib.handlePluginCommand(args, pluginList, args.pluginList);
return;
// Log stream for the ctl session. Skipped in testing.
if (!noLoggerTransport) {
logger.add(
new ConsoleTransport({
errorLevels: Object.keys(levels),
level: args.logLevel,
format: new lib.TerminalFormat(),
})
);
lib.handleUnhandledErrors();
}
logger.verbose("Loading Plugins");
let ctlPlugins = await loadPlugins(pluginList);
// Discover and load plugins. This check exists to allow tests to inject plugins.
if (!ctlPlugins || args._[0] === "plugin") {
logger.verbose(`Loading available plugins from ${args.pluginList}`);
const pluginList = await lib.loadPluginList(args.pluginList);
// Add all cluster management commands including ones from plugins
let rootCommands = await commands.registerCommands(ctlPlugins, yargs);
// If the command is plugin management we don't try to load plugins
if (args._[0] === "plugin") {
await lib.handlePluginCommand(args, pluginList, args.pluginList);
return { args, shouldRun: false };
}
// Reparse after commands have been added with help and strict checking.
logger.verbose("Loading Plugins");
ctlPlugins = await loadPlugins(pluginList);
}
// Add all commands including from plugins and reparse with help and strict checking.
const rootCommands = await commands.registerCommands(ctlPlugins, yargs);
args = yargs
.help()
.strict()
.parse() as CtlArguments
.parse(argv) as CtlArguments
;
let controlConfig;
@@ -233,18 +248,34 @@ async function startControl() {
// Handle the control-config command before trying to connect.
if (args._[0] === "control-config") {
await lib.handleConfigCommand(args, controlConfig);
return;
return { args, controlConfig, ctlPlugins, rootCommands, shouldRun: false };
}
// Determine which command is being executed.
return { args, controlConfig, ctlPlugins, rootCommands, shouldRun: true };
}
export function selectTargetCommand(args: CtlArguments, rootCommands: lib.CommandTree): lib.Command {
let commandPath = [...args._] as string[];
let targetCommand: lib.CommandTree | lib.Command = rootCommands;
while (commandPath.length && targetCommand instanceof lib.CommandTree) {
targetCommand = targetCommand.get(commandPath.shift()!)!;
}
assert(targetCommand instanceof lib.Command);
return targetCommand;
}
async function startControl() {
const {
args,
shouldRun,
ctlPlugins,
rootCommands,
controlConfig,
} = await initialize(process.argv.slice(2));
if (!shouldRun || !ctlPlugins || !rootCommands || !controlConfig) {
return;
}
// The remaining commands require connecting to the controller.
if (!controlConfig.get("control.controller_url") || !controlConfig.get("control.controller_token")) {
logger.error("Missing URL and/or token to connect with. See README.md for setting up access.");
process.exitCode = 1;
@@ -263,6 +294,7 @@ async function startControl() {
tlsCa,
controlConfig.get("control.controller_token")!,
);
let control = new Control(controlConnector, controlConfig, tlsCa, ctlPlugins);
try {
await controlConnector.connect();
@@ -284,6 +316,7 @@ async function startControl() {
});
try {
const targetCommand = selectTargetCommand(args, rootCommands);
await targetCommand.run(args, control);
} catch (err) {
-1
View File
@@ -26,7 +26,6 @@ describe("global_chat plugin", function() {
let instancePlugin;
before(async function() {
lib.Link.register(ChatEvent);
instancePlugin = new instance.InstancePlugin(info, new mock.MockInstance(), new mock.MockHost());
await instancePlugin.init();
});
+49 -48
View File
@@ -13,7 +13,8 @@ const { wait } = lib;
const testStrings = require("../lib/factorio/test_strings");
const {
TestControl, TestControlConnector, url, controlToken, slowTest,
exec, execCtl, sendRcon, getControl, spawnNode, instancesDir, factorioDir,
exec, execCtl, execCtlProcess, execHost, sendRcon, getControl,
spawnNode, instancesDir, factorioDir,
} = require("./index");
@@ -39,11 +40,11 @@ async function startAltHost() {
await fs.remove(path.join("temp", "test", "alt-instances"));
await fs.remove(path.join("temp", "test", "alt-mods"));
await execCtl(`host create-config --id 5 --name alt-host --generate-token --output ${config}`);
await exec(`node ../../packages/host --config ${config} config set host.tls_ca ../../test/file/tls/cert.pem`);
await exec(`node ../../packages/host --config ${config} config set host.instances_directory alt-instances`);
await execHost(`--config ${config} config set host.tls_ca ../../test/file/tls/cert.pem`);
await execHost(`--config ${config} config set host.instances_directory alt-instances`);
const dir = path.isAbsolute(factorioDir) ? factorioDir : path.join("..", "..", factorioDir);
await exec(`node ../../packages/host --config ${config} config set host.factorio_directory ${dir}`);
await exec(`node ../../packages/host --config ${config} config set host.mods_directory alt-mods`);
await execHost(`--config ${config} config set host.factorio_directory ${dir}`);
await execHost(`--config ${config} config set host.mods_directory alt-mods`);
return await spawnAltHost(config);
}
@@ -259,9 +260,9 @@ describe("Integration of Clusterio", function() {
describe("controller config set", function() {
it("sets given config option", async function() {
await execCtl('controller config set controller.name "Test Cluster"');
await execCtl("controller config set controller.name Test-Cluster");
let result = await getControl().send(new lib.ControllerConfigGetRequest());
assert.equal(result["controller.name"], "Test Cluster");
assert.equal(result["controller.name"], "Test-Cluster");
});
it("should not allow setting auth_secret", async function() {
await assert.rejects(execCtl("controller config set controller.auth_secret root"));
@@ -277,9 +278,9 @@ describe("Integration of Clusterio", function() {
describe("controller plugin update", function() {
it("runs", async function() {
// In dev plugins have no npm package, so best we can do is get an error from the controller
assert.rejects(
await assert.rejects(
execCtl("controller plugin update foo"),
"Plugin foo is not installed on this machine"
/Plugin foo is not installed on this machine/
);
});
// Update always fails, we can not test restart option
@@ -289,9 +290,9 @@ describe("Integration of Clusterio", function() {
it("runs", async function() {
// Default is to disallow updates, changing this value would require a restart
// Additionally, it can not be changed via ctl, so best we can do is get an error from the controller
assert.rejects(
await assert.rejects(
execCtl("controller plugin install foo"),
"Plugin installs are disabled on this machine"
/Plugin installs are disabled on this machine/
);
});
// Install always fails, we can not test restart option
@@ -303,9 +304,9 @@ describe("Integration of Clusterio", function() {
});
it("accepts --restart", async function() {
// We cannot restart the controller, so we check for controller error instead
assert.rejects(
await assert.rejects(
execCtl("controller update --restart"),
"Cannot restart, controller does not have a process monitor to restart it."
/Cannot restart, controller does not have a process monitor to restart it./
);
});
});
@@ -313,9 +314,9 @@ describe("Integration of Clusterio", function() {
describe("controller restart", function() {
it("runs", async function() {
// We cannot restart the controller, so we check for controller error instead
assert.rejects(
await assert.rejects(
execCtl("controller restart"),
"Cannot restart, controller does not have a process monitor to restart it."
/Cannot restart, controller does not have a process monitor to restart it./
);
});
});
@@ -329,7 +330,7 @@ describe("Integration of Clusterio", function() {
describe("host config", function() {
it("changes host config", async function() {
await execCtl("host config set 4 host.name My-Host");
const result = await execCtl("host config list 4");
const result = await execCtlProcess("host config list 4");
assert(/My-Host/.test(result.stdout), "New host name not in config output");
});
it("should not allow setting host.controller_token", async function() {
@@ -359,9 +360,9 @@ describe("Integration of Clusterio", function() {
describe("host plugin update", function() {
it("runs", async function() {
// In dev plugins have no npm package, so best we can do is get an error from the host
assert.rejects(
await assert.rejects(
execCtl("host plugin update 4 foo"),
"Plugin foo is not installed on this machine"
/Plugin foo is not installed on this machine/
);
});
// Update always fails, we can not test restart option
@@ -371,9 +372,9 @@ describe("Integration of Clusterio", function() {
it("runs", async function() {
// Default is to disallow updates, changing this value would require a restart
// Additionally, it can not be changed via ctl, so best we can do is get an error from the host
assert.rejects(
await assert.rejects(
execCtl("host plugin install 4 foo"),
"Plugin installs are disabled on this machine"
/Plugin installs are disabled on this machine/
);
});
// Install always fails, we can not test restart option
@@ -385,9 +386,9 @@ describe("Integration of Clusterio", function() {
});
it("accepts --restart", async function() {
// We cannot restart the host, so we check for host error instead
assert.rejects(
await assert.rejects(
execCtl("host update 4 --restart"),
"Cannot restart, host does not have a process monitor to restart it."
/Cannot restart, host does not have a process monitor to restart it./
);
});
});
@@ -395,9 +396,9 @@ describe("Integration of Clusterio", function() {
describe("host restart", function() {
it("runs", async function() {
// We cannot restart the host, so we check for host error instead
assert.rejects(
await assert.rejects(
execCtl("host restart 4"),
"Cannot restart, host does not have a process monitor to restart it."
/Cannot restart, host does not have a process monitor to restart it./
);
});
});
@@ -416,9 +417,12 @@ describe("Integration of Clusterio", function() {
slowTest(this);
let sawDisconnected;
await runWithAltHost(async () => {
getControl().hostUpdates = [];
const control = getControl();
control.hostUpdates = [];
await wait(50); // Allow for host to update instances
await execCtl("host revoke-token 5");
for (let update of getControl().hostUpdates) {
await wait(50); // Allow controller to notify control
for (let update of control.hostUpdates) {
if (update.name !== "alt-host") {
continue;
}
@@ -448,10 +452,8 @@ describe("Integration of Clusterio", function() {
assert.equal(instances.get(44).status, "unassigned", "incorrect instance status");
// Make sure the following tests does not fail due to not having internet
let value = JSON.stringify({ lan: true, public: false }).replace(
/"/g, process.platform === "win32" ? '""' : '\\"'
);
await execCtl(`instance config set-prop test factorio.settings visibility "${value}"`);
const value = jsonArg({ lan: true, public: false });
await execCtlProcess(`instance config set-prop test factorio.settings visibility ${value}`);
await execCtl("instance config set-prop test factorio.settings require_user_verification false");
});
it("can clone an instance", async function() {
@@ -466,7 +468,7 @@ describe("Integration of Clusterio", function() {
});
it("errors when cloning an invalid instance", async function() {
slowTest(this);
assert.rejects(
await assert.rejects(
execCtl("instance create testClone --id 440 --from 441"),
new lib.RequestError("Instance with ID 441 does not exist")
);
@@ -500,7 +502,7 @@ describe("Integration of Clusterio", function() {
describe("instance save list", function() {
it("lists the created save", async function() {
slowTest(this);
let result = await execCtl("instance save list test");
let result = await execCtlProcess("instance save list test");
assert(/world\.zip/.test(result.stdout), "world.zip not present in list save output");
});
});
@@ -615,7 +617,7 @@ describe("Integration of Clusterio", function() {
assert(r1.log.some(info => /\[COMMAND\]/.test(info.message)), "Command was not sent");
await execCtl("instance config set test factorio.enable_script_commands false");
assert.rejects(
await assert.rejects(
execCtl("instance send-rcon test /c"),
new Error(
"Attempted to use script command while disabled. " +
@@ -698,8 +700,8 @@ describe("Integration of Clusterio", function() {
];
for (let [prop, value] of testConfigs) {
let args = `test factorio.settings ${prop} ${jsonArg(value)}`;
await execCtl(`instance config set-prop ${args}`);
const args = `test factorio.settings ${prop} ${jsonArg(value)}`;
await execCtlProcess(`instance config set-prop ${args}`);
}
// Do this afterwards to leave enough to time for the
@@ -909,6 +911,7 @@ describe("Integration of Clusterio", function() {
await execCtl("instance config set 44 research_sync.load_plugin false");
await execCtl("instance config set 44 statistics_exporter.load_plugin false");
await execCtl("instance config set 44 subspace_storage.load_plugin false");
await execCtl("instance config set 44 inventory_sync.load_plugin false");
await execCtl("instance start 44");
const instance = (await getInstances()).get(44);
@@ -1188,7 +1191,7 @@ describe("Integration of Clusterio", function() {
});
it("should allow setting all fields", async function() {
const color = { r: 1, g: 0, b: 1, a: 0 };
await execCtl(
await execCtlProcess(
"mod-pack create full-pack 0.17.59 " +
"--description Description " +
"--mods empty_mod:1.0.0 " +
@@ -1220,7 +1223,7 @@ describe("Integration of Clusterio", function() {
describe("mod-pack list", function() {
let result = null;
it("runs", async function() {
result = await execCtl("mod-pack list");
result = await execCtlProcess("mod-pack list");
});
it("contains defaults", function() {
assert(result !== null, "Failed to return a value");
@@ -1249,7 +1252,7 @@ describe("Integration of Clusterio", function() {
reference.settings["runtime-global"].set("MyDouble", { value: 12.25 });
reference.settings["runtime-per-user"].set("MyString", { value: "a-string" });
await execCtl(`mod-pack import ${reference.toModPackString()}`);
const result = await execCtl("mod-pack export imported-pack");
const result = await execCtlProcess("mod-pack export imported-pack");
const roundtrip = lib.ModPack.fromModPackString(result.stdout.trim());
roundtrip.id = reference.id;
assert.deepEqual(roundtrip, reference);
@@ -1308,7 +1311,7 @@ describe("Integration of Clusterio", function() {
describe("mod show", function() {
it("gives details of a mod", async function() {
let result = await execCtl("mod show empty_mod 1.0.0");
let result = await execCtlProcess("mod show empty_mod 1.0.0");
let hash = await lib.hashFile(path.join("temp", "test", "mods", "empty_mod_1.0.0.zip"));
let stat = await fs.stat(path.join("temp", "test", "mods", "empty_mod_1.0.0.zip"));
assert.equal(
@@ -1333,14 +1336,14 @@ describe("Integration of Clusterio", function() {
describe("mod list", function() {
it("shows the list of mods", async function() {
let result = await execCtl("mod list");
let result = await execCtlProcess("mod list");
assert(result.stdout.indexOf("empty_mod") !== -1, "empty_mod is not in the list");
});
});
describe("mod search", function() {
it("searches the list of mods", async function() {
let result = await execCtl("mod search 1.1 name:empty_mod");
let result = await execCtlProcess("mod search 1.1 name:empty_mod");
assert(result.stdout.indexOf("empty_mod") !== -1, "empty_mod is not in the result");
});
});
@@ -1415,7 +1418,7 @@ describe("Integration of Clusterio", function() {
describe("role edit", function() {
it("should modify the given role", async function() {
let args = "--name new --description \"A new role\" --set-perms";
await execCtl(`role edit temp ${args}`);
await execCtlProcess(`role edit temp ${args}`);
let roles = await getControl().send(new lib.RoleListRequest());
let newRole = roles.find(role => role.name === "new");
if (newRole) { newRole.updatedAtMs = 0; }
@@ -1497,7 +1500,7 @@ describe("Integration of Clusterio", function() {
describe("user set-roles", function() {
it("should set the roles on the user", async function() {
getControl().userUpdates = [];
await execCtl('user set-roles temp "Cluster Admin"');
await execCtlProcess('user set-roles temp "Cluster Admin"');
let users = await getControl().send(new lib.UserListRequest());
let tempUser = users.find(user => user.id === "temp");
assert.deepEqual(tempUser.roleIds, new Set([0]));
@@ -1505,7 +1508,7 @@ describe("Integration of Clusterio", function() {
});
it("should restrict actions based on roles", async function() {
await execCtl('user set-roles temp "Player"');
await execCtl("user set-roles temp Player");
let tempControl;
try {
let tlsCa = await fs.readFile("test/file/tls/cert.pem");
@@ -1650,7 +1653,7 @@ describe("Integration of Clusterio", function() {
);
});
it("should reject multiple provided options", async function() {
assert.rejects(execCtl("user import --bans --admins import-admins.json"));
await assert.rejects(execCtl("user import --bans --admins import-admins.json"));
});
});
@@ -1659,7 +1662,6 @@ describe("Integration of Clusterio", function() {
await execCtl("user create export_control");
});
it("should export users", async function() {
slowTest(this);
await execCtl("user set-admin export_user --create");
await execCtl("user set-whitelisted export_user");
await execCtl("user export --users user-export.json");
@@ -1671,7 +1673,6 @@ describe("Integration of Clusterio", function() {
});
});
it("should export bans", async function() {
slowTest(this);
await execCtl("user set-banned export_ban --create");
await execCtl("user set-banned export_ban_reason --create --reason banned");
await execCtl("user export --bans ban-export.json");
@@ -1781,7 +1782,7 @@ describe("Integration of Clusterio", function() {
assert(data.indexOf("restore_control") >= 0, "restore_control is missing");
});
it("should reject multiple provided options", async function() {
assert.rejects(execCtl("user restore --bans --admins restore-admins.json"));
await assert.rejects(execCtl("user restore --bans --admins restore-admins.json"));
});
});
});
+40 -11
View File
@@ -11,6 +11,8 @@ const events = require("events");
const lib = require("@clusterio/lib");
const { LineSplitter, ConsoleTransport, logger } = lib;
const { selectTargetCommand, initialize: initializeCtl } = require("@clusterio/ctl");
// Make sure permissions from plugins are loaded
require("../../plugins/global_chat/dist/node/index");
require("../../plugins/player_auth/dist/node/index");
@@ -84,6 +86,10 @@ class TestControl extends lib.Link {
async handleUserUpdatesEvent(event) {
this.userUpdates.push(...event.updates);
}
async setLogSubscriptions(args) {
// Do nothing
}
}
class TestControlConnector extends lib.WebSocketClientConnector {
@@ -185,11 +191,27 @@ async function execHost(...args) {
return await exec(...args);
}
async function execCtl(...args) {
async function execCtlProcess(...args) {
args[0] = `node --enable-source-maps ../../packages/ctl ${args[0]}`;
return await exec(...args);
}
async function execCtl(command) {
process.chdir("temp/test");
try {
const initArgs = await initializeCtl(command, control.plugins, true);
if (!initArgs.shouldRun) {
return;
}
control.config = initArgs.controlConfig;
const targetCommand = selectTargetCommand(initArgs.args, initArgs.rootCommands);
await targetCommand.run(initArgs.args, control);
} finally {
process.chdir("../..");
}
}
async function sendRcon(instanceId, command) {
return await control.sendTo({ instanceId }, new lib.InstanceSendRconRequest(command));
}
@@ -291,33 +313,38 @@ before(async function() {
await execController("config set controller.tls_private_key ../../test/file/tls/key.pem");
console.log("Setting Controller Plugins");
await execCtl("plugin add ../../plugins/global_chat");
await execCtl("plugin add ../../plugins/research_sync");
await execCtl("plugin add ../../plugins/statistics_exporter");
await execCtl("plugin add ../../plugins/subspace_storage");
await execCtl("plugin add ../../plugins/player_auth");
await execCtlProcess("plugin add ../../plugins/global_chat");
await execCtlProcess("plugin add ../../plugins/research_sync");
await execCtlProcess("plugin add ../../plugins/statistics_exporter");
await execCtlProcess("plugin add ../../plugins/subspace_storage");
await execCtlProcess("plugin add ../../plugins/inventory_sync");
await execCtlProcess("plugin add ../../plugins/player_auth");
console.log("Bootstrapping");
await execController("bootstrap create-admin test");
await execController("bootstrap create-ctl-config test");
await execCtl("control-config set control.tls_ca ../../test/file/tls/cert.pem");
await execCtlProcess("control-config set control.tls_ca ../../test/file/tls/cert.pem");
controllerProcess = await spawnNode("controller:", "../../packages/controller run", /Started controller/);
await execCtl("host create-config --id 4 --name host --generate-token");
const relativeFactorioDir = path.isAbsolute(factorioDir) ? factorioDir : path.join("..", "..", factorioDir);
await execCtlProcess("host create-config --id 4 --name host --generate-token");
await execHost(`config set host.factorio_directory ${relativeFactorioDir}`);
await execHost("config set host.tls_ca ../../test/file/tls/cert.pem");
hostProcess = await spawnNode("host:", "../../packages/host run", /Started host/);
let tlsCa = await fs.readFile("test/file/tls/cert.pem");
let controlConnector = new TestControlConnector(url, 2, tlsCa);
const tlsCa = await fs.readFile("test/file/tls/cert.pem");
const controlConnector = new TestControlConnector(url, 2, tlsCa);
controlConnector.token = controlToken;
control = new TestControl(controlConnector);
await controlConnector.connect();
const initArgs = await initializeCtl(`--plugin-list ${pluginListPath} control-config list`, undefined, true);
control.config = initArgs.controlConfig;
control.plugins = initArgs.ctlPlugins;
control.tlsCa = tlsCa;
const testPack = lib.ModPack.fromJSON({});
testPack.id = 12;
testPack.name = "subspace_storage-pack";
@@ -358,10 +385,12 @@ module.exports = {
TestControl,
TestControlConnector,
TestHostConnector,
execCtlProcess,
slowTest,
get,
exec,
execCtl,
execHost,
sendRcon,
getControl,
spawn,
+6 -6
View File
@@ -3,7 +3,7 @@ const assert = require("assert").strict;
const lib = require("@clusterio/lib");
const {
slowTest, exec, execCtl, sendRcon, getControl,
slowTest, exec, execCtl, execCtlProcess, sendRcon, getControl,
} = require("./index");
const instId = 48;
@@ -31,12 +31,12 @@ describe("Clusterio Instance", function() {
// Create a new instance
await execCtl(`instance create ${instName} --id ${instId}`);
await execCtl(`instance config set ${instName} factorio.enable_whitelist true`);
await execCtl(`instance config set-prop ${instName} factorio.settings visibility "${visibility}"`);
await execCtlProcess(`instance config set-prop ${instName} factorio.settings visibility "${visibility}"`);
await execCtl(`instance config set-prop ${instName} factorio.settings require_user_verification false`);
await execCtl(`instance assign ${instName} 4`);
for (const plugin of [
"global_chat", "research_sync", "statistics_exporter", "subspace_storage", "player_auth",
"global_chat", "research_sync", "statistics_exporter", "subspace_storage", "player_auth", "inventory_sync",
]) {
await execCtl(`instance config set ${instName} ${plugin}.load_plugin false`);
}
@@ -44,7 +44,7 @@ describe("Clusterio Instance", function() {
// Create a new alt instance
await execCtl(`instance create ${instAltName} --id ${instAltId}`);
await execCtl(`instance config set ${instAltName} factorio.enable_whitelist true`);
await execCtl(`instance config set-prop ${instAltName} factorio.settings visibility "${visibility}"`);
await execCtlProcess(`instance config set-prop ${instAltName} factorio.settings visibility "${visibility}"`);
await execCtl(`instance config set-prop ${instAltName} factorio.settings require_user_verification false`);
await execCtl(`instance assign ${instAltName} 4`);
await execCtl(`instance start ${instAltName}`);
@@ -75,12 +75,12 @@ describe("Clusterio Instance", function() {
if (savePatchingEnabled) {
// IPC expects save patching to be enabled
it("should do nothing for an unknown type", async function() {
assert.rejects(getUser("DoesNotExist"), "User should not exist");
await assert.rejects(getUser("DoesNotExist"), "User should not exist");
await sendRcon(instId,
`/sc ${requireApi} api.send_json("player_event",` +
"{ type='invalid type', name='DoesNotExist' })"
);
assert.rejects(getUser("DoesNotExist"), "User was created");
await assert.rejects(getUser("DoesNotExist"), "User was created");
});
it("should respond to a player join and leave event", async function() {
await sendRcon(instId,
+5 -21
View File
@@ -201,32 +201,16 @@ describe("lib/config/classes", function() {
const filepath = path.join("temp", "test", "config_test.json");
it("should throw for file and json errors", async function() {
await fs.writeFile(filepath, "abc");
assert.rejects(
TestConfig.fromFile("local", filepath),
new Error(
`${filepath}: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data`
)
);
assert.rejects(
TestConfig.fromFile("local", `${filepath}.notExist`),
);
await assert.rejects(TestConfig.fromFile("local", filepath));
await assert.rejects(TestConfig.fromFile("local", `${filepath}.notExist`));
});
it("should throw on incorrect input passed", async function() {
await fs.writeFile(filepath, "null");
await assert.rejects(
TestConfig.fromFile("local", filepath),
new Error("Invalid config")
);
await assert.rejects(TestConfig.fromFile("local", filepath));
await fs.writeFile(filepath, "undefined");
assert.rejects(
TestConfig.fromFile("local", filepath),
new Error("Invalid config")
);
await assert.rejects(TestConfig.fromFile("local", filepath));
await fs.writeFile(filepath, "[]");
assert.rejects(
TestConfig.fromFile("local", filepath),
new Error("Invalid config")
);
await assert.rejects(TestConfig.fromFile("local", filepath));
});
it("should load defaults for missing fields", async function() {
await fs.writeJSON(filepath, {
+7 -7
View File
@@ -22,9 +22,9 @@ describe("rce_ops", function() {
await lib.handlePluginUpdate("foo", [{ npmPackage: "foo" }]);
});
it("rejects when plugin not installed", async function() {
assert.rejects(
await assert.rejects(
lib.handlePluginUpdate("foo", []),
"Plugin foo is not installed on this machine"
/Plugin foo is not installed on this machine/
);
});
});
@@ -50,16 +50,16 @@ describe("rce_ops", function() {
});
it("rejects when name too long", async function() {
const pluginName = "a".repeat(215);
assert.rejects(
await assert.rejects(
lib.handlePluginInstall(pluginName),
`Invalid plugin name: ${pluginName}`
{ message: `Invalid plugin name: ${pluginName}` }
);
});
it("rejects when invalid symbol present", async function() {
const pluginName = "?";
assert.rejects(
await assert.rejects(
lib.handlePluginInstall(pluginName),
`Invalid plugin name: ${pluginName}`
{ message: `Invalid plugin name: ${pluginName}` },
);
});
it("rejects unregistered packages", async function() {
@@ -69,7 +69,7 @@ describe("rce_ops", function() {
return { ok: false };
};
assert.rejects(lib.handlePluginInstall("foo"), "Unknown plugin: foo");
await assert.rejects(lib.handlePluginInstall("foo"), /Unknown plugin: foo/);
assert.equal(calledWith, "https://registry.npmjs.com/foo");
});
});
+6 -6
View File
@@ -240,20 +240,20 @@ describe("lib/subscriptions", function() {
subscriptions.handle(RegisteredEvent);
});
it("should not accept subscriptions to unregistered events", function() {
it("should not accept subscriptions to unregistered events", async function() {
const request = new lib.SubscriptionRequest(RegisteredEvent.name, true);
request.eventName = UnregisteredEvent.name;
assert.rejects(
await assert.rejects(
subscriptions.handleRequest(getLink(0), request, addr({ controlId: 0 }), addr("controller")),
new Error(`Unregistered Event class ${UnregisteredEvent.name}`)
new Error(`Event ${UnregisteredEvent.name} is not a registered event`)
);
});
it("should not accept subscriptions to events not handled by the class", function() {
it("should not accept subscriptions to events not handled by the class", async function() {
const request = new lib.SubscriptionRequest(RegisteredEvent.name, true);
request.eventName = StringPermissionEvent.name;
assert.rejects(
await assert.rejects(
subscriptions.handleRequest(getLink(0), request, addr({ controlId: 0 }), addr("controller")),
new Error(`Event ${StringPermissionEvent.eventName} is not a registered as subscribable`)
new Error(`Event ${StringPermissionEvent.name} is not a registered as subscribable`)
);
});
it("should accept a subscription", async function() {
+2 -2
View File
@@ -28,9 +28,9 @@ describe("messages/controller", function() {
});
it("rejects if updates are disabled", async function() {
controller.config.set("controller.allow_remote_updates", false);
assert.rejects(
await assert.rejects(
controlConnection.handleControllerUpdateRequest(new lib.ControllerUpdateRequest()),
"Remote updates are disabled on this machine"
/Remote updates are disabled on this machine/
);
});
});
+2 -2
View File
@@ -24,9 +24,9 @@ describe("messages/controller", function() {
});
it("rejects if updates are disabled", async function() {
host.config.set("host.allow_remote_updates", false);
assert.rejects(
await assert.rejects(
host.handleHostUpdateRequest(new lib.HostUpdateRequest()),
"Remote updates are disabled on this machine"
/Remote updates are disabled on this machine/
);
});
});
+10 -10
View File
@@ -115,9 +115,9 @@ describe("messages/plugin", function() {
});
it("rejects if updates are disabled on the controller", async function() {
controller.config.set("controller.allow_plugin_updates", false);
assert.rejects(
await assert.rejects(
controlConnection.handlePluginUpdateRequest(new lib.PluginUpdateRequest("foo")),
"Plugin updates are disabled on this machine"
/Plugin updates are disabled on this machine/
);
});
it("runs on a host", async function() {
@@ -127,9 +127,9 @@ describe("messages/plugin", function() {
});
it("rejects if updates are disabled on the host", async function() {
host.config.set("host.allow_plugin_updates", false);
assert.rejects(
await assert.rejects(
host.handlePluginUpdateRequest(new lib.PluginUpdateRequest("foo")),
"Plugin updates are disabled on this machine"
/Plugin updates are disabled on this machine/
);
});
});
@@ -154,22 +154,22 @@ describe("messages/plugin", function() {
controller.config.set("controller.allow_plugin_install", true);
await controlConnection.handlePluginInstallRequest(new lib.PluginInstallRequest("foo"));
});
it("rejects if updates are disabled on the controller", async function() {
it("rejects if installs are disabled on the controller", async function() {
controller.config.set("controller.allow_plugin_install", false);
assert.rejects(
await assert.rejects(
controlConnection.handlePluginInstallRequest(new lib.PluginInstallRequest("foo")),
"Plugin updates are disabled on this machine"
/Plugin installs are disabled on this machine/
);
});
it("runs on a host", async function() {
host.config.set("host.allow_plugin_install", true);
await host.handlePluginInstallRequest(new lib.PluginInstallRequest("foo"));
});
it("rejects if updates are disabled on the host", async function() {
it("rejects if installs are disabled on the host", async function() {
host.config.set("host.allow_plugin_install", false);
assert.rejects(
await assert.rejects(
host.handlePluginInstallRequest(new lib.PluginInstallRequest("foo")),
"Plugin updates are disabled on this machine"
/Plugin installs are disabled on this machine/
);
});
});
-1
View File
@@ -218,7 +218,6 @@ class MockController {
}
async function createControllerPlugin(ControllerPluginClass, info) {
lib.registerPluginMessages([info]);
let controller = new MockController();
let metrics = {};
let logger = new MockLogger();