bridge: publish through a Publisher; devices no longer hold the broker client
src/transport.ts has the Publisher interface, MqttPublisher (the client the bridge has at the time) and MemoryPublisher (tests without a broker); src/topics.ts names the four topics the library publishes to. Device, AlexaStatusMessage, AlexaErrorResponse and sendSceneResponse shared three copies of the publish-and-report code: they now call one send() that resolves the topic or "" and never rejects. registerDevice() and addDevice() work before connect(); a send() without a connection resolves "" and the "error" event says to call connect(). unregisterDevice() and clearDevices() take the publisher from the device. Device.setMqttClient() is gone, the first constructor argument of Device is ignored, and the message classes take a Publisher where they took the client. Tests: 108 -> 113. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
46fa06728c
commit
6789a1a077
39 changed files with 839 additions and 246 deletions
|
|
@ -1,10 +1,10 @@
|
|||
"use strict";
|
||||
// The broker connection: the default host, an outage reported as events that never crash the host, disconnect() then
|
||||
// connect(), and a publish that fails without rejecting.
|
||||
// The broker connection: the default host, an outage reported as events that never crash the host, devices declared
|
||||
// before connect(), disconnect() then connect(), and a publish that fails without rejecting.
|
||||
const { test } = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const { Alex2MQTT, AlexaInterfaceType, DisplayCategory, PowerController, DEFAULT_HOST } = require("alex2node");
|
||||
const { broker, setup, connected, directive, until, sleep, cleanup } = require("./helpers/harness.js");
|
||||
const { broker, watcher, setup, connected, directive, until, sleep, cleanup } = require("./helpers/harness.js");
|
||||
|
||||
// Nothing listens on port 1, so every attempt is refused at once.
|
||||
const DEAD_BROKER = { host: "mqtt://127.0.0.1:1", mqtt: { reconnectPeriod: 50, connectTimeout: 200 } };
|
||||
|
|
@ -32,8 +32,27 @@ test("a dead broker: 'offline'/'error' events when listened to, and NO crash whe
|
|||
await until(() => seen.includes("ECONNREFUSED") && seen.includes("reconnect"), 3000, "error + reconnect events");
|
||||
});
|
||||
|
||||
test("registerDevice before connect throws (unchanged from 1.4.0)", () => {
|
||||
assert.throws(() => new Alex2MQTT("u", "p", "root").registerDevice("x", "1", null), /connect before/);
|
||||
test("devices declared before connect() (1.x threw): a send() is refused until the bridge connects, then they answer", async () => {
|
||||
const { url } = await broker();
|
||||
const alexa = await watcher(url, "root-early/#");
|
||||
const bridge = new Alex2MQTT("u", "p", "root-early", false, { host: url });
|
||||
const errors = [];
|
||||
bridge.on("error", (e) => errors.push(e.message));
|
||||
const lamp = bridge.registerDevice("Lamp", "lamp-1", DisplayCategory.LIGHT);
|
||||
const plug = bridge.addDevice({ endpointId: "plug-1", name: "Plug", categories: ["SMARTPLUG"] });
|
||||
for (const device of [lamp, plug]) {
|
||||
device.on("Event", (d) => device.getStatusMessage(d.header.correlationToken, true).addPowerControllerProp(PowerController.ON).send());
|
||||
}
|
||||
|
||||
assert.equal(await lamp.getStatusMessage("early", true).addPowerControllerProp(PowerController.ON).send(), "");
|
||||
assert.deepEqual(errors, ["nothing was published to root-early/lamp-1/alexaResponce: the bridge is not connected, call connect() first"]);
|
||||
|
||||
await connected(bridge);
|
||||
for (const id of ["lamp-1", "plug-1"]) {
|
||||
alexa.send("root-early", directive("Alexa.PowerController", "TurnOn", id, `ct-${id}`));
|
||||
await until(() => alexa.on(`root-early/${id}/alexaResponce`).length === 1, 3000, `the response of ${id}`);
|
||||
assert.equal(alexa.on(`root-early/${id}/alexaResponce`)[0].event.header.correlationToken, `ct-${id}`);
|
||||
}
|
||||
});
|
||||
|
||||
test("disconnect() then connect(): devices registered before still answer (1.5.1 left them on the closed client)", async () => {
|
||||
|
|
@ -66,7 +85,7 @@ test("1.5.2: a failed publish never rejects send() - it resolves \"\" and reache
|
|||
await connected(bridge);
|
||||
const lamp = bridge.registerDevice("Lamp", "lamp-send", null);
|
||||
lamp.addCapability(AlexaInterfaceType.POWER_CONTROLLER);
|
||||
await bridge.disconnect(); // the device still holds the ended client until the next connect(): every publish now fails
|
||||
await bridge.disconnect(); // the bridge has no client until the next connect(): every publish is refused
|
||||
|
||||
const status = await lamp.getStatusMessage("ct", true).addPowerControllerProp(PowerController.ON).send();
|
||||
const error = await lamp.getErrorMessage("ct").send();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue