inventoresed
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
158 lines (132 loc) • 4.47 kB
text/typescript
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 { 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("marking a node with a pending message as asleep does not mess up the remaining transactions", async () => {
// Repro from #1107
// Node 10's awake timer elapses before its ping is rejected,
// this causes mismatched responses for all following messages
const node10 = new ZWaveNode(10, driver);
const node17 = new ZWaveNode(17, driver);
(driver.controller.nodes as ThrowingMap<number, ZWaveNode>).set(
10,
node10,
);
(driver.controller.nodes as ThrowingMap<number, ZWaveNode>).set(
17,
node17,
);
// Add event handlers for the nodes
for (const node of driver.controller.nodes.values()) {
driver["addNodeEventHandlers"](node);
}
node10["isListening"] = false;
node10["isFrequentListening"] = false;
node10.markAsAwake();
expect(node10.status).toBe(NodeStatus.Awake);
// TODO: remove hack in packages/shared/src/wrappingCounter.ts when reworking this test to the new testing setup
(driver.getNextCallbackId as any).value = 2;
const ACK = Buffer.from([MessageHeaders.ACK]);
const pingPromise10 = node10.ping();
await wait(1);
node10.commandClasses.Basic.set(60);
await wait(1);
const pingPromise17 = node17.ping();
await wait(1);
// » [Node 010] [REQ] [SendData]
// │ transmit options: 0x25
// │ callback id: 3
// └─[NoOperationCC]
expect(serialport.lastWrite).toEqual(
Buffer.from("010800130a01002503c9", "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);
node10.markAsAsleep();
await wait(1);
expect(node10.status).toBe(NodeStatus.Asleep);
// The command queue should now abort the ongoing transaction
// » [REQ] [SendDataAbort]
expect(serialport.lastWrite).toEqual(Buffer.from("01030016ea", "hex"));
await wait(10);
serialport.receiveData(ACK);
await wait(50);
// Callback for previous message comes
// « [REQ] [SendData]
// callback id: 3
// transmit status: NoAck
serialport.receiveData(
Buffer.from(
"011800130301019b007f7f7f7f7f010107000000000204000012",
"hex",
),
);
// await wait(1);
expect(serialport.lastWrite).toEqual(ACK);
// Abort was acknowledged, Ping for 10 should be failed
await wait(50);
await expect(pingPromise10).resolves.toBe(false);
// Now the Ping for 17 should go out
// » [Node 017] [REQ] [SendData]
// │ transmit options: 0x25
// │ callback id: 4
// └─[NoOperationCC]
expect(serialport.lastWrite).toEqual(
Buffer.from("010800131101002504d5", "hex"),
);
serialport.receiveData(ACK);
await wait(50);
// Ping 17 does not get resolved by the other callback
await expect(Promise.race([pingPromise17, wait(50)])).resolves.toBe(
undefined,
);
// « [RES] [SendData]
// was sent: true
serialport.receiveData(Buffer.from("0104011301e8", "hex"));
// » [ACK]
expect(serialport.lastWrite).toEqual(ACK);
await wait(50);
// Callback for ping node 17 (failed)
// « [REQ] [SendData]
// callback id: 4
// transmit status: NoAck
serialport.receiveData(
Buffer.from(
"011800130401019d007f7f7f7f7f010107000000000204000013",
"hex",
),
);
expect(serialport.lastWrite).toEqual(ACK);
await expect(pingPromise17).resolves.toBeFalse();
driver.driverLog.sendQueue(driver["sendThread"].state.context.queue);
}, 30000);
});