fix(ci): make wss not depend on external dependencys (#6622)

pull/6612/head^2
Frank Elsinga 4 months ago committed by GitHub
parent 56175bce85
commit 8d11807f77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -53,7 +53,7 @@ class WebSocketMonitorType extends MonitorType {
/**
* Uses the ws Node.js library to establish a connection to target server
* @param {object} monitor The monitor object for input parameters.
* @returns {[ string, int ]} Array containing a status message and response code
* @returns {Promise<[ string, int ]>} Array containing a status message and response code
*/
async attemptUpgrade(monitor) {
return new Promise((resolve) => {

@ -4,13 +4,13 @@ const assert = require("node:assert");
const { WebSocketMonitorType } = require("../../../server/monitor-types/websocket-upgrade");
const { UP, PENDING } = require("../../../src/util");
const net = require("node:net");
const http = require("node:http");
/**
* Simulates non compliant WS Server, doesnt send Sec-WebSocket-Accept header
* @param {number} port Port the server listens on. Defaults to 8080
* @returns {Promise} Promise that resolves to the created server once listening
* @returns {Promise<{server: net.Server, port: number}>} Promise that resolves to the created server and its port
*/
function nonCompliantWS(port = 8080) {
function nonCompliantWS() {
const srv = net.createServer((socket) => {
socket.once("data", (buf) => {
socket.write("HTTP/1.1 101 Switching Protocols\r\n" +
@ -19,16 +19,56 @@ function nonCompliantWS(port = 8080) {
socket.destroy();
});
});
return new Promise((resolve) => srv.listen(port, () => resolve(srv)));
return new Promise((resolve) => {
srv.listen(0, () => {
resolve({ server: srv,
port: srv.address().port });
});
});
}
/**
* Creates a regular HTTP server (non-WebSocket) for testing WebSocket rejection
* @returns {Promise<{server: http.Server, port: number}>} Promise that resolves to the created server and its port
*/
function httpServer() {
const srv = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("This is not a WebSocket server");
});
return new Promise((resolve) => {
srv.listen(0, () => {
resolve({ server: srv,
port: srv.address().port });
});
});
}
/**
* Creates a WebSocket server for testing
* @param {object} options Options to pass to WebSocketServer
* @returns {Promise<{server: WebSocketServer, port: number}>} Promise that resolves to the created server and its port
*/
function createWebSocketServer(options = {}) {
return new Promise((resolve) => {
const wss = new WebSocketServer({ port: 0,
...options });
wss.on("listening", () => {
resolve({ server: wss,
port: wss.address().port });
});
});
}
describe("WebSocket Monitor", {
}, () => {
test("check() rejects with unexpected server response when connecting to non-WebSocket server", {}, async () => {
test("check() rejects with unexpected server response when connecting to non-WebSocket server", {}, async (t) => {
const websocketMonitor = new WebSocketMonitorType();
const { server: srv, port } = await httpServer();
t.after(() => srv.close());
const monitor = {
url: "wss://example.org",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
timeout: 30,
};
@ -44,11 +84,13 @@ describe("WebSocket Monitor", {
);
});
test("check() sets status to UP when connecting to secure WebSocket server", async () => {
test("check() sets status to UP when connecting to WebSocket server", async (t) => {
const websocketMonitor = new WebSocketMonitorType();
const { server: wss, port } = await createWebSocketServer();
t.after(() => wss.close());
const monitor = {
url: "wss://echo.websocket.org",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
@ -69,12 +111,12 @@ describe("WebSocket Monitor", {
});
test("check() sets status to UP when connecting to insecure WebSocket server", async (t) => {
t.after(() => wss.close());
const websocketMonitor = new WebSocketMonitorType();
const wss = new WebSocketServer({ port: 8080 });
const { server: wss, port } = await createWebSocketServer();
t.after(() => wss.close());
const monitor = {
url: "ws://localhost:8080",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
@ -94,11 +136,13 @@ describe("WebSocket Monitor", {
assert.deepStrictEqual(heartbeat, expected);
});
test("check() rejects when status code does not match expected value", async () => {
test("check() rejects when status code does not match expected value", async (t) => {
const websocketMonitor = new WebSocketMonitorType();
const { server: wss, port } = await createWebSocketServer();
t.after(() => wss.close());
const monitor = {
url: "wss://echo.websocket.org",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "1001" ]),
timeout: 30,
@ -115,11 +159,13 @@ describe("WebSocket Monitor", {
);
});
test("check() rejects when expected status code is empty", async () => {
test("check() rejects when expected status code is empty", async (t) => {
const websocketMonitor = new WebSocketMonitorType();
const { server: wss, port } = await createWebSocketServer();
t.after(() => wss.close());
const monitor = {
url: "wss://echo.websocket.org",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "" ]),
timeout: 30,
@ -137,12 +183,12 @@ describe("WebSocket Monitor", {
});
test("check() rejects when Sec-WebSocket-Accept header is invalid", async (t) => {
t.after(() => wss.close());
const websocketMonitor = new WebSocketMonitorType();
const wss = await nonCompliantWS();
const { server: wss, port } = await nonCompliantWS();
t.after(() => wss.close());
const monitor = {
url: "ws://localhost:8080",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
@ -160,12 +206,12 @@ describe("WebSocket Monitor", {
});
test("check() sets status to UP when ignoring invalid Sec-WebSocket-Accept header", async (t) => {
t.after(() => wss.close());
const websocketMonitor = new WebSocketMonitorType();
const wss = await nonCompliantWS();
const { server: wss, port } = await nonCompliantWS();
t.after(() => wss.close());
const monitor = {
url: "ws://localhost:8080",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: true,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
@ -185,11 +231,13 @@ describe("WebSocket Monitor", {
assert.deepStrictEqual(heartbeat, expected);
});
test("check() sets status to UP for compliant WebSocket server when ignoring Sec-WebSocket-Accept", async () => {
test("check() sets status to UP for compliant WebSocket server when ignoring Sec-WebSocket-Accept", async (t) => {
const websocketMonitor = new WebSocketMonitorType();
const { server: wss, port } = await createWebSocketServer();
t.after(() => wss.close());
const monitor = {
url: "wss://echo.websocket.org",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: true,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
@ -209,11 +257,13 @@ describe("WebSocket Monitor", {
assert.deepStrictEqual(heartbeat, expected);
});
test("check() rejects non-WebSocket server even when ignoring Sec-WebSocket-Accept", async () => {
test("check() rejects non-WebSocket server even when ignoring Sec-WebSocket-Accept", async (t) => {
const websocketMonitor = new WebSocketMonitorType();
const { server: srv, port } = await httpServer();
t.after(() => srv.close());
const monitor = {
url: "wss://example.org",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: true,
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
timeout: 30,
@ -230,11 +280,18 @@ describe("WebSocket Monitor", {
);
});
test("check() rejects when server does not support requested subprotocol", async () => {
test("check() rejects when server does not support requested subprotocol", async (t) => {
const websocketMonitor = new WebSocketMonitorType();
const { server: wss, port } = await createWebSocketServer({
handleProtocols: (protocols) => {
// Explicitly reject all subprotocols
return null;
}
});
t.after(() => wss.close());
const monitor = {
url: "wss://echo.websocket.org",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
wsSubprotocol: "ocpp1.6",
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
@ -252,11 +309,13 @@ describe("WebSocket Monitor", {
);
});
test("check() rejects when multiple subprotocols contain invalid characters", async () => {
test("check() rejects when multiple subprotocols contain invalid characters", async (t) => {
const websocketMonitor = new WebSocketMonitorType();
const { server: wss, port } = await createWebSocketServer();
t.after(() => wss.close());
const monitor = {
url: "wss://echo.websocket.org",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
wsSubprotocol: " # & ,ocpp2.0 [] , ocpp1.6 , ,, ; ",
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
@ -275,16 +334,16 @@ describe("WebSocket Monitor", {
});
test("check() sets status to UP when subprotocol with multiple spaces is accepted", async (t) => {
t.after(() => wss.close());
const websocketMonitor = new WebSocketMonitorType();
const wss = new WebSocketServer({ port: 8080,
const { server: wss, port } = await createWebSocketServer({
handleProtocols: (protocols) => {
return Array.from(protocols).includes("test") ? "test" : null;
}
});
t.after(() => wss.close());
const monitor = {
url: "ws://localhost:8080",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
wsSubprotocol: "invalid , test ",
accepted_statuscodes_json: JSON.stringify([ "1000" ]),
@ -306,16 +365,16 @@ describe("WebSocket Monitor", {
});
test("check() sets status to UP when server supports requested subprotocol", async (t) => {
t.after(() => wss.close());
const websocketMonitor = new WebSocketMonitorType();
const wss = new WebSocketServer({ port: 8080,
const { server: wss, port } = await createWebSocketServer({
handleProtocols: (protocols) => {
return Array.from(protocols).includes("test") ? "test" : null;
}
});
t.after(() => wss.close());
const monitor = {
url: "ws://localhost:8080",
url: `ws://localhost:${port}`,
wsIgnoreSecWebsocketAcceptHeader: false,
wsSubprotocol: "invalid,test",
accepted_statuscodes_json: JSON.stringify([ "1000" ]),

Loading…
Cancel
Save