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
|
|
@ -5,7 +5,7 @@ const { test } = require("node:test");
|
|||
const assert = require("node:assert/strict");
|
||||
const {
|
||||
Alex2MQTT, AlexaErrorResponse, AlexaErrorType, AlexaInterfaceType, AlexaStatusMessage, DisplayCategory, EndpointHealth,
|
||||
PowerController, TemperatureSensorScale,
|
||||
MemoryPublisher, PowerController, TemperatureSensorScale,
|
||||
} = require("alex2node");
|
||||
const { setup, sleep, UUID_V4 } = require("../helpers/harness.js");
|
||||
|
||||
|
|
@ -28,12 +28,6 @@ const property = (namespace, name, value, more = {}) => (
|
|||
{ namespace, name, value, timeOfSample: "<time>", uncertaintyInMilliseconds: 0, ...more }
|
||||
);
|
||||
|
||||
// A client that keeps what it is asked to publish
|
||||
function recorder(error) {
|
||||
const published = [];
|
||||
return { published, publish: (topic, payload, done) => { published.push({ topic, payload: JSON.parse(payload) }); done(error); } };
|
||||
}
|
||||
|
||||
test("a Response with every add...Prop helper: the JSON of 1.5.2", () => {
|
||||
const message = new AlexaStatusMessage("ct", "root", "5020AA", null, true)
|
||||
.addPowerControllerProp(PowerController.ON)
|
||||
|
|
@ -131,8 +125,8 @@ test("wire change: the namespace of an ErrorResponse follows the type (1.5.2: al
|
|||
});
|
||||
|
||||
test("an ErrorResponse with the fields of its type: the JSON of 1.5.2, sent to the topic asked for", async () => {
|
||||
const client = recorder();
|
||||
const error = new AlexaErrorResponse("ct", "root", "5020AA", client);
|
||||
const sent = new MemoryPublisher();
|
||||
const error = new AlexaErrorResponse("ct", "root", "5020AA", sent);
|
||||
error.setErrorMessage(AlexaErrorType.VALUE_OUT_OF_RANGE, "too high", { validRange: { minimumValue: 1, maximumValue: 10 } });
|
||||
const expected = {
|
||||
event: {
|
||||
|
|
@ -144,7 +138,7 @@ test("an ErrorResponse with the fields of its type: the JSON of 1.5.2, sent to t
|
|||
assert.deepEqual(settled(error), expected);
|
||||
assert.equal(await error.send(), "root/5020AA/alexaResponce");
|
||||
assert.equal(await error.send(true), "root/5020AA/deferredResponse");
|
||||
assert.deepEqual(client.published.map(({ topic, payload }) => [topic, settled(payload)]), [
|
||||
assert.deepEqual(sent.published.map(({ topic, message }) => [topic, settled(message)]), [
|
||||
["root/5020AA/alexaResponce", expected],
|
||||
["root/5020AA/deferredResponse", expected],
|
||||
]);
|
||||
|
|
@ -157,14 +151,16 @@ test("an ErrorResponse nobody gave a type is an INTERNAL_ERROR", () => {
|
|||
});
|
||||
|
||||
test("send: the topic of the message; a publish that fails resolves \"\" and is reported, never rejected", async () => {
|
||||
const client = recorder();
|
||||
const status = (...flags) => new AlexaStatusMessage("ct", "root", "5020AA", client, ...flags).addPowerControllerProp(PowerController.ON);
|
||||
const sent = new MemoryPublisher();
|
||||
const status = (...flags) => new AlexaStatusMessage("ct", "root", "5020AA", sent, ...flags).addPowerControllerProp(PowerController.ON);
|
||||
assert.equal(await status(true).send(), "root/5020AA/alexaResponce");
|
||||
assert.equal(await status(true).send(true), "root/5020AA/deferredResponse");
|
||||
assert.equal(await status(false, false, "PHYSICAL_INTERACTION").send(), "root/changeReport");
|
||||
assert.deepEqual(client.published.map(({ payload }) => payload.event.header.name), ["Response", "Response", "ChangeReport"]);
|
||||
assert.deepEqual(sent.published.map(({ message }) => message.event.header.name), ["Response", "Response", "ChangeReport"]);
|
||||
|
||||
const failing = new AlexaStatusMessage("ct", "root", "5020AA", recorder(new Error("broker gone")), true);
|
||||
const gone = new MemoryPublisher();
|
||||
gone.failWith = new Error("broker gone");
|
||||
const failing = new AlexaStatusMessage("ct", "root", "5020AA", gone, true);
|
||||
const reported = [];
|
||||
failing.onPublishError = (err) => reported.push(err.message);
|
||||
assert.equal(await failing.send(), "");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue