mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-12 23:04:52 +09:00
Refactor user and instance manager (#837)
* 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>
This commit is contained in:
1 parent
5bea930d05
commit
2235294c59
60 files changed
+3371
-1227
No files matched your search
@@ -0,0 +1,156 @@
|
||||
"use strict";
|
||||
const assert = require("assert").strict;
|
||||
const { Role, SubscribableDatastore } = require("@clusterio/lib");
|
||||
const { User } = require("@clusterio/controller");
|
||||
|
||||
describe("controller/User", function () {
|
||||
/** @type {SubscribableDatastore<UserRecord>} */
|
||||
let users;
|
||||
/** @type {SubscribableDatastore<Role>} */
|
||||
let roles;
|
||||
/** @type {User} */
|
||||
let user;
|
||||
|
||||
beforeEach(function () {
|
||||
users = new SubscribableDatastore();
|
||||
roles = new SubscribableDatastore();
|
||||
|
||||
// Create a role and user used in most tests
|
||||
roles.set(Role.fromJSON({ id: 1, name: "connectRole", permissions: ["core.control.connect"] }));
|
||||
user = User.fromJSON({ name: "Alice", roles: [1] }, users, roles);
|
||||
|
||||
users.set(user);
|
||||
user.updatedAtMs = 1000; // Known low value
|
||||
});
|
||||
|
||||
describe("get roles", function () {
|
||||
it("should return roles from _controllerRoles", function () {
|
||||
const roleSet = user.roles;
|
||||
assert.equal(roleSet.size, 1);
|
||||
assert.equal([...roleSet][0].id, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".saveRecord() / set", function () {
|
||||
it("should update updatedAtMs", function () {
|
||||
const prev = user.updatedAtMs;
|
||||
user.saveRecord();
|
||||
assert(user.updatedAtMs > prev);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".set()", function () {
|
||||
it("should update updatedAtMs", function () {
|
||||
const prev = user.updatedAtMs;
|
||||
user.set("isAdmin", true);
|
||||
assert.equal(user.isAdmin, true);
|
||||
assert(user.updatedAtMs > prev);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".invalidateToken()", function () {
|
||||
it("should update tokenValidAfter to current time", function () {
|
||||
const prevValid = user.tokenValidAfter;
|
||||
const prevUpdate = user.updatedAtMs;
|
||||
user.invalidateToken();
|
||||
assert(user.tokenValidAfter > prevValid);
|
||||
assert(user.updatedAtMs > prevUpdate);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".addRole()", function () {
|
||||
it("should add role if exists", function () {
|
||||
roles.set(Role.fromJSON({ id: 2, name: "admin", permissions: ["core.admin"] }));
|
||||
const prev = user.updatedAtMs;
|
||||
|
||||
user.addRole(2);
|
||||
assert(user.roleIds.has(2));
|
||||
assert(user.updatedAtMs > prev);
|
||||
});
|
||||
|
||||
it("should throw if role does not exist", function () {
|
||||
assert.throws(() => user.addRole(999), /role 999 does not exist/);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".removeRole()", function () {
|
||||
it("should remove existing role", function () {
|
||||
const prev = user.updatedAtMs;
|
||||
const result = user.removeRole(1);
|
||||
assert(result);
|
||||
assert(!user.roleIds.has(1));
|
||||
assert(user.updatedAtMs > prev);
|
||||
});
|
||||
|
||||
it("should return false if role was not assigned", function () {
|
||||
const prev = user.updatedAtMs;
|
||||
const result = user.removeRole(999);
|
||||
assert.equal(result, false);
|
||||
assert(user.updatedAtMs === prev); // unchanged
|
||||
});
|
||||
});
|
||||
|
||||
describe(".notifyJoin() / .notifyLeave()", function () {
|
||||
it("should add instance on notifyJoin", function () {
|
||||
const prev = user.updatedAtMs;
|
||||
user.notifyJoin(10);
|
||||
assert(user.instances.has(10));
|
||||
assert(user.updatedAtMs > prev);
|
||||
});
|
||||
|
||||
it("should remove instance on notifyLeave", function () {
|
||||
user.notifyJoin(10);
|
||||
user.updatedAtMs = 1000; // Known low value
|
||||
user.notifyLeave(10);
|
||||
assert(!user.instances.has(10));
|
||||
assert(user.updatedAtMs > 1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".clearInstanceStats()", function () {
|
||||
it("should remove instanceStats and recalculate playerStats", function () {
|
||||
const instanceId = 5;
|
||||
const userWithStats = User.fromJSON({
|
||||
name: "Bob",
|
||||
instanceStats: [[instanceId, { join_count: 1 }]],
|
||||
}, users, roles);
|
||||
|
||||
users.set(userWithStats);
|
||||
userWithStats.updatedAtMs = 1000; // Known low value
|
||||
|
||||
userWithStats.clearInstanceStats(instanceId);
|
||||
assert(!userWithStats.instanceStats.has(instanceId));
|
||||
assert(userWithStats.updatedAtMs > 1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".checkPermission()", function () {
|
||||
it("should allow if role has core.control.connect", function () {
|
||||
assert.doesNotThrow(() => user.checkPermission("core.control.connect"));
|
||||
});
|
||||
|
||||
it("should allow if role has core.admin", function () {
|
||||
roles.set(Role.fromJSON({ id: 2, name: "admin", permissions: ["core.admin"] }));
|
||||
const adminUser = User.fromJSON({ name: "Charlie", roles: [2] }, users, roles);
|
||||
assert.doesNotThrow(() => adminUser.checkPermission("core.admin"));
|
||||
});
|
||||
|
||||
it("should not error if user has invalid role", function () {
|
||||
user.roleIds = {
|
||||
[Symbol.iterator]: function* () {
|
||||
// We need the invalid id (99) to be before the valid id (1)
|
||||
for (const roleId of [99, 1]) { yield roleId; }
|
||||
},
|
||||
};
|
||||
assert.doesNotThrow(() => user.checkPermission("core.control.connect"));
|
||||
});
|
||||
|
||||
it("should throw if permission not granted", function () {
|
||||
assert.throws(() => user.checkPermission("core.admin"), /Permission denied/);
|
||||
});
|
||||
|
||||
it("should throw if permission does not exist", function () {
|
||||
assert.throws(() => user.checkPermission("nonexistent.permission"), /does not exist/);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user