mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 23:04:52 +09:00
* Refactor UserManager to use Datastore * Rename lib.User to UserDetails also adds to/fromUserDetails * Fix existing tests * Add user class tests * Add tests for finaliseUsers * Move HostDetails to own file with tests * Move InstanceDetails to its own file with tests * Rename HostInfo and add tests * Rename InstanceInfo and add tests - Also changes the names of the host properties related to instances - Also removes the need to specify the location of InstanceInfo * Make json round trip test validate schema * Add InstanceManager * Fix lint errors * Extra tests * Add final test coverage * Add one last test to InstanceManager * Response to comments * Use generator rather than return anonumous generator Co-authored-by: Hornwitser <github@hornwitser.no> * Fix lint issue with generator --------- Co-authored-by: Hornwitser <github@hornwitser.no>
173 lines
6.1 KiB
JavaScript
173 lines
6.1 KiB
JavaScript
"use strict";
|
|
const path = require("path");
|
|
const fs = require("fs-extra");
|
|
const assert = require("assert").strict;
|
|
const jwt = require("jsonwebtoken");
|
|
const { Role, SubscribableDatastore, ControllerConfig } = require("@clusterio/lib");
|
|
const { UserRecord, UserManager } = require("@clusterio/controller");
|
|
|
|
const TEMP_DIR = path.join("temp", "test", "UserManager");
|
|
|
|
describe("controller/UserManager", function () {
|
|
/** @type {SubscribableDatastore<UserRecord>} */
|
|
let records;
|
|
/** @type {SubscribableDatastore<Role>} */
|
|
let roles;
|
|
/** @type {ControllerConfig} */
|
|
let config;
|
|
/** @type {UserManager} */
|
|
let userManager;
|
|
|
|
beforeEach(async function () {
|
|
records = new SubscribableDatastore();
|
|
roles = new SubscribableDatastore();
|
|
config = new ControllerConfig("controller", {
|
|
"controller.default_role_id": null,
|
|
"controller.auth_secret": Buffer.from("mysecret").toString("base64"),
|
|
});
|
|
userManager = new UserManager(records, roles, config);
|
|
await fs.emptyDir(TEMP_DIR);
|
|
});
|
|
|
|
describe(".has() / .get() / .getMutable() / .hasName() / .getByName() / .getByNameMutable()", function () {
|
|
it("should return user when exists", function () {
|
|
const user = userManager.createUser("Alice");
|
|
assert.deepEqual(userManager.has(user.id), true);
|
|
assert.deepEqual(userManager.get(user.id), user);
|
|
assert.deepEqual(userManager.getMutable(user.id), user);
|
|
assert.deepEqual(userManager.hasName("Alice"), true);
|
|
assert.deepEqual(userManager.getByName("Alice"), user);
|
|
assert.deepEqual(userManager.getByNameMutable("Alice"), user);
|
|
});
|
|
|
|
it("should return undefined when user does not exist", function () {
|
|
assert.equal(userManager.has("nonexistent"), false);
|
|
assert.equal(userManager.get("nonexistent"), undefined);
|
|
assert.equal(userManager.hasName("nonexistent"), false);
|
|
assert.equal(userManager.getByName("nonexistent"), undefined);
|
|
});
|
|
});
|
|
|
|
describe(".values() / .valuesMutable()", function () {
|
|
it("should iterate all users", function () {
|
|
const u1 = userManager.createUser("Alice");
|
|
const u2 = userManager.createUser("Bob");
|
|
|
|
const values = Array.from(userManager.values());
|
|
const valuesMutable = Array.from(userManager.valuesMutable());
|
|
|
|
assert.deepEqual(values, [u1, u2]);
|
|
assert.deepEqual(valuesMutable, [u1, u2]);
|
|
});
|
|
});
|
|
|
|
describe(".createUser()", function () {
|
|
it("should create and store a new user", function () {
|
|
const user = userManager.createUser("Charlie");
|
|
assert.deepEqual(userManager.getByName("Charlie"), user);
|
|
assert.deepEqual(records.getMutable(user.id).toJSON(), user.toJSON());
|
|
});
|
|
|
|
it("should throw if user already exists", function () {
|
|
userManager.createUser("Dave");
|
|
assert.throws(() => userManager.createUser("Dave"), /already exists/);
|
|
});
|
|
|
|
it("should assign default role if configured and exists", function () {
|
|
roles.set(new Role(1, "admin"));
|
|
config.set("controller.default_role_id", 1);
|
|
const user = userManager.createUser("Eve");
|
|
assert(user.roleIds.has(1));
|
|
});
|
|
});
|
|
|
|
describe(".getOrCreateUser()", function () {
|
|
it("should return existing user", function () {
|
|
const existing = userManager.createUser("Frank");
|
|
const found = userManager.getOrCreateUser("Frank");
|
|
assert.deepEqual(found, existing);
|
|
});
|
|
|
|
it("should create user if missing", function () {
|
|
const found = userManager.getOrCreateUser("Grace");
|
|
assert(userManager.getByName("Grace"));
|
|
assert.deepEqual(found, userManager.getByName("Grace"));
|
|
});
|
|
});
|
|
|
|
describe(".deleteUser()", function () {
|
|
it("should delete user from records", function () {
|
|
const user = userManager.createUser("Heidi");
|
|
assert(userManager.getByName("Heidi"));
|
|
userManager.deleteUser(user);
|
|
assert.equal(userManager.getByName("Heidi"), undefined);
|
|
});
|
|
});
|
|
|
|
describe(".signUserToken()", function () {
|
|
it("should return a valid JWT for user", function () {
|
|
const user = userManager.createUser("Ivan");
|
|
const token = userManager.signUserToken(user);
|
|
const payload = jwt.verify(
|
|
token,
|
|
Buffer.from(config.get("controller.auth_secret"), "base64")
|
|
);
|
|
const { iat, ...rest } = payload;
|
|
assert.equal(typeof iat, "number");
|
|
assert.deepEqual(rest, { aud: "user", user: user.id });
|
|
});
|
|
});
|
|
|
|
describe(".clearStatsOfInstance()", function () {
|
|
it("should clear instance stats for all users", function () {
|
|
const instanceId = 42;
|
|
|
|
records.set(UserRecord.fromJSON({ name: "Jack", instance_stats: [[instanceId, { join_count: 1 }]] }));
|
|
records.set(UserRecord.fromJSON({ name: "Jill", instance_stats: [[instanceId, { join_count: 1 }]] }));
|
|
|
|
userManager.clearStatsOfInstance(instanceId);
|
|
|
|
for (const user of userManager.values()) {
|
|
assert(!user.instanceStats.has(instanceId), `${user.id} still has instanceStats for ${instanceId}`);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("static attemptMigrateLegacyUsersFile()", function () {
|
|
const usersFile = path.join(TEMP_DIR, "users.json");
|
|
const rolesFile = path.join(TEMP_DIR, "roles.json");
|
|
|
|
it("should do nothing if file does not exist", async function () {
|
|
await UserManager.attemptMigrateLegacyUsersFile(usersFile, rolesFile);
|
|
});
|
|
|
|
it("should do nothing if roles key missing", async function () {
|
|
await fs.writeJson(usersFile, { users: [] });
|
|
await UserManager.attemptMigrateLegacyUsersFile(usersFile, rolesFile);
|
|
const content = await fs.readJson(usersFile);
|
|
assert.deepEqual(content, { users: [] });
|
|
});
|
|
|
|
it("should throw if users key missing in legacy file", async function () {
|
|
await fs.writeJson(usersFile, { roles: [] });
|
|
await assert.rejects(
|
|
() => UserManager.attemptMigrateLegacyUsersFile(usersFile, rolesFile),
|
|
/Error: Legacy users json does not contain users property/
|
|
);
|
|
});
|
|
|
|
it("should migrate valid legacy file", async function () {
|
|
const legacy = { roles: [{ id: 1 }, { id: 2 }], users: [{ name: "Karl" }] };
|
|
await fs.writeJson(usersFile, legacy);
|
|
|
|
await UserManager.attemptMigrateLegacyUsersFile(usersFile, rolesFile);
|
|
|
|
const writtenRoles = await fs.readJson(rolesFile);
|
|
const writtenUsers = await fs.readJson(usersFile);
|
|
|
|
assert.deepEqual(writtenRoles, [{ id: 1 }, { id: 2 }]);
|
|
assert.deepEqual(writtenUsers, [{ name: "Karl" }]);
|
|
});
|
|
});
|
|
});
|