inventoresed
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
124 lines (106 loc) • 3.48 kB
text/typescript
import { BasicCCSet } from "@zwave-js/cc";
import { MessagePriority } from "@zwave-js/core";
import { MessageHeaders, MockSerialPort } from "@zwave-js/serial";
import type { ThrowingMap } from "@zwave-js/shared";
import { wait } from "alcalzone-shared/async";
import type { Driver } from "../../driver/Driver";
import { ZWaveNode } from "../../node/Node";
import { NodeStatus } from "../../node/_Types";
import type { SendDataRequest } from "../../serialapi/transport/SendDataMessages";
import { createAndStartDriver } from "../utils";
import { isFunctionSupported_NoBridge } from "./fixtures";
describe("regression tests", () => {
let driver: Driver;
let serialport: MockSerialPort;
process.env.LOGLEVEL = "debug";
beforeEach(async () => {
({ driver, serialport } = await createAndStartDriver());
driver["_controller"] = {
ownNodeId: 1,
isFunctionSupported: isFunctionSupported_NoBridge,
nodes: new Map(),
incrementStatistics: () => {},
removeAllListeners: () => {},
} as any;
});
afterEach(async () => {
await driver.destroy();
driver.removeAllListeners();
});
it("when a node does not respond because it is asleep, the transaction does not get rejected", async () => {
// Repro from #1078
const node2 = new ZWaveNode(2, driver);
(driver.controller.nodes as ThrowingMap<number, ZWaveNode>).set(
2,
node2,
);
// Add event handlers for the nodes
for (const node of driver.controller.nodes.values()) {
driver["addNodeEventHandlers"](node);
}
node2["isListening"] = false;
node2["isFrequentListening"] = false;
node2.markAsAwake();
expect(node2.status).toBe(NodeStatus.Awake);
const ACK = Buffer.from([MessageHeaders.ACK]);
const command1 = new BasicCCSet(driver, {
nodeId: 2,
targetValue: 99,
});
const basicSetPromise1 = driver.sendCommand(command1, {
maxSendAttempts: 1,
});
const command2 = new BasicCCSet(driver, {
nodeId: 2,
targetValue: 50,
});
driver.sendCommand(command2, {
maxSendAttempts: 1,
});
await wait(1);
// » [Node 002] [REQ] [SendData]
// │ transmit options: 0x25
// │ callback id: 1
// └─[BasicCCSet]
// └─ targetValue: 99
expect(serialport.lastWrite).toEqual(
Buffer.from("010a00130203200163250181", "hex"),
);
await wait(10);
serialport.receiveData(ACK);
await wait(50);
// « [RES] [SendData]
// was sent: true
serialport.receiveData(Buffer.from("0104011301e8", "hex"));
// » [ACK]
expect(serialport.lastWrite).toEqual(ACK);
await wait(50);
// « [REQ] [SendData]
// callback id: 1
// transmit status: NoACK
serialport.receiveData(Buffer.from("0107001301010002e9", "hex"));
expect(serialport.lastWrite).toEqual(ACK);
await expect(
Promise.race([basicSetPromise1, wait(50).then(() => "OK")]),
).resolves.toBe("OK");
// Both transactions should still be in the queue
const sendQueue = driver["sendThread"].state.context.queue;
expect(sendQueue.length).toBe(2);
expect(sendQueue.get(0)?.priority).toBe(MessagePriority.WakeUp);
expect(sendQueue.get(1)?.priority).toBe(MessagePriority.WakeUp);
expect(node2.status).toBe(NodeStatus.Asleep);
// And the order should be correct
expect(
(
(sendQueue.get(0)?.message as SendDataRequest)
.command as BasicCCSet
).targetValue,
).toBe(99);
expect(
(
(sendQueue.get(1)?.message as SendDataRequest)
.command as BasicCCSet
).targetValue,
).toBe(50);
}, 5000);
});