Fix jwt-token

This commit is contained in:
2025-09-14 21:17:12 +02:00
parent 019eb8c2b2
commit 35cb55ab20
5 changed files with 2012 additions and 31 deletions

View File

@@ -0,0 +1,797 @@
const { describe, it, beforeEach, afterEach, before, after } = require('mocha');
const { expect } = require('chai');
const sinon = require('sinon');
const { setupTestEnvironment, teardownTestEnvironment, cleanDatabase, createTestUser, createTestTenant, createTestDevice, generateTestToken } = require('../setup');
describe('Drone Detection Advanced Processing', () => {
let models, sequelize;
before(async () => {
({ models, sequelize } = await setupTestEnvironment());
});
after(async () => {
await teardownTestEnvironment();
});
beforeEach(async () => {
await cleanDatabase();
});
describe('Detection Pattern Analysis', () => {
it('should analyze drone movement patterns', async () => {
const tenant = await createTestTenant();
const device = await createTestDevice({
tenant_id: tenant.id,
is_approved: true,
geo_lat: 59.3293,
geo_lon: 18.0686
});
const droneId = 12345;
const detections = [];
// Create a pattern of detections showing drone movement
const baseTime = Date.now();
const movementPattern = [
{ lat: 59.3293, lon: 18.0686, rssi: -80, distance: 1000 },
{ lat: 59.3295, lon: 18.0688, rssi: -75, distance: 800 },
{ lat: 59.3297, lon: 18.0690, rssi: -70, distance: 600 },
{ lat: 59.3299, lon: 18.0692, rssi: -65, distance: 400 },
{ lat: 59.3301, lon: 18.0694, rssi: -60, distance: 200 }
];
for (let i = 0; i < movementPattern.length; i++) {
const point = movementPattern[i];
const detection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: point.lat,
geo_lon: point.lon,
device_timestamp: new Date(baseTime + i * 30000), // 30 seconds apart
drone_type: 2,
rssi: point.rssi,
freq: 2400,
drone_id: droneId,
threat_level: 'medium'
});
detections.push(detection);
}
// Analyze movement pattern
const analyzeMovementPattern = (detections) => {
if (detections.length < 2) return null;
const sortedDetections = detections.sort((a, b) =>
new Date(a.device_timestamp) - new Date(b.device_timestamp)
);
let totalDistance = 0;
let isApproaching = true;
let averageSpeed = 0;
for (let i = 1; i < sortedDetections.length; i++) {
const prev = sortedDetections[i - 1];
const curr = sortedDetections[i];
// Calculate distance between points
const distance = calculateDistance(
prev.geo_lat, prev.geo_lon,
curr.geo_lat, curr.geo_lon
);
totalDistance += distance;
// Check if approaching (RSSI getting stronger)
if (curr.rssi <= prev.rssi) {
isApproaching = false;
}
// Calculate speed
const timeDiff = new Date(curr.device_timestamp) - new Date(prev.device_timestamp);
const speed = distance / (timeDiff / 1000); // meters per second
averageSpeed += speed;
}
averageSpeed = averageSpeed / (sortedDetections.length - 1);
return {
totalDistance,
isApproaching,
averageSpeed,
duration: new Date(sortedDetections[sortedDetections.length - 1].device_timestamp) -
new Date(sortedDetections[0].device_timestamp),
detectionCount: sortedDetections.length
};
};
const calculateDistance = (lat1, lon1, lat2, lon2) => {
const R = 6371000; // Earth's radius in meters
const φ1 = lat1 * Math.PI / 180;
const φ2 = lat2 * Math.PI / 180;
const Δφ = (lat2 - lat1) * Math.PI / 180;
const Δλ = (lon2 - lon1) * Math.PI / 180;
const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
};
const pattern = analyzeMovementPattern(detections);
expect(pattern).to.exist;
expect(pattern.totalDistance).to.be.greaterThan(0);
expect(pattern.isApproaching).to.be.true; // RSSI strengthening
expect(pattern.averageSpeed).to.be.greaterThan(0);
expect(pattern.detectionCount).to.equal(5);
});
it('should detect stationary drone patterns', async () => {
const tenant = await createTestTenant();
const device = await createTestDevice({ tenant_id: tenant.id });
const droneId = 67890;
// Create detections from same location (stationary drone)
const stationaryDetections = [];
for (let i = 0; i < 10; i++) {
const detection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: 59.3293, // Same coordinates
geo_lon: 18.0686,
device_timestamp: new Date(Date.now() + i * 60000), // 1 minute apart
drone_type: 3,
rssi: -65 + Math.random() * 10 - 5, // Small RSSI variation
freq: 2400,
drone_id: droneId
});
stationaryDetections.push(detection);
}
const analyzeStationaryPattern = (detections) => {
const coordinates = detections.map(d => ({ lat: d.geo_lat, lon: d.geo_lon }));
// Calculate variance in coordinates
const latVariance = calculateVariance(coordinates.map(c => c.lat));
const lonVariance = calculateVariance(coordinates.map(c => c.lon));
const isStationary = latVariance < 0.0001 && lonVariance < 0.0001; // Very small variance
return {
isStationary,
latVariance,
lonVariance,
detectionCount: detections.length,
duration: new Date(detections[detections.length - 1].device_timestamp) -
new Date(detections[0].device_timestamp)
};
};
const calculateVariance = (values) => {
const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
const squaredDiffs = values.map(val => Math.pow(val - mean, 2));
return squaredDiffs.reduce((sum, diff) => sum + diff, 0) / values.length;
};
const pattern = analyzeStationaryPattern(stationaryDetections);
expect(pattern.isStationary).to.be.true;
expect(pattern.latVariance).to.be.lessThan(0.0001);
expect(pattern.lonVariance).to.be.lessThan(0.0001);
expect(pattern.detectionCount).to.equal(10);
});
it('should identify swarm drone patterns', async () => {
const tenant = await createTestTenant();
const device = await createTestDevice({ tenant_id: tenant.id });
// Create multiple drones detected simultaneously (swarm pattern)
const swarmDetections = [];
const baseTime = Date.now();
const swarmCenter = { lat: 59.3293, lon: 18.0686 };
for (let droneIndex = 0; droneIndex < 5; droneIndex++) {
for (let timeIndex = 0; timeIndex < 3; timeIndex++) {
const detection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: swarmCenter.lat + (Math.random() - 0.5) * 0.01, // Within 1km radius
geo_lon: swarmCenter.lon + (Math.random() - 0.5) * 0.01,
device_timestamp: new Date(baseTime + timeIndex * 10000), // 10 seconds apart
drone_type: 2,
rssi: -60 - Math.random() * 20,
freq: 2400,
drone_id: 1000 + droneIndex
});
swarmDetections.push(detection);
}
}
const detectSwarmPattern = (detections, timeWindow = 60000) => {
// Group detections by time windows
const timeGroups = {};
detections.forEach(detection => {
const timeKey = Math.floor(new Date(detection.device_timestamp).getTime() / timeWindow);
if (!timeGroups[timeKey]) {
timeGroups[timeKey] = [];
}
timeGroups[timeKey].push(detection);
});
// Find groups with multiple unique drones
const swarmGroups = Object.values(timeGroups).filter(group => {
const uniqueDrones = new Set(group.map(d => d.drone_id));
return uniqueDrones.size >= 3; // 3 or more drones detected simultaneously
});
const maxConcurrentDrones = Math.max(...Object.values(timeGroups).map(group =>
new Set(group.map(d => d.drone_id)).size
));
return {
isSwarm: swarmGroups.length > 0,
maxConcurrentDrones,
swarmGroupCount: swarmGroups.length,
totalUniqueDrones: new Set(detections.map(d => d.drone_id)).size
};
};
const swarmAnalysis = detectSwarmPattern(swarmDetections);
expect(swarmAnalysis.isSwarm).to.be.true;
expect(swarmAnalysis.maxConcurrentDrones).to.be.greaterThan(2);
expect(swarmAnalysis.totalUniqueDrones).to.equal(5);
});
});
describe('Advanced Threat Assessment', () => {
it('should assess threat level based on proximity to sensitive areas', async () => {
const tenant = await createTestTenant();
const device = await createTestDevice({
tenant_id: tenant.id,
geo_lat: 59.3293, // Stockholm coordinates
geo_lon: 18.0686,
location_description: 'Airport Security Zone'
});
// Define sensitive areas
const sensitiveAreas = [
{ name: 'Airport Runway', lat: 59.3293, lon: 18.0686, radius: 1000, threat_multiplier: 3.0 },
{ name: 'Government Building', lat: 59.3300, lon: 18.0700, radius: 500, threat_multiplier: 2.5 },
{ name: 'Power Plant', lat: 59.3280, lon: 18.0650, radius: 2000, threat_multiplier: 2.0 }
];
const assessThreatLevel = (detection, sensitiveAreas) => {
let baseThreatLevel = 1.0;
let maxThreatMultiplier = 1.0;
let proximityFactors = [];
sensitiveAreas.forEach(area => {
const distance = calculateDistance(
detection.geo_lat, detection.geo_lon,
area.lat, area.lon
);
if (distance <= area.radius) {
const proximityFactor = 1 - (distance / area.radius);
const threatIncrease = area.threat_multiplier * proximityFactor;
proximityFactors.push({
area: area.name,
distance,
proximityFactor,
threatIncrease
});
maxThreatMultiplier = Math.max(maxThreatMultiplier, threatIncrease);
}
});
const finalThreatLevel = baseThreatLevel * maxThreatMultiplier;
let threatCategory;
if (finalThreatLevel >= 2.5) threatCategory = 'critical';
else if (finalThreatLevel >= 2.0) threatCategory = 'high';
else if (finalThreatLevel >= 1.5) threatCategory = 'medium';
else threatCategory = 'low';
return {
threatLevel: finalThreatLevel,
threatCategory,
proximityFactors
};
};
const calculateDistance = (lat1, lon1, lat2, lon2) => {
const R = 6371000;
const φ1 = lat1 * Math.PI / 180;
const φ2 = lat2 * Math.PI / 180;
const Δφ = (lat2 - lat1) * Math.PI / 180;
const Δλ = (lon2 - lon1) * Math.PI / 180;
const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
};
// Test detection near airport (high threat)
const airportDetection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: 59.3295, // Very close to airport
geo_lon: 18.0688,
device_timestamp: new Date(),
drone_type: 2,
rssi: -45
});
const airportThreat = assessThreatLevel(airportDetection, sensitiveAreas);
expect(airportThreat.threatCategory).to.be.oneOf(['high', 'critical']);
expect(airportThreat.proximityFactors).to.have.length.greaterThan(0);
// Test detection far from sensitive areas (low threat)
const remoteDetection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: 59.4000, // Far from sensitive areas
geo_lon: 18.1000,
device_timestamp: new Date(),
drone_type: 2,
rssi: -80
});
const remoteThreat = assessThreatLevel(remoteDetection, sensitiveAreas);
expect(remoteThreat.threatCategory).to.equal('low');
expect(remoteThreat.proximityFactors).to.have.length(0);
});
it('should factor drone type into threat assessment', async () => {
const tenant = await createTestTenant();
const device = await createTestDevice({ tenant_id: tenant.id });
const droneTypes = require('../../utils/droneTypes');
const assessDroneThreat = (droneType, additionalFactors = {}) => {
const droneInfo = droneTypes.getDroneTypeInfo(droneType);
let threatScore = 0;
// Base threat from drone type
switch (droneInfo.threatLevel) {
case 'critical': threatScore += 4; break;
case 'high': threatScore += 3; break;
case 'medium': threatScore += 2; break;
case 'low': threatScore += 1; break;
}
// Additional factors
if (additionalFactors.strongSignal) threatScore += 1; // Close proximity
if (additionalFactors.militaryFreq) threatScore += 2; // Military frequency
if (additionalFactors.jamming) threatScore += 3; // Electronic warfare
if (additionalFactors.nightTime) threatScore += 1; // Suspicious timing
return {
baseScore: threatScore,
droneInfo,
factors: additionalFactors,
finalThreatLevel: threatScore >= 6 ? 'critical' :
threatScore >= 4 ? 'high' :
threatScore >= 2 ? 'medium' : 'low'
};
};
// Test military drone (high threat)
const militaryDetection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: 59.3293,
geo_lon: 18.0686,
device_timestamp: new Date(),
drone_type: 2, // Orlan (military)
rssi: -45 // Strong signal
});
const militaryThreat = assessDroneThreat(2, {
strongSignal: true,
militaryFreq: true
});
expect(militaryThreat.finalThreatLevel).to.be.oneOf(['high', 'critical']);
// Test commercial drone (lower threat)
const commercialDetection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: 59.3293,
geo_lon: 18.0686,
device_timestamp: new Date(),
drone_type: 8, // DJI (commercial)
rssi: -75 // Weak signal
});
const commercialThreat = assessDroneThreat(8, { strongSignal: false });
expect(commercialThreat.finalThreatLevel).to.be.oneOf(['low', 'medium']);
});
it('should assess threat escalation over time', async () => {
const tenant = await createTestTenant();
const device = await createTestDevice({ tenant_id: tenant.id });
const droneId = 12345;
// Create escalating threat scenario
const escalationDetections = [];
const baseTime = Date.now();
const scenarios = [
{ time: 0, rssi: -80, lat: 59.3200, threat: 'low' }, // Distant
{ time: 300000, rssi: -70, lat: 59.3220, threat: 'low' }, // Approaching
{ time: 600000, rssi: -60, lat: 59.3240, threat: 'medium' }, // Closer
{ time: 900000, rssi: -50, lat: 59.3260, threat: 'medium' }, // Getting close
{ time: 1200000, rssi: -40, lat: 59.3280, threat: 'high' } // Very close
];
for (const scenario of scenarios) {
const detection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: scenario.lat,
geo_lon: 18.0686,
device_timestamp: new Date(baseTime + scenario.time),
drone_type: 2,
rssi: scenario.rssi,
drone_id: droneId
});
escalationDetections.push(detection);
}
const analyzeEscalation = (detections) => {
const sortedDetections = detections.sort((a, b) =>
new Date(a.device_timestamp) - new Date(b.device_timestamp)
);
const escalationEvents = [];
let previousThreatLevel = 0;
sortedDetections.forEach((detection, index) => {
// Simple threat scoring based on RSSI
let currentThreatLevel;
if (detection.rssi > -50) currentThreatLevel = 3; // High
else if (detection.rssi > -65) currentThreatLevel = 2; // Medium
else currentThreatLevel = 1; // Low
if (currentThreatLevel > previousThreatLevel) {
escalationEvents.push({
timestamp: detection.device_timestamp,
fromLevel: previousThreatLevel,
toLevel: currentThreatLevel,
rssi: detection.rssi,
position: { lat: detection.geo_lat, lon: detection.geo_lon }
});
}
previousThreatLevel = currentThreatLevel;
});
return {
escalationCount: escalationEvents.length,
maxThreatLevel: Math.max(...sortedDetections.map(d => d.rssi > -50 ? 3 : d.rssi > -65 ? 2 : 1)),
escalationEvents,
totalDuration: new Date(sortedDetections[sortedDetections.length - 1].device_timestamp) -
new Date(sortedDetections[0].device_timestamp)
};
};
const escalationAnalysis = analyzeEscalation(escalationDetections);
expect(escalationAnalysis.escalationCount).to.be.greaterThan(0);
expect(escalationAnalysis.maxThreatLevel).to.equal(3);
expect(escalationAnalysis.escalationEvents).to.have.length.greaterThan(2);
});
});
describe('Detection Correlation and Clustering', () => {
it('should correlate detections from multiple devices', async () => {
const tenant = await createTestTenant();
const device1 = await createTestDevice({
id: 101,
tenant_id: tenant.id,
geo_lat: 59.3293,
geo_lon: 18.0686
});
const device2 = await createTestDevice({
id: 102,
tenant_id: tenant.id,
geo_lat: 59.3300,
geo_lon: 18.0700
});
const droneId = 99999;
const detectionTime = new Date();
// Same drone detected by multiple devices
const detection1 = await models.DroneDetection.create({
device_id: device1.id,
tenant_id: tenant.id,
geo_lat: 59.3295,
geo_lon: 18.0690,
device_timestamp: detectionTime,
drone_type: 2,
rssi: -60,
drone_id: droneId
});
const detection2 = await models.DroneDetection.create({
device_id: device2.id,
tenant_id: tenant.id,
geo_lat: 59.3297,
geo_lon: 18.0692,
device_timestamp: new Date(detectionTime.getTime() + 5000), // 5 seconds later
drone_type: 2,
rssi: -65,
drone_id: droneId
});
const correlateDetections = (detections, timeWindow = 30000, maxDistance = 5000) => {
const correlationGroups = [];
detections.forEach(detection => {
let foundGroup = false;
correlationGroups.forEach(group => {
const timeMatch = group.detections.some(d =>
Math.abs(new Date(d.device_timestamp) - new Date(detection.device_timestamp)) <= timeWindow
);
const droneMatch = group.droneId === detection.drone_id;
if (timeMatch && droneMatch) {
group.detections.push(detection);
group.devices.add(detection.device_id);
foundGroup = true;
}
});
if (!foundGroup) {
correlationGroups.push({
droneId: detection.drone_id,
detections: [detection],
devices: new Set([detection.device_id])
});
}
});
return correlationGroups.map(group => ({
droneId: group.droneId,
detectionCount: group.detections.length,
deviceCount: group.devices.size,
isCorrelated: group.devices.size > 1,
timeSpan: group.detections.length > 1 ?
Math.max(...group.detections.map(d => new Date(d.device_timestamp))) -
Math.min(...group.detections.map(d => new Date(d.device_timestamp))) : 0,
detections: group.detections
}));
};
const allDetections = [detection1, detection2];
const correlations = correlateDetections(allDetections);
expect(correlations).to.have.length(1);
expect(correlations[0].isCorrelated).to.be.true;
expect(correlations[0].deviceCount).to.equal(2);
expect(correlations[0].detectionCount).to.equal(2);
});
it('should identify detection clusters in geographic areas', async () => {
const tenant = await createTestTenant();
const device = await createTestDevice({ tenant_id: tenant.id });
// Create clustered detections (multiple drones in same area)
const clusterCenter = { lat: 59.3293, lon: 18.0686 };
const clusterDetections = [];
for (let i = 0; i < 10; i++) {
const detection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: clusterCenter.lat + (Math.random() - 0.5) * 0.005, // Within ~500m
geo_lon: clusterCenter.lon + (Math.random() - 0.5) * 0.005,
device_timestamp: new Date(Date.now() + i * 60000),
drone_type: Math.floor(Math.random() * 5) + 1,
rssi: -60 - Math.random() * 20,
drone_id: 2000 + i
});
clusterDetections.push(detection);
}
// Create isolated detection (not in cluster)
const isolatedDetection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: 59.4000, // Far from cluster
geo_lon: 18.1000,
device_timestamp: new Date(),
drone_type: 2,
rssi: -70,
drone_id: 3000
});
const clusterDetectionsArray = [...clusterDetections, isolatedDetection];
const identifyClusters = (detections, maxClusterDistance = 1000, minClusterSize = 3) => {
const clusters = [];
const processed = new Set();
detections.forEach((detection, index) => {
if (processed.has(index)) return;
const cluster = [detection];
processed.add(index);
detections.forEach((otherDetection, otherIndex) => {
if (otherIndex === index || processed.has(otherIndex)) return;
const distance = calculateDistance(
detection.geo_lat, detection.geo_lon,
otherDetection.geo_lat, otherDetection.geo_lon
);
if (distance <= maxClusterDistance) {
cluster.push(otherDetection);
processed.add(otherIndex);
}
});
if (cluster.length >= minClusterSize) {
clusters.push({
center: {
lat: cluster.reduce((sum, d) => sum + d.geo_lat, 0) / cluster.length,
lon: cluster.reduce((sum, d) => sum + d.geo_lon, 0) / cluster.length
},
detections: cluster,
size: cluster.length,
uniqueDrones: new Set(cluster.map(d => d.drone_id)).size,
timeSpan: Math.max(...cluster.map(d => new Date(d.device_timestamp))) -
Math.min(...cluster.map(d => new Date(d.device_timestamp)))
});
}
});
return clusters;
};
const calculateDistance = (lat1, lon1, lat2, lon2) => {
const R = 6371000;
const φ1 = lat1 * Math.PI / 180;
const φ2 = lat2 * Math.PI / 180;
const Δφ = (lat2 - lat1) * Math.PI / 180;
const Δλ = (lon2 - lon1) * Math.PI / 180;
const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
};
const clusters = identifyClusters(clusterDetectionsArray);
expect(clusters).to.have.length(1); // One cluster found
expect(clusters[0].size).to.be.greaterThan(3);
expect(clusters[0].uniqueDrones).to.be.greaterThan(3);
expect(Math.abs(clusters[0].center.lat - clusterCenter.lat)).to.be.lessThan(0.01);
});
});
describe('Real-time Detection Processing', () => {
it('should handle rapid detection streams efficiently', async () => {
const tenant = await createTestTenant();
const device = await createTestDevice({
tenant_id: tenant.id,
is_approved: true
});
const processDetectionStream = async (detections) => {
const results = [];
const startTime = Date.now();
for (const detectionData of detections) {
const detection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
...detectionData
});
// Simulate real-time processing
const processingResult = {
id: detection.id,
processed_at: new Date(),
threat_assessment: detectionData.rssi > -50 ? 'high' : 'medium',
processing_time: Date.now() - startTime
};
results.push(processingResult);
}
return {
processed_count: results.length,
total_time: Date.now() - startTime,
average_processing_time: results.reduce((sum, r) => sum + r.processing_time, 0) / results.length,
results
};
};
// Generate rapid detection stream
const detectionStream = [];
for (let i = 0; i < 20; i++) {
detectionStream.push({
geo_lat: 59.3293 + (Math.random() - 0.5) * 0.01,
geo_lon: 18.0686 + (Math.random() - 0.5) * 0.01,
device_timestamp: new Date(Date.now() + i * 1000),
drone_type: 2,
rssi: -60 - Math.random() * 30,
drone_id: 4000 + Math.floor(i / 4) // Multiple detections per drone
});
}
const streamResults = await processDetectionStream(detectionStream);
expect(streamResults.processed_count).to.equal(20);
expect(streamResults.total_time).to.be.lessThan(5000); // Should process quickly
expect(streamResults.average_processing_time).to.be.a('number');
});
it('should maintain detection accuracy under load', async () => {
const tenant = await createTestTenant();
const device = await createTestDevice({ tenant_id: tenant.id });
// Test detection accuracy with varying signal strengths
const testCases = [
{ rssi: -40, expected_accuracy: 'high', expected_range: '<100m' },
{ rssi: -60, expected_accuracy: 'medium', expected_range: '100-500m' },
{ rssi: -80, expected_accuracy: 'low', expected_range: '>500m' }
];
const assessDetectionAccuracy = (rssi) => {
let accuracy, estimatedRange;
if (rssi > -50) {
accuracy = 'high';
estimatedRange = '<100m';
} else if (rssi > -70) {
accuracy = 'medium';
estimatedRange = '100-500m';
} else {
accuracy = 'low';
estimatedRange = '>500m';
}
return { accuracy, estimatedRange, confidence: Math.max(0, 100 + rssi) };
};
for (const testCase of testCases) {
const detection = await models.DroneDetection.create({
device_id: device.id,
tenant_id: tenant.id,
geo_lat: 59.3293,
geo_lon: 18.0686,
device_timestamp: new Date(),
drone_type: 2,
rssi: testCase.rssi,
drone_id: Math.floor(Math.random() * 10000)
});
const accuracy = assessDetectionAccuracy(detection.rssi);
expect(accuracy.accuracy).to.equal(testCase.expected_accuracy);
expect(accuracy.estimatedRange).to.equal(testCase.expected_range);
expect(accuracy.confidence).to.be.a('number');
}
});
});
});