ffffng/server/services/monitoringService.test.ts

477 lines
12 KiB
TypeScript

import moment from 'moment';
import {ParsedNode, parseNode, parseNodesJson, parseTimestamp} from "./monitoringService";
import {NodeState} from "../types";
import Logger from '../logger';
import {MockLogger} from "../__mocks__/logger";
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";
beforeEach(() => {
mockedLogger.reset();
});
test('parseTimestamp() should fail parsing non-string timestamp', () => {
// given
const timestamp = {};
// when
const parsedTimestamp = parseTimestamp(timestamp);
// then
expect(parsedTimestamp.isValid()).toBe(false);
});
test('parseTimestamp() should fail parsing empty timestamp string', () => {
// given
const timestamp = "";
// when
const parsedTimestamp = parseTimestamp(timestamp);
// then
expect(parsedTimestamp.isValid()).toBe(false);
});
test('parseTimestamp() should fail parsing invalid timestamp string', () => {
// given
const timestamp = TIMESTAMP_INVALID_STRING;
// when
const parsedTimestamp = parseTimestamp(timestamp);
// then
expect(parsedTimestamp.isValid()).toBe(false);
});
test('parseTimestamp() should succeed parsing valid timestamp string', () => {
// given
const timestamp = TIMESTAMP_VALID_STRING;
// when
const parsedTimestamp = parseTimestamp(timestamp);
// then
expect(parsedTimestamp.isValid()).toBe(true);
expect(parsedTimestamp.toISOString()).toEqual(timestamp);
});
test('parseNode() should fail parsing node for undefined node data', () => {
// given
const importTimestamp = moment();
const nodeData = undefined;
// then
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
});
test('parseNode() should fail parsing node for empty node data', () => {
// given
const importTimestamp = moment();
const nodeData = {};
// then
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
});
test('parseNode() should fail parsing node for empty node info', () => {
// given
const importTimestamp = moment();
const nodeData = {
nodeinfo: {}
};
// then
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
});
test('parseNode() should fail parsing node for non-string node id', () => {
// given
const importTimestamp = moment();
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 = moment();
const nodeData = {
nodeinfo: {
node_id: ""
}
};
// then
expect(() => parseNode(importTimestamp, nodeData)).toThrowError();
});
test('parseNode() should fail parsing node for empty network info', () => {
// given
const importTimestamp = moment();
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 = moment();
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 = moment();
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 = moment();
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 = moment();
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 = moment();
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 = moment();
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",
importTimestamp: importTimestamp,
state: NodeState.ONLINE,
lastSeen: parseTimestamp(TIMESTAMP_VALID_STRING),
site: '<unknown-site>',
domain: '<unknown-domain>'
};
expect(parseNode(importTimestamp, nodeData)).toEqual(expectedParsedNode);
});
test('parseNode() should succeed parsing node with site and domain', () => {
// given
const importTimestamp = moment();
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",
importTimestamp: importTimestamp,
state: NodeState.ONLINE,
lastSeen: parseTimestamp(TIMESTAMP_VALID_STRING),
site: 'test-site',
domain: 'test-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.importTimestamp.isValid()).toBe(true);
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.importTimestamp.isValid()).toBe(true);
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",
importTimestamp: parseTimestamp(TIMESTAMP_VALID_STRING),
state: NodeState.ONLINE,
lastSeen: parseTimestamp(TIMESTAMP_VALID_STRING),
site: 'test-site',
domain: 'test-domain'
};
expect(result.importTimestamp.isValid()).toBe(true);
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);
});