mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 23:24:52 +09:00
Flatten lib namespace
Move all functions and classes currently available through lib/name and libName to be under a single flat namespace in lib. This make reorganising the lib namespace much simpler as the location of symbols can move without breaking the consumers of lib. The multi-entrypoint design was already problematic for the web plugin system which couldn't effectively use it due to how webpack's shared module system is awkward to set up with multiple entrypoints per package.
This commit is contained in:
1 parent
bb58670597
commit
bfe119eaa3
143 files changed
+1798
-1918
No files matched your search
@@ -7,7 +7,6 @@ const util = require("util");
|
||||
|
||||
const phin = require("phin");
|
||||
|
||||
const { wait } = require("@clusterio/lib/helpers");
|
||||
const HttpCloser = require("@clusterio/controller/src/HttpCloser");
|
||||
|
||||
// Time to wait during async operations to ensure they happened in order.
|
||||
|
||||
@@ -6,7 +6,7 @@ const jwt = require("jsonwebtoken");
|
||||
const http = require("http");
|
||||
const phin = require("phin");
|
||||
|
||||
const { wait } = require("@clusterio/lib/helpers");
|
||||
const { wait } = require("@clusterio/lib");
|
||||
const routes = require("@clusterio/controller/src/routes");
|
||||
const mock = require("../mock");
|
||||
|
||||
|
||||
+13
-14
@@ -2,13 +2,12 @@
|
||||
const assert = require("assert").strict;
|
||||
const path = require("path");
|
||||
|
||||
const libConfig = require("@clusterio/lib/config");
|
||||
const libData = require("@clusterio/lib/data");
|
||||
const lib = require("@clusterio/lib");
|
||||
const Host = require("@clusterio/host/src/Host");
|
||||
|
||||
describe("Host testing", function() {
|
||||
before(function() {
|
||||
libConfig.InstanceConfig.finalize();
|
||||
lib.InstanceConfig.finalize();
|
||||
});
|
||||
|
||||
describe("discoverInstances()", function() {
|
||||
@@ -16,7 +15,7 @@ describe("Host testing", function() {
|
||||
let instancePath = path.join("test", "file", "instances");
|
||||
let instanceInfos = await Host._discoverInstances(instancePath);
|
||||
|
||||
let referenceConfig = new libConfig.InstanceConfig("host");
|
||||
let referenceConfig = new lib.InstanceConfig("host");
|
||||
await referenceConfig.init();
|
||||
referenceConfig.set("instance.id", 1);
|
||||
referenceConfig.set("instance.name", "test");
|
||||
@@ -45,7 +44,7 @@ describe("Host testing", function() {
|
||||
handleSyncUserListsEvent: Host.prototype.handleSyncUserListsEvent,
|
||||
syncLists(adminlist, banlist, whitelist) {
|
||||
return this.handleSyncUserListsEvent(
|
||||
new libData.SyncUserListsEvent(adminlist, banlist, whitelist)
|
||||
new lib.SyncUserListsEvent(adminlist, banlist, whitelist)
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -56,8 +55,8 @@ describe("Host testing", function() {
|
||||
await mockHost.syncLists(["admin1", "admin2"], [], []);
|
||||
|
||||
assert.deepEqual(mockHost.broadcasts, [
|
||||
new libData.InstanceAdminlistUpdateEvent("admin1", true),
|
||||
new libData.InstanceAdminlistUpdateEvent("admin2", true),
|
||||
new lib.InstanceAdminlistUpdateEvent("admin1", true),
|
||||
new lib.InstanceAdminlistUpdateEvent("admin2", true),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -65,7 +64,7 @@ describe("Host testing", function() {
|
||||
mockHost.adminlist.add("admin1").add("admin2");
|
||||
await mockHost.syncLists(["admin1"], [], []);
|
||||
assert.deepEqual(mockHost.broadcasts, [
|
||||
new libData.InstanceAdminlistUpdateEvent("admin2", false),
|
||||
new lib.InstanceAdminlistUpdateEvent("admin2", false),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -74,8 +73,8 @@ describe("Host testing", function() {
|
||||
await mockHost.syncLists([], [], ["player1", "player2"]);
|
||||
|
||||
assert.deepEqual(mockHost.broadcasts, [
|
||||
new libData.InstanceWhitelistUpdateEvent("player1", true),
|
||||
new libData.InstanceWhitelistUpdateEvent("player2", true),
|
||||
new lib.InstanceWhitelistUpdateEvent("player1", true),
|
||||
new lib.InstanceWhitelistUpdateEvent("player2", true),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -84,7 +83,7 @@ describe("Host testing", function() {
|
||||
await mockHost.syncLists([], [], ["player1"]);
|
||||
|
||||
assert.deepEqual(mockHost.broadcasts, [
|
||||
new libData.InstanceWhitelistUpdateEvent("player2", false),
|
||||
new lib.InstanceWhitelistUpdateEvent("player2", false),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -93,8 +92,8 @@ describe("Host testing", function() {
|
||||
await mockHost.syncLists([], [["badie1", "greifing"], ["badie2", "annoying"]], []);
|
||||
|
||||
assert.deepEqual(mockHost.broadcasts, [
|
||||
new libData.InstanceBanlistUpdateEvent("badie1", true, "greifing"),
|
||||
new libData.InstanceBanlistUpdateEvent("badie2", true, "annoying"),
|
||||
new lib.InstanceBanlistUpdateEvent("badie1", true, "greifing"),
|
||||
new lib.InstanceBanlistUpdateEvent("badie2", true, "annoying"),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -103,7 +102,7 @@ describe("Host testing", function() {
|
||||
await mockHost.syncLists([], [["badie1", "greifing"]], []);
|
||||
|
||||
assert.deepEqual(mockHost.broadcasts, [
|
||||
new libData.InstanceBanlistUpdateEvent("badie2", false, ""),
|
||||
new lib.InstanceBanlistUpdateEvent("badie2", false, ""),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
+13
-15
@@ -2,19 +2,17 @@
|
||||
const assert = require("assert").strict;
|
||||
const path = require("path");
|
||||
|
||||
const libConfig = require("@clusterio/lib/config");
|
||||
const libData = require("@clusterio/lib/data");
|
||||
const { wait } = require("@clusterio/lib/helpers");
|
||||
const PlayerStats = require("@clusterio/lib/PlayerStats");
|
||||
const lib = require("@clusterio/lib");
|
||||
const { PlayerStats, wait } = lib;
|
||||
const Instance = require("@clusterio/host/src/Instance");
|
||||
const { MockConnector, MockServer } = require("../mock");
|
||||
|
||||
const addr = libData.Address.fromShorthand;
|
||||
const addr = lib.Address.fromShorthand;
|
||||
|
||||
|
||||
describe("class Instance", function() {
|
||||
before(function() {
|
||||
libConfig.InstanceConfig.finalize();
|
||||
lib.InstanceConfig.finalize();
|
||||
});
|
||||
|
||||
let src;
|
||||
@@ -22,7 +20,7 @@ describe("class Instance", function() {
|
||||
let instance;
|
||||
let connector;
|
||||
beforeEach(async function() {
|
||||
let instanceConfig = new libConfig.InstanceConfig("host");
|
||||
let instanceConfig = new lib.InstanceConfig("host");
|
||||
await instanceConfig.init();
|
||||
instanceConfig.set("instance.name", "foo");
|
||||
src = addr({ instanceId: instanceConfig.get("instance.id") });
|
||||
@@ -64,9 +62,9 @@ describe("class Instance", function() {
|
||||
let stats = instance.playerStats.get("player");
|
||||
assert.deepEqual(
|
||||
connector.sentMessages[0],
|
||||
new libData.MessageEvent(
|
||||
new lib.MessageEvent(
|
||||
1, src, addr("controller"), "InstancePlayerUpdateEvent",
|
||||
new libData.InstancePlayerUpdateEvent(
|
||||
new lib.InstancePlayerUpdateEvent(
|
||||
"join", "player", undefined,
|
||||
new PlayerStats({
|
||||
join_count: 1,
|
||||
@@ -109,9 +107,9 @@ describe("class Instance", function() {
|
||||
let stats = instance.playerStats.get("player");
|
||||
assert.deepEqual(
|
||||
connector.sentMessages[1],
|
||||
new libData.MessageEvent(
|
||||
new lib.MessageEvent(
|
||||
2, src, addr("controller"), "InstancePlayerUpdateEvent",
|
||||
new libData.InstancePlayerUpdateEvent(
|
||||
new lib.InstancePlayerUpdateEvent(
|
||||
"leave", "player", "quit",
|
||||
new PlayerStats({
|
||||
join_count: 1,
|
||||
@@ -159,9 +157,9 @@ describe("class Instance", function() {
|
||||
let stats = instance.playerStats.get("foo");
|
||||
assert.deepEqual(
|
||||
connector.sentMessages[1],
|
||||
new libData.MessageEvent(
|
||||
new lib.MessageEvent(
|
||||
2, src, addr("controller"), "InstancePlayerUpdateEvent",
|
||||
new libData.InstancePlayerUpdateEvent(
|
||||
new lib.InstancePlayerUpdateEvent(
|
||||
"join", "foo", undefined,
|
||||
new PlayerStats({
|
||||
join_count: 1,
|
||||
@@ -180,9 +178,9 @@ describe("class Instance", function() {
|
||||
let stats = instance.playerStats.get("player");
|
||||
assert.deepEqual(
|
||||
connector.sentMessages[1],
|
||||
new libData.MessageEvent(
|
||||
new lib.MessageEvent(
|
||||
2, src, addr("controller"), "InstancePlayerUpdateEvent",
|
||||
new libData.InstancePlayerUpdateEvent(
|
||||
new lib.InstancePlayerUpdateEvent(
|
||||
"leave", "player", "quit",
|
||||
new PlayerStats({
|
||||
join_count: 1,
|
||||
|
||||
@@ -6,12 +6,9 @@ const path = require("path");
|
||||
const events = require("events");
|
||||
const phin = require("phin");
|
||||
|
||||
const lib = require("@clusterio/lib");
|
||||
const libBuildMod = require("@clusterio/lib/build_mod");
|
||||
const libData = require("@clusterio/lib/data");
|
||||
const libHash = require("@clusterio/lib/hash");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libUsers = require("@clusterio/lib/users");
|
||||
const { wait } = require("@clusterio/lib/helpers");
|
||||
const { wait } = lib;
|
||||
|
||||
const testStrings = require("../lib/factorio/test_strings");
|
||||
const {
|
||||
@@ -21,7 +18,7 @@ const {
|
||||
|
||||
|
||||
async function getInstances() {
|
||||
let instances = await getControl().send(new libData.InstanceDetailsListRequest());
|
||||
let instances = await getControl().send(new lib.InstanceDetailsListRequest());
|
||||
return new Map(instances.map(instance => [instance.id, instance]));
|
||||
}
|
||||
|
||||
@@ -45,11 +42,11 @@ async function uploadSave(instanceId, name, content) {
|
||||
}
|
||||
|
||||
async function deleteSave(instanceId, save) {
|
||||
await getControl().send(new libData.InstanceDeleteSaveRequest(instanceId, save));
|
||||
await getControl().send(new lib.InstanceDeleteSaveRequest(instanceId, save));
|
||||
}
|
||||
|
||||
async function getUsers() {
|
||||
let users = await getControl().send(new libData.UserListRequest());
|
||||
let users = await getControl().send(new lib.UserListRequest());
|
||||
return new Map(users.map(user => [user.name, user]));
|
||||
}
|
||||
|
||||
@@ -95,12 +92,12 @@ describe("Integration of Clusterio", function() {
|
||||
|
||||
describe("queryLogRequestHandler", function() {
|
||||
it("should honnor the limit", async function() {
|
||||
let result = await getControl().send(new libData.LogQueryRequest(true, false, [], [], null, 10, "asc"));
|
||||
let result = await getControl().send(new lib.LogQueryRequest(true, false, [], [], null, 10, "asc"));
|
||||
assert.equal(result.log.length, 10);
|
||||
});
|
||||
it("should return entries by order", async function() {
|
||||
let first = await getControl().send(new libData.LogQueryRequest(true, false, [], [], null, 1, "asc"));
|
||||
let last = await getControl().send(new libData.LogQueryRequest(true, false, [], [], null, 1, "desc"));
|
||||
let first = await getControl().send(new lib.LogQueryRequest(true, false, [], [], null, 1, "asc"));
|
||||
let last = await getControl().send(new lib.LogQueryRequest(true, false, [], [], null, 1, "desc"));
|
||||
assert(first.log[0].timestamp < last.log[0].timestamp, "first log entry happened after last");
|
||||
});
|
||||
});
|
||||
@@ -165,7 +162,7 @@ describe("Integration of Clusterio", function() {
|
||||
assert(sawConnected, "No host update with status connected was sent");
|
||||
assert(sawDisconnected, "No host update with status disconnected was sent");
|
||||
|
||||
let result = await getControl().send(new libData.HostListRequest());
|
||||
let result = await getControl().send(new lib.HostListRequest());
|
||||
let hosts = new Map(result.map(instance => [instance.id, instance]));
|
||||
assert(hosts.has(5), "Host list was not updated");
|
||||
});
|
||||
@@ -178,7 +175,7 @@ describe("Integration of Clusterio", function() {
|
||||
await execCtl("controller config list");
|
||||
});
|
||||
it("should not leak auth_secret", async function() {
|
||||
let result = await getControl().send(new libData.ControllerConfigGetRequest());
|
||||
let result = await getControl().send(new lib.ControllerConfigGetRequest());
|
||||
let done = false;
|
||||
for (let group of result.serializedConfig.groups) {
|
||||
if (group.name === "controller") {
|
||||
@@ -193,7 +190,7 @@ 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"');
|
||||
let result = await getControl().send(new libData.ControllerConfigGetRequest());
|
||||
let result = await getControl().send(new lib.ControllerConfigGetRequest());
|
||||
let done = false;
|
||||
for (let group of result.serializedConfig.groups) {
|
||||
if (group.name === "controller") {
|
||||
@@ -289,7 +286,7 @@ describe("Integration of Clusterio", function() {
|
||||
let exportPath = path.join("temp", "test", "static");
|
||||
await fs.remove(exportPath);
|
||||
await execCtl("instance export-data test");
|
||||
let modPack = await getControl().send(new libData.ModPackGetDefaultRequest());
|
||||
let modPack = await getControl().send(new lib.ModPackGetDefaultRequest());
|
||||
let assets = modPack.exportManifest.assets;
|
||||
assert(Object.keys(assets).length > 1, "Export assets is empty");
|
||||
for (let key of ["settings", "prototypes", "item-metadata", "item-spritesheet", "locale"]) {
|
||||
@@ -338,7 +335,7 @@ describe("Integration of Clusterio", function() {
|
||||
let savesDir = path.join("temp", "test", "instances", "test", "saves");
|
||||
await fs.copy(path.join(savesDir, "world.zip"), path.join(savesDir, "_autosave1.zip"));
|
||||
await execCtl("instance start test");
|
||||
let saves = await getControl().sendTo({ instanceId: 44 }, new libData.InstanceListSavesRequest());
|
||||
let saves = await getControl().sendTo({ instanceId: 44 }, new lib.InstanceListSavesRequest());
|
||||
let running = saves.find(s => s.loaded);
|
||||
assert(running.name !== "_autosave1.zip");
|
||||
});
|
||||
@@ -349,7 +346,7 @@ describe("Integration of Clusterio", function() {
|
||||
slowTest(this);
|
||||
await execCtl("instance send-rcon test technobabble");
|
||||
let { log } = await getControl().send(
|
||||
new libData.LogQueryRequest(false, false, [], [44], null, 10, "desc")
|
||||
new lib.LogQueryRequest(false, false, [], [44], null, 10, "desc")
|
||||
);
|
||||
assert(log.some(info => /technobabble/.test(info.message)), "Command was not sent");
|
||||
});
|
||||
@@ -461,14 +458,14 @@ describe("Integration of Clusterio", function() {
|
||||
|
||||
describe("user set-admin/whitelisted/banned", function() {
|
||||
async function getUser(name) {
|
||||
return await getControl().send(new libData.UserGetRequest(name));
|
||||
return await getControl().send(new lib.UserGetRequest(name));
|
||||
}
|
||||
|
||||
let lists = [["admin", "isAdmin"], ["whitelisted", "isWhitelisted"], ["banned", "isBanned"]];
|
||||
it("should add and remove the given user to the list", async function() {
|
||||
slowTest(this);
|
||||
getControl().userUpdates = [];
|
||||
await getControl().send(new libData.UserCreateRequest("list_test"));
|
||||
await getControl().send(new lib.UserCreateRequest("list_test"));
|
||||
let user = (await getUsers()).get("list_test");
|
||||
for (let [listName, prop] of lists) {
|
||||
assert.equal(user[prop], false, `unexpected ${listName} status`);
|
||||
@@ -806,7 +803,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("mod-pack create", function() {
|
||||
it("should create a mod-pack", async function() {
|
||||
await execCtl("mod-pack create empty-pack 1.1.0");
|
||||
let modPacks = await getControl().send(new libData.ModPackListRequest());
|
||||
let modPacks = await getControl().send(new lib.ModPackListRequest());
|
||||
assert(modPacks.some(modPack => modPack.name === "empty-pack"), "created pack is not in the list");
|
||||
});
|
||||
it("should allow setting all fields", async function() {
|
||||
@@ -819,10 +816,10 @@ describe("Integration of Clusterio", function() {
|
||||
"--double-setting runtime-global MyDouble 12.25 " +
|
||||
"--string-setting runtime-per-user MyString a-string"
|
||||
);
|
||||
let modPacks = await getControl().send(new libData.ModPackListRequest());
|
||||
let modPacks = await getControl().send(new lib.ModPackListRequest());
|
||||
let modPack = modPacks.find(entry => entry.name === "full-pack");
|
||||
assert(modPack, "created mod pack not found");
|
||||
let reference = libData.ModPack.fromJSON({});
|
||||
let reference = lib.ModPack.fromJSON({});
|
||||
reference.id = modPack.id;
|
||||
reference.name = "full-pack";
|
||||
reference.description = "Description";
|
||||
@@ -851,7 +848,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("mod-pack import/export", function() {
|
||||
it("should should roundtrip a mod-pack", async function() {
|
||||
slowTest(this);
|
||||
let reference = libData.ModPack.fromJSON({});
|
||||
let reference = lib.ModPack.fromJSON({});
|
||||
reference.name = "imported-pack";
|
||||
reference.description = "Description";
|
||||
reference.factorioVersion = "0.17.59";
|
||||
@@ -862,7 +859,7 @@ describe("Integration of Clusterio", function() {
|
||||
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 roundtrip = libData.ModPack.fromModPackString(result.stdout.trim());
|
||||
const roundtrip = lib.ModPack.fromModPackString(result.stdout.trim());
|
||||
roundtrip.id = reference.id;
|
||||
assert.deepEqual(roundtrip, reference);
|
||||
});
|
||||
@@ -871,7 +868,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("mod-pack edit", function() {
|
||||
it("runs", async function() {
|
||||
await execCtl("mod-pack edit full-pack --factorio-version 1.2.0");
|
||||
let modPacks = await getControl().send(new libData.ModPackListRequest());
|
||||
let modPacks = await getControl().send(new lib.ModPackListRequest());
|
||||
let modPack = modPacks.find(entry => entry.name === "full-pack");
|
||||
assert(modPack, "created mod pack not found");
|
||||
assert.equal(modPack.factorioVersion, "1.2.0");
|
||||
@@ -881,7 +878,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("mod-pack delete", function() {
|
||||
it("deletes the pack", async function() {
|
||||
await execCtl("mod-pack delete full-pack");
|
||||
let modPacks = await getControl().send(new libData.ModPackListRequest());
|
||||
let modPacks = await getControl().send(new lib.ModPackListRequest());
|
||||
let modPack = modPacks.find(entry => entry.name === "full-pack");
|
||||
assert(!modPack, "mod pack not deleted");
|
||||
});
|
||||
@@ -906,7 +903,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 hash = await libHash.hashFile(path.join("temp", "test", "mods", "empty_mod_1.0.0.zip"));
|
||||
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(
|
||||
result.stdout,
|
||||
@@ -997,11 +994,11 @@ describe("Integration of Clusterio", function() {
|
||||
it("should create the given role", async function() {
|
||||
let args = "--description \"A temp role\" --permissions core.control.connect";
|
||||
await execCtl(`role create temp ${args}`);
|
||||
let roles = await getControl().send(new libData.RoleListRequest());
|
||||
let roles = await getControl().send(new lib.RoleListRequest());
|
||||
let tempRole = roles.find(role => role.name === "temp");
|
||||
assert.deepEqual(
|
||||
tempRole,
|
||||
new libData.RawRole(5, "temp", "A temp role", ["core.control.connect"])
|
||||
new lib.RawRole(5, "temp", "A temp role", ["core.control.connect"])
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1010,29 +1007,29 @@ describe("Integration of Clusterio", 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}`);
|
||||
let roles = await getControl().send(new libData.RoleListRequest());
|
||||
let roles = await getControl().send(new lib.RoleListRequest());
|
||||
let newRole = roles.find(role => role.name === "new");
|
||||
assert.deepEqual(newRole, new libData.RawRole(5, "new", "A new role", []));
|
||||
assert.deepEqual(newRole, new lib.RawRole(5, "new", "A new role", []));
|
||||
});
|
||||
it("should add permissions with --add-perms", async function() {
|
||||
let args = "--name new --add-perms core.host.list core.instance.list";
|
||||
await execCtl(`role edit new ${args}`);
|
||||
let roles = await getControl().send(new libData.RoleListRequest());
|
||||
let roles = await getControl().send(new lib.RoleListRequest());
|
||||
let newRole = roles.find(role => role.name === "new");
|
||||
assert.deepEqual(newRole.permissions, ["core.host.list", "core.instance.list"]);
|
||||
});
|
||||
it("should remove permissions with --remove-perms", async function() {
|
||||
let args = "--name new --remove-perms core.host.list";
|
||||
await execCtl(`role edit new ${args}`);
|
||||
let roles = await getControl().send(new libData.RoleListRequest());
|
||||
let roles = await getControl().send(new lib.RoleListRequest());
|
||||
let newRole = roles.find(role => role.name === "new");
|
||||
assert.deepEqual(newRole.permissions, ["core.instance.list"]);
|
||||
});
|
||||
it("should grant default permissions with --grant-default", async function() {
|
||||
await execCtl("role edit new --grant-default");
|
||||
let roles = await getControl().send(new libData.RoleListRequest());
|
||||
let roles = await getControl().send(new lib.RoleListRequest());
|
||||
let newRole = roles.find(role => role.name === "new");
|
||||
let defaultPermissions = [...libUsers.permissions.values()]
|
||||
let defaultPermissions = [...lib.permissions.values()]
|
||||
.filter(p => p.grantByDefault)
|
||||
.map(p => p.name)
|
||||
;
|
||||
@@ -1043,7 +1040,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("role delete", function() {
|
||||
it("should delete the given role", async function() {
|
||||
await execCtl("role delete new");
|
||||
let roles = await getControl().send(new libData.RoleListRequest());
|
||||
let roles = await getControl().send(new lib.RoleListRequest());
|
||||
let newRole = roles.find(role => role.name === "new");
|
||||
assert(!newRole, "Role was not deleted");
|
||||
});
|
||||
@@ -1059,7 +1056,7 @@ describe("Integration of Clusterio", function() {
|
||||
it("should create the given user", async function() {
|
||||
getControl().userUpdates = [];
|
||||
await execCtl("user create temp");
|
||||
let users = await getControl().send(new libData.UserListRequest());
|
||||
let users = await getControl().send(new lib.UserListRequest());
|
||||
let tempUser = users.find(user => user.name === "temp");
|
||||
assert(tempUser, "user was not created");
|
||||
assert.equal(getControl().userUpdates.length, 1);
|
||||
@@ -1070,7 +1067,7 @@ describe("Integration of Clusterio", function() {
|
||||
describe("user revoke-token", function() {
|
||||
it("should kick existing sessions for the user", async function() {
|
||||
slowTest(this);
|
||||
await getControl().send(new libData.UserCreateRequest("revokee"));
|
||||
await getControl().send(new lib.UserCreateRequest("revokee"));
|
||||
let tlsCa = await fs.readFile("test/file/tls/cert.pem");
|
||||
let connector = new TestControlConnector(url, 2, tlsCa);
|
||||
connector.token = jwt.sign(
|
||||
@@ -1091,7 +1088,7 @@ describe("Integration of Clusterio", function() {
|
||||
it("should set the roles on the user", async function() {
|
||||
getControl().userUpdates = [];
|
||||
await execCtl('user set-roles temp "Cluster Admin"');
|
||||
let users = await getControl().send(new libData.UserListRequest());
|
||||
let users = await getControl().send(new lib.UserListRequest());
|
||||
let tempUser = users.find(user => user.name === "temp");
|
||||
assert.deepEqual(tempUser.roles, [0]);
|
||||
assert.equal(getControl().userUpdates.length, 1);
|
||||
@@ -1110,7 +1107,7 @@ describe("Integration of Clusterio", function() {
|
||||
await connector.connect();
|
||||
|
||||
await assert.rejects(
|
||||
tempControl.send(new libData.UserCreateRequest("notallowed")),
|
||||
tempControl.send(new lib.UserCreateRequest("notallowed")),
|
||||
new Error("Permission denied")
|
||||
);
|
||||
|
||||
@@ -1127,7 +1124,7 @@ describe("Integration of Clusterio", function() {
|
||||
it("should delete the user", async function() {
|
||||
getControl().userUpdates = [];
|
||||
await execCtl("user delete temp");
|
||||
let users = await getControl().send(new libData.UserListRequest());
|
||||
let users = await getControl().send(new lib.UserListRequest());
|
||||
let tempUser = users.find(user => user.name === "temp");
|
||||
assert(!tempUser, "user was note deleted");
|
||||
assert.equal(getControl().userUpdates.length, 1);
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
const assert = require("assert").strict;
|
||||
const path = require("path");
|
||||
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("Integration of lib/factorio/export", function() {
|
||||
describe("exportLocale()", function() {
|
||||
it("returns a nested Map with base game locale information", async function() {
|
||||
let writePath = path.join("temp", "test", "server");
|
||||
let testServer = new libFactorio.FactorioServer("factorio", writePath, {});
|
||||
let testServer = new lib.FactorioServer("factorio", writePath, {});
|
||||
await testServer.init();
|
||||
|
||||
let locale = await libFactorio._exportLocale(testServer, new Map(), ["base"], "en");
|
||||
let locale = await lib._exportLocale(testServer, new Map(), ["base"], "en");
|
||||
|
||||
assert(locale instanceof Map, "locale is not a map");
|
||||
assert.equal(locale.get("entity-name.fish"), "Fish");
|
||||
|
||||
+23
-26
@@ -8,11 +8,8 @@ const phin = require("phin");
|
||||
const util = require("util");
|
||||
const events = require("events");
|
||||
|
||||
const libData = require("@clusterio/lib/data");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const { LineSplitter } = require("@clusterio/lib/stream");
|
||||
const { ConsoleTransport, logger } = require("@clusterio/lib/logging");
|
||||
const libLoggingUtils = require("@clusterio/lib/logging_utils");
|
||||
const lib = require("@clusterio/lib");
|
||||
const { LineSplitter, ConsoleTransport, logger } = lib;
|
||||
|
||||
// Make sure permissions from plugins are loaded
|
||||
require("../../plugins/global_chat/info");
|
||||
@@ -22,7 +19,7 @@ require("../../plugins/statistics_exporter/info");
|
||||
require("../../plugins/subspace_storage/info");
|
||||
|
||||
|
||||
class TestControl extends libLink.Link {
|
||||
class TestControl extends lib.Link {
|
||||
constructor(connector, subscribe = true) {
|
||||
super(connector);
|
||||
this.hostUpdates = [];
|
||||
@@ -37,29 +34,29 @@ class TestControl extends libLink.Link {
|
||||
return;
|
||||
}
|
||||
this.send(
|
||||
new libData.HostSetSubscriptionsRequest(true, [])
|
||||
new lib.HostSetSubscriptionsRequest(true, [])
|
||||
).catch(err => logger.error(`Error setting host subscriptions:\n${err.stack}`));
|
||||
this.send(
|
||||
new libData.InstanceDetailsSetSubscriptionsRequest(true, [])
|
||||
new lib.InstanceDetailsSetSubscriptionsRequest(true, [])
|
||||
).catch(err => logger.error(`Error setting instance subscriptions:\n${err.stack}`));
|
||||
this.send(
|
||||
new libData.InstanceSetSaveListSubscriptionsRequest(true, [])
|
||||
new lib.InstanceSetSaveListSubscriptionsRequest(true, [])
|
||||
).catch(err => logger.error(`Error setting save list subscriptions:\n${err.stack}`));
|
||||
this.send(
|
||||
new libData.ModSetSubscriptionsRequest(true, [])
|
||||
new lib.ModSetSubscriptionsRequest(true, [])
|
||||
).catch(err => logger.error(`Error setting mod subscriptions:\n${err.stack}`));
|
||||
this.send(
|
||||
new libData.UserSetSubscriptionsRequest(true, [])
|
||||
new lib.UserSetSubscriptionsRequest(true, [])
|
||||
).catch(err => logger.error(`Error setting user subscriptions:\n${err.stack}`));
|
||||
});
|
||||
|
||||
this.handle(libData.AccountUpdateEvent);
|
||||
this.handle(libData.HostUpdateEvent, this.handleHostUpdateEvent.bind(this));
|
||||
this.handle(libData.InstanceDetailsUpdateEvent, this.handleInstanceDetailsUpdateEvent.bind(this));
|
||||
this.handle(libData.InstanceSaveListUpdateEvent, this.handleInstanceSaveListUpdateEvent.bind(this));
|
||||
this.handle(libData.ModUpdateEvent, this.handleModUpdateEvent.bind(this));
|
||||
this.handle(libData.ModPackUpdateEvent, this.handleModPackUpdateEvent.bind(this));
|
||||
this.handle(libData.UserUpdateEvent, this.handleUserUpdateEvent.bind(this));
|
||||
this.handle(lib.AccountUpdateEvent);
|
||||
this.handle(lib.HostUpdateEvent, this.handleHostUpdateEvent.bind(this));
|
||||
this.handle(lib.InstanceDetailsUpdateEvent, this.handleInstanceDetailsUpdateEvent.bind(this));
|
||||
this.handle(lib.InstanceSaveListUpdateEvent, this.handleInstanceSaveListUpdateEvent.bind(this));
|
||||
this.handle(lib.ModUpdateEvent, this.handleModUpdateEvent.bind(this));
|
||||
this.handle(lib.ModPackUpdateEvent, this.handleModPackUpdateEvent.bind(this));
|
||||
this.handle(lib.UserUpdateEvent, this.handleUserUpdateEvent.bind(this));
|
||||
}
|
||||
|
||||
async handleHostUpdateEvent(event) {
|
||||
@@ -87,11 +84,11 @@ class TestControl extends libLink.Link {
|
||||
}
|
||||
}
|
||||
|
||||
class TestControlConnector extends libLink.WebSocketClientConnector {
|
||||
class TestControlConnector extends lib.WebSocketClientConnector {
|
||||
register() {
|
||||
this.sendHandshake(
|
||||
new libData.MessageRegisterControl(
|
||||
new libData.RegisterControlData(
|
||||
new lib.MessageRegisterControl(
|
||||
new lib.RegisterControlData(
|
||||
this.token,
|
||||
"clusterioctl",
|
||||
"test",
|
||||
@@ -150,7 +147,7 @@ async function execCtl(...args) {
|
||||
}
|
||||
|
||||
async function sendRcon(instanceId, command) {
|
||||
return await control.sendTo({ instanceId }, new libData.InstanceSendRconRequest(command));
|
||||
return await control.sendTo({ instanceId }, new lib.InstanceSendRconRequest(command));
|
||||
}
|
||||
|
||||
function getControl() {
|
||||
@@ -183,7 +180,7 @@ before(async function() {
|
||||
// Some integration tests may cause log events
|
||||
logger.add(new ConsoleTransport({
|
||||
level: "info",
|
||||
format: new libLoggingUtils.TerminalFormat(),
|
||||
format: new lib.TerminalFormat(),
|
||||
}));
|
||||
|
||||
await fs.remove(databaseDir);
|
||||
@@ -228,16 +225,16 @@ before(async function() {
|
||||
control = new TestControl(controlConnector);
|
||||
await controlConnector.connect();
|
||||
|
||||
const testPack = libData.ModPack.fromJSON({});
|
||||
const testPack = lib.ModPack.fromJSON({});
|
||||
testPack.id = 12;
|
||||
testPack.name = "subspace_storage-pack";
|
||||
testPack.factorioVersion = "1.1.0";
|
||||
testPack.mods.set("clusterio_lib", { name: "clusterio_lib", enabled: true, version: "0.1.2" });
|
||||
testPack.mods.set("subspace_storage", { name: "subspace_storage", enabled: true, version: "1.99.8" });
|
||||
await control.sendTo("controller", new libData.ModPackCreateRequest(testPack));
|
||||
await control.sendTo("controller", new lib.ModPackCreateRequest(testPack));
|
||||
await control.sendTo(
|
||||
"controller",
|
||||
new libData.ControllerConfigSetFieldRequest("controller.default_mod_pack_id", "12"),
|
||||
new lib.ControllerConfigSetFieldRequest("controller.default_mod_pack_id", "12"),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ const fs = require("fs-extra");
|
||||
const JSZip = require("jszip");
|
||||
const path = require("path");
|
||||
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
const { slowTest } = require("./index");
|
||||
|
||||
@@ -17,7 +17,7 @@ describe("Integration of lib/factorio/patch", function() {
|
||||
let savePath = path.join("temp", "test", "integration", "saves", "test.zip");
|
||||
it("should patch a freeplay game", async function() {
|
||||
slowTest(this);
|
||||
await libFactorio.patch(savePath, [{
|
||||
await lib.patch(savePath, [{
|
||||
name: "test",
|
||||
version: "1.0.0",
|
||||
dependencies: {},
|
||||
@@ -39,7 +39,7 @@ describe("Integration of lib/factorio/patch", function() {
|
||||
});
|
||||
it("should remove old modules in a save", async function() {
|
||||
slowTest(this);
|
||||
await libFactorio.patch(savePath, []);
|
||||
await lib.patch(savePath, []);
|
||||
let zip = await JSZip.loadAsync(await fs.readFile(savePath));
|
||||
assert.equal(zip.file("test/modules/test/test.lua"), null);
|
||||
});
|
||||
|
||||
@@ -4,9 +4,8 @@ const events = require("events");
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const { logger } = require("@clusterio/lib/logging");
|
||||
const lib = require("@clusterio/lib");
|
||||
const { logger } = lib;
|
||||
|
||||
const { slowTest } = require("./index");
|
||||
|
||||
@@ -14,7 +13,7 @@ const { slowTest } = require("./index");
|
||||
describe("Integration of lib/factorio/server", function() {
|
||||
describe("_getVersion()", function() {
|
||||
it("should get a version from factorio's changelog.txt", async function() {
|
||||
let version = await libFactorio._getVersion(path.join("factorio", "data", "changelog.txt"));
|
||||
let version = await lib._getVersion(path.join("factorio", "data", "changelog.txt"));
|
||||
if (!/^\d+\.\d+\.\d+$/.test(version)) {
|
||||
assert.fail(`Detected version '${version}' does not followed the format x.y.z`);
|
||||
}
|
||||
@@ -23,7 +22,7 @@ describe("Integration of lib/factorio/server", function() {
|
||||
|
||||
describe("class FactorioServer", function() {
|
||||
let writePath = path.join("temp", "test", "integration");
|
||||
let server = new libFactorio.FactorioServer("factorio", writePath, {});
|
||||
let server = new lib.FactorioServer("factorio", writePath, {});
|
||||
let logFile;
|
||||
|
||||
before(async function() {
|
||||
@@ -231,7 +230,7 @@ describe("Integration of lib/factorio/server", function() {
|
||||
|
||||
await assert.rejects(
|
||||
startPromise,
|
||||
new libErrors.EnvironmentError(
|
||||
new lib.EnvironmentError(
|
||||
"Factorio server was unexpectedly killed, is the system low on memory?"
|
||||
)
|
||||
);
|
||||
@@ -243,7 +242,7 @@ describe("Integration of lib/factorio/server", function() {
|
||||
|
||||
await assert.rejects(
|
||||
server.start("does-not-exist.zip"),
|
||||
new libErrors.EnvironmentError("Factorio server unexpectedly shut down with code 1")
|
||||
new lib.EnvironmentError("Factorio server unexpectedly shut down with code 1")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const ExponentialBackoff = require("@clusterio/lib/ExponentialBackoff");
|
||||
const { ExponentialBackoff } = require("@clusterio/lib");
|
||||
|
||||
describe("lib/ExponentialBackoff", function() {
|
||||
describe("class ExponentialBackoff", function() {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const { wait } = require("@clusterio/lib/helpers");
|
||||
const RateLimiter = require("@clusterio/lib/RateLimiter");
|
||||
const { RateLimiter, wait } = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/RateLimiter", function() {
|
||||
|
||||
+20
-23
@@ -1,70 +1,67 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const libCommand = require("@clusterio/lib/command");
|
||||
const libData = require("@clusterio/lib/data");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const lib = require("@clusterio/lib");
|
||||
const mock = require("../mock");
|
||||
|
||||
const addr = libData.Address.fromShorthand;
|
||||
const addr = lib.Address.fromShorthand;
|
||||
|
||||
|
||||
describe("lib/command", function() {
|
||||
let testRole = libData.RawRole.fromJSON({ id: 28, name: "Test Role", description: "Test", permissions: [] });
|
||||
let testRole = lib.RawRole.fromJSON({ id: 28, name: "Test Role", description: "Test", permissions: [] });
|
||||
|
||||
let [controlConnector, controllerConnector] = libLink.VirtualConnector.makePair(
|
||||
let [controlConnector, controllerConnector] = lib.VirtualConnector.makePair(
|
||||
addr({ controlId: 1}), addr("controller")
|
||||
);
|
||||
let testControl = new mock.MockControl(controlConnector);
|
||||
let testController = new libLink.Link(controllerConnector);
|
||||
let testController = new lib.Link(controllerConnector);
|
||||
testController.handle(
|
||||
libData.HostListRequest, () => [new libData.HostDetails("test", "0.1", "Test Host", 11, false)]
|
||||
lib.HostListRequest, () => [new lib.HostDetails("test", "0.1", "Test Host", 11, false)]
|
||||
);
|
||||
testController.handle(
|
||||
libData.InstanceDetailsListRequest, () => [new libData.InstanceDetails("Test Instance", 57, 4, null, "stopped")]
|
||||
lib.InstanceDetailsListRequest, () => [new lib.InstanceDetails("Test Instance", 57, 4, null, "stopped")]
|
||||
);
|
||||
testController.handle(libData.RoleListRequest, () => [testRole]);
|
||||
testController.handle(lib.RoleListRequest, () => [testRole]);
|
||||
|
||||
describe("resolveHost", function() {
|
||||
it("should pass an integer like string back", async function() {
|
||||
assert.equal(await libCommand.resolveHost(null, "123"), 123);
|
||||
assert.equal(await lib.resolveHost(null, "123"), 123);
|
||||
});
|
||||
it("should resolve a host name with the controller", async function() {
|
||||
assert.equal(await libCommand.resolveHost(testControl, "Test Host"), 11);
|
||||
assert.equal(await lib.resolveHost(testControl, "Test Host"), 11);
|
||||
});
|
||||
it("should throw if host is not found", async function() {
|
||||
await assert.rejects(
|
||||
libCommand.resolveHost(testControl, "invalid"),
|
||||
new libErrors.CommandError("No host named invalid")
|
||||
lib.resolveHost(testControl, "invalid"),
|
||||
new lib.CommandError("No host named invalid")
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("resolveInstance", function() {
|
||||
it("should pass an integer like string back", async function() {
|
||||
assert.equal(await libCommand.resolveInstance(null, "123"), 123);
|
||||
assert.equal(await lib.resolveInstance(null, "123"), 123);
|
||||
});
|
||||
it("should resolve an instance name with the controller", async function() {
|
||||
assert.equal(await libCommand.resolveInstance(testControl, "Test Instance"), 57);
|
||||
assert.equal(await lib.resolveInstance(testControl, "Test Instance"), 57);
|
||||
});
|
||||
it("should throw if instance is not found", async function() {
|
||||
await assert.rejects(
|
||||
libCommand.resolveInstance(testControl, "invalid"),
|
||||
new libErrors.CommandError("No instance named invalid")
|
||||
lib.resolveInstance(testControl, "invalid"),
|
||||
new lib.CommandError("No instance named invalid")
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("retrieveRole", function() {
|
||||
it("should retrieve a role by id from an integer like string", async function() {
|
||||
assert.deepEqual(await libCommand.retrieveRole(testControl, "28"), testRole);
|
||||
assert.deepEqual(await lib.retrieveRole(testControl, "28"), testRole);
|
||||
});
|
||||
it("should retrieve a role by name from a string", async function() {
|
||||
assert.deepEqual(await libCommand.retrieveRole(testControl, "Test Role"), testRole);
|
||||
assert.deepEqual(await lib.retrieveRole(testControl, "Test Role"), testRole);
|
||||
});
|
||||
it("should throw if role is not found", async function() {
|
||||
await assert.rejects(
|
||||
libCommand.retrieveRole(testControl, "invalid"),
|
||||
new libErrors.CommandError("No role named invalid")
|
||||
lib.retrieveRole(testControl, "invalid"),
|
||||
new lib.CommandError("No role named invalid")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+20
-20
@@ -1,5 +1,5 @@
|
||||
"use strict";
|
||||
const classes = require("@clusterio/lib/config/classes");
|
||||
const lib = require("@clusterio/lib");
|
||||
const assert = require("assert").strict;
|
||||
const events = require("events");
|
||||
|
||||
@@ -8,12 +8,12 @@ describe("lib/config/classes", function() {
|
||||
describe("ConfigGroup", function() {
|
||||
let mockConfig = new events.EventEmitter();
|
||||
mockConfig.location = "local";
|
||||
class TestGroup extends classes.ConfigGroup { }
|
||||
class TestGroup extends lib.ConfigGroup { }
|
||||
TestGroup.defaultAccess = ["local", "remote"];
|
||||
TestGroup.groupName = "test_group";
|
||||
describe(".define()", function() {
|
||||
it("should throw if groupName is not set", function() {
|
||||
class NoGroupName extends classes.ConfigGroup { }
|
||||
class NoGroupName extends lib.ConfigGroup { }
|
||||
assert.throws(
|
||||
() => NoGroupName.define({ name: "a", type: "string", optional: true }),
|
||||
new Error("Expected ConfigGroup class NoGroupName to have the groupName property set to a string")
|
||||
@@ -68,7 +68,7 @@ describe("lib/config/classes", function() {
|
||||
}
|
||||
});
|
||||
it("should throw on defaultAccess not set", function() {
|
||||
class NoAccessGroup extends classes.ConfigGroup { }
|
||||
class NoAccessGroup extends lib.ConfigGroup { }
|
||||
NoAccessGroup.groupName = "no_access";
|
||||
assert.throws(
|
||||
() => NoAccessGroup.define({ name: "a", type: "string", optional: true }),
|
||||
@@ -134,7 +134,7 @@ describe("lib/config/classes", function() {
|
||||
|
||||
describe(".finalize()", function() {
|
||||
it("should throw if groupName is not set", function() {
|
||||
class NoGroupName extends classes.ConfigGroup { }
|
||||
class NoGroupName extends lib.ConfigGroup { }
|
||||
assert.throws(
|
||||
() => NoGroupName.finalize(),
|
||||
new Error("Expected ConfigGroup class NoGroupName to have the groupName property set to a string")
|
||||
@@ -360,7 +360,7 @@ describe("lib/config/classes", function() {
|
||||
it("should throw if field is inaccessible", function() {
|
||||
assert.throws(
|
||||
() => testInstance.get("priv", "remote"),
|
||||
new classes.InvalidAccess("Field 'priv' is not accessible from remote")
|
||||
new lib.InvalidAccess("Field 'priv' is not accessible from remote")
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -375,14 +375,14 @@ describe("lib/config/classes", function() {
|
||||
it("should throw if field does not exist", function() {
|
||||
assert.throws(
|
||||
() => testInstance.set("bar", 1),
|
||||
new classes.InvalidField("No field named 'bar'")
|
||||
new lib.InvalidField("No field named 'bar'")
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw if field is inaccesible", function() {
|
||||
assert.throws(
|
||||
() => testInstance.set("priv", "bad", "remote"),
|
||||
new classes.InvalidAccess("Field 'priv' is not accessible from remote")
|
||||
new lib.InvalidAccess("Field 'priv' is not accessible from remote")
|
||||
);
|
||||
});
|
||||
|
||||
@@ -430,7 +430,7 @@ describe("lib/config/classes", function() {
|
||||
|
||||
assert.throws(
|
||||
() => testInstance.set("bool", "blah"),
|
||||
new classes.InvalidValue("Expected type of bool to be boolean, not string")
|
||||
new lib.InvalidValue("Expected type of bool to be boolean, not string")
|
||||
);
|
||||
});
|
||||
|
||||
@@ -449,7 +449,7 @@ describe("lib/config/classes", function() {
|
||||
|
||||
assert.throws(
|
||||
() => testInstance.set("func", "blah"),
|
||||
new classes.InvalidValue("Expected type of func to be number, not string")
|
||||
new lib.InvalidValue("Expected type of func to be number, not string")
|
||||
);
|
||||
});
|
||||
|
||||
@@ -465,7 +465,7 @@ describe("lib/config/classes", function() {
|
||||
}
|
||||
assert.throws(
|
||||
() => testInstance.set("json", "blah"),
|
||||
new classes.InvalidValue(`Error parsing value for json: ${errMsg}`)
|
||||
new lib.InvalidValue(`Error parsing value for json: ${errMsg}`)
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -482,21 +482,21 @@ describe("lib/config/classes", function() {
|
||||
it("should throw if field does not exist", function() {
|
||||
assert.throws(
|
||||
() => testInstance.setProp("bar", 1),
|
||||
new classes.InvalidField("No field named 'bar'")
|
||||
new lib.InvalidField("No field named 'bar'")
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw if field is inaccesible", function() {
|
||||
assert.throws(
|
||||
() => testInstance.setProp("priv", "prop", "bad", "remote"),
|
||||
new classes.InvalidAccess("Field 'priv' is not accessible from remote")
|
||||
new lib.InvalidAccess("Field 'priv' is not accessible from remote")
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw if field is not an object", function() {
|
||||
assert.throws(
|
||||
() => testInstance.setProp("enum", "prop", "a"),
|
||||
new classes.InvalidField("Cannot set property on non-object field 'enum'")
|
||||
new lib.InvalidField("Cannot set property on non-object field 'enum'")
|
||||
);
|
||||
});
|
||||
|
||||
@@ -521,13 +521,13 @@ describe("lib/config/classes", function() {
|
||||
});
|
||||
|
||||
describe("Config", function() {
|
||||
class AlphaGroup extends classes.ConfigGroup { }
|
||||
class AlphaGroup extends lib.ConfigGroup { }
|
||||
AlphaGroup.defaultAccess = ["local", "remote"];
|
||||
AlphaGroup.groupName = "alpha";
|
||||
class BetaGroup extends classes.ConfigGroup { }
|
||||
class BetaGroup extends lib.ConfigGroup { }
|
||||
BetaGroup.defaultAccess = ["local", "remote"];
|
||||
BetaGroup.groupName = "beta";
|
||||
class TestConfig extends classes.Config { }
|
||||
class TestConfig extends lib.Config { }
|
||||
|
||||
before(function() {
|
||||
AlphaGroup.define({ name: "foo", type: "string", optional: true });
|
||||
@@ -540,9 +540,9 @@ describe("lib/config/classes", function() {
|
||||
|
||||
describe(".registerGroup()", function() {
|
||||
it("should throw if the class is finalized", function() {
|
||||
class FinalizedConfig extends classes.Config { }
|
||||
class FinalizedConfig extends lib.Config { }
|
||||
FinalizedConfig.finalize();
|
||||
class TestGroup extends classes.ConfigGroup { }
|
||||
class TestGroup extends lib.ConfigGroup { }
|
||||
TestGroup.groupName = "test";
|
||||
TestGroup.finalize();
|
||||
|
||||
@@ -552,7 +552,7 @@ describe("lib/config/classes", function() {
|
||||
);
|
||||
});
|
||||
it("should throw if the group is not finalized", function() {
|
||||
class UnfinishedGroup extends classes.ConfigGroup { }
|
||||
class UnfinishedGroup extends lib.ConfigGroup { }
|
||||
|
||||
assert.throws(
|
||||
() => TestConfig.registerGroup(UnfinishedGroup),
|
||||
|
||||
@@ -3,16 +3,15 @@ const assert = require("assert").strict;
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const libSchema = require("@clusterio/lib/schema");
|
||||
const libHash = require("@clusterio/lib/hash");
|
||||
const lib = require("@clusterio/lib");
|
||||
const libBuildMod = require("@clusterio/lib/build_mod");
|
||||
const ModInfo = require("@clusterio/lib/data/ModInfo");
|
||||
const { ModInfo } = lib;
|
||||
|
||||
|
||||
describe("lib/data/ModInfo", function() {
|
||||
describe("class ModInfo", function() {
|
||||
it("should round trip serialize", function() {
|
||||
const validate = libSchema.compile(ModInfo.jsonSchema);
|
||||
const validate = lib.compile(ModInfo.jsonSchema);
|
||||
function check(pack) {
|
||||
const json = JSON.parse(JSON.stringify(pack));
|
||||
if (!validate(json)) {
|
||||
@@ -78,7 +77,7 @@ describe("lib/data/ModInfo", function() {
|
||||
outputDir: path.join("temp", "test"),
|
||||
});
|
||||
const filePath = path.join("temp", "test", "empty_mod_1.0.0.zip");
|
||||
const hash = await libHash.hashFile(filePath);
|
||||
const hash = await lib.hashFile(filePath);
|
||||
const stat = await fs.stat(filePath);
|
||||
const mod = await ModInfo.fromModFile(filePath);
|
||||
assert.deepEqual(
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
const assert = require("assert").strict;
|
||||
const zlib = require("zlib");
|
||||
|
||||
const libSchema = require("@clusterio/lib/schema");
|
||||
const ExportManifest = require("@clusterio/lib/data/ExportManifest");
|
||||
const ModPack = require("@clusterio/lib/data/ModPack");
|
||||
const lib = require("@clusterio/lib");
|
||||
const { ModPack } = lib;
|
||||
|
||||
|
||||
describe("lib/data/ModPack", function() {
|
||||
describe("class ModPack", function() {
|
||||
it("should round trip serialize", function() {
|
||||
const validate = libSchema.compile(ModPack.jsonSchema);
|
||||
const validate = lib.compile(ModPack.jsonSchema);
|
||||
function check(pack) {
|
||||
const json = JSON.parse(JSON.stringify(pack));
|
||||
if (!validate(json)) {
|
||||
|
||||
+34
-34
@@ -3,24 +3,24 @@ const assert = require("assert").strict;
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const libDatabase = require("@clusterio/lib/database");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
describe("lib/database", function() {
|
||||
describe("mapToObject()", function() {
|
||||
it("should throw on non-string key", function() {
|
||||
assert.throws(
|
||||
() => libDatabase.mapToObject(new Map([[1, 1]])),
|
||||
() => lib.mapToObject(new Map([[1, 1]])),
|
||||
new Error("Expected all keys to be string but got number")
|
||||
);
|
||||
assert.throws(
|
||||
() => libDatabase.mapToObject(new Map([[Symbol("test"), 1]])),
|
||||
() => lib.mapToObject(new Map([[Symbol("test"), 1]])),
|
||||
new Error("Expected all keys to be string but got symbol")
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw convert a map to an object", function() {
|
||||
assert.deepEqual(
|
||||
libDatabase.mapToObject(new Map([["a", 1], ["b", true]])),
|
||||
lib.mapToObject(new Map([["a", 1], ["b", true]])),
|
||||
{ "a": 1, "b": true }
|
||||
);
|
||||
});
|
||||
@@ -32,7 +32,7 @@ describe("lib/database", function() {
|
||||
for (let type of badTypes) {
|
||||
it(`should reject on ${type} JSON`, async function() {
|
||||
await assert.rejects(
|
||||
libDatabase.loadJsonAsMap(path.join("test", "file", "json", `${type}.json`)),
|
||||
lib.loadJsonAsMap(path.join("test", "file", "json", `${type}.json`)),
|
||||
new Error(`Expected object but got ${type}`)
|
||||
);
|
||||
});
|
||||
@@ -40,21 +40,21 @@ describe("lib/database", function() {
|
||||
|
||||
it("should work on empty object JSON", async function() {
|
||||
assert.deepEqual(
|
||||
await libDatabase.loadJsonAsMap(path.join("test", "file", "json", "object.json")),
|
||||
await lib.loadJsonAsMap(path.join("test", "file", "json", "object.json")),
|
||||
new Map()
|
||||
);
|
||||
});
|
||||
|
||||
it("should work on object JSON", async function() {
|
||||
assert.deepEqual(
|
||||
await libDatabase.loadJsonAsMap(path.join("test", "file", "json", "load_map.json")),
|
||||
await lib.loadJsonAsMap(path.join("test", "file", "json", "load_map.json")),
|
||||
new Map([["a", 1], ["b", true]])
|
||||
);
|
||||
});
|
||||
|
||||
it("should give an empty Map for non-existant file", async function() {
|
||||
assert.deepEqual(
|
||||
await libDatabase.loadJsonAsMap(path.join("test", "file", "json", "does-not-exist")),
|
||||
await lib.loadJsonAsMap(path.join("test", "file", "json", "does-not-exist")),
|
||||
new Map()
|
||||
);
|
||||
});
|
||||
@@ -75,7 +75,7 @@ describe("lib/database", function() {
|
||||
}
|
||||
|
||||
await deleteTestFile();
|
||||
await libDatabase.saveMapAsJson(
|
||||
await lib.saveMapAsJson(
|
||||
testFile, new Map([["c", {}], ["d", "foo"]])
|
||||
);
|
||||
|
||||
@@ -92,7 +92,7 @@ describe("lib/database", function() {
|
||||
for (let type of badTypes) {
|
||||
it(`should reject on ${type} JSON`, async function() {
|
||||
await assert.rejects(
|
||||
libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", `${type}.json`)),
|
||||
lib.loadJsonArrayAsMap(path.join("test", "file", "json", `${type}.json`)),
|
||||
new Error(`Expected array but got ${type}`)
|
||||
);
|
||||
});
|
||||
@@ -100,35 +100,35 @@ describe("lib/database", function() {
|
||||
|
||||
it("should reject on null element", async function() {
|
||||
await assert.rejects(
|
||||
libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "array_null.json")),
|
||||
lib.loadJsonArrayAsMap(path.join("test", "file", "json", "array_null.json")),
|
||||
new Error("Expected all elements to be objects")
|
||||
);
|
||||
});
|
||||
|
||||
it("should reject on element missing id", async function() {
|
||||
await assert.rejects(
|
||||
libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "array_object.json")),
|
||||
lib.loadJsonArrayAsMap(path.join("test", "file", "json", "array_object.json")),
|
||||
new Error("Expected all elements to have an id property")
|
||||
);
|
||||
});
|
||||
|
||||
it("should work on empty array JSON", async function() {
|
||||
assert.deepEqual(
|
||||
await libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "array.json")),
|
||||
await lib.loadJsonArrayAsMap(path.join("test", "file", "json", "array.json")),
|
||||
new Map()
|
||||
);
|
||||
});
|
||||
|
||||
it("should work on array JSON", async function() {
|
||||
assert.deepEqual(
|
||||
await libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "load_array_map.json")),
|
||||
await lib.loadJsonArrayAsMap(path.join("test", "file", "json", "load_array_map.json")),
|
||||
new Map([["a", { id: "a" }], ["b", { id: "b" }]])
|
||||
);
|
||||
});
|
||||
|
||||
it("should give an empty Map for non-existant file", async function() {
|
||||
assert.deepEqual(
|
||||
await libDatabase.loadJsonArrayAsMap(path.join("test", "file", "json", "does-not-exist")),
|
||||
await lib.loadJsonArrayAsMap(path.join("test", "file", "json", "does-not-exist")),
|
||||
new Map()
|
||||
);
|
||||
});
|
||||
@@ -149,7 +149,7 @@ describe("lib/database", function() {
|
||||
}
|
||||
|
||||
await deleteTestFile();
|
||||
await libDatabase.saveMapAsJsonArray(
|
||||
await lib.saveMapAsJsonArray(
|
||||
testFile, new Map([["c", { id: "c" }], ["d", { id: "d" }]])
|
||||
);
|
||||
|
||||
@@ -163,23 +163,23 @@ describe("lib/database", function() {
|
||||
describe("class ItemDatabase", function() {
|
||||
describe("constructor()", function() {
|
||||
it("should create an empty database with no args", function() {
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
let items = new lib.ItemDatabase();
|
||||
assert.deepEqual(items._items, new Map());
|
||||
});
|
||||
|
||||
it("should restore the passed serialized database", function() {
|
||||
let items = new libDatabase.ItemDatabase({ "a": 1, "b": 2 });
|
||||
let items = new lib.ItemDatabase({ "a": 1, "b": 2 });
|
||||
assert.deepEqual(items._items, new Map([["a", 1], ["b", 2]]));
|
||||
});
|
||||
|
||||
it("should throw on invalid serialized database", function() {
|
||||
assert.throws(
|
||||
() => new libDatabase.ItemDatabase({ "a": NaN }),
|
||||
() => new lib.ItemDatabase({ "a": NaN }),
|
||||
new Error("count must be a number")
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => new libDatabase.ItemDatabase({ "a": "a" }),
|
||||
() => new lib.ItemDatabase({ "a": "a" }),
|
||||
new Error("count must be a number")
|
||||
);
|
||||
});
|
||||
@@ -187,36 +187,36 @@ describe("lib/database", function() {
|
||||
|
||||
describe(".serialize()", function() {
|
||||
it("should return a serialized database", function() {
|
||||
let items = new libDatabase.ItemDatabase({ "a": 10 });
|
||||
let items = new lib.ItemDatabase({ "a": 10 });
|
||||
assert.deepEqual(items.serialize(), { "a": 10 });
|
||||
});
|
||||
|
||||
it("should remove zero count entries", function() {
|
||||
let items = new libDatabase.ItemDatabase({ "a": 0 });
|
||||
let items = new lib.ItemDatabase({ "a": 0 });
|
||||
assert.deepEqual(items.serialize(), {});
|
||||
});
|
||||
});
|
||||
|
||||
describe(".size", function() {
|
||||
it("should give an approximate size of the database", function() {
|
||||
let items = new libDatabase.ItemDatabase({ "a": 10 });
|
||||
let items = new lib.ItemDatabase({ "a": 10 });
|
||||
assert.equal(items.size, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".getItemCount()", function() {
|
||||
it("should return the count of the given item", function() {
|
||||
let items = new libDatabase.ItemDatabase({ "a": 10 });
|
||||
let items = new lib.ItemDatabase({ "a": 10 });
|
||||
assert.equal(items.getItemCount("a"), 10);
|
||||
});
|
||||
|
||||
it("should return zero if item does not exist", function() {
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
let items = new lib.ItemDatabase();
|
||||
assert.equal(items.getItemCount("b"), 0);
|
||||
});
|
||||
|
||||
it("should throw on invalid name", function() {
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
let items = new lib.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.getItemCount(2),
|
||||
new Error("name must be a string")
|
||||
@@ -226,19 +226,19 @@ describe("lib/database", function() {
|
||||
|
||||
describe(".addItem()", function() {
|
||||
it("should add a new item", function() {
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
let items = new lib.ItemDatabase();
|
||||
items.addItem("a", 10);
|
||||
assert.deepEqual(items._items, new Map([["a", 10]]));
|
||||
});
|
||||
|
||||
it("should add an existing item", function() {
|
||||
let items = new libDatabase.ItemDatabase({ "a": 10 });
|
||||
let items = new lib.ItemDatabase({ "a": 10 });
|
||||
items.addItem("a", 10);
|
||||
assert.deepEqual(items._items, new Map([["a", 20]]));
|
||||
});
|
||||
|
||||
it("should throw on invalid name", function() {
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
let items = new lib.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.addItem(2, 10),
|
||||
new Error("name must be a string")
|
||||
@@ -246,7 +246,7 @@ describe("lib/database", function() {
|
||||
});
|
||||
|
||||
it("should throw on invalid count", function() {
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
let items = new lib.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.addItem("a", NaN),
|
||||
new Error("count must be a number")
|
||||
@@ -260,19 +260,19 @@ describe("lib/database", function() {
|
||||
|
||||
describe(".removeItem()", function() {
|
||||
it("should remove an existing item", function() {
|
||||
let items = new libDatabase.ItemDatabase({ "a": 20 });
|
||||
let items = new lib.ItemDatabase({ "a": 20 });
|
||||
items.removeItem("a", 10);
|
||||
assert.deepEqual(items._items, new Map([["a", 10]]));
|
||||
});
|
||||
|
||||
it("should turn a non-existing item negative", function() {
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
let items = new lib.ItemDatabase();
|
||||
items.removeItem("a", 10);
|
||||
assert.deepEqual(items._items, new Map([["a", -10]]));
|
||||
});
|
||||
|
||||
it("should throw on invalid name", function() {
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
let items = new lib.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.removeItem(2, 10),
|
||||
new Error("name must be a string")
|
||||
@@ -280,7 +280,7 @@ describe("lib/database", function() {
|
||||
});
|
||||
|
||||
it("should throw on invalid count", function() {
|
||||
let items = new libDatabase.ItemDatabase();
|
||||
let items = new lib.ItemDatabase();
|
||||
assert.throws(
|
||||
() => items.removeItem("a", "b"),
|
||||
new Error("count must be a number")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
const assert = require("assert").strict;
|
||||
const zlib = require("zlib");
|
||||
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
const testStrings = require("./test_strings");
|
||||
|
||||
@@ -23,26 +23,26 @@ class Random {
|
||||
describe("lib/factorio/exchange_string", function() {
|
||||
describe("readMapExchangeString", function() {
|
||||
it("should parse a valid string", function() {
|
||||
let result = libFactorio.readMapExchangeString(testStrings.default);
|
||||
let result = lib.readMapExchangeString(testStrings.default);
|
||||
assert.equal(result.map_gen_settings.seed, 1234567890);
|
||||
|
||||
result = libFactorio.readMapExchangeString(testStrings.modified);
|
||||
result = lib.readMapExchangeString(testStrings.modified);
|
||||
assert.equal(result.checksum, 4092204126);
|
||||
});
|
||||
|
||||
it("should handle malformed strings", function() {
|
||||
assert.throws(
|
||||
() => libFactorio.readMapExchangeString("<<blah>>"),
|
||||
() => lib.readMapExchangeString("<<blah>>"),
|
||||
new Error("Not a map exchange string")
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => libFactorio.readMapExchangeString(testStrings.default.slice(0, 100)),
|
||||
() => lib.readMapExchangeString(testStrings.default.slice(0, 100)),
|
||||
new Error("Not a map exchange string")
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => libFactorio.readMapExchangeString(`>>>${Buffer.from("abk430ia404ah3b4").toString("base64")}<<<`),
|
||||
() => lib.readMapExchangeString(`>>>${Buffer.from("abk430ia404ah3b4").toString("base64")}<<<`),
|
||||
new Error("Malformed map exchange string: zlib inflate failed")
|
||||
);
|
||||
|
||||
@@ -56,7 +56,7 @@ describe("lib/factorio/exchange_string", function() {
|
||||
// eslint-disable-next-line node/no-sync
|
||||
data = zlib.deflateSync(data);
|
||||
assert.throws(
|
||||
() => libFactorio.readMapExchangeString(`>>>${data.toString("base64")}<<<`),
|
||||
() => lib.readMapExchangeString(`>>>${data.toString("base64")}<<<`),
|
||||
new Error("Malformed map exchange string: reached end before finishing parsing")
|
||||
);
|
||||
}
|
||||
@@ -65,7 +65,7 @@ describe("lib/factorio/exchange_string", function() {
|
||||
// eslint-disable-next-line node/no-sync
|
||||
pastEnd = zlib.deflateSync(Buffer.concat([zlib.inflateSync(pastEnd), Buffer.from("junk")]));
|
||||
assert.throws(
|
||||
() => libFactorio.readMapExchangeString(`>>>${pastEnd.toString("base64")}<<<`),
|
||||
() => lib.readMapExchangeString(`>>>${pastEnd.toString("base64")}<<<`),
|
||||
new Error("Malformed map exchange string: data after end")
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
const assert = require("assert").strict;
|
||||
const path = require("path");
|
||||
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/factorio/export", function() {
|
||||
@@ -10,12 +10,12 @@ describe("lib/factorio/export", function() {
|
||||
let testServer;
|
||||
before(async function() {
|
||||
let writePath = path.join("temp", "test", "server");
|
||||
testServer = new libFactorio.FactorioServer(path.join("test", "file", "factorio"), writePath, {});
|
||||
testServer = new lib.FactorioServer(path.join("test", "file", "factorio"), writePath, {});
|
||||
await testServer.init();
|
||||
});
|
||||
|
||||
it("returns a flattened mapping with locale definitions", async function() {
|
||||
let locale = await libFactorio._exportLocale(testServer, new Map(), ["base"], "en");
|
||||
let locale = await lib._exportLocale(testServer, new Map(), ["base"], "en");
|
||||
assert.deepEqual(locale, new Map([["test.key-a", "1"], ["test.key-b", "2"]]));
|
||||
});
|
||||
});
|
||||
|
||||
+12
-12
@@ -4,7 +4,7 @@ const fs = require("fs-extra");
|
||||
const JSZip = require("jszip");
|
||||
const path = require("path");
|
||||
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/factorio", function() {
|
||||
@@ -38,7 +38,7 @@ describe("lib/factorio", function() {
|
||||
};
|
||||
|
||||
it("should produce output matching the reference", function() {
|
||||
assert.equal(libFactorio._generateLoader(patchInfo), reference);
|
||||
assert.equal(lib._generateLoader(patchInfo), reference);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,7 +48,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "a", version: "1.0.0", dependencies: {"b": "*"} },
|
||||
{ name: "b", version: "1.0.0", dependencies: {} },
|
||||
];
|
||||
libFactorio._reorderDependencies(modules);
|
||||
lib._reorderDependencies(modules);
|
||||
assert(modules[0].name === "b", "Dependency was not reorederd");
|
||||
});
|
||||
it("should throw on invalid version", function() {
|
||||
@@ -56,7 +56,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "a", version: "foo", dependencies: {} },
|
||||
];
|
||||
assert.throws(
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
() => lib._reorderDependencies(modules),
|
||||
new Error("Invalid version 'foo' for module a")
|
||||
);
|
||||
});
|
||||
@@ -65,7 +65,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "a", version: "1.0.0", dependencies: {"b": "invalid"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
() => lib._reorderDependencies(modules),
|
||||
new Error("Invalid version range 'invalid' for dependency b on module a")
|
||||
);
|
||||
});
|
||||
@@ -74,7 +74,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "a", version: "1.0.0", dependencies: {"b": "*"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
() => lib._reorderDependencies(modules),
|
||||
new Error("Missing dependency b for module a")
|
||||
);
|
||||
modules = [
|
||||
@@ -83,7 +83,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "c", version: "1.0.0", dependencies: {"d": "*"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
() => lib._reorderDependencies(modules),
|
||||
new Error("Missing dependency d for module c")
|
||||
);
|
||||
});
|
||||
@@ -93,7 +93,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "b", version: "1.0.0", dependencies: {"a": ">=2"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
() => lib._reorderDependencies(modules),
|
||||
new Error("Module b requires a >=2")
|
||||
);
|
||||
});
|
||||
@@ -103,7 +103,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "b", version: "1.0.0", dependencies: {"a": "*"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
() => lib._reorderDependencies(modules),
|
||||
new Error("Module dependency loop detected: a -> b -> a")
|
||||
);
|
||||
modules = [
|
||||
@@ -113,7 +113,7 @@ describe("lib/factorio", function() {
|
||||
{ name: "c", version: "1.0.0", dependencies: {"a": "*"} },
|
||||
];
|
||||
assert.throws(
|
||||
() => libFactorio._reorderDependencies(modules),
|
||||
() => lib._reorderDependencies(modules),
|
||||
new Error("Module dependency loop detected: b -> c -> a -> b")
|
||||
);
|
||||
});
|
||||
@@ -153,7 +153,7 @@ describe("lib/factorio", function() {
|
||||
}
|
||||
let success = false;
|
||||
try {
|
||||
libFactorio._reorderDependencies(modules);
|
||||
lib._reorderDependencies(modules);
|
||||
success = true;
|
||||
} catch (err) { }
|
||||
if (success) {
|
||||
@@ -176,7 +176,7 @@ describe("lib/factorio", function() {
|
||||
await fs.outputFile(zipPath, await zip.generateAsync({ type: "nodebuffer" }));
|
||||
|
||||
await assert.rejects(
|
||||
libFactorio.patch(zipPath, []),
|
||||
lib.patch(zipPath, []),
|
||||
new Error("Unable to patch save, unknown scenario (3acc3be3861144e55604f5ac2f2555071885ebc4)")
|
||||
);
|
||||
});
|
||||
|
||||
+21
-21
@@ -4,23 +4,23 @@ const events = require("events");
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const libFactorio = require("@clusterio/lib/factorio");
|
||||
const { wait } = require("@clusterio/lib/helpers");
|
||||
const lib = require("@clusterio/lib");
|
||||
const { wait } = lib;
|
||||
const { testLines } = require("./lines");
|
||||
|
||||
|
||||
describe("lib/factorio/server", function() {
|
||||
describe("_getVersion()", function() {
|
||||
it("should get the version from a changelog", async function() {
|
||||
let version = await libFactorio._getVersion(path.join("test", "file", "changelog-test.txt"));
|
||||
let version = await lib._getVersion(path.join("test", "file", "changelog-test.txt"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should return null if unable to find the version", async function() {
|
||||
let version = await libFactorio._getVersion(path.join("test", "file", "changelog-bad.txt"));
|
||||
let version = await lib._getVersion(path.join("test", "file", "changelog-bad.txt"));
|
||||
assert.equal(version, null);
|
||||
});
|
||||
it("should return null if file does not exist", async function() {
|
||||
let version = await libFactorio._getVersion(path.join("test", "file", "does-not-exist.txt"));
|
||||
let version = await lib._getVersion(path.join("test", "file", "does-not-exist.txt"));
|
||||
assert.equal(version, null);
|
||||
});
|
||||
});
|
||||
@@ -28,7 +28,7 @@ describe("lib/factorio/server", function() {
|
||||
describe("_versionOrder()", function() {
|
||||
it("should sort an array of versions", function() {
|
||||
let versions = ["1.2.3", "0.1.4", "0.1.2", "1.2.3", "0.1.5", "1.10.2"];
|
||||
versions.sort(libFactorio._versionOrder);
|
||||
versions.sort(lib._versionOrder);
|
||||
assert.deepEqual(
|
||||
versions,
|
||||
["1.10.2", "1.2.3", "1.2.3", "0.1.5", "0.1.4", "0.1.2"]
|
||||
@@ -39,46 +39,46 @@ describe("lib/factorio/server", function() {
|
||||
describe("_findVersion()", function() {
|
||||
it("should find a given install dir with latest as target", async function() {
|
||||
let installDir = path.join("test", "file", "factorio");
|
||||
let [dir, version] = await libFactorio._findVersion(installDir, "latest");
|
||||
let [dir, version] = await lib._findVersion(installDir, "latest");
|
||||
assert.equal(dir, path.join(installDir, "data"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should find a given install dir with correct version as target", async function() {
|
||||
let installDir = path.join("test", "file", "factorio");
|
||||
let [dir, version] = await libFactorio._findVersion(installDir, "0.1.1");
|
||||
let [dir, version] = await lib._findVersion(installDir, "0.1.1");
|
||||
assert.equal(dir, path.join(installDir, "data"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should reject if the install dir version does not match target version", async function() {
|
||||
let installDir = path.join("test", "file", "factorio");
|
||||
await assert.rejects(
|
||||
libFactorio._findVersion(installDir, "0.1.2"),
|
||||
lib._findVersion(installDir, "0.1.2"),
|
||||
new Error("Factorio version 0.1.2 was requested, but install directory contains 0.1.1")
|
||||
);
|
||||
});
|
||||
it("should search given directory for latest Factorio install", async function() {
|
||||
let installDir = path.join("test", "file");
|
||||
let [dir, version] = await libFactorio._findVersion(installDir, "latest");
|
||||
let [dir, version] = await lib._findVersion(installDir, "latest");
|
||||
assert.equal(dir, path.join(installDir, "factorio", "data"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should search given directory for given Factorio install", async function() {
|
||||
let installDir = path.join("test", "file");
|
||||
let [dir, version] = await libFactorio._findVersion(installDir, "0.1.1");
|
||||
let [dir, version] = await lib._findVersion(installDir, "0.1.1");
|
||||
assert.equal(dir, path.join(installDir, "factorio", "data"));
|
||||
assert.equal(version, "0.1.1");
|
||||
});
|
||||
it("should reject if no factorio install with the given version was found", async function() {
|
||||
let installDir = path.join("test", "file");
|
||||
await assert.rejects(
|
||||
libFactorio._findVersion(installDir, "0.1.2"),
|
||||
lib._findVersion(installDir, "0.1.2"),
|
||||
new Error("Unable to find Factorio version 0.1.2")
|
||||
);
|
||||
});
|
||||
it("should reject if no factorio install was found", async function() {
|
||||
let installDir = path.join("test", "file", "instances");
|
||||
await assert.rejects(
|
||||
libFactorio._findVersion(installDir, "latest"),
|
||||
lib._findVersion(installDir, "latest"),
|
||||
new Error(`Unable to find any Factorio install in ${installDir}`)
|
||||
);
|
||||
});
|
||||
@@ -86,7 +86,7 @@ describe("lib/factorio/server", function() {
|
||||
|
||||
describe("randomDynamicPort()", function() {
|
||||
it("should return a port number", function() {
|
||||
let port = libFactorio._randomDynamicPort();
|
||||
let port = lib._randomDynamicPort();
|
||||
assert.equal(typeof port, "number");
|
||||
assert(Number.isInteger(port));
|
||||
assert(0 <= port && port < 2**16);
|
||||
@@ -97,24 +97,24 @@ describe("lib/factorio/server", function() {
|
||||
return (49152 <= port && port <= 65535);
|
||||
}
|
||||
for (let i=0; i < 20; i++) {
|
||||
assert(validate(libFactorio._randomDynamicPort()));
|
||||
assert(validate(lib._randomDynamicPort()));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("generatePassword()", function() {
|
||||
it("should return a string", async function() {
|
||||
let password = await libFactorio._generatePassword(1);
|
||||
let password = await lib._generatePassword(1);
|
||||
assert.equal(typeof password, "string");
|
||||
});
|
||||
|
||||
it("should return a string of the given length", async function() {
|
||||
let password = await libFactorio._generatePassword(10);
|
||||
let password = await lib._generatePassword(10);
|
||||
assert.equal(password.length, 10);
|
||||
});
|
||||
|
||||
it("should contain only a-z, A-Z, 0-9", async function() {
|
||||
let password = await libFactorio._generatePassword(10);
|
||||
let password = await lib._generatePassword(10);
|
||||
assert(/^[a-zA-Z0-9]+$/.test(password), `${password} failed test`);
|
||||
});
|
||||
});
|
||||
@@ -123,7 +123,7 @@ describe("lib/factorio/server", function() {
|
||||
it("should parse the test lines", function() {
|
||||
for (let [line, reference] of testLines) {
|
||||
reference.source = "test";
|
||||
let output = libFactorio._parseOutput(line, "test");
|
||||
let output = lib._parseOutput(line, "test");
|
||||
assert.deepEqual(output, reference);
|
||||
}
|
||||
});
|
||||
@@ -131,12 +131,12 @@ describe("lib/factorio/server", function() {
|
||||
|
||||
describe("class FactorioServer", function() {
|
||||
let writePath = path.join("temp", "test", "server");
|
||||
let server = new libFactorio.FactorioServer(path.join("test", "file", "factorio"), writePath, {});
|
||||
let server = new lib.FactorioServer(path.join("test", "file", "factorio"), writePath, {});
|
||||
|
||||
describe("constructor()", function() {
|
||||
it("should handle dashes in write path with strapPaths enabled", function() {
|
||||
// eslint-disable-next-line no-new
|
||||
new libFactorio.FactorioServer(
|
||||
new lib.FactorioServer(
|
||||
path.join("test", "file", "factorio"),
|
||||
path.join("temp", "test", "server-1"),
|
||||
{ stripPaths: true }
|
||||
|
||||
+15
-15
@@ -3,7 +3,7 @@ const assert = require("assert").strict;
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const libFileOps = require("@clusterio/lib/file_ops");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
describe("lib/file_ops", function() {
|
||||
let baseDir = path.join("temp", "test", "file_ops");
|
||||
@@ -28,30 +28,30 @@ describe("lib/file_ops", function() {
|
||||
|
||||
describe("getNewestFile()", function() {
|
||||
it("returns a string in a directory with files", async function() {
|
||||
let newest = await libFileOps.getNewestFile(path.join(baseDir, "test"));
|
||||
let newest = await lib.getNewestFile(path.join(baseDir, "test"));
|
||||
assert.equal(typeof newest, "string");
|
||||
});
|
||||
it("returns undefined if all entries were filtered out", async function() {
|
||||
let newest = await libFileOps.getNewestFile(path.join(baseDir, "test"), (name) => !name.endsWith(".txt"));
|
||||
let newest = await lib.getNewestFile(path.join(baseDir, "test"), (name) => !name.endsWith(".txt"));
|
||||
assert.equal(newest, undefined);
|
||||
});
|
||||
it("returns undefined if directory is empty", async function() {
|
||||
let newest = await libFileOps.getNewestFile(path.join(baseDir, "test", "folder"));
|
||||
let newest = await lib.getNewestFile(path.join(baseDir, "test", "folder"));
|
||||
assert.equal(newest, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getNewestFile()", function() {
|
||||
it("returns 0 if directory does not exist", async function() {
|
||||
let size = await libFileOps.directorySize(path.join(baseDir, "invalid"));
|
||||
let size = await lib.directorySize(path.join(baseDir, "invalid"));
|
||||
assert.equal(size, 0);
|
||||
});
|
||||
it("returns 0 if directory is empty", async function() {
|
||||
let size = await libFileOps.directorySize(path.join(baseDir, "test", "folder"));
|
||||
let size = await lib.directorySize(path.join(baseDir, "test", "folder"));
|
||||
assert.equal(size, 0);
|
||||
});
|
||||
it("returns size of files in directory", async function() {
|
||||
let size = await libFileOps.directorySize(path.join(baseDir, "test"));
|
||||
let size = await lib.directorySize(path.join(baseDir, "test"));
|
||||
assert.equal(size, 21);
|
||||
});
|
||||
});
|
||||
@@ -64,7 +64,7 @@ describe("lib/file_ops", function() {
|
||||
[["file.txt", ".txt"], "file.txt"],
|
||||
];
|
||||
for (let [args, expected] of cases) {
|
||||
let actual = await libFileOps.findUnusedName(path.join(baseDir, "test", "folder"), ...args);
|
||||
let actual = await lib.findUnusedName(path.join(baseDir, "test", "folder"), ...args);
|
||||
assert.equal(actual, expected);
|
||||
}
|
||||
});
|
||||
@@ -78,7 +78,7 @@ describe("lib/file_ops", function() {
|
||||
[["bar-1.txt", ".txt"], "bar-3.txt"],
|
||||
];
|
||||
for (let [args, expected] of cases) {
|
||||
let actual = await libFileOps.findUnusedName(path.join(baseDir, "find"), ...args);
|
||||
let actual = await lib.findUnusedName(path.join(baseDir, "find"), ...args);
|
||||
assert.equal(actual, expected);
|
||||
}
|
||||
});
|
||||
@@ -87,14 +87,14 @@ describe("lib/file_ops", function() {
|
||||
describe("safeOutputFile()", function() {
|
||||
it("should write new target file", async function() {
|
||||
let target = path.join(baseDir, "safe", "simple.txt");
|
||||
await libFileOps.safeOutputFile(target, "a text file", "utf8");
|
||||
await lib.safeOutputFile(target, "a text file", "utf8");
|
||||
assert(!await fs.pathExists(`${target}.tmp`), "temporary was left behind");
|
||||
assert.equal(await fs.readFile(target, "utf8"), "a text file");
|
||||
});
|
||||
it("should overwrite existing target file", async function() {
|
||||
let target = path.join(baseDir, "safe", "exists.txt");
|
||||
await fs.outputFile(target, "previous", "utf8");
|
||||
await libFileOps.safeOutputFile(target, "current", "utf8");
|
||||
await lib.safeOutputFile(target, "current", "utf8");
|
||||
assert(!await fs.pathExists(`${target}.tmp`), "temporary was left behind");
|
||||
assert.equal(await fs.readFile(target, "utf8"), "current");
|
||||
});
|
||||
@@ -102,11 +102,11 @@ describe("lib/file_ops", function() {
|
||||
|
||||
describe("checkFilename()", function() {
|
||||
it("should allow a basic name", function() {
|
||||
libFileOps.checkFilename("file");
|
||||
lib.checkFilename("file");
|
||||
});
|
||||
|
||||
function check(item, msg) {
|
||||
assert.throws(() => libFileOps.checkFilename(item), new Error(msg));
|
||||
assert.throws(() => lib.checkFilename(item), new Error(msg));
|
||||
}
|
||||
|
||||
it("should throw on non-string", function() {
|
||||
@@ -152,7 +152,7 @@ describe("lib/file_ops", function() {
|
||||
|
||||
describe("cleanFilename()", function() {
|
||||
function clean(item, expected) {
|
||||
assert.equal(libFileOps.cleanFilename(item), expected);
|
||||
assert.equal(lib.cleanFilename(item), expected);
|
||||
}
|
||||
|
||||
it("should allow a basic name", function() {
|
||||
@@ -160,7 +160,7 @@ describe("lib/file_ops", function() {
|
||||
});
|
||||
|
||||
function check(item, msg) {
|
||||
assert.throws(() => libFileOps.cleanFilename(item), new Error(msg));
|
||||
assert.throws(() => lib.cleanFilename(item), new Error(msg));
|
||||
}
|
||||
|
||||
it("should throw on non-string", function() {
|
||||
|
||||
+3
-3
@@ -3,21 +3,21 @@ const assert = require("assert").strict;
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const libHash = require("@clusterio/lib/hash");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/hash", function() {
|
||||
describe("hashStream()", function() {
|
||||
it("should hash a stream of bytes", async function() {
|
||||
let stream = fs.createReadStream(path.join("test", "file", "hash.txt"));
|
||||
let result = await libHash.hashStream(stream);
|
||||
let result = await lib.hashStream(stream);
|
||||
assert.equal(result, "be417768b5c3c5c1d9bcb2e7c119196dd76b5570");
|
||||
});
|
||||
});
|
||||
|
||||
describe("hashFile()", function() {
|
||||
it("should hash a file", async function() {
|
||||
let result = await libHash.hashFile(path.join("test", "file", "hash.txt"));
|
||||
let result = await lib.hashFile(path.join("test", "file", "hash.txt"));
|
||||
assert.equal(result, "be417768b5c3c5c1d9bcb2e7c119196dd76b5570");
|
||||
});
|
||||
});
|
||||
|
||||
+15
-15
@@ -2,25 +2,25 @@
|
||||
const assert = require("assert").strict;
|
||||
const hrtime = process.hrtime.bigint;
|
||||
|
||||
const libHelpers = require("@clusterio/lib/helpers");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/helpers", function() {
|
||||
describe("basicType()", function() {
|
||||
it("should return the expected values", function() {
|
||||
assert.equal(libHelpers.basicType("s"), "string");
|
||||
assert.equal(libHelpers.basicType(null), "null");
|
||||
assert.equal(libHelpers.basicType(undefined), "undefined");
|
||||
assert.equal(libHelpers.basicType([1, 2]), "array");
|
||||
assert.equal(libHelpers.basicType(7), "number");
|
||||
assert.equal(libHelpers.basicType({ a: 1 }), "object");
|
||||
assert.equal(lib.basicType("s"), "string");
|
||||
assert.equal(lib.basicType(null), "null");
|
||||
assert.equal(lib.basicType(undefined), "undefined");
|
||||
assert.equal(lib.basicType([1, 2]), "array");
|
||||
assert.equal(lib.basicType(7), "number");
|
||||
assert.equal(lib.basicType({ a: 1 }), "object");
|
||||
});
|
||||
});
|
||||
|
||||
describe("wait", function() {
|
||||
it("should wait the approximate amount of time given", async function() {
|
||||
let startNs = hrtime();
|
||||
await libHelpers.wait(100);
|
||||
await lib.wait(100);
|
||||
let duration = Number(hrtime() - startNs) / 1e6;
|
||||
|
||||
// On windows the time waited is normally up to 15 ms late with outliers in the 20ms range.
|
||||
@@ -30,22 +30,22 @@ describe("lib/helpers", function() {
|
||||
|
||||
describe("timeout", function() {
|
||||
it("should return the result of an already resolved promise", async function() {
|
||||
assert.equal(await libHelpers.timeout(Promise.resolve("value"), 10, "timeout"), "value");
|
||||
assert.equal(await lib.timeout(Promise.resolve("value"), 10, "timeout"), "value");
|
||||
});
|
||||
it("should return the result of the promise if received before timeout", async function() {
|
||||
assert.equal(await libHelpers.timeout(
|
||||
(async () => { await libHelpers.wait(10); return "value"; })(), 20, "timeout"
|
||||
assert.equal(await lib.timeout(
|
||||
(async () => { await lib.wait(10); return "value"; })(), 20, "timeout"
|
||||
), "value");
|
||||
});
|
||||
it("should return the timeoutResult if not received before timeout", async function() {
|
||||
assert.equal(await libHelpers.timeout(
|
||||
(async () => { await libHelpers.wait(20); return "value"; })(), 10, "timeout"
|
||||
assert.equal(await lib.timeout(
|
||||
(async () => { await lib.wait(20); return "value"; })(), 10, "timeout"
|
||||
), "timeout");
|
||||
});
|
||||
});
|
||||
|
||||
function parse(input, attributes) {
|
||||
const result = libHelpers.parseSearchString(input, attributes);
|
||||
const result = lib.parseSearchString(input, attributes);
|
||||
if (!result.issues.length) {
|
||||
return result.terms;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ describe("lib/helpers", function() {
|
||||
});
|
||||
});
|
||||
describe("wordMatches()", function() {
|
||||
const match = libHelpers.wordMatches;
|
||||
const match = lib.wordMatches;
|
||||
it("should match any inputs", function() {
|
||||
assert(match(parse("word")[0], "a word in a string"), "one text");
|
||||
assert(!match(parse("word")[0], "a string without"), "one text no match");
|
||||
|
||||
+12
-12
@@ -1,60 +1,60 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
const libIni = require("@clusterio/lib/ini");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
describe("lib/ini", function() {
|
||||
describe("parse()", function() {
|
||||
it("should ignore comments", function() {
|
||||
assert.deepEqual(
|
||||
libIni.parse("# A comment\n; Another comment\nfoo=bar\n"),
|
||||
lib.parse("# A comment\n; Another comment\nfoo=bar\n"),
|
||||
{ foo: "bar" },
|
||||
);
|
||||
});
|
||||
it("should ignore certain whitespace", function() {
|
||||
assert.deepEqual(
|
||||
libIni.parse(" # A comment \n\n [spam] \t \n \tfoo=bar\n"),
|
||||
lib.parse(" # A comment \n\n [spam] \t \n \tfoo=bar\n"),
|
||||
{ spam: { foo: "bar" }}
|
||||
);
|
||||
});
|
||||
it("should preserve certain whitespace", function() {
|
||||
assert.deepEqual(
|
||||
libIni.parse("[\t spam\t ]\nfoo =\t bar \n"),
|
||||
lib.parse("[\t spam\t ]\nfoo =\t bar \n"),
|
||||
{ "\t spam\t ": { "foo ": "\t bar " }}
|
||||
);
|
||||
});
|
||||
it("should not treat characters specially", function() {
|
||||
assert.deepEqual(
|
||||
libIni.parse("[#;spam]\nfoo#;=#;bar=#;'\""),
|
||||
lib.parse("[#;spam]\nfoo#;=#;bar=#;'\""),
|
||||
{ "#;spam": { "foo#;": "#;bar=#;'\"" }}
|
||||
);
|
||||
});
|
||||
it("should handle windows line endings", function() {
|
||||
assert.deepEqual(
|
||||
libIni.parse("[spam]\r\nfoo=bar\r\n"),
|
||||
lib.parse("[spam]\r\nfoo=bar\r\n"),
|
||||
{ "spam": { "foo": "bar" }}
|
||||
);
|
||||
});
|
||||
it("should throw on incomplete section", function() {
|
||||
assert.throws(
|
||||
() => libIni.parse("[spam"),
|
||||
() => lib.parse("[spam"),
|
||||
new Error("Unterminated section header on line 1")
|
||||
);
|
||||
});
|
||||
it("should throw on missing value", function() {
|
||||
assert.throws(
|
||||
() => libIni.parse("key"),
|
||||
() => lib.parse("key"),
|
||||
new Error("Missing value for key key on line 1")
|
||||
);
|
||||
});
|
||||
it("should throw on duplicated section", function() {
|
||||
assert.throws(
|
||||
() => libIni.parse("[spam]\n[spam]\n"),
|
||||
() => lib.parse("[spam]\n[spam]\n"),
|
||||
new Error("Duplicated section [spam] on line 2")
|
||||
);
|
||||
});
|
||||
it("should throw on duplicated keys", function() {
|
||||
assert.throws(
|
||||
() => libIni.parse("key=value\nkey=value\n"),
|
||||
() => lib.parse("key=value\nkey=value\n"),
|
||||
new Error("Duplicated key key on line 2")
|
||||
);
|
||||
});
|
||||
@@ -73,7 +73,7 @@ describe("lib/ini", function() {
|
||||
[{ "#;spam": { "foo#;": "#;bar=#;'\"" }}, "[#;spam]\nfoo#;=#;bar=#;'\"\n"],
|
||||
];
|
||||
for (let [input, expected] of cases) {
|
||||
assert.equal(libIni.stringify(input), expected);
|
||||
assert.equal(lib.stringify(input), expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -86,7 +86,7 @@ describe("lib/ini", function() {
|
||||
{ first: { foo: "1", bar: "2" }, second: { spam: "true" }},
|
||||
{ '"#;[] ': ' "#;[] ', ' #;"[ ': { '"#;[] ': ' "#;[ ' }},
|
||||
]) {
|
||||
let actual = libIni.parse(libIni.stringify(expected));
|
||||
let actual = lib.parse(lib.stringify(expected));
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
});
|
||||
|
||||
+14
-15
@@ -3,13 +3,12 @@ const assert = require("assert").strict;
|
||||
const events = require("events");
|
||||
|
||||
const mock = require("../../mock");
|
||||
const libData = require("@clusterio/lib/data");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/link/connectors", function() {
|
||||
describe("class WebSocketBaseConnector", function() {
|
||||
let testConnector = new libLink.WebSocketBaseConnector();
|
||||
let testConnector = new lib.WebSocketBaseConnector();
|
||||
|
||||
describe("._dropSendBufferSeq()", function() {
|
||||
beforeEach(function() {
|
||||
@@ -35,7 +34,7 @@ describe("lib/link/connectors", function() {
|
||||
});
|
||||
|
||||
describe("class WebSocketClientConnector", function() {
|
||||
let testConnector = new libLink.WebSocketClientConnector("url", 1);
|
||||
let testConnector = new lib.WebSocketClientConnector("url", 1);
|
||||
testConnector._socket = new mock.MockSocket();
|
||||
|
||||
describe(".register()", function() {
|
||||
@@ -51,7 +50,7 @@ describe("lib/link/connectors", function() {
|
||||
it("calls send on the socket", function() {
|
||||
testConnector._state = "connecting";
|
||||
testConnector._socket.sentMessages = [];
|
||||
testConnector.sendHandshake(new libData.MessageInvalidate());
|
||||
testConnector.sendHandshake(new lib.MessageInvalidate());
|
||||
assert.deepEqual(
|
||||
testConnector._socket.sentMessages.map(JSON.parse),
|
||||
[{ type: "invalidate" }]
|
||||
@@ -63,7 +62,7 @@ describe("lib/link/connectors", function() {
|
||||
it("calls send on the socket", function() {
|
||||
testConnector._state = "connected";
|
||||
testConnector._socket.sentMessages = [];
|
||||
testConnector.send(new libData.MessageHeartbeat(1));
|
||||
testConnector.send(new lib.MessageHeartbeat(1));
|
||||
assert.deepEqual(
|
||||
testConnector._socket.sentMessages.map(JSON.parse),
|
||||
[{ seq: 1, type: "heartbeat"}]
|
||||
@@ -96,8 +95,8 @@ describe("lib/link/connectors", function() {
|
||||
let called = false;
|
||||
testConnector.register = () => { called = true; };
|
||||
testConnector._processHandshake(
|
||||
new libData.MessageHello(
|
||||
new libData.HelloData("test", {})
|
||||
new lib.MessageHello(
|
||||
new lib.HelloData("test", {})
|
||||
)
|
||||
);
|
||||
assert(called, "register was not called");
|
||||
@@ -105,9 +104,9 @@ describe("lib/link/connectors", function() {
|
||||
it("should emit connect on ready", async function() {
|
||||
let result = events.once(testConnector, "connect");
|
||||
testConnector._processHandshake(
|
||||
new libData.MessageReady(
|
||||
new libData.ReadyData(
|
||||
new libData.Address(libData.Address.control, 1),
|
||||
new lib.MessageReady(
|
||||
new lib.ReadyData(
|
||||
new lib.Address(lib.Address.control, 1),
|
||||
"x",
|
||||
20,
|
||||
10,
|
||||
@@ -128,7 +127,7 @@ describe("lib/link/connectors", function() {
|
||||
it("should throw on message received in invalid state", function() {
|
||||
testConnector._state = "closed";
|
||||
assert.throws(
|
||||
() => testConnector._socket.events.get("message")(JSON.stringify(new libData.MessageInvalidate())),
|
||||
() => testConnector._socket.events.get("message")(JSON.stringify(new lib.MessageInvalidate())),
|
||||
new Error("Received message in unexpected state closed")
|
||||
);
|
||||
});
|
||||
@@ -136,15 +135,15 @@ describe("lib/link/connectors", function() {
|
||||
testConnector._state = "connecting";
|
||||
let called = false;
|
||||
testConnector._processHandshake = () => { called = true; };
|
||||
testConnector._socket.events.get("message")(JSON.stringify(new libData.MessageInvalidate()));
|
||||
testConnector._socket.events.get("message")(JSON.stringify(new lib.MessageInvalidate()));
|
||||
assert(called, "_processHandshake was not called");
|
||||
});
|
||||
it("should emit message on message in connected state", async function() {
|
||||
testConnector._socket.sentMessages = [];
|
||||
testConnector._state = "connected";
|
||||
let result = events.once(testConnector, "message");
|
||||
let addr = new libData.Address(libData.Address.control, 1);
|
||||
let event = new libData.MessageEvent(1, addr, addr, "TestEvent");
|
||||
let addr = new lib.Address(lib.Address.control, 1);
|
||||
let event = new lib.MessageEvent(1, addr, addr, "TestEvent");
|
||||
testConnector._socket.events.get("message")(JSON.stringify(event));
|
||||
assert.deepEqual((await result)[0], event);
|
||||
});
|
||||
|
||||
+76
-78
@@ -2,12 +2,10 @@
|
||||
const assert = require("assert").strict;
|
||||
const events = require("events");
|
||||
|
||||
const libData = require("@clusterio/lib/data");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libErrors = require("@clusterio/lib/errors");
|
||||
const lib = require("@clusterio/lib");
|
||||
const mock = require("../../mock");
|
||||
|
||||
const addr = libData.Address.fromShorthand;
|
||||
const addr = lib.Address.fromShorthand;
|
||||
|
||||
describe("lib/link/link", function() {
|
||||
function throwSimple(message) {
|
||||
@@ -28,7 +26,7 @@ describe("lib/link/link", function() {
|
||||
static dst = ["controller", "control"];
|
||||
static permission = null;
|
||||
}
|
||||
libLink.Link.register(SimpleRequest);
|
||||
lib.Link.register(SimpleRequest);
|
||||
class NumberRequest {
|
||||
static type = "request";
|
||||
static src = ["controller", "control"];
|
||||
@@ -45,14 +43,14 @@ describe("lib/link/link", function() {
|
||||
toJSON() { return this.value; }
|
||||
static fromJSON(json) { return new this(json); }
|
||||
};
|
||||
libLink.Link.register(NumberRequest);
|
||||
lib.Link.register(NumberRequest);
|
||||
class SimpleEvent {
|
||||
static type = "event";
|
||||
static src = ["controller", "control"];
|
||||
static dst = ["controller", "control"];
|
||||
static permission = null;
|
||||
}
|
||||
libLink.Link.register(SimpleEvent);
|
||||
lib.Link.register(SimpleEvent);
|
||||
class NumberEvent {
|
||||
static type = "event";
|
||||
static src = ["controller", "control"];
|
||||
@@ -63,11 +61,11 @@ describe("lib/link/link", function() {
|
||||
toJSON() { return this.value; }
|
||||
static fromJSON(json) { return new this(json); }
|
||||
}
|
||||
libLink.Link.register(NumberEvent);
|
||||
lib.Link.register(NumberEvent);
|
||||
|
||||
beforeEach(function() {
|
||||
testConnector = new mock.MockConnector(src, dst);
|
||||
testLink = new libLink.Link(testConnector);
|
||||
testLink = new lib.Link(testConnector);
|
||||
});
|
||||
|
||||
it("should handle unknown message", async function() {
|
||||
@@ -76,13 +74,13 @@ describe("lib/link/link", function() {
|
||||
|
||||
describe("Request handling", function() {
|
||||
it("should give an error response back on unrecognized request", function() {
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, src, "UnhandledRequest"));
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, src, "UnhandledRequest"));
|
||||
assert.deepEqual(testConnector.sentMessages, [
|
||||
new libData.MessageResponseError(
|
||||
new lib.MessageResponseError(
|
||||
testConnector._seq - 1,
|
||||
src,
|
||||
dst,
|
||||
new libData.ResponseError("Unrecognized request UnhandledRequest")
|
||||
new lib.ResponseError("Unrecognized request UnhandledRequest")
|
||||
),
|
||||
]);
|
||||
});
|
||||
@@ -92,14 +90,14 @@ describe("lib/link/link", function() {
|
||||
static src = "controller";
|
||||
static dst = "control";
|
||||
}
|
||||
libLink.Link.register(UnhandledRequest);
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, src, "UnhandledRequest"));
|
||||
lib.Link.register(UnhandledRequest);
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, src, "UnhandledRequest"));
|
||||
assert.deepEqual(testConnector.sentMessages, [
|
||||
new libData.MessageResponseError(
|
||||
new lib.MessageResponseError(
|
||||
testConnector._seq - 1,
|
||||
src,
|
||||
dst,
|
||||
new libData.ResponseError("No handler for UnhandledRequest")
|
||||
new lib.ResponseError("No handler for UnhandledRequest")
|
||||
),
|
||||
]);
|
||||
});
|
||||
@@ -109,14 +107,14 @@ describe("lib/link/link", function() {
|
||||
static src = "host";
|
||||
static dst = "control";
|
||||
}
|
||||
libLink.Link.register(InvalidSrcRequest);
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, src, "InvalidSrcRequest"));
|
||||
lib.Link.register(InvalidSrcRequest);
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, src, "InvalidSrcRequest"));
|
||||
assert.deepEqual(testConnector.sentMessages, [
|
||||
new libData.MessageResponseError(
|
||||
new lib.MessageResponseError(
|
||||
testConnector._seq - 1,
|
||||
src,
|
||||
dst,
|
||||
new libData.ResponseError("Source [Address controller:0] is not allowed for InvalidSrcRequest")
|
||||
new lib.ResponseError("Source [Address controller:0] is not allowed for InvalidSrcRequest")
|
||||
),
|
||||
]);
|
||||
});
|
||||
@@ -126,38 +124,38 @@ describe("lib/link/link", function() {
|
||||
static src = "controller";
|
||||
static dst = "host";
|
||||
}
|
||||
libLink.Link.register(InvalidDstRequest);
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, src, "InvalidDstRequest"));
|
||||
lib.Link.register(InvalidDstRequest);
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, src, "InvalidDstRequest"));
|
||||
assert.deepEqual(testConnector.sentMessages, [
|
||||
new libData.MessageResponseError(
|
||||
new lib.MessageResponseError(
|
||||
testConnector._seq - 1,
|
||||
src,
|
||||
dst,
|
||||
new libData.ResponseError(
|
||||
new lib.ResponseError(
|
||||
"Destination [Address control:1] is not allowed for InvalidDstRequest"
|
||||
)
|
||||
),
|
||||
]);
|
||||
});
|
||||
it("should give an error response back on broadcast src", function() {
|
||||
testConnector.emit("message", new libData.MessageRequest(1, addr("allControls"), src, "SimpleRequest"));
|
||||
testConnector.emit("message", new lib.MessageRequest(1, addr("allControls"), src, "SimpleRequest"));
|
||||
assert.deepEqual(testConnector.sentMessages, [
|
||||
new libData.MessageResponseError(
|
||||
new lib.MessageResponseError(
|
||||
testConnector._seq - 1,
|
||||
src,
|
||||
addr("allControls"),
|
||||
new libData.ResponseError("Message src may not be broadcast")
|
||||
new lib.ResponseError("Message src may not be broadcast")
|
||||
),
|
||||
]);
|
||||
});
|
||||
it("should give an error response back on requst with broadcast dst", function() {
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, addr("allControls"), "SimpleRequest"));
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, addr("allControls"), "SimpleRequest"));
|
||||
assert.deepEqual(testConnector.sentMessages, [
|
||||
new libData.MessageResponseError(
|
||||
new lib.MessageResponseError(
|
||||
testConnector._seq - 1,
|
||||
src,
|
||||
dst,
|
||||
new libData.ResponseError("Destination [Address 4:control] is not allowed for SimpleRequest")
|
||||
new lib.ResponseError("Destination [Address 4:control] is not allowed for SimpleRequest")
|
||||
),
|
||||
]);
|
||||
});
|
||||
@@ -165,7 +163,7 @@ describe("lib/link/link", function() {
|
||||
|
||||
describe("Event handling", function() {
|
||||
it("should ignore unrecognized event", function() {
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, src, "UnhandledEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, src, "UnhandledEvent"));
|
||||
assert.deepEqual(testConnector.sentMessages, []);
|
||||
});
|
||||
it("should ignore unhandled event", function() {
|
||||
@@ -174,8 +172,8 @@ describe("lib/link/link", function() {
|
||||
static src = "controller";
|
||||
static dst = "control";
|
||||
}
|
||||
libLink.Link.register(UnhandledEvent);
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, src, "UnhandledEvent"));
|
||||
lib.Link.register(UnhandledEvent);
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, src, "UnhandledEvent"));
|
||||
assert.deepEqual(testConnector.sentMessages, []);
|
||||
});
|
||||
it("should ignore invalid src", function() {
|
||||
@@ -185,9 +183,9 @@ describe("lib/link/link", function() {
|
||||
static dst = "control";
|
||||
}
|
||||
let handled = false;
|
||||
libLink.Link.register(InvalidSrcEvent);
|
||||
lib.Link.register(InvalidSrcEvent);
|
||||
testLink.snoopEvent(InvalidSrcEvent, async () => { handled = true; });
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, src, "InvalidSrcEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, src, "InvalidSrcEvent"));
|
||||
assert(!handled, "event was not ignored");
|
||||
assert.deepEqual(testConnector.sentMessages, []);
|
||||
});
|
||||
@@ -197,25 +195,25 @@ describe("lib/link/link", function() {
|
||||
static src = "controller";
|
||||
static dst = "host";
|
||||
}
|
||||
libLink.Link.register(InvalidDstEvent);
|
||||
lib.Link.register(InvalidDstEvent);
|
||||
let handled = false;
|
||||
testLink.snoopEvent(InvalidDstEvent, async () => { handled = true; });
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, src, "InvalidDstEvent"));
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, addr("allControls"), "InvalidDstEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, src, "InvalidDstEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, addr("allControls"), "InvalidDstEvent"));
|
||||
assert(!handled, "event was not ignored");
|
||||
assert.deepEqual(testConnector.sentMessages, []);
|
||||
});
|
||||
it("should ignore broadcast src", function() {
|
||||
let handled = false;
|
||||
testLink.snoopEvent(SimpleEvent, async () => { handled = true; });
|
||||
testConnector.emit("message", new libData.MessageEvent(1, addr("allControls"), src, "SimpleEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, addr("allControls"), src, "SimpleEvent"));
|
||||
assert(!handled, "event was not ignored");
|
||||
assert.deepEqual(testConnector.sentMessages, []);
|
||||
});
|
||||
it("should handle event with broadcast dst", function() {
|
||||
let handled = false;
|
||||
testLink.snoopEvent(SimpleEvent, async () => { handled = true; });
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, addr("allControls"), "SimpleEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, addr("allControls"), "SimpleEvent"));
|
||||
assert(handled, "event was ignored");
|
||||
assert.deepEqual(testConnector.sentMessages, []);
|
||||
});
|
||||
@@ -225,14 +223,14 @@ describe("lib/link/link", function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
testConnector.emit("disconnectPrepare");
|
||||
assert.deepEqual(await message, [new libData.MessageDisconnect("ready")]);
|
||||
assert.deepEqual(await message, [new lib.MessageDisconnect("ready")]);
|
||||
});
|
||||
it("should send ready on connector prepareDisconnect if an error occurs", async function() {
|
||||
testLink.prepareDisconnect = async () => { throwSimple("Error occured"); };
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
testConnector.emit("disconnectPrepare");
|
||||
assert.deepEqual(await message, [new libData.MessageDisconnect("ready")]);
|
||||
assert.deepEqual(await message, [new lib.MessageDisconnect("ready")]);
|
||||
});
|
||||
|
||||
it("should reject pending requests on close", async function() {
|
||||
@@ -253,39 +251,39 @@ describe("lib/link/link", function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
testLink.send(new SimpleRequest());
|
||||
let srcReq = new libData.Address(libData.Address.control, 1, 1);
|
||||
let srcReq = new lib.Address(lib.Address.control, 1, 1);
|
||||
assert.deepEqual(
|
||||
await message,
|
||||
[new libData.MessageRequest(1, srcReq, dst, "SimpleRequest", undefined)]
|
||||
[new lib.MessageRequest(1, srcReq, dst, "SimpleRequest", undefined)]
|
||||
);
|
||||
});
|
||||
it("should send request with data to the other side of the link", async function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
testLink.send(new NumberRequest(22));
|
||||
let srcReq = new libData.Address(libData.Address.control, 1, 1);
|
||||
let srcReq = new lib.Address(lib.Address.control, 1, 1);
|
||||
assert.deepEqual(
|
||||
await message,
|
||||
[new libData.MessageRequest(1, srcReq, dst, "NumberRequest", new NumberRequest(22))]
|
||||
[new lib.MessageRequest(1, srcReq, dst, "NumberRequest", new NumberRequest(22))]
|
||||
);
|
||||
});
|
||||
it("should send request and resolve when response is received", async function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
let request = testLink.send(new SimpleRequest());
|
||||
let srcReq = new libData.Address(libData.Address.control, 1, 1);
|
||||
testConnector.emit("message", new libData.MessageResponse(1, dst, srcReq));
|
||||
let srcReq = new lib.Address(lib.Address.control, 1, 1);
|
||||
testConnector.emit("message", new lib.MessageResponse(1, dst, srcReq));
|
||||
await request;
|
||||
});
|
||||
it("should send request and reject with error when error response is received", async function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
let request = testLink.send(new SimpleRequest());
|
||||
let srcReq = new libData.Address(libData.Address.control, 1, 1);
|
||||
let srcReq = new lib.Address(lib.Address.control, 1, 1);
|
||||
testConnector.emit(
|
||||
"message",
|
||||
new libData.MessageResponseError(
|
||||
1, dst, srcReq, new libData.ResponseError("Error")
|
||||
new lib.MessageResponseError(
|
||||
1, dst, srcReq, new lib.ResponseError("Error")
|
||||
)
|
||||
);
|
||||
await assert.rejects(
|
||||
@@ -297,8 +295,8 @@ describe("lib/link/link", function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
let request = testLink.send(new NumberRequest(22));
|
||||
let srcReq = new libData.Address(libData.Address.control, 1, 1);
|
||||
testConnector.emit("message", new libData.MessageResponse(1, dst, srcReq, 44));
|
||||
let srcReq = new lib.Address(lib.Address.control, 1, 1);
|
||||
testConnector.emit("message", new lib.MessageResponse(1, dst, srcReq, 44));
|
||||
assert.deepEqual(await request, new NumberRequest.Response(44));
|
||||
});
|
||||
it("should send event to the other side of the link", async function() {
|
||||
@@ -307,7 +305,7 @@ describe("lib/link/link", function() {
|
||||
testLink.send(new SimpleEvent());
|
||||
assert.deepEqual(
|
||||
await message,
|
||||
[new libData.MessageEvent(1, src, dst, "SimpleEvent", undefined)]
|
||||
[new lib.MessageEvent(1, src, dst, "SimpleEvent", undefined)]
|
||||
);
|
||||
});
|
||||
it("should send event with data to the other side of the link", async function() {
|
||||
@@ -316,7 +314,7 @@ describe("lib/link/link", function() {
|
||||
testLink.send(new NumberEvent(22));
|
||||
assert.deepEqual(
|
||||
await message,
|
||||
[new libData.MessageEvent(1, src, dst, "NumberEvent", new NumberEvent(22))]
|
||||
[new lib.MessageEvent(1, src, dst, "NumberEvent", new NumberEvent(22))]
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -325,18 +323,18 @@ describe("lib/link/link", function() {
|
||||
let handled = false;
|
||||
testLink.handle(SimpleRequest, async () => { handled = true; });
|
||||
assert(testLink._requestHandlers.has(SimpleRequest), "request handler was not registered");
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, src, "SimpleRequest"));
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, src, "SimpleRequest"));
|
||||
assert(handled, "request was not handled");
|
||||
});
|
||||
it("should send response error from request handler throwing", async function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
testLink.handle(SimpleRequest, async () => { throwSimple("Error"); });
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, src, "SimpleRequest"));
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, src, "SimpleRequest"));
|
||||
assert.deepEqual(
|
||||
await message,
|
||||
[new libData.MessageResponseError(
|
||||
1, src, dst, new libData.ResponseError("Error", undefined, "Error")
|
||||
[new lib.MessageResponseError(
|
||||
1, src, dst, new lib.ResponseError("Error", undefined, "Error")
|
||||
)]
|
||||
);
|
||||
});
|
||||
@@ -344,13 +342,13 @@ describe("lib/link/link", function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
testLink.handle(NumberRequest, async () => 1);
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, src, "NumberRequest", "not a number"));
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, src, "NumberRequest", "not a number"));
|
||||
let response = (await message)[0];
|
||||
assert.deepEqual(
|
||||
response,
|
||||
new libData.MessageResponseError(
|
||||
new lib.MessageResponseError(
|
||||
1, src, dst,
|
||||
new libData.ResponseError(
|
||||
new lib.ResponseError(
|
||||
"Request NumberRequest failed validation",
|
||||
response.data.code,
|
||||
response.data.stack,
|
||||
@@ -362,13 +360,13 @@ describe("lib/link/link", function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
testLink.handle(NumberRequest, async () => "not a number");
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, src, "NumberRequest", 1));
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, src, "NumberRequest", 1));
|
||||
let response = (await message)[0];
|
||||
assert.deepEqual(
|
||||
response,
|
||||
new libData.MessageResponseError(
|
||||
new lib.MessageResponseError(
|
||||
1, src, dst,
|
||||
new libData.ResponseError(
|
||||
new lib.ResponseError(
|
||||
"Response for request NumberRequest failed validation",
|
||||
response.data.code,
|
||||
response.data.stack,
|
||||
@@ -380,29 +378,29 @@ describe("lib/link/link", function() {
|
||||
let message = events.once(testConnector, "send");
|
||||
message.catch(() => {});
|
||||
testLink.handle(NumberRequest, async (request) => request.value + 4);
|
||||
testConnector.emit("message", new libData.MessageRequest(1, dst, src, "NumberRequest", 1));
|
||||
testConnector.emit("message", new lib.MessageRequest(1, dst, src, "NumberRequest", 1));
|
||||
let response = (await message)[0];
|
||||
assert.deepEqual(
|
||||
response,
|
||||
new libData.MessageResponse(1, src, dst, 5)
|
||||
new lib.MessageResponse(1, src, dst, 5)
|
||||
);
|
||||
});
|
||||
it("should register an event handler", function() {
|
||||
let handled = false;
|
||||
testLink.handle(SimpleEvent, async () => { handled = true; });
|
||||
assert(testLink._eventHandlers.has(SimpleEvent), "event handler was not registered");
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, src, "SimpleEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, src, "SimpleEvent"));
|
||||
assert(handled, "event was not handled");
|
||||
});
|
||||
it("should pass value to event handler", async function() {
|
||||
let value;
|
||||
testLink.handle(NumberEvent, async (event) => { value = event.value; });
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, src, "NumberEvent", 9));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, src, "NumberEvent", 9));
|
||||
assert.deepEqual(value, 9);
|
||||
});
|
||||
it("should log errors from event handler", function() {
|
||||
testLink.handle(SimpleEvent, async () => { throwSimple("Error"); });
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, src, "SimpleEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, src, "SimpleEvent"));
|
||||
});
|
||||
it("should throw on unknown type", function() {
|
||||
assert.throws(
|
||||
@@ -432,7 +430,7 @@ describe("lib/link/link", function() {
|
||||
static jsonSchema = {};
|
||||
}
|
||||
assert.throws(
|
||||
() => libLink.Link.register(BadRequest1),
|
||||
() => lib.Link.register(BadRequest1),
|
||||
new Error("Request BadRequest1 has static jsonSchema but is missing static fromJSON")
|
||||
);
|
||||
class BadRequest2 {
|
||||
@@ -442,7 +440,7 @@ describe("lib/link/link", function() {
|
||||
static fromJSON() {};
|
||||
}
|
||||
assert.throws(
|
||||
() => libLink.Link.register(BadRequest2),
|
||||
() => lib.Link.register(BadRequest2),
|
||||
new Error("Request BadRequest2 has static fromJSON but is missing static jsonSchema")
|
||||
);
|
||||
});
|
||||
@@ -454,7 +452,7 @@ describe("lib/link/link", function() {
|
||||
static jsonSchema = {};
|
||||
}
|
||||
assert.throws(
|
||||
() => libLink.Link.register(BadEvent1),
|
||||
() => lib.Link.register(BadEvent1),
|
||||
new Error("Event BadEvent1 has static jsonSchema but is missing static fromJSON")
|
||||
);
|
||||
class BadEvent2 {
|
||||
@@ -464,7 +462,7 @@ describe("lib/link/link", function() {
|
||||
static fromJSON() {};
|
||||
}
|
||||
assert.throws(
|
||||
() => libLink.Link.register(BadEvent2),
|
||||
() => lib.Link.register(BadEvent2),
|
||||
new Error("Event BadEvent2 has static fromJSON but is missing static jsonSchema")
|
||||
);
|
||||
});
|
||||
@@ -486,10 +484,10 @@ describe("lib/link/link", function() {
|
||||
static jsonSchema = { type: "string" };
|
||||
static fromJSON(json) { return new this(json); };
|
||||
}
|
||||
libLink.Link.register(StringEvent);
|
||||
lib.Link.register(StringEvent);
|
||||
testLink.handle(StringEvent, () => {});
|
||||
assert.throws(
|
||||
() => testLink._processMessage(new libData.MessageEvent(1, dst, src, "StringEvent", 99)),
|
||||
() => testLink._processMessage(new lib.MessageEvent(1, dst, src, "StringEvent", 99)),
|
||||
{ message: "Event StringEvent failed validation" }
|
||||
);
|
||||
});
|
||||
@@ -500,12 +498,12 @@ describe("lib/link/link", function() {
|
||||
let handled = false;
|
||||
testLink.snoopEvent(SimpleEvent, async () => { handled = true; });
|
||||
assert(testLink._eventSnoopers.has(SimpleEvent), "event was not snooped");
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, src, "SimpleEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, src, "SimpleEvent"));
|
||||
assert(handled, "event was not handled");
|
||||
});
|
||||
it("should log errors from snoop handler", function() {
|
||||
testLink.snoopEvent(SimpleEvent, async () => { throwSimple("Error"); });
|
||||
testConnector.emit("message", new libData.MessageEvent(1, dst, src, "SimpleEvent"));
|
||||
testConnector.emit("message", new lib.MessageEvent(1, dst, src, "SimpleEvent"));
|
||||
});
|
||||
it("should throw on double registration", function() {
|
||||
testLink.snoopEvent(SimpleEvent);
|
||||
|
||||
+18
-21
@@ -2,19 +2,16 @@
|
||||
const assert = require("assert").strict;
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
const util = require("util");
|
||||
|
||||
|
||||
const { testLines } = require("./factorio/lines");
|
||||
const libLoggingUtils = require("@clusterio/lib/logging_utils");
|
||||
const libStream = require("@clusterio/lib/stream");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/logging_utils.js", function() {
|
||||
describe("formatServerOutput", function() {
|
||||
it("should pass the test lines", function() {
|
||||
for (let [reference, output] of testLines) {
|
||||
let line = libLoggingUtils._formatServerOutput(output);
|
||||
let line = lib._formatServerOutput(output);
|
||||
// Strip colours
|
||||
line = line.replace(/\x1B\[\d+m/g, "");
|
||||
assert.deepEqual(line, reference);
|
||||
@@ -25,11 +22,11 @@ describe("lib/logging_utils.js", function() {
|
||||
let logDir = path.join("test", "file", "log");
|
||||
describe("class LogIndex", function() {
|
||||
it("should create a new empty index if index.json does not exist", async function() {
|
||||
let logIndex = await libLoggingUtils.LogIndex.load(logDir);
|
||||
let logIndex = await lib.LogIndex.load(logDir);
|
||||
assert.deepEqual(logIndex.index, new Map());
|
||||
});
|
||||
it("should build index of only past log files", async function() {
|
||||
let logIndex = await libLoggingUtils.LogIndex.load(logDir);
|
||||
let logIndex = await lib.LogIndex.load(logDir);
|
||||
await logIndex.buildIndex();
|
||||
assert.deepEqual(
|
||||
new Set(logIndex.index.keys()),
|
||||
@@ -37,12 +34,12 @@ describe("lib/logging_utils.js", function() {
|
||||
);
|
||||
});
|
||||
it("should roundtrip index on save load cycle", async function() {
|
||||
let logIndex = await libLoggingUtils.LogIndex.load(logDir);
|
||||
let logIndex = await lib.LogIndex.load(logDir);
|
||||
await logIndex.buildIndex();
|
||||
let tempDir = path.join("temp", "test", "log");
|
||||
logIndex.logDirectory = tempDir;
|
||||
await logIndex.save();
|
||||
let loadedIndex = await libLoggingUtils.LogIndex.load(tempDir);
|
||||
let loadedIndex = await lib.LogIndex.load(tempDir);
|
||||
assert.deepEqual(
|
||||
loadedIndex,
|
||||
logIndex
|
||||
@@ -51,7 +48,7 @@ describe("lib/logging_utils.js", function() {
|
||||
it("should handle loading broken index", async function() {
|
||||
let tempDir = path.join("temp", "test", "log");
|
||||
await fs.outputFile(path.join(tempDir, "index.json"), "Broken JSON");
|
||||
let logIndex = await libLoggingUtils.LogIndex.load(tempDir);
|
||||
let logIndex = await lib.LogIndex.load(tempDir);
|
||||
assert.deepEqual(logIndex.index, new Map());
|
||||
});
|
||||
});
|
||||
@@ -64,7 +61,7 @@ describe("lib/logging_utils.js", function() {
|
||||
continue;
|
||||
}
|
||||
let fileStream = fs.createReadStream(path.join(logDir, file));
|
||||
let lineStream = new libStream.LineSplitter({ readableObjectMode: true });
|
||||
let lineStream = new lib.LineSplitter({ readableObjectMode: true });
|
||||
fileStream.pipe(lineStream);
|
||||
for await (let line of lineStream) {
|
||||
try {
|
||||
@@ -75,7 +72,7 @@ describe("lib/logging_utils.js", function() {
|
||||
}
|
||||
}
|
||||
|
||||
logIndex = await libLoggingUtils.LogIndex.load(logDir);
|
||||
logIndex = await lib.LogIndex.load(logDir);
|
||||
await logIndex.buildIndex();
|
||||
});
|
||||
|
||||
@@ -83,45 +80,45 @@ describe("lib/logging_utils.js", function() {
|
||||
for (let index of [() => undefined, () => logIndex]) {
|
||||
describe(index() === undefined ? "without index" : "with index", function() {
|
||||
it("returns nothing with an empty filter", async function() {
|
||||
let log = await libLoggingUtils.queryLog(logDir, {}, index());
|
||||
let log = await lib.queryLog(logDir, {}, index());
|
||||
assert.deepEqual(log, []);
|
||||
});
|
||||
it("should return the whole log when querying all", async function() {
|
||||
let log = await libLoggingUtils.queryLog(logDir, { all: true }, index());
|
||||
let log = await lib.queryLog(logDir, { all: true }, index());
|
||||
assert.deepEqual(log, allLines);
|
||||
});
|
||||
it("should return the whole log in reverse when querying all desc", async function() {
|
||||
let log = await libLoggingUtils.queryLog(logDir, { all: true, order: "desc" }, index());
|
||||
let log = await lib.queryLog(logDir, { all: true, order: "desc" }, index());
|
||||
assert.deepEqual(log, [...allLines].reverse());
|
||||
});
|
||||
it("should limit by limit", async function() {
|
||||
let log = await libLoggingUtils.queryLog(logDir, { limit: 2, all: true }, index());
|
||||
let log = await lib.queryLog(logDir, { limit: 2, all: true }, index());
|
||||
assert.deepEqual(log, allLines.slice(0, 2));
|
||||
});
|
||||
it("should filter by maxLevel", async function() {
|
||||
let log = await libLoggingUtils.queryLog(logDir, { maxLevel: "info", all: true }, index());
|
||||
let log = await lib.queryLog(logDir, { maxLevel: "info", all: true }, index());
|
||||
assert.deepEqual(log, allLines.filter(
|
||||
info => ["fatal", "error", "warn", "audit", "info"].includes(info.level)
|
||||
));
|
||||
log = await libLoggingUtils.queryLog(logDir, { maxLevel: "fatal", all: true }, index());
|
||||
log = await lib.queryLog(logDir, { maxLevel: "fatal", all: true }, index());
|
||||
assert.deepEqual(log, allLines.filter(
|
||||
info => ["fatal"].includes(info.level)
|
||||
));
|
||||
});
|
||||
it("should filter by controller", async function() {
|
||||
let log = await libLoggingUtils.queryLog(logDir, { controller: true }, index());
|
||||
let log = await lib.queryLog(logDir, { controller: true }, index());
|
||||
assert.deepEqual(log, allLines.filter(
|
||||
info => info.host_id === undefined && info.instance_id === undefined
|
||||
));
|
||||
});
|
||||
it("should filter by hostIds", async function() {
|
||||
let log = await libLoggingUtils.queryLog(logDir, { hostIds: [1, 2] }, index());
|
||||
let log = await lib.queryLog(logDir, { hostIds: [1, 2] }, index());
|
||||
assert.deepEqual(log, allLines.filter(
|
||||
info => [1, 2].includes(info.host_id) && info.instance_id === undefined
|
||||
));
|
||||
});
|
||||
it("should filter by instanceIds", async function() {
|
||||
let log = await libLoggingUtils.queryLog(logDir, { instanceIds: [10, 11] }, index());
|
||||
let log = await lib.queryLog(logDir, { instanceIds: [10, 11] }, index());
|
||||
assert.deepEqual(log, allLines.filter(info => [10, 11].includes(info.instance_id)));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const libLuaTools = require("@clusterio/lib/lua_tools");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/lua_tools", function() {
|
||||
describe("escapeString()", function() {
|
||||
it("should escape backslashes", function() {
|
||||
assert.equal(libLuaTools.escapeString("\\a"), "\\\\a");
|
||||
assert.equal(lib.escapeString("\\a"), "\\\\a");
|
||||
});
|
||||
it("should escape double quotes", function() {
|
||||
assert.equal(libLuaTools.escapeString('"a"'), '\\"a\\"');
|
||||
assert.equal(lib.escapeString('"a"'), '\\"a\\"');
|
||||
});
|
||||
it("should escape single quotes", function() {
|
||||
assert.equal(libLuaTools.escapeString("'a'"), "\\'a\\'");
|
||||
assert.equal(lib.escapeString("'a'"), "\\'a\\'");
|
||||
});
|
||||
it("should escape nul bytes", function() {
|
||||
assert.equal(libLuaTools.escapeString("a\0b"), "a\\0b");
|
||||
assert.equal(lib.escapeString("a\0b"), "a\\0b");
|
||||
});
|
||||
it("should escape newlines", function() {
|
||||
assert.equal(libLuaTools.escapeString("a\nb"), "a\\nb");
|
||||
assert.equal(lib.escapeString("a\nb"), "a\\nb");
|
||||
});
|
||||
it("should escape carriage return", function() {
|
||||
assert.equal(libLuaTools.escapeString("a\rb"), "a\\rb");
|
||||
assert.equal(lib.escapeString("a\rb"), "a\\rb");
|
||||
});
|
||||
it("should escape all combined", function() {
|
||||
assert.equal(libLuaTools.escapeString("a\\b\"c'd\0e\nf\rg"), "a\\\\b\\\"c\\'d\\0e\\nf\\rg");
|
||||
assert.equal(lib.escapeString("a\\b\"c'd\0e\nf\rg"), "a\\\\b\\\"c\\'d\\0e\\nf\\rg");
|
||||
});
|
||||
});
|
||||
});
|
||||
+6
-6
@@ -2,14 +2,14 @@
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const mock = require("../mock");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/plugin", function() {
|
||||
describe("class BaseInstancePlugin", function() {
|
||||
let instancePlugin;
|
||||
it("should be constructible", async function() {
|
||||
instancePlugin = new libPlugin.BaseInstancePlugin({}, new mock.MockInstance(), {});
|
||||
instancePlugin = new lib.BaseInstancePlugin({}, new mock.MockInstance(), {});
|
||||
await instancePlugin.init();
|
||||
});
|
||||
it("should define defaults for hooks", async function() {
|
||||
@@ -56,7 +56,7 @@ describe("lib/plugin", function() {
|
||||
describe("class BaseControllerPlugin", function() {
|
||||
let controllerPlugin;
|
||||
it("should be constructible", async function() {
|
||||
controllerPlugin = new libPlugin.BaseControllerPlugin({}, {}, {}, new mock.MockLogger());
|
||||
controllerPlugin = new lib.BaseControllerPlugin({}, {}, {}, new mock.MockLogger());
|
||||
await controllerPlugin.init();
|
||||
});
|
||||
it("should define defaults for hooks", async function() {
|
||||
@@ -87,15 +87,15 @@ describe("lib/plugin", function() {
|
||||
}],
|
||||
]);
|
||||
it("should invoke the hook on the plugin", async function() {
|
||||
await libPlugin.invokeHook(plugins, "test");
|
||||
await lib.invokeHook(plugins, "test");
|
||||
assert(betaTestCalled, "Hook was not called");
|
||||
});
|
||||
it("should pass and return args", async function() {
|
||||
let result = await libPlugin.invokeHook(plugins, "pass", 1234);
|
||||
let result = await lib.invokeHook(plugins, "pass", 1234);
|
||||
assert.deepEqual(result, [1234]);
|
||||
});
|
||||
it("should ignore errors", async function() {
|
||||
await libPlugin.invokeHook(plugins, "error");
|
||||
await lib.invokeHook(plugins, "error");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,8 +3,8 @@ const assert = require("assert").strict;
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const libPluginLoader = require("@clusterio/lib/plugin_loader");
|
||||
const { escapeRegExp } = require("@clusterio/lib/helpers");
|
||||
const lib = require("@clusterio/lib");
|
||||
const { escapeRegExp } = lib;
|
||||
|
||||
|
||||
describe("lib/plugin_loader", function() {
|
||||
@@ -34,13 +34,13 @@ describe("lib/plugin_loader", function() {
|
||||
|
||||
it("should throw on missing plugin", async function() {
|
||||
await assert.rejects(
|
||||
libPluginLoader.loadPluginInfos(new Map([["missing", missingPlugin]]), []),
|
||||
lib.loadPluginInfos(new Map([["missing", missingPlugin]]), []),
|
||||
new RegExp(`^Error: PluginError: Cannot find module '${escapeRegExp(missingPlugin)}/info'`)
|
||||
);
|
||||
});
|
||||
it("should load test plugin", async function() {
|
||||
assert.deepEqual(
|
||||
await libPluginLoader.loadPluginInfos(new Map([["test", path.resolve(testPlugin)]])),
|
||||
await lib.loadPluginInfos(new Map([["test", path.resolve(testPlugin)]])),
|
||||
[{ name: "test", version: "0.0.1", requirePath: path.resolve(testPlugin) }]
|
||||
);
|
||||
});
|
||||
@@ -53,13 +53,13 @@ describe("lib/plugin_loader", function() {
|
||||
brokenMessage = err.message;
|
||||
}
|
||||
await assert.rejects(
|
||||
libPluginLoader.loadPluginInfos(new Map([["broken", path.resolve(brokenPlugin)]])),
|
||||
lib.loadPluginInfos(new Map([["broken", path.resolve(brokenPlugin)]])),
|
||||
{ message: `PluginError: ${brokenMessage}` }
|
||||
);
|
||||
});
|
||||
it("should reject on invalid plugin", async function() {
|
||||
await assert.rejects(
|
||||
libPluginLoader.loadPluginInfos(new Map([["invalid", path.resolve(invalidPlugin)]])),
|
||||
lib.loadPluginInfos(new Map([["invalid", path.resolve(invalidPlugin)]])),
|
||||
{ message: `Expected plugin at ${path.resolve(invalidPlugin)} to be named invalid but got wrong` }
|
||||
);
|
||||
});
|
||||
@@ -80,7 +80,7 @@ describe("lib/plugin_loader", function() {
|
||||
});
|
||||
it("should throw if class is missing from entrypoint", async function() {
|
||||
await assert.rejects(
|
||||
libPluginLoader.loadControllerPluginClass({
|
||||
lib.loadControllerPluginClass({
|
||||
name: "test",
|
||||
controllerEntrypoint: "controller",
|
||||
requirePath: path.resolve(missingClass),
|
||||
@@ -94,7 +94,7 @@ describe("lib/plugin_loader", function() {
|
||||
});
|
||||
it("should throw if class is not a subclass of BaseControllerPlugin", async function() {
|
||||
await assert.rejects(
|
||||
libPluginLoader.loadControllerPluginClass({
|
||||
lib.loadControllerPluginClass({
|
||||
name: "test",
|
||||
controllerEntrypoint: "controller",
|
||||
requirePath: path.resolve(wrongParentClass),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
|
||||
const prometheus = require("@clusterio/lib/prometheus");
|
||||
const prometheus = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/prometheus", function() {
|
||||
|
||||
+6
-7
@@ -1,12 +1,11 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
const events = require("events");
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
const stream = require("stream");
|
||||
const util = require("util");
|
||||
|
||||
const libStream = require("@clusterio/lib/stream");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
const finished = util.promisify(stream.finished);
|
||||
|
||||
@@ -14,7 +13,7 @@ const finished = util.promisify(stream.finished);
|
||||
describe("lib/stream", function() {
|
||||
describe("class LineSplitter", function() {
|
||||
function createSplitter(lines) {
|
||||
let lineStream = new libStream.LineSplitter({ readableObjectMode: true });
|
||||
let lineStream = new lib.LineSplitter({ readableObjectMode: true });
|
||||
lineStream.on("data", line => lines.push(line.toString("utf-8")));
|
||||
return lineStream;
|
||||
}
|
||||
@@ -61,7 +60,7 @@ describe("lib/stream", function() {
|
||||
|
||||
describe("class ReverseLineSplitter", function() {
|
||||
function createReverseSplitter(lines) {
|
||||
let lineStream = new libStream.ReverseLineSplitter({ readableObjectMode: true });
|
||||
let lineStream = new lib.ReverseLineSplitter({ readableObjectMode: true });
|
||||
lineStream.on("data", line => lines.push(line.toString("utf-8")));
|
||||
return lineStream;
|
||||
}
|
||||
@@ -111,7 +110,7 @@ describe("lib/stream", function() {
|
||||
let content = "";
|
||||
for (let i = 0; i < 10; i++) { content += String(i).repeat(10); }
|
||||
await fs.outputFile(path.join("temp", "test", "reverse.txt"), content);
|
||||
let reverseStream = await libStream.createReverseReadStream(
|
||||
let reverseStream = await lib.createReverseReadStream(
|
||||
path.join("temp", "test", "reverse.txt"),
|
||||
{ encoding: "utf8", highWaterMark: 10 }
|
||||
);
|
||||
@@ -131,9 +130,9 @@ describe("lib/stream", function() {
|
||||
ws.end();
|
||||
await finished(ws);
|
||||
|
||||
let lineStream = new libStream.ReverseLineSplitter({ readableObjectMode: true });
|
||||
let lineStream = new lib.ReverseLineSplitter({ readableObjectMode: true });
|
||||
let index = 99999;
|
||||
let rs = await libStream.createReverseReadStream(path.join("temp", "test", "reverse.txt"));
|
||||
let rs = await lib.createReverseReadStream(path.join("temp", "test", "reverse.txt"));
|
||||
lineStream.on("data", line => {
|
||||
let n = Number(line.toString());
|
||||
if (index !== n) {
|
||||
|
||||
+29
-29
@@ -1,25 +1,25 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
const libUsers = require("@clusterio/lib/users");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/users", function() {
|
||||
describe("definePermission()", function() {
|
||||
it("should validate the types of its arguments", function() {
|
||||
assert.throws(
|
||||
() => libUsers.definePermission({ name: 123, title: "Test", description: "A test" }),
|
||||
() => lib.definePermission({ name: 123, title: "Test", description: "A test" }),
|
||||
new Error("Expected name to be a non-empty string")
|
||||
);
|
||||
assert.throws(
|
||||
() => libUsers.definePermission({ name: "test", title: 123, description: "A test" }),
|
||||
() => lib.definePermission({ name: "test", title: 123, description: "A test" }),
|
||||
new Error("Expected title to be a non-empty string")
|
||||
);
|
||||
assert.throws(
|
||||
() => libUsers.definePermission({ name: "test", title: "Test", description: 123 }),
|
||||
() => lib.definePermission({ name: "test", title: "Test", description: 123 }),
|
||||
new Error("Expected description to be a non-empty string")
|
||||
);
|
||||
assert.throws(
|
||||
() => libUsers.definePermission({
|
||||
() => lib.definePermission({
|
||||
name: "test", title: "Test", description: "A test", grantByDefault: 1,
|
||||
}),
|
||||
new Error("Expected grantByDefault to be a boolean")
|
||||
@@ -27,10 +27,10 @@ describe("lib/users", function() {
|
||||
});
|
||||
|
||||
it("should define a permission", function() {
|
||||
libUsers.definePermission({ name: "test", title: "Test", description: "A test" });
|
||||
assert(libUsers.permissions.has("test"), "Permission was not defined");
|
||||
lib.definePermission({ name: "test", title: "Test", description: "A test" });
|
||||
assert(lib.permissions.has("test"), "Permission was not defined");
|
||||
|
||||
let test = libUsers.permissions.get("test");
|
||||
let test = lib.permissions.get("test");
|
||||
assert.equal(test.name, "test");
|
||||
assert.equal(test.title, "Test");
|
||||
assert.equal(test.description, "A test");
|
||||
@@ -39,7 +39,7 @@ describe("lib/users", function() {
|
||||
|
||||
it("should throw on already defined permission", function() {
|
||||
assert.throws(
|
||||
() => libUsers.definePermission({ name: "test", title: "Test", description: "A test" }),
|
||||
() => lib.definePermission({ name: "test", title: "Test", description: "A test" }),
|
||||
new Error("Permission 'test' is already defined")
|
||||
);
|
||||
});
|
||||
@@ -47,19 +47,19 @@ describe("lib/users", function() {
|
||||
|
||||
describe("class Role", function() {
|
||||
it("should round trip serialize", function() {
|
||||
let orig = new libUsers.Role({ id: 11, name: "Role", description: "My Role", permissions: ["test"] });
|
||||
let copy = new libUsers.Role(orig.serialize());
|
||||
let orig = new lib.Role({ id: 11, name: "Role", description: "My Role", permissions: ["test"] });
|
||||
let copy = new lib.Role(orig.serialize());
|
||||
assert.deepEqual(copy, orig);
|
||||
});
|
||||
|
||||
describe(".grantDefaultRoles()", function() {
|
||||
it("should only grant permissions with grantByDefault", function() {
|
||||
let role = new libUsers.Role({ id: 11, name: "Role", description: "My Role" });
|
||||
let role = new lib.Role({ id: 11, name: "Role", description: "My Role" });
|
||||
role.grantDefaultPermissions();
|
||||
assert(role.permissions.size > 0, "No permissions were granted");
|
||||
for (let permission of role.permissions) {
|
||||
assert(
|
||||
libUsers.permissions.get(permission).grantByDefault === true,
|
||||
lib.permissions.get(permission).grantByDefault === true,
|
||||
"Non-default permission granted"
|
||||
);
|
||||
}
|
||||
@@ -69,15 +69,15 @@ describe("lib/users", function() {
|
||||
|
||||
describe("class User", function() {
|
||||
let roles = new Map([
|
||||
[1, new libUsers.Role({ id: 1, name: "a", description: "a role", permissions: ["core.admin"] })],
|
||||
[2, new libUsers.Role({ id: 2, name: "b", description: "b role", permissions: ["test"] })],
|
||||
[1, new lib.Role({ id: 1, name: "a", description: "a role", permissions: ["core.admin"] })],
|
||||
[2, new lib.Role({ id: 2, name: "b", description: "b role", permissions: ["test"] })],
|
||||
]);
|
||||
it("should round trip serialize", function() {
|
||||
function test_roundtrip(serialized) {
|
||||
let user = new libUsers.User(serialized, roles);
|
||||
let user = new lib.User(serialized, roles);
|
||||
let user_serialized = user.serialize();
|
||||
assert.deepEqual(user_serialized, serialized);
|
||||
let user_deserialized = new libUsers.User(user_serialized, roles);
|
||||
let user_deserialized = new lib.User(user_serialized, roles);
|
||||
assert.deepEqual(user_deserialized, user);
|
||||
}
|
||||
|
||||
@@ -88,36 +88,36 @@ describe("lib/users", function() {
|
||||
test_roundtrip({ name: "user", instance_stats: [[1, { join_count: 1 }]]});
|
||||
});
|
||||
it("should ignore invalid roles", function() {
|
||||
let user = new libUsers.User({ name: "test", roles: [1, 4, 55] }, roles);
|
||||
let user = new lib.User({ name: "test", roles: [1, 4, 55] }, roles);
|
||||
assert.equal(user.roles.size, 1, "Unexpected count of roles");
|
||||
});
|
||||
it("should track online users", function() {
|
||||
let user = new libUsers.User({ name: "admin", roles: [1] }, roles);
|
||||
assert(!libUsers.User.onlineUsers.has(user));
|
||||
let user = new lib.User({ name: "admin", roles: [1] }, roles);
|
||||
assert(!lib.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set());
|
||||
|
||||
user.notifyJoin(12);
|
||||
assert(libUsers.User.onlineUsers.has(user));
|
||||
assert(lib.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set([12]));
|
||||
|
||||
user.notifyJoin(8);
|
||||
assert(libUsers.User.onlineUsers.has(user));
|
||||
assert(lib.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set([12, 8]));
|
||||
|
||||
user.notifyLeave(11);
|
||||
assert(libUsers.User.onlineUsers.has(user));
|
||||
assert(lib.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set([12, 8]));
|
||||
|
||||
user.notifyLeave(12);
|
||||
assert(libUsers.User.onlineUsers.has(user));
|
||||
assert(lib.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set([8]));
|
||||
|
||||
user.notifyLeave(8);
|
||||
assert(!libUsers.User.onlineUsers.has(user));
|
||||
assert(!lib.User.onlineUsers.has(user));
|
||||
assert.deepEqual(user.instances, new Set());
|
||||
});
|
||||
it("should calculate playerStats", function() {
|
||||
let user = new libUsers.User({ name: "test", roles: [1], instance_stats: [
|
||||
let user = new lib.User({ name: "test", roles: [1], instance_stats: [
|
||||
[1, {
|
||||
join_count: 1,
|
||||
online_time_ms: 60e3,
|
||||
@@ -148,9 +148,9 @@ describe("lib/users", function() {
|
||||
|
||||
describe(".checkPermission()", function() {
|
||||
it("should correctly resolve permissions", function() {
|
||||
let a = new libUsers.User({ name: "admin", roles: [1] }, roles);
|
||||
let b = new libUsers.User({ name: "user", roles: [2] }, roles);
|
||||
let c = new libUsers.User({ name: "null", roles: [] }, roles);
|
||||
let a = new lib.User({ name: "admin", roles: [1] }, roles);
|
||||
let b = new lib.User({ name: "user", roles: [2] }, roles);
|
||||
let c = new lib.User({ name: "null", roles: [] }, roles);
|
||||
|
||||
a.checkPermission("core.control.connect");
|
||||
assert.throws(() => b.checkPermission("core.control.connect"), new Error("Permission denied"));
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
const assert = require("assert").strict;
|
||||
const JSZip = require("jszip");
|
||||
|
||||
const { findRoot } = require("@clusterio/lib/zip_ops");
|
||||
const { findRoot } = require("@clusterio/lib");
|
||||
|
||||
|
||||
describe("lib/factorio", function() {
|
||||
|
||||
+12
-17
@@ -3,16 +3,11 @@ const events = require("events");
|
||||
const http = require("http");
|
||||
const express = require("express");
|
||||
|
||||
const libData = require("@clusterio/lib/data");
|
||||
const libHelpers = require("@clusterio/lib/helpers");
|
||||
const libLink = require("@clusterio/lib/link");
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
const libUsers = require("@clusterio/lib/users");
|
||||
const libPrometheus = require("@clusterio/lib/prometheus");
|
||||
const lib = require("@clusterio/lib");
|
||||
|
||||
const UserManager = require("@clusterio/controller/src/UserManager");
|
||||
|
||||
const addr = libData.Address.fromShorthand;
|
||||
const addr = lib.Address.fromShorthand;
|
||||
|
||||
class MockLogger {
|
||||
child() { return this; }
|
||||
@@ -72,7 +67,7 @@ class MockSocket {
|
||||
}
|
||||
}
|
||||
|
||||
class MockConnector extends libLink.BaseConnector {
|
||||
class MockConnector extends lib.BaseConnector {
|
||||
constructor(src, dst) {
|
||||
super(src, dst);
|
||||
|
||||
@@ -107,7 +102,7 @@ class MockServer extends events.EventEmitter {
|
||||
result = { response: result };
|
||||
}
|
||||
if (result.time) {
|
||||
await libHelpers.wait(result.time);
|
||||
await lib.wait(result.time);
|
||||
}
|
||||
if (result.response instanceof Error) {
|
||||
throw result.response;
|
||||
@@ -116,7 +111,7 @@ class MockServer extends events.EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
class MockInstance extends libLink.Link {
|
||||
class MockInstance extends lib.Link {
|
||||
constructor() {
|
||||
super(new MockConnector(addr({ instanceId: 7357 }), addr({ hostId: 1 })));
|
||||
this.logger = new MockLogger();
|
||||
@@ -143,13 +138,13 @@ class MockInstance extends libLink.Link {
|
||||
}
|
||||
}
|
||||
|
||||
class MockHost extends libLink.Link {
|
||||
class MockHost extends lib.Link {
|
||||
constructor() {
|
||||
super(new MockConnector(addr({ hostId: 1 }), addr("controller")));
|
||||
}
|
||||
}
|
||||
|
||||
class MockControl extends libLink.Link { }
|
||||
class MockControl extends lib.Link { }
|
||||
|
||||
class MockController {
|
||||
constructor() {
|
||||
@@ -172,14 +167,14 @@ class MockController {
|
||||
|
||||
this.userManager = new UserManager();
|
||||
this.userManager.roles = new Map([
|
||||
[0, new libUsers.Role({ id: 0, name: "Admin", description: "admin", permissions: ["core.admin"] })],
|
||||
[1, new libUsers.Role({ id: 1, name: "Player", description: "player", permissions: [] })],
|
||||
[0, new lib.Role({ id: 0, name: "Admin", description: "admin", permissions: ["core.admin"] })],
|
||||
[1, new lib.Role({ id: 1, name: "Player", description: "player", permissions: [] })],
|
||||
]);
|
||||
this.userManager.roles.get(1).grantDefaultPermissions();
|
||||
|
||||
this.userManager.users = new Map([
|
||||
["test", new libUsers.User({ name: "test", roles: [0, 1] }, this.userManager.roles)],
|
||||
["player", new libUsers.User({ name: "player", roles: [1] }, this.userManager.roles)],
|
||||
["test", new lib.User({ name: "test", roles: [0, 1] }, this.userManager.roles)],
|
||||
["player", new lib.User({ name: "player", roles: [1] }, this.userManager.roles)],
|
||||
]);
|
||||
this.instances = new Map();
|
||||
this.hosts = new Map();
|
||||
@@ -210,7 +205,7 @@ class MockController {
|
||||
}
|
||||
|
||||
async function createControllerPlugin(ControllerPluginClass, info) {
|
||||
libLink.registerPluginMessages([info]);
|
||||
lib.registerPluginMessages([info]);
|
||||
let controller = new MockController();
|
||||
let metrics = {};
|
||||
let logger = new MockLogger();
|
||||
|
||||
Reference in new issue
Block a user