Cover UDP error paths and sendUdp in tests

Codecov flagged the sendUdp methods on Instance and BaseInstancePlugin,
the bind, socket error, malformed packet and send failure paths in
FactorioServer, and the --enable-lua-udp branch of startScenario.  Add
unit tests for each and start the integration scenario test with UDP
enabled on Factorio 2.0.59+.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
bbassieandClaude Fable 5.1 committed 2026-10-15 16:38:34 +00:00
1 parent 788ae17657
commit 4b0238b64b
5 files changed
+95

No files matched your search

+6
View File
@@ -66,6 +66,12 @@ describe("host/src/BaseInstancePlugin", function() {
await assert.rejects(instancePlugin.sendRcon("a"), new Error("ref"));
});
});
describe("sendUdp", function() {
it("should send message to the instance", async function() {
await instancePlugin.sendUdp("a");
assert.deepEqual(instancePlugin.instance.server.udpMessages, ["a"]);
});
});
describe("sendOrderedRcon", function() {
it("should send commands in order", async function() {
instancePlugin.instance.server.rconCommandResults.set("a", { time: 100, response: "a" });
+12
View File
@@ -240,6 +240,18 @@ describe("class Instance", function() {
});
});
describe(".sendUdp()", function() {
it("should throw when Lua UDP is disabled", async function() {
await assert.rejects(instance.sendUdp("data"), /Lua UDP is disabled/);
assert.deepEqual(instance.server.udpMessages, []);
});
it("should send to the server when enabled", async function() {
instance.config.set("factorio.enable_lua_udp", true);
await instance.sendUdp("data");
assert.deepEqual(instance.server.udpMessages, ["data"]);
});
});
describe("._recordPlayerJoin()", function() {
it("should add player to playersOnline", function() {
instance._recordPlayerJoin("player");
+65
View File
@@ -399,6 +399,71 @@ describe("host/server", function() {
assert.equal(server._udpSocket, null);
assert.equal(server.hostUdpPort, undefined);
});
it("should warn on packets not in IPC format", async function() {
server.luaUdpPort = udpServer.address().port;
await server._bindUdpSocket();
const logger = server._logger;
let warnings = [];
server._logger = { warn: msg => warnings.push(msg) };
try {
udpServer.send(Buffer.from("not ipc"), server.hostUdpPort, "127.0.0.1");
while (warnings.length < 1) {
await wait(1);
}
assert.equal(warnings[0], "Ignoring UDP packet not in IPC format: not ipc");
} finally {
server._logger = logger;
server._resetState();
}
});
it("should emit error on malformed IPC packets", async function() {
server.luaUdpPort = udpServer.address().port;
await server._bindUdpSocket();
try {
let waiter = events.once(server, "error");
udpServer.send(Buffer.from("\f$ipc:no_separator"), server.hostUdpPort, "127.0.0.1");
let [err] = await waiter;
assert.equal(err.message, 'Malformed IPC line "\f$ipc:no_separator"');
} finally {
server._resetState();
}
});
it("should forward socket errors", async function() {
await server._bindUdpSocket();
try {
let waiter = events.once(server, "error");
server._udpSocket.emit("error", new Error("socket failed"));
let [err] = await waiter;
assert.equal(err.message, "socket failed");
} finally {
server._resetState();
}
});
it("should reject sendUdp when sending fails", async function() {
server.luaUdpPort = udpServer.address().port;
await server._bindUdpSocket();
server._state = "running";
try {
// Larger than the maximum size of a UDP datagram
await assert.rejects(server.sendUdp(Buffer.alloc(70000)), { code: "EMSGSIZE" });
} finally {
server._resetState();
}
});
it("should close the socket if binding fails", async function() {
const createSocket = dgram.createSocket;
dgram.createSocket = (...args) => {
const socket = createSocket(...args);
socket.bind = () => process.nextTick(() => socket.emit("error", new Error("bind failed")));
return socket;
};
try {
await assert.rejects(server._bindUdpSocket(), new Error("bind failed"));
} finally {
dgram.createSocket = createSocket;
}
assert.equal(server._udpSocket, null);
});
});
describe(".stop()", function() {
+3
View File
@@ -179,6 +179,8 @@ describe("Integration of host/src/server", function() {
slowTest(this);
log(".startScenario()");
// --enable-lua-udp was added in Factorio 2.0.59
server.enableLuaUdp = lib.integerFullVersion(server.version) >= lib.integerFullVersion("2.0.59");
let pass = false;
function filter(output) {
if (output.message === "test_scenario init") {
@@ -191,6 +193,7 @@ describe("Integration of host/src/server", function() {
log(".stop()");
await server.stop();
server.enableLuaUdp = false;
server.off("output", filter);
assert(pass, "server did not output line from test scenario");
+9
View File
@@ -95,6 +95,11 @@ export class MockServer extends events.EventEmitter {
reset() {
this.rconCommands = [];
this.rconCommandResults = new Map();
this.udpMessages = [];
}
async sendUdp(message) {
this.udpMessages.push(message);
}
async sendRcon(command) {
@@ -144,6 +149,10 @@ export class MockInstance extends lib.Link {
async sendRcon(command, expectEmpty, plugin) {
return await this.server.sendRcon(command);
}
async sendUdp(message) {
await this.server.sendUdp(message);
}
}
export class MockHost extends lib.Link {