"use strict"; // What the bridge subscribes to: /discover and /+/alexaDirective. 1.x subscribed to /#, which also // delivered everything the bridge published itself and the backend's /alexaDirective_e. const { test } = require("node:test"); const assert = require("node:assert/strict"); const { Alex2MQTT, DisplayCategory, PowerController, topics } = require("alex2node"); const { broker, watcher, connected, directive, until, sleep } = require("./helpers/harness.js"); test("topics: the two filters, and the endpointId of a directive topic", () => { assert.deepEqual(topics.subscriptions("root"), ["root/discover", "root/+/alexaDirective"]); assert.equal(topics.directive("root", "lamp-1"), "root/lamp-1/alexaDirective"); assert.equal(topics.directiveEndpoint("root", "root/lamp-1/alexaDirective"), "lamp-1"); for (const other of [ "root/lamp-1/alexaDirective_e", "root/lamp-1/alexaResponce", "root/alexaDirective", "root/a/b/alexaDirective", "root//alexaDirective", "root2/lamp-1/alexaDirective", "root/discover", ]) { assert.equal(topics.directiveEndpoint("root", other), null, other); } }); test("the bridge subscribes to discover and +/alexaDirective: two endpoints get their directives, no other topic reaches the bridge", async () => { const { aedes, url } = await broker(); const subscribed = []; aedes.on("subscribe", (subscriptions, client) => { if (client.id === "bridge-under-test") subscribed.push(...subscriptions.map((s) => s.topic)); }); const alexa = await watcher(url, "root/#"); const received = []; const log = (line, detail) => { if (line === "MQTT Message Received") received.push(detail.topic); }; const bridge = await connected(new Alex2MQTT("u", "p", "root", false, { host: url, log, mqtt: { clientId: "bridge-under-test" } })); assert.deepEqual(subscribed.sort(), ["root/+/alexaDirective", "root/discover"]); const heard = []; for (const id of ["lamp-1", "lamp-2"]) { const lamp = bridge.registerDevice(id, id, DisplayCategory.LIGHT); const answer = (d) => { heard.push(`${id} ${d.header.name}`); return lamp.getStatusMessage(d.header.correlationToken, true).addPowerControllerProp(PowerController.ON).send(); }; lamp.on("Event", answer); lamp.on("ReportState", answer); } bridge.on("directive", ({ endpointId, name }) => heard.push(`bridge ${endpointId} ${name}`)); // Under the root, and none of them for the bridge: the last three are what the bridge and the backend publish const turnOn = directive("Alexa.PowerController", "TurnOn", "lamp-1", "not-for-the-bridge"); for (const topic of ["root/lamp-1/alexaDirective_e", "root/lamp-1/status", "root/lamp-1/alexaDirective/more", "root/alexaDirective"]) { alexa.publish(topic, turnOn); } alexa.publish("root/lamp-1/alexaResponce", { event: {} }); alexa.publish("root/changeReport", { event: {} }); alexa.publish("root/discover_r", []); alexa.send("root", directive("Alexa.PowerController", "TurnOn", "lamp-1", "ct-1")); alexa.send("root", directive("Alexa.PowerController", "TurnOff", "lamp-2", "ct-2")); alexa.publish("root/discover", ""); const answered = (id) => alexa.on(`root/${id}/alexaResponce`).some((m) => m.event.header); await until(() => answered("lamp-1") && answered("lamp-2") && alexa.on("root/discover_r").length === 2, 3000, "both responses and the discovery answer"); await sleep(100); // time for the echo of the bridge's own publishes, which must not come assert.deepEqual(heard, ["bridge lamp-1 TurnOn", "lamp-1 TurnOn", "bridge lamp-2 TurnOff", "lamp-2 TurnOff"]); assert.deepEqual(received, ["root/lamp-1/alexaDirective", "root/lamp-2/alexaDirective", "root/discover"]); });