111 lines
3.0 KiB
JavaScript
111 lines
3.0 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const test = require('node:test');
|
|
|
|
const { PassengerTelemetryController } = require('../src/controllers/passengerTelemetryController');
|
|
const { decorateOfficialVehicle } = require('../src/services/liveVehicleMapper');
|
|
|
|
function createResponse() {
|
|
return {
|
|
statusCode: null,
|
|
body: null,
|
|
status(code) {
|
|
this.statusCode = code;
|
|
return this;
|
|
},
|
|
json(payload) {
|
|
this.body = payload;
|
|
return this;
|
|
}
|
|
};
|
|
}
|
|
|
|
test('POST passenger telemetry ingest returns accepted response and broadcasts virtual vehicles', async () => {
|
|
const broadcasts = [];
|
|
const service = {
|
|
async ingest(payload) {
|
|
assert.equal(payload.session_id, 'temporary-anonymous-id');
|
|
return {
|
|
accepted: true,
|
|
routeId: 12,
|
|
virtualVehicles: [
|
|
{
|
|
vehicle_id: 'crowd:12:abc123',
|
|
route_id: 12,
|
|
source: 'crowdsourced',
|
|
source_ref: null,
|
|
is_estimated: true
|
|
}
|
|
]
|
|
};
|
|
}
|
|
};
|
|
|
|
const controller = new PassengerTelemetryController({
|
|
service,
|
|
broadcastToRoute: (routeId, message) => broadcasts.push({ routeId, message })
|
|
});
|
|
controller.getRouteSnapshot = async () => [
|
|
{
|
|
vehicle_id: 'crowd:12:abc123',
|
|
route_id: 12,
|
|
source: 'crowdsourced',
|
|
source_ref: null,
|
|
is_estimated: true
|
|
}
|
|
];
|
|
const res = createResponse();
|
|
|
|
await controller.ingest({
|
|
body: {
|
|
session_id: 'temporary-anonymous-id',
|
|
latitude: 55.485,
|
|
longitude: 28.768
|
|
}
|
|
}, res);
|
|
|
|
assert.equal(res.statusCode, 202);
|
|
assert.deepEqual(res.body, { accepted: true });
|
|
assert.equal(broadcasts.length, 1);
|
|
assert.equal(broadcasts[0].routeId, 12);
|
|
assert.equal(broadcasts[0].message.type, 'snapshot:route');
|
|
assert.equal(broadcasts[0].message.vehicles[0].source, 'crowdsourced');
|
|
assert.equal('session_id' in broadcasts[0].message.vehicles[0], false);
|
|
});
|
|
|
|
test('passenger telemetry controller maps validation failures to 400', async () => {
|
|
const service = {
|
|
async ingest() {
|
|
const error = new Error('latitude must be between -90 and 90');
|
|
error.status = 400;
|
|
throw error;
|
|
}
|
|
};
|
|
const controller = new PassengerTelemetryController({
|
|
service,
|
|
broadcastToRoute: () => {}
|
|
});
|
|
const res = createResponse();
|
|
|
|
await controller.ingest({ body: {} }, res);
|
|
|
|
assert.equal(res.statusCode, 400);
|
|
assert.deepEqual(res.body, { error: 'latitude must be between -90 and 90' });
|
|
});
|
|
|
|
test('official live vehicle mapping adds optional realtime fields', () => {
|
|
const vehicle = decorateOfficialVehicle({
|
|
vehicle_id: 7,
|
|
vehicle_number: 'DEMO-7A',
|
|
route_id: 12,
|
|
latitude: '55.485',
|
|
longitude: '28.768',
|
|
accuracy_meters: '5.5',
|
|
last_seen_at: '2026-05-20T12:29:58Z'
|
|
});
|
|
|
|
assert.equal(vehicle.source, 'official');
|
|
assert.equal(vehicle.confidence, 1);
|
|
assert.equal(vehicle.accuracy_m, 5.5);
|
|
assert.equal(vehicle.is_estimated, false);
|
|
});
|