431 lines
11 KiB
TypeScript
431 lines
11 KiB
TypeScript
import { ParsedNode, parseNode, parseNodesJson } from "./monitoringService";
|
|
import { Domain, MAC, OnlineState, Site, UnixTimestampSeconds } from "../types";
|
|
import Logger from "../logger";
|
|
import type { MockLogger } from "../__mocks__/logger";
|
|
import { now, parseTimestamp } from "../utils/time";
|
|
|
|
const mockedLogger = Logger as MockLogger;
|
|
|
|
jest.mock("../logger");
|
|
jest.mock("../db/database");
|
|
|
|
const NODES_JSON_INVALID_VERSION = 1;
|
|
const NODES_JSON_VALID_VERSION = 2;
|
|
|
|
const TIMESTAMP_INVALID_STRING = "2020-01-02T42:99:23.000Z";
|
|
const TIMESTAMP_VALID_STRING = "2020-01-02T12:34:56.000Z";
|
|
|
|
const PARSED_TIMESTAMP_VALID = parseTimestamp(TIMESTAMP_VALID_STRING);
|
|
if (PARSED_TIMESTAMP_VALID === null) {
|
|
fail("Should not happen: Parsed valid timestamp as invalid.");
|
|
}
|
|
const TIMESTAMP_VALID: UnixTimestampSeconds = PARSED_TIMESTAMP_VALID;
|
|
|
|
beforeEach(() => {
|
|
mockedLogger.reset();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for empty node data", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for empty node info", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {},
|
|
};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for non-string node id", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: 42,
|
|
},
|
|
};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for empty node id", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: "",
|
|
},
|
|
};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for empty network info", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {},
|
|
},
|
|
};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for invalid mac", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {
|
|
mac: "xxx",
|
|
},
|
|
},
|
|
};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for missing flags", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {
|
|
mac: "12:34:56:78:90:ab",
|
|
},
|
|
},
|
|
};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for empty flags", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {
|
|
mac: "12:34:56:78:90:ab",
|
|
},
|
|
},
|
|
flags: {},
|
|
};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for missing last seen timestamp", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {
|
|
mac: "12:34:56:78:90:ab",
|
|
},
|
|
},
|
|
flags: {
|
|
online: true,
|
|
},
|
|
};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should fail parsing node for invalid last seen timestamp", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {
|
|
mac: "12:34:56:78:90:ab",
|
|
},
|
|
},
|
|
flags: {
|
|
online: true,
|
|
},
|
|
lastseen: 42,
|
|
};
|
|
|
|
// then
|
|
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
|
|
});
|
|
|
|
test("parseNode() should succeed parsing node without site and domain", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {
|
|
mac: "12:34:56:78:90:ab",
|
|
},
|
|
},
|
|
flags: {
|
|
online: true,
|
|
},
|
|
lastseen: TIMESTAMP_VALID_STRING,
|
|
};
|
|
|
|
// then
|
|
const expectedParsedNode: ParsedNode = {
|
|
mac: "12:34:56:78:90:AB" as MAC,
|
|
importTimestamp: importTimestamp,
|
|
state: OnlineState.ONLINE,
|
|
lastSeen: TIMESTAMP_VALID,
|
|
site: undefined,
|
|
domain: undefined,
|
|
};
|
|
expect(parseNode(importTimestamp, nodeData)).toEqual(expectedParsedNode);
|
|
});
|
|
|
|
test("parseNode() should succeed parsing node with site and domain", () => {
|
|
// given
|
|
const importTimestamp = now();
|
|
const nodeData = {
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {
|
|
mac: "12:34:56:78:90:ab",
|
|
},
|
|
system: {
|
|
site_code: "test-site",
|
|
domain_code: "test-domain",
|
|
},
|
|
},
|
|
flags: {
|
|
online: true,
|
|
},
|
|
lastseen: TIMESTAMP_VALID_STRING,
|
|
};
|
|
|
|
// then
|
|
const expectedParsedNode: ParsedNode = {
|
|
mac: "12:34:56:78:90:AB" as MAC,
|
|
importTimestamp: importTimestamp,
|
|
state: OnlineState.ONLINE,
|
|
lastSeen: TIMESTAMP_VALID,
|
|
site: "test-site" as Site,
|
|
domain: "test-domain" as Domain,
|
|
};
|
|
expect(parseNode(importTimestamp, nodeData)).toEqual(expectedParsedNode);
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing empty string", () => {
|
|
// given
|
|
const json = "";
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing malformed JSON", () => {
|
|
// given
|
|
const json = '{"version": 2]';
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing JSON null", () => {
|
|
// given
|
|
const json = JSON.stringify(null);
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing JSON string", () => {
|
|
// given
|
|
const json = JSON.stringify("foo");
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing JSON number", () => {
|
|
// given
|
|
const json = JSON.stringify(42);
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing empty JSON object", () => {
|
|
// given
|
|
const json = JSON.stringify({});
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing for mismatching version", () => {
|
|
// given
|
|
const json = JSON.stringify({
|
|
version: NODES_JSON_INVALID_VERSION,
|
|
});
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing for missing timestamp", () => {
|
|
// given
|
|
const json = JSON.stringify({
|
|
version: NODES_JSON_VALID_VERSION,
|
|
nodes: [],
|
|
});
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing for invalid timestamp", () => {
|
|
// given
|
|
const json = JSON.stringify({
|
|
version: NODES_JSON_VALID_VERSION,
|
|
timestamp: TIMESTAMP_INVALID_STRING,
|
|
nodes: [],
|
|
});
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should fail parsing for nodes object instead of array", () => {
|
|
// given
|
|
const json = JSON.stringify({
|
|
version: NODES_JSON_VALID_VERSION,
|
|
timestamp: TIMESTAMP_VALID_STRING,
|
|
nodes: {},
|
|
});
|
|
|
|
// then
|
|
expect(() => parseNodesJson(json)).toThrowError();
|
|
});
|
|
|
|
test("parseNodesJson() should succeed parsing no nodes", () => {
|
|
// given
|
|
const json = JSON.stringify({
|
|
version: NODES_JSON_VALID_VERSION,
|
|
timestamp: TIMESTAMP_VALID_STRING,
|
|
nodes: [],
|
|
});
|
|
|
|
// when
|
|
const result = parseNodesJson(json);
|
|
|
|
// then
|
|
expect(result.nodes).toEqual([]);
|
|
expect(result.failedNodesCount).toEqual(0);
|
|
expect(result.totalNodesCount).toEqual(0);
|
|
});
|
|
|
|
test("parseNodesJson() should skip parsing invalid nodes", () => {
|
|
// given
|
|
const json = JSON.stringify({
|
|
version: NODES_JSON_VALID_VERSION,
|
|
timestamp: TIMESTAMP_VALID_STRING,
|
|
nodes: [
|
|
{},
|
|
{
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {
|
|
mac: "12:34:56:78:90:ab",
|
|
},
|
|
system: {
|
|
site_code: "test-site",
|
|
domain_code: "test-domain",
|
|
},
|
|
},
|
|
flags: {
|
|
online: true,
|
|
},
|
|
lastseen: TIMESTAMP_INVALID_STRING,
|
|
},
|
|
],
|
|
});
|
|
|
|
// when
|
|
const result = parseNodesJson(json);
|
|
|
|
// then
|
|
expect(result.nodes).toEqual([]);
|
|
expect(result.failedNodesCount).toEqual(2);
|
|
expect(result.totalNodesCount).toEqual(2);
|
|
expect(
|
|
mockedLogger.getMessages("error", "monitoring", "parsing-nodes-json")
|
|
.length
|
|
).toEqual(2);
|
|
});
|
|
|
|
test("parseNodesJson() should parse valid nodes", () => {
|
|
// given
|
|
const json = JSON.stringify({
|
|
version: NODES_JSON_VALID_VERSION,
|
|
timestamp: TIMESTAMP_VALID_STRING,
|
|
nodes: [
|
|
{}, // keep an invalid one for good measure
|
|
{
|
|
nodeinfo: {
|
|
node_id: "1234567890ab",
|
|
network: {
|
|
mac: "12:34:56:78:90:ab",
|
|
},
|
|
system: {
|
|
site_code: "test-site",
|
|
domain_code: "test-domain",
|
|
},
|
|
},
|
|
flags: {
|
|
online: true,
|
|
},
|
|
lastseen: TIMESTAMP_VALID_STRING,
|
|
},
|
|
],
|
|
});
|
|
|
|
// when
|
|
const result = parseNodesJson(json);
|
|
|
|
// then
|
|
const expectedParsedNode: ParsedNode = {
|
|
mac: "12:34:56:78:90:AB" as MAC,
|
|
importTimestamp: TIMESTAMP_VALID,
|
|
state: OnlineState.ONLINE,
|
|
lastSeen: TIMESTAMP_VALID,
|
|
site: "test-site" as Site,
|
|
domain: "test-domain" as Domain,
|
|
};
|
|
|
|
expect(result.nodes).toEqual([expectedParsedNode]);
|
|
expect(result.failedNodesCount).toEqual(1);
|
|
expect(result.totalNodesCount).toEqual(2);
|
|
expect(
|
|
mockedLogger.getMessages("error", "monitoring", "parsing-nodes-json")
|
|
.length
|
|
).toEqual(1);
|
|
});
|