inventoresed
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
519 lines (511 loc) • 15.9 kB
text/typescript
import { getErrorSuffix, ZWaveError, ZWaveErrorCodes } from "@zwave-js/core";
import path from "path";
import { createSentryContext } from "./sentry";
describe("The Sentry telemetry", () => {
const defaultRootDir = path.join(__dirname, "../../..");
it("should ignore errors that are caused outside zwave-js", () => {
const context = createSentryContext(defaultRootDir);
const event = {
exception: {
values: [
{
type: "SyntaxError",
value: "Unexpected token o in JSON at position 1",
stacktrace: {
frames: [
{
function: "process._tickCallback",
module: "next_tick",
filename: "internal/process/next_tick.js",
abs_path: "internal/process/next_tick.js",
},
{
function: "null.<anonymous>",
module: "node-red-contrib-nextcloud:nextcloud",
filename:
"/home/pi/.node-red/node_modules/node-red-contrib-nextcloud/nextcloud.js",
abs_path:
"/home/pi/.node-red/node_modules/node-red-contrib-nextcloud/nextcloud.js",
},
{
function: "JSON.parse",
in_app: true,
},
],
},
mechanism: {
type: "onunhandledrejection",
handled: false,
},
},
],
},
} as any;
expect(context.shouldIgnore(event)).toBeTrue();
});
it("should NOT ignore errors that are explicitly whitelisted", () => {
const context = createSentryContext(
"/opt/iobroker/node_modules/zwave-js",
);
const event = {
exception: {
values: [
{
type: "TypeError",
value: "Cannot read property 'nodeId' of undefined",
stacktrace: {
frames: [
{
function: "processImmediate",
module: "timers",
filename: "internal/timers.js",
abs_path: "internal/timers.js",
},
{
function: "Immediate.<anonymous>",
module: "iobroker.js-controller.lib:adapter",
filename:
"/opt/iobroker/node_modules/iobroker.js-controller/lib/adapter.js",
abs_path:
"/opt/iobroker/node_modules/iobroker.js-controller/lib/adapter.js",
},
{
function: "ZWave2.EventEmitter.emit",
module: "domain",
filename: "domain.js",
abs_path: "domain.js",
},
{
function: "ZWave2.emit",
module: "events",
filename: "events.js",
abs_path: "events.js",
},
{
function: "ZWave2.onStateChange",
module: "iobroker.zwave2.src:main.ts",
filename:
"/opt/iobroker/node_modules/iobroker.zwave2/src/main.ts",
abs_path:
"/opt/iobroker/node_modules/iobroker.zwave2/src/main.ts",
},
],
},
mechanism: {
type: "onunhandledrejection",
handled: false,
},
},
],
},
} as any;
expect(context.shouldIgnore(event)).toBeFalse();
});
it("should ignore errors that must be handled by the developer", () => {
const context = createSentryContext(
"/home/michel/dashboard/servers/zwave/node_modules/zwave-js",
);
const event = {
exception: {
values: [
{
type: "ZWaveError",
value: "Node 6 did not respond after 3 attempts, it is presumed dead",
stacktrace: {
frames: [
{
function: "__awaiter",
module: "devices:powerswitch",
filename:
"/home/michel/dashboard/servers/zwave/devices/powerswitch.js",
abs_path:
"/home/michel/dashboard/servers/zwave/devices/powerswitch.js",
in_app: true,
},
{
function: "new Promise",
in_app: true,
},
{
function: "null.<anonymous>",
module: "devices:powerswitch",
filename:
"/home/michel/dashboard/servers/zwave/devices/powerswitch.js",
abs_path:
"/home/michel/dashboard/servers/zwave/devices/powerswitch.js",
in_app: true,
},
{
function: "Generator.next",
in_app: true,
},
{
function: "PowerSwitch.<anonymous>",
module: "devices:powerswitch",
filename:
"/home/michel/dashboard/servers/zwave/devices/powerswitch.js",
abs_path:
"/home/michel/dashboard/servers/zwave/devices/powerswitch.js",
},
{
function: "new Promise",
in_app: true,
},
{
function: "null.<anonymous>",
module: "devices:powerswitch",
filename:
"/home/michel/dashboard/servers/zwave/devices/powerswitch.js",
abs_path:
"/home/michel/dashboard/servers/zwave/devices/powerswitch.js",
},
{
function: "Proxy.set",
module: "zwave-js.src.lib.commandclass:BinarySwitchCC.ts",
filename:
"/home/michel/dashboard/servers/zwave/node_modules/zwave-js/src/lib/commandclass/BinarySwitchCC.ts",
abs_path:
"/home/michel/dashboard/servers/zwave/node_modules/zwave-js/src/lib/commandclass/BinarySwitchCC.ts",
},
{
function: "Driver.sendCommand",
module: "zwave-js.src.lib.driver:Driver.ts",
filename:
"/home/michel/dashboard/servers/zwave/node_modules/zwave-js/src/lib/driver/Driver.ts",
abs_path:
"/home/michel/dashboard/servers/zwave/node_modules/zwave-js/src/lib/driver/Driver.ts",
},
{
function: "Driver.sendMessage",
module: "zwave-js.src.lib.driver:Driver.ts",
filename:
"/home/michel/dashboard/servers/zwave/node_modules/zwave-js/src/lib/driver/Driver.ts",
abs_path:
"/home/michel/dashboard/servers/zwave/node_modules/zwave-js/src/lib/driver/Driver.ts",
},
],
},
mechanism: {
type: "onunhandledrejection",
handled: false,
},
},
],
},
} as any;
const hint = {
originalException: new ZWaveError(
"This should be handled by the dev",
ZWaveErrorCodes.Controller_MessageDropped,
),
} as any;
expect(context.shouldIgnore(event, hint)).toBeTrue();
});
it("should ignore errors that must be handled by the developer, unless whitelisted", () => {
const context = createSentryContext(
"/opt/iobroker/node_modules/zwave-js",
);
const event = {
exception: {
values: [
{
type: "ZWaveError",
value: "Timeout while waiting for an ACK from the controller",
stacktrace: {
frames: [
{
function: "processImmediate",
module: "timers",
filename: "internal/timers.js",
abs_path: "internal/timers.js",
},
{
function: "Immediate._onImmediate",
module: "@iobroker.db-states-redis.lib.states:statesInRedisClient",
filename:
"/opt/iobroker/node_modules/@iobroker/db-states-redis/lib/states/statesInRedisClient.js",
abs_path:
"/opt/iobroker/node_modules/@iobroker/db-states-redis/lib/states/statesInRedisClient.js",
},
{
function: "change",
module: "iobroker.js-controller.lib:adapter",
filename:
"/opt/iobroker/node_modules/iobroker.js-controller/lib/adapter.js",
abs_path:
"/opt/iobroker/node_modules/iobroker.js-controller/lib/adapter.js",
},
{
function: "ZWave2.EventEmitter.emit",
module: "domain",
filename: "domain.js",
abs_path: "domain.js",
},
{
function: "ZWave2.emit",
module: "events",
filename: "events.js",
abs_path: "events.js",
},
{
function: "ZWave2.onMessage",
module: "iobroker.zwave2.src:main.ts",
filename:
"/opt/iobroker/node_modules/iobroker.zwave2/src/main.ts",
abs_path:
"/opt/iobroker/node_modules/iobroker.zwave2/src/main.ts",
},
{ function: "Array.map", in_app: true },
{
function: "null.<anonymous>",
module: "iobroker.zwave2.src:main.ts",
filename:
"/opt/iobroker/node_modules/iobroker.zwave2/src/main.ts",
abs_path:
"/opt/iobroker/node_modules/iobroker.zwave2/src/main.ts",
},
{
function:
"ZWaveController.getNodeNeighbors",
module: "zwave-js.src.lib.controller:Controller.ts",
filename:
"/opt/iobroker/node_modules/zwave-js/src/lib/controller/Controller.ts",
abs_path:
"/opt/iobroker/node_modules/zwave-js/src/lib/controller/Controller.ts",
},
{
function: "Driver.sendMessage",
module: "zwave-js.src.lib.driver:Driver.ts",
filename:
"/opt/iobroker/node_modules/zwave-js/src/lib/driver/Driver.ts",
abs_path:
"/opt/iobroker/node_modules/zwave-js/src/lib/driver/Driver.ts",
},
],
},
mechanism: {
type: "onunhandledrejection",
handled: false,
},
},
],
},
} as any;
const hint = {
originalException: new ZWaveError(
"This should be handled by the dev",
ZWaveErrorCodes.Controller_MessageDropped,
),
} as any;
expect(context.shouldIgnore(event, hint)).toBeFalse();
});
describe("regression tests for ignored errors", () => {
it("test 1: testing in the REPL", () => {
const context = createSentryContext(
"/Users/ross/code/temp/zwave/node_modules/zwave-js",
);
const event = {
culprit:
"Map.<anonymous>(zwave-js.src.lib.controller:Controller.ts)",
exception: {
values: [
{
type: "ZWaveError",
value: "Node 255 was not found!",
stacktrace: {
frames: [
{
function:
"REPLServer.runBound [as eval]",
module: "domain",
filename: "domain.js",
abs_path: "domain.js",
in_app: false,
},
{
function: "bound",
module: "domain",
filename: "domain.js",
abs_path: "domain.js",
in_app: false,
},
{
function: "REPLServer.defaultEval",
module: "repl",
filename: "repl.js",
abs_path: "repl.js",
in_app: false,
},
{
function: "Script.runInContext",
module: "vm",
filename: "vm.js",
abs_path: "vm.js",
in_app: false,
},
{
function: "null.<anonymous>",
module: "REPL1",
filename: "REPL1",
abs_path: "REPL1",
in_app: false,
},
{
function:
"ZWaveController.addAssociations",
module: "zwave-js.src.lib.controller:Controller.ts",
filename:
"/Users/ross/code/temp/zwave/node_modules/zwave-js/src/lib/controller/Controller.ts",
abs_path:
"/Users/ross/code/temp/zwave/node_modules/zwave-js/src/lib/controller/Controller.ts",
in_app: false,
},
{ function: "Array.filter", in_app: true },
{
function: "null.<anonymous>",
module: "zwave-js.src.lib.controller:Controller.ts",
filename:
"/Users/ross/code/temp/zwave/node_modules/zwave-js/src/lib/controller/Controller.ts",
abs_path:
"/Users/ross/code/temp/zwave/node_modules/zwave-js/src/lib/controller/Controller.ts",
in_app: false,
},
{
function:
"ZWaveController.isAssociationAllowed",
module: "zwave-js.src.lib.controller:Controller.ts",
filename:
"/Users/ross/code/temp/zwave/node_modules/zwave-js/src/lib/controller/Controller.ts",
abs_path:
"/Users/ross/code/temp/zwave/node_modules/zwave-js/src/lib/controller/Controller.ts",
in_app: false,
},
{
function: "Map.<anonymous>",
module: "zwave-js.src.lib.controller:Controller.ts",
filename:
"/Users/ross/code/temp/zwave/node_modules/zwave-js/src/lib/controller/Controller.ts",
abs_path:
"/Users/ross/code/temp/zwave/node_modules/zwave-js/src/lib/controller/Controller.ts",
in_app: false,
},
],
},
mechanism: {
type: "onunhandledrejection",
handled: false,
},
},
],
},
} as any;
expect(context.shouldIgnore(event)).toBeTrue();
});
it("test 2: clearly a connection issue", () => {
const context = createSentryContext(
"/home/pi/zwave/node_modules/zwave-js",
);
const event = {
culprit:
"Map.<anonymous>(zwave-js.src.lib.controller:Controller.ts)",
exception: {
values: [
{
type: "ZWaveError",
value: "Failed to send the message after 3 attempts",
stacktrace: {
frames: [
{
function: "__awaiter",
module: "fn",
filename: "/home/pi/zwave/build/fn.js",
abs_path: "/home/pi/zwave/build/fn.js",
in_app: true,
},
{
function: "new Promise",
in_app: true,
},
{
function: "null.<anonymous>",
module: "fn",
filename: "/home/pi/zwave/build/fn.js",
abs_path: "/home/pi/zwave/build/fn.js",
in_app: true,
},
{
function: "Generator.next",
in_app: true,
},
{
function: "null.<anonymous>",
module: "fn.ts",
filename: "/home/pi/zwave/fn.ts",
abs_path: "/home/pi/zwave/fn.ts",
in_app: true,
},
{
function: "ZWaveNode.setValue",
module: "zwave-js.src.lib.node:Node.ts",
filename:
"/home/pi/zwave/node_modules/zwave-js/src/lib/node/Node.ts",
abs_path:
"/home/pi/zwave/node_modules/zwave-js/src/lib/node/Node.ts",
in_app: false,
},
{
function:
"Proxy.ConfigurationCCAPI.<computed>",
module: "zwave-js.src.lib.commandclass:ConfigurationCC.ts",
filename:
"/home/pi/zwave/node_modules/zwave-js/src/lib/commandclass/ConfigurationCC.ts",
abs_path:
"/home/pi/zwave/node_modules/zwave-js/src/lib/commandclass/ConfigurationCC.ts",
in_app: false,
},
{
function: "ConfigurationCCAPI.set",
module: "zwave-js.src.lib.commandclass:ConfigurationCC.ts",
filename:
"/home/pi/zwave/node_modules/zwave-js/src/lib/commandclass/ConfigurationCC.ts",
abs_path:
"/home/pi/zwave/node_modules/zwave-js/src/lib/commandclass/ConfigurationCC.ts",
in_app: false,
},
{
function: "Driver.sendCommand",
module: "zwave-js.src.lib.driver:Driver.ts",
filename:
"/home/pi/zwave/node_modules/zwave-js/src/lib/driver/Driver.ts",
abs_path:
"/home/pi/zwave/node_modules/zwave-js/src/lib/driver/Driver.ts",
in_app: false,
},
{
function: "Driver.sendMessage",
module: "zwave-js.src.lib.driver:Driver.ts",
filename:
"/home/pi/zwave/node_modules/zwave-js/src/lib/driver/Driver.ts",
abs_path:
"/home/pi/zwave/node_modules/zwave-js/src/lib/driver/Driver.ts",
in_app: false,
},
],
},
mechanism: {
type: "onunhandledrejection",
handled: false,
},
},
],
},
} as any;
const hint = {
originalException: `Failed to send the message after 3 attempts (${getErrorSuffix(
ZWaveErrorCodes.Controller_MessageDropped,
)})`,
} as any;
expect(context.shouldIgnore(event, hint)).toBeTrue();
});
});
});