mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-12 07: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>
359 lines
10 KiB
JavaScript
359 lines
10 KiB
JavaScript
"use strict";
|
|
const assert = require("assert").strict;
|
|
const lib = require("@clusterio/lib");
|
|
|
|
const { Controller, InstanceRecord, InstanceManager } = require("@clusterio/controller");
|
|
|
|
describe("controller/InstanceManager", function () {
|
|
/** @type {Controller} */
|
|
let controller;
|
|
/** @type {InstanceManager} */
|
|
let instances;
|
|
/** @type {InstanceRecord} */
|
|
let instance;
|
|
|
|
beforeEach(function () {
|
|
const controllerConfig = new lib.ControllerConfig("controller", {
|
|
"controller.name": "TestController",
|
|
});
|
|
const instanceConfig = new lib.InstanceConfig("controller", {
|
|
"instance.id": 1,
|
|
"instance.name": "Test",
|
|
});
|
|
|
|
const datastoreInstances = new lib.SubscribableDatastore();
|
|
datastoreInstances.set(new InstanceRecord(instanceConfig, "unassigned"));
|
|
|
|
controller = new Controller(lib.logger, [], controllerConfig,
|
|
undefined, undefined, undefined, undefined, datastoreInstances);
|
|
instances = controller.instances;
|
|
instance = instances.getMutable(1);
|
|
});
|
|
|
|
describe("constructor()", function () {
|
|
it("should call _notifyConfigFieldChanged when config changes", async function () {
|
|
let called = false;
|
|
|
|
instances._notifyConfigFieldChanged = async (
|
|
inst, field, curr, prev
|
|
) => {
|
|
called = true;
|
|
assert.equal(inst.id, 1);
|
|
assert.equal(field, "instance.name");
|
|
assert.equal(prev, "Test");
|
|
assert.equal(curr, "Updated");
|
|
};
|
|
|
|
instance.config.set("instance.name", "Updated");
|
|
|
|
assert.equal(called, true);
|
|
});
|
|
|
|
it("should update datastore when config changes", function () {
|
|
let setCalled = false;
|
|
|
|
const originalSet = instances.records.set.bind(instances.records);
|
|
instances.records.set = function (value) {
|
|
setCalled = true;
|
|
return originalSet(value);
|
|
};
|
|
|
|
instance.config.set("instance.name", "Changed");
|
|
|
|
assert.equal(setCalled, true);
|
|
});
|
|
});
|
|
|
|
describe(".has() / .get() / .getMutable()", function () {
|
|
it("should return instance when exists", async function () {
|
|
assert.equal(instances.has(instance.id), true);
|
|
assert.equal(instances.get(instance.id), instance);
|
|
assert.equal(instances.getMutable(instance.id), instance);
|
|
});
|
|
|
|
it("should return undefined when missing", function () {
|
|
assert.equal(instances.has(999), false);
|
|
assert.equal(instances.get(999), undefined);
|
|
});
|
|
});
|
|
|
|
describe(".values() / .valuesMutable()", function () {
|
|
it("should iterate all instances", async function () {
|
|
const config1 = new lib.InstanceConfig("controller", {
|
|
"instance.id": 2,
|
|
"instance.name": "A",
|
|
});
|
|
const config2 = new lib.InstanceConfig("controller", {
|
|
"instance.id": 3,
|
|
"instance.name": "B",
|
|
});
|
|
|
|
const i1 = await instances.createInstance(config1);
|
|
const i2 = await instances.createInstance(config2);
|
|
|
|
assert.deepEqual(Array.from(instances.values()), [instance, i1, i2]);
|
|
assert.deepEqual(Array.from(instances.valuesMutable()), [instance, i1, i2]);
|
|
});
|
|
});
|
|
|
|
describe(".getForRequest()", function () {
|
|
it("should return instance when exists", async function () {
|
|
assert.equal(instances.getForRequest(1), instance);
|
|
});
|
|
|
|
it("should throw when missing", function () {
|
|
assert.throws(() => instances.getForRequest(999), lib.RequestError);
|
|
});
|
|
});
|
|
|
|
describe(".createInstance()", function () {
|
|
it("should create new instance with id 2", async function () {
|
|
let notified = false;
|
|
instances._notifyStatusChanged = async () => { notified = true; };
|
|
|
|
const config = new lib.InstanceConfig("controller", {
|
|
"instance.id": 2,
|
|
"instance.name": "Second",
|
|
});
|
|
|
|
const created = await instances.createInstance(config);
|
|
|
|
assert.equal(created.id, 2);
|
|
assert(instances.get(2), created);
|
|
assert.equal(notified, true);
|
|
});
|
|
|
|
it("should call notify on config change", async function () {
|
|
let notified = false;
|
|
instances._notifyConfigFieldChanged = async () => { notified = true; };
|
|
|
|
const config = new lib.InstanceConfig("controller", {
|
|
"instance.id": 2,
|
|
"instance.name": "Second",
|
|
});
|
|
|
|
const created = await instances.createInstance(config);
|
|
|
|
created.config.set("instance.name", "Updated");
|
|
|
|
assert.equal(created.id, 2);
|
|
assert.equal(instances.get(2), created);
|
|
assert.equal(notified, true);
|
|
});
|
|
|
|
it("should throw if id already exists", async function () {
|
|
const config = new lib.InstanceConfig("controller", {
|
|
"instance.id": 1,
|
|
"instance.name": "Duplicate",
|
|
});
|
|
|
|
await assert.rejects(
|
|
() => instances.createInstance(config),
|
|
lib.RequestError
|
|
);
|
|
});
|
|
|
|
it("should suppress changes when flag set", async function () {
|
|
let notified = false;
|
|
instances._notifyStatusChanged = async () => { notified = true; };
|
|
|
|
const config = new lib.InstanceConfig("controller", {
|
|
"instance.id": 2,
|
|
"instance.name": "Suppressed",
|
|
});
|
|
|
|
const created = await instances.createInstance(config, true);
|
|
|
|
assert.equal(instances.get(2), undefined);
|
|
assert.equal(notified, false);
|
|
});
|
|
});
|
|
|
|
describe(".assignInstance()", function () {
|
|
it("should throw if host not connected", async function () {
|
|
await assert.rejects(
|
|
() => instances.assignInstance(1, 5),
|
|
lib.RequestError
|
|
);
|
|
});
|
|
|
|
it("should do nothing if the host would not change", async function () {
|
|
let assignRequest;
|
|
controller.wsServer.hostConnections.set(5, {
|
|
send: async (request) => {
|
|
assignRequest = request;
|
|
},
|
|
connector: { closing: false },
|
|
});
|
|
|
|
instance.config.set("instance.assigned_host", 5);
|
|
|
|
await instances.assignInstance(1, 5);
|
|
assert.equal(assignRequest, undefined);
|
|
});
|
|
|
|
it("should not unassign if new host is not connected", async function () {
|
|
let unassignRequest;
|
|
controller.wsServer.hostConnections.set(5, {
|
|
send: async (request) => {
|
|
unassignRequest = request;
|
|
},
|
|
connector: { closing: false },
|
|
});
|
|
|
|
instance.config.set("instance.assigned_host", 5);
|
|
|
|
await assert.rejects(
|
|
() => instances.assignInstance(1, 6),
|
|
lib.RequestError
|
|
);
|
|
|
|
assert.equal(unassignRequest, undefined);
|
|
});
|
|
|
|
it("should assign to connected host", async function () {
|
|
let assignRequest;
|
|
controller.wsServer.hostConnections.set(5, {
|
|
send: async (request) => {
|
|
assignRequest = request;
|
|
},
|
|
connector: { closing: false },
|
|
});
|
|
|
|
await instances.assignInstance(1, 5);
|
|
|
|
assert.equal(instance.config.get("instance.assigned_host"), 5);
|
|
assert(assignRequest instanceof lib.InstanceAssignInternalRequest);
|
|
assert.equal(assignRequest.instanceId, 1);
|
|
});
|
|
|
|
it("should not fail when host has id of 0", async function () {
|
|
let lastEvent;
|
|
controller.wsServer.hostConnections.set(0, {
|
|
send: async (request) => {
|
|
lastEvent = request;
|
|
},
|
|
connector: { closing: false },
|
|
});
|
|
|
|
await instances.assignInstance(1, 0);
|
|
|
|
assert.equal(instance.config.get("instance.assigned_host"), 0);
|
|
assert(lastEvent instanceof lib.InstanceAssignInternalRequest);
|
|
assert.equal(lastEvent.instanceId, 1);
|
|
|
|
await instances.assignInstance(1, null);
|
|
|
|
assert.equal(instance.config.get("instance.assigned_host"), null);
|
|
assert(lastEvent instanceof lib.InstanceUnassignInternalRequest);
|
|
assert.equal(lastEvent.instanceId, 1);
|
|
});
|
|
|
|
it("should unassign old host if connected", async function () {
|
|
let unassignRequest;
|
|
controller.wsServer.hostConnections.set(5, {
|
|
send: async (request) => {
|
|
unassignRequest = request;
|
|
},
|
|
connector: { closing: false },
|
|
});
|
|
|
|
let assignRequest;
|
|
controller.wsServer.hostConnections.set(6, {
|
|
send: async (request) => {
|
|
assignRequest = request;
|
|
},
|
|
connector: { closing: false },
|
|
});
|
|
|
|
instance.config.set("instance.assigned_host", 5);
|
|
await instances.assignInstance(1, 6);
|
|
|
|
assert(unassignRequest instanceof lib.InstanceUnassignInternalRequest);
|
|
assert.equal(unassignRequest.instanceId, 1);
|
|
assert(assignRequest instanceof lib.InstanceAssignInternalRequest);
|
|
assert.equal(assignRequest.instanceId, 1);
|
|
});
|
|
|
|
it("should not unassign if old host closing", async function () {
|
|
let unassignRequest;
|
|
controller.wsServer.hostConnections.set(5, {
|
|
send: async (request) => {
|
|
unassignRequest = request;
|
|
},
|
|
connector: { closing: true },
|
|
});
|
|
|
|
let assignRequest;
|
|
controller.wsServer.hostConnections.set(6, {
|
|
send: async (request) => {
|
|
assignRequest = request;
|
|
},
|
|
connector: { closing: false },
|
|
});
|
|
|
|
instance.config.set("instance.assigned_host", 5);
|
|
await instances.assignInstance(1, 6);
|
|
|
|
assert.equal(unassignRequest, undefined);
|
|
assert(assignRequest instanceof lib.InstanceAssignInternalRequest);
|
|
assert.equal(assignRequest.instanceId, 1);
|
|
});
|
|
});
|
|
|
|
describe(".unassignInstance()", function () {
|
|
it("should unassign an instance", async function () {
|
|
controller.wsServer.hostConnections.set(5, {
|
|
send: async () => {},
|
|
connector: { closing: true },
|
|
});
|
|
|
|
await instances.assignInstance(instance.id, 5);
|
|
await instances.unassignInstance(instance.id);
|
|
assert.equal(instance.config.get("instance.assigned_host"), null);
|
|
assert.equal(instance.status, "unassigned");
|
|
});
|
|
it("should do nothing if the host would not change", async function () {
|
|
instance.config.set("instance.assigned_host", null);
|
|
|
|
let fieldChanged;
|
|
instance.config.on("fieldChanged", name => {
|
|
fieldChanged = name;
|
|
});
|
|
|
|
await instances.unassignInstance(1);
|
|
assert.equal(fieldChanged, undefined);
|
|
});
|
|
});
|
|
|
|
describe(".deleteInstance()", function () {
|
|
it("should delete and notify", async function () {
|
|
let notified = false;
|
|
instances._notifyStatusChanged = async () => { notified = true; };
|
|
|
|
await instances.deleteInstance(1);
|
|
|
|
assert.equal(instances.get(1), undefined);
|
|
assert.equal(notified, true);
|
|
});
|
|
|
|
it("should send delete to host if assigned", async function () {
|
|
let sentRequest;
|
|
controller.sendTo = async (_target, request) => {
|
|
sentRequest = request;
|
|
};
|
|
|
|
controller.wsServer.hostConnections.set(5, {
|
|
send: async () => {},
|
|
connector: { closing: false },
|
|
});
|
|
|
|
await instances.assignInstance(1, 5);
|
|
await instances.deleteInstance(1);
|
|
|
|
assert(sentRequest instanceof lib.InstanceDeleteInternalRequest);
|
|
assert.equal(sentRequest.instanceId, 1);
|
|
});
|
|
});
|
|
});
|