Skip to content
Snippets Groups Projects
Commit 577604e8 authored by Marcos Pieras's avatar Marcos Pieras
Browse files

test: adds tests for insights

parent 8412bf26
No related branches found
No related tags found
4 merge requests!42test: adds return message to handle e2e tests,!40test: adds test on populate template,!37chore: adds precommit and commitlint,!35test: adds tests on statcheck and diffcheck
......@@ -5,6 +5,10 @@ import type { GraphQueryResultMetaFromBackend } from 'ts-common/src/model/webSoc
import { ums } from '../variables';
import type { InsightModel } from 'ts-common';
export const compareHashedQueryResults = (previousHash: string | null, currentHash: string): boolean => {
return !previousHash || !hashIsEqual(currentHash, previousHash);
};
export const diffCheck = async (
insight: InsightModel,
ss: SaveState,
......@@ -20,7 +24,8 @@ export const diffCheck = async (
});
log.debug('Comparing hash values from current and previous query');
const changed = !previousQueryResult || !hashIsEqual(queryResultHash, previousQueryResult);
const changed = compareHashedQueryResults(previousQueryResult, queryResultHash);
insight.status ||= changed;
log.debug('Updated node and edge ids in SaveState');
......
import type { GraphQueryResultMetaFromBackend, InsightModel } from 'ts-common';
import { log } from '../logger';
function processAlarmStats(alarmStat: InsightModel, resultQuery: GraphQueryResultMetaFromBackend): boolean {
export function processAlarmStats(alarmStat: InsightModel, resultQuery: GraphQueryResultMetaFromBackend): boolean {
for (const condition of alarmStat.conditionsCheck) {
const ssInsightNode = condition.nodeLabel;
const ssInsightStatistic = condition.statistic;
......
import { expect, test, describe, it } from 'bun:test';
import type { GraphQueryResultMetaFromBackend } from 'ts-common';
import { hashDictionary, hashIsEqual } from '../../utils/hashing';
import { compareHashedQueryResults } from './../../readers/diffCheck';
describe('Hash Comparison Tests', () => {
it('should detect different hashes for different graph structures', () => {
// First query result
const query1: GraphQueryResultMetaFromBackend = {
nodes: [{ _id: 'node1' }, { _id: 'node2' }],
edges: [{ _id: 'edge1' }],
} as GraphQueryResultMetaFromBackend;
// Second query result with different structure
const query2: GraphQueryResultMetaFromBackend = {
nodes: [{ _id: 'node1' }, { _id: 'node2' }, { _id: 'node3' }],
edges: [{ _id: 'edge1' }, { _id: 'edge2' }],
} as GraphQueryResultMetaFromBackend;
const hash1 = hashDictionary({
nodes: query1.nodes.map(node => node._id),
edges: query1.edges.map(edge => edge._id),
});
const hash2 = hashDictionary({
nodes: query2.nodes.map(node => node._id),
edges: query2.edges.map(edge => edge._id),
});
// Test direct hash comparison
expect(hashIsEqual(hash1, hash2)).toBe(false);
// Test using compareHashedQueryResults
expect(compareHashedQueryResults(hash1, hash2)).toBe(true);
});
it('should detect identical hashes for same graph structures', () => {
const query1 = {
nodes: [{ _id: 'node1' }, { _id: 'node2' }],
edges: [{ _id: 'edge1' }],
} as GraphQueryResultMetaFromBackend;
const query2 = {
nodes: [{ _id: 'node1' }, { _id: 'node2' }],
edges: [{ _id: 'edge1' }],
} as GraphQueryResultMetaFromBackend;
const hash1 = hashDictionary({
nodes: query1.nodes.map(node => node._id),
edges: query1.edges.map(edge => edge._id),
});
const hash2 = hashDictionary({
nodes: query2.nodes.map(node => node._id),
edges: query2.edges.map(edge => edge._id),
});
// Test direct hash comparison
expect(hashIsEqual(hash1, hash2)).toBe(true);
// Test using compareHashedQueryResults
expect(compareHashedQueryResults(hash1, hash2)).toBe(false);
});
});
import { expect, test, describe, it } from 'bun:test';
import type { GraphQueryResultMetaFromBackend, InsightModel } from 'ts-common';
import { processAlarmStats } from './../../readers/statCheck';
const baseInsight: Omit<InsightModel, 'conditionsCheck'> = {
id: 1,
name: 'Test Insight',
description: 'Base insight for testing',
recipients: ['test@example.com'],
frequency: 'daily',
template: 'default',
saveStateId: 'save-state-1',
type: 'alert',
alarmMode: 'conditional',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
previousResultHash: 'abc123',
lastProcessedAt: new Date().toISOString(),
status: true,
};
describe('QueryprocessAlarmStats', () => {
it('should return true when condition is met', () => {
const alarmStat: InsightModel = {
...baseInsight,
conditionsCheck: [
{
nodeLabel: 'TestNode',
statistic: 'count',
operator: '>',
value: 1,
},
],
};
const resultQuery: GraphQueryResultMetaFromBackend = {
nodes: [
{
_id: 'node1',
label: 'TestNode',
attributes: {
name: 'Test Node 1',
value: 123,
},
},
{
_id: 'node2',
label: 'TestNode',
attributes: {
name: 'Test Node 2',
value: 456,
},
},
],
edges: [
{
_id: 'edge1',
label: 'CONNECTS',
from: 'node1',
to: 'node2',
attributes: {
weight: 1,
timestamp: '2025-03-06',
},
},
],
metaData: {
topological: {
density: 0.5,
self_loops: 0,
},
nodes: {
count: 2,
labels: ['TestNode'],
types: {
TestNode: {
count: 2,
avgDegreeIn: 0.5,
avgDegreeOut: 0.5,
attributes: {
name: {
attributeType: 'string',
statistics: {
uniqueItems: 2,
values: ['Test Node 1', 'Test Node 2'],
mode: 'Test Node 1',
count: 2,
},
},
value: {
attributeType: 'number',
statistics: {
min: 123,
max: 456,
average: 289.5,
count: 2,
},
},
},
},
},
},
edges: {
count: 1,
labels: ['CONNECTS'],
types: {
CONNECTS: {
count: 1,
attributes: {
weight: {
attributeType: 'number',
statistics: {
min: 1,
max: 1,
average: 1,
count: 1,
},
},
timestamp: {
attributeType: 'datetime',
statistics: {
min: 1743782400,
max: 1743782400,
range: 0,
},
},
},
},
},
},
},
nodeCounts: {
TestNode: 2,
updatedAt: 122331,
},
};
expect(processAlarmStats(alarmStat, resultQuery)).toBe(true);
});
it('should return false when condition is not met', () => {
const alarmStat: InsightModel = {
...baseInsight,
conditionsCheck: [
{
nodeLabel: 'TestNode',
statistic: 'count',
operator: '<',
value: 1,
},
],
};
const resultQuery: GraphQueryResultMetaFromBackend = {
nodes: [
{
_id: 'node1',
label: 'TestNode',
attributes: {
name: 'Test Node 1',
value: 123,
},
},
{
_id: 'node2',
label: 'TestNode',
attributes: {
name: 'Test Node 2',
value: 456,
},
},
],
edges: [
{
_id: 'edge1',
label: 'CONNECTS',
from: 'node1',
to: 'node2',
attributes: {
weight: 1,
timestamp: '2025-03-06',
},
},
],
metaData: {
topological: {
density: 0.5,
self_loops: 0,
},
nodes: {
count: 2,
labels: ['TestNode'],
types: {
TestNode: {
count: 2,
avgDegreeIn: 0.5,
avgDegreeOut: 0.5,
attributes: {
name: {
attributeType: 'string',
statistics: {
uniqueItems: 2,
values: ['Test Node 1', 'Test Node 2'],
mode: 'Test Node 1',
count: 2,
},
},
value: {
attributeType: 'number',
statistics: {
min: 123,
max: 456,
average: 289.5,
count: 2,
},
},
},
},
},
},
edges: {
count: 1,
labels: ['CONNECTS'],
types: {
CONNECTS: {
count: 1,
attributes: {
weight: {
attributeType: 'number',
statistics: {
min: 1,
max: 1,
average: 1,
count: 1,
},
},
timestamp: {
attributeType: 'datetime',
statistics: {
min: 1743782400,
max: 1743782400,
range: 0,
},
},
},
},
},
},
},
nodeCounts: {
TestNode: 2,
updatedAt: 122331,
},
};
expect(processAlarmStats(alarmStat, resultQuery)).toBe(false);
});
it('should return false when nodeLabel is not found', () => {
const alarmStat: InsightModel = {
...baseInsight,
conditionsCheck: [
{
nodeLabel: 'NonExistentNode',
statistic: 'count',
operator: '>',
value: 5,
},
],
};
const resultQuery: GraphQueryResultMetaFromBackend = {
nodes: [
{
_id: 'node1',
label: 'TestNode',
attributes: {
name: 'Test Node 1',
value: 123,
},
},
{
_id: 'node2',
label: 'TestNode',
attributes: {
name: 'Test Node 2',
value: 456,
},
},
],
edges: [
{
_id: 'edge1',
label: 'CONNECTS',
from: 'node1',
to: 'node2',
attributes: {
weight: 1,
timestamp: '2025-03-06',
},
},
],
metaData: {
topological: {
density: 0.5,
self_loops: 0,
},
nodes: {
count: 2,
labels: ['TestNode'],
types: {
TestNode: {
count: 2,
avgDegreeIn: 0.5,
avgDegreeOut: 0.5,
attributes: {
name: {
attributeType: 'string',
statistics: {
uniqueItems: 2,
values: ['Test Node 1', 'Test Node 2'],
mode: 'Test Node 1',
count: 2,
},
},
value: {
attributeType: 'number',
statistics: {
min: 123,
max: 456,
average: 289.5,
count: 2,
},
},
},
},
},
},
edges: {
count: 1,
labels: ['CONNECTS'],
types: {
CONNECTS: {
count: 1,
attributes: {
weight: {
attributeType: 'number',
statistics: {
min: 1,
max: 1,
average: 1,
count: 1,
},
},
timestamp: {
attributeType: 'datetime',
statistics: {
min: 1743782400,
max: 1743782400,
range: 0,
},
},
},
},
},
},
},
nodeCounts: {
TestNode: 2,
updatedAt: 122331,
},
};
expect(processAlarmStats(alarmStat, resultQuery)).toBe(false);
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment