osrm-backend/test/nodejs/trip.js
Michael Bell db7946d762
Add support for disabling feature datasets (#6666)
This change adds support for disabling datasets, such that specific
files are not loaded into memory when running OSRM. This enables users
to not pay the memory cost for features they do not intend to use.

Initially, there are two options:
- ROUTE_GEOMETRY, for disabling overview, steps, annotations and waypoints.
- ROUTE_STEPS, for disabling steps only.

Attempts to query features for which the datasets are disabled will
lead to a DisabledDatasetException being returned.
2023-08-04 18:43:37 +01:00

433 lines
16 KiB
JavaScript

var OSRM = require('../../');
var test = require('tape');
var data_path = require('./constants').data_path;
var mld_data_path = require('./constants').mld_data_path;
var three_test_coordinates = require('./constants').three_test_coordinates;
var two_test_coordinates = require('./constants').two_test_coordinates;
const flatbuffers = require('../../features/support/flatbuffers').flatbuffers;
const FBResult = require('../../features/support/fbresult_generated').osrm.engine.api.fbresult.FBResult;
test('trip: trip in Monaco with flatbuffers format', function(assert) {
assert.plan(2);
var osrm = new OSRM(data_path);
osrm.trip({coordinates: two_test_coordinates, format: 'flatbuffers'}, function(err, trip) {
assert.ifError(err);
const fb = FBResult.getRootAsFBResult(new flatbuffers.ByteBuffer(trip));
assert.equal(fb.routesLength(), 1);
});
});
test('trip: trip in Monaco', function(assert) {
assert.plan(2);
var osrm = new OSRM(data_path);
osrm.trip({coordinates: two_test_coordinates}, function(err, trip) {
assert.ifError(err);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(trip.trips[t].geometry);
}
});
});
test('trip: trip in Monaco as a buffer', function(assert) {
assert.plan(3);
var osrm = new OSRM(data_path);
osrm.trip({coordinates: two_test_coordinates}, { format: 'json_buffer' }, function(err, trip) {
assert.ifError(err);
assert.ok(trip instanceof Buffer);
trip = JSON.parse(trip);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(trip.trips[t].geometry);
}
});
});
test('trip: trip with many locations in Monaco', function(assert) {
assert.plan(2);
var many = 5;
var osrm = new OSRM(data_path);
var opts = {coordinates: three_test_coordinates.slice(0, many)};
osrm.trip(opts, function(err, trip) {
assert.ifError(err);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(trip.trips[t].geometry);
}
});
});
test('trip: throws with too few or invalid args', function(assert) {
assert.plan(3);
var osrm = new OSRM(data_path);
assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}) },
/Two arguments required/);
assert.throws(function() { osrm.trip(null, function(err, trip) {}) },
/First arg must be an object/);
assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}, { format: 'invalid' }, function(err, trip) {}) },
/format must be a string:/);
});
test('trip: throws with bad params', function(assert) {
assert.plan(14);
var osrm = new OSRM(data_path);
assert.throws(function () { osrm.trip({coordinates: []}, function(err) {}) });
assert.throws(function() { osrm.trip({}, function(err, trip) {}) },
/Must provide a coordinates property/);
assert.throws(function() { osrm.trip({
coordinates: null
}, function(err, trip) {}) },
/Coordinates must be an array of \(lon\/lat\) pairs/);
assert.throws(function() { osrm.trip({
coordinates: three_test_coordinates[0]
}, function(err, trip) {}) },
/Coordinates must be an array of \(lon\/lat\) pairs/);
assert.throws(function() { osrm.trip({
coordinates: [three_test_coordinates[0][0], three_test_coordinates[0][1]]
}, function(err, trip) {}) },
/Coordinates must be an array of \(lon\/lat\) pairs/);
assert.throws(function() { osrm.trip({
coordinates: two_test_coordinates,
hints: null
}, function(err, trip) {}) },
/Hints must be an array of strings\/null/);
var options = {
coordinates: [three_test_coordinates[0], three_test_coordinates[1]],
hints: three_test_coordinates[0]
};
assert.throws(function() { osrm.trip(options, function(err, trip) {}); },
/Hint must be null or string/);
options.hints = [null];
assert.throws(function() { osrm.trip(options, function(err, trip) {}); },
/Hints array must have the same length as coordinates array/);
delete options.hints;
options.geometries = 'false';
assert.throws(function() { osrm.trip(options, function(err, trip) {}); },
/'geometries' param must be one of \[polyline, polyline6, geojson\]/);
delete options.geometries;
options.source = false;
assert.throws(function() { osrm.trip(options, function(err, trip) {}); },
/Source must be a string: \[any, first\]/);
options.source = 'false';
assert.throws(function() { osrm.trip(options, function(err, trip) {}); },
/'source' param must be one of \[any, first\]/);
delete options.source;
options.destination = true;
assert.throws(function() { osrm.trip(options, function(err, trip) {}); },
/Destination must be a string: \[any, last\]/);
options.destination = 'true';
assert.throws(function() { osrm.trip(options, function(err, trip) {}); },
/'destination' param must be one of \[any, last\]/);
options.roundtrip = 'any';
assert.throws(function() { osrm.trip(options, function(err, trip) {}); },
/'roundtrip' param must be a boolean/);
});
test('trip: routes Monaco using shared memory', function(assert) {
assert.plan(2);
var osrm = new OSRM();
osrm.trip({coordinates: two_test_coordinates}, function(err, trip) {
assert.ifError(err);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(trip.trips[t].geometry);
}
});
});
test('trip: routes Monaco with hints', function(assert) {
assert.plan(5);
var osrm = new OSRM(data_path);
var options = {
coordinates: two_test_coordinates,
steps: false
};
osrm.trip(options, function(err, first) {
assert.ifError(err);
for (t = 0; t < first.trips.length; t++) {
assert.ok(first.trips[t].geometry);
}
var hints = first.waypoints.map(function(wp) { return wp.hint; });
assert.ok(hints.every(function(h) { return typeof h === 'string'; }));
options.hints = hints;
osrm.trip(options, function(err, second) {
assert.ifError(err);
assert.deepEqual(first, second);
});
});
});
test('trip: trip through Monaco with geometry compression', function(assert) {
assert.plan(2);
var osrm = new OSRM(data_path);
var options = {
coordinates: [three_test_coordinates[0], three_test_coordinates[1]]
};
osrm.trip(options, function(err, trip) {
assert.ifError(err);
for (t = 0; t < trip.trips.length; t++) {
assert.equal('string', typeof trip.trips[t].geometry);
}
});
});
test('trip: trip through Monaco without geometry compression', function(assert) {
assert.plan(2);
var osrm = new OSRM(data_path);
var options = {
coordinates: two_test_coordinates,
geometries: 'geojson'
};
osrm.trip(options, function(err, trip) {
assert.ifError(err);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(Array.isArray(trip.trips[t].geometry.coordinates));
}
});
});
test('trip: trip through Monaco with speed annotations options', function(assert) {
assert.plan(12);
var osrm = new OSRM(data_path);
var options = {
coordinates: two_test_coordinates,
steps: true,
annotations: ['speed'],
overview: 'false'
};
osrm.trip(options, function(err, trip) {
assert.ifError(err);
assert.equal(trip.trips.length, 1);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(trip.trips[t]);
assert.ok(trip.trips[t].legs.every(function(l) { return l.steps.length > 0; }), 'every leg has steps')
assert.ok(trip.trips[t].legs.every(function(l) { return l.annotation; }), 'every leg has annotations')
assert.ok(trip.trips[t].legs.every(function(l) { return l.annotation.speed; }), 'every leg has annotations for speed')
assert.notOk(trip.trips[t].legs.every(function(l) { return l.annotation.weight; }), 'has no annotations for weight')
assert.notOk(trip.trips[t].legs.every(function(l) { return l.annotation.datasources; }), 'has no annotations for datasources')
assert.notOk(trip.trips[t].legs.every(function(l) { return l.annotation.duration; }), 'has no annotations for duration')
assert.notOk(trip.trips[t].legs.every(function(l) { return l.annotation.distance; }), 'has no annotations for distance')
assert.notOk(trip.trips[t].legs.every(function(l) { return l.annotation.nodes; }), 'has no annotations for nodes')
assert.notOk(trip.trips[t].geometry);
}
});
});
test('trip: trip through Monaco with several (duration, distance, nodes) annotations options', function(assert) {
assert.plan(12);
var osrm = new OSRM(data_path);
var options = {
coordinates: two_test_coordinates,
steps: true,
annotations: ['duration', 'distance', 'nodes'],
overview: 'false'
};
osrm.trip(options, function(err, trip) {
assert.ifError(err);
assert.equal(trip.trips.length, 1);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(trip.trips[t]);
assert.ok(trip.trips[t].legs.every(function(l) { return l.steps.length > 0; }), 'every leg has steps')
assert.ok(trip.trips[t].legs.every(function(l) { return l.annotation; }), 'every leg has annotations')
assert.ok(trip.trips[t].legs.every(function(l) { return l.annotation.duration; }), 'every leg has annotations for duration')
assert.ok(trip.trips[t].legs.every(function(l) { return l.annotation.distance; }), 'every leg has annotations for distance')
assert.ok(trip.trips[t].legs.every(function(l) { return l.annotation.nodes; }), 'every leg has annotations for nodes')
assert.notOk(trip.trips[t].legs.every(function(l) { return l.annotation.weight; }), 'has no annotations for weight')
assert.notOk(trip.trips[t].legs.every(function(l) { return l.annotation.datasources; }), 'has no annotations for datasources')
assert.notOk(trip.trips[t].legs.every(function(l) { return l.annotation.speed; }), 'has no annotations for speed')
assert.notOk(trip.trips[t].geometry);
}
});
});
test('trip: trip through Monaco with options', function(assert) {
assert.plan(6);
var osrm = new OSRM(data_path);
var options = {
coordinates: two_test_coordinates,
steps: true,
annotations: true,
overview: 'false'
};
osrm.trip(options, function(err, trip) {
assert.ifError(err);
assert.equal(trip.trips.length, 1);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(trip.trips[t]);
assert.ok(trip.trips[t].legs.every(function(l) { return l.steps.length > 0; }), 'every leg has steps')
assert.ok(trip.trips[t].legs.every(function(l) { return l.annotation; }), 'every leg has annotations')
assert.notOk(trip.trips[t].geometry);
}
});
});
test('trip: routes Monaco with null hints', function(assert) {
assert.plan(1);
var osrm = new OSRM(data_path);
var options = {
coordinates: [three_test_coordinates[0], three_test_coordinates[1]],
hints: [null, null]
};
osrm.trip(options, function(err, second) {
assert.ifError(err);
});
});
test('trip: service combinations that are not implemented', function(assert) {
assert.plan(1);
var osrm = new OSRM(data_path);
// no fixed start, no fixed end, non-roundtrip
var options = {
coordinates: two_test_coordinates,
source: 'any',
destination: 'any',
roundtrip: false
};
osrm.trip(options, function(err, second) {
assert.equal('NotImplemented', err.message);
});
});
test('trip: fixed start and end combinations', function(assert) {
var osrm = new OSRM(data_path);
var options = {
coordinates: two_test_coordinates,
source: 'first',
destination: 'last',
roundtrip: false,
geometries: 'geojson'
};
// variations of non roundtrip
var nonRoundtripChecks = function(options) {
osrm.trip(options, function(err, fseTrip) {
assert.ifError(err);
assert.equal(1, fseTrip.trips.length);
var coordinates = fseTrip.trips[0].geometry.coordinates;
assert.notEqual(JSON.stringify(coordinates[0]), JSON.stringify(coordinates[coordinates.length - 1]));
});
};
// variations of roundtrip
var roundtripChecks = function(options) {
osrm.trip(options, function(err, trip) {
assert.ifError(err);
assert.equal(1, trip.trips.length);
var coordinates = trip.trips[0].geometry.coordinates;
assert.equal(JSON.stringify(coordinates[0]), JSON.stringify(coordinates[coordinates.length - 1]));
});
};
// fixed start and end, non-roundtrip
nonRoundtripChecks(options);
// fixed start, non-roundtrip
delete options.destination;
options.source = 'first';
nonRoundtripChecks(options);
// fixed end, non-roundtrip
delete options.source;
options.destination = 'last';
nonRoundtripChecks(options);
// roundtrip, source and destination not specified
roundtripChecks({coordinates: options.coordinates, geometries: options.geometries});
// roundtrip, fixed destination
options.roundtrip = true;
delete options.source;
options.destination = 'last';
roundtripChecks(options);
//roundtrip, fixed source
delete options.destination;
options.source = 'first';
roundtripChecks(options);
// roundtrip, non-fixed source, non-fixed destination
options.source = 'any';
options.destination = 'any';
roundtripChecks(options);
assert.end();
});
test('trip: trip in Monaco without motorways', function(assert) {
assert.plan(3);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: two_test_coordinates,
exclude: ['motorway']
};
osrm.trip(options, function(err, response) {
assert.ifError(err);
assert.equal(response.waypoints.length, 2);
assert.equal(response.trips.length, 1);
});
});
test('trip: throws on disabled geometry', function (assert) {
assert.plan(1);
var osrm = new OSRM({'path': data_path, 'disable_feature_dataset': ['ROUTE_GEOMETRY']});
var options = {
coordinates: three_test_coordinates.concat(three_test_coordinates),
};
osrm.trip(options, function(err, route) {
console.log(err)
assert.match(err.message, /DisabledDatasetException/);
});
});
test('trip: ok on disabled geometry', function (assert) {
assert.plan(2);
var osrm = new OSRM({'path': data_path, 'disable_feature_dataset': ['ROUTE_GEOMETRY']});
var options = {
steps: false,
overview: 'false',
annotations: false,
skip_waypoints: true,
coordinates: three_test_coordinates.concat(three_test_coordinates),
};
osrm.trip(options, function(err, response) {
assert.ifError(err);
assert.equal(response.trips.length, 1);
});
});
test('trip: throws on disabled steps', function (assert) {
assert.plan(1);
var osrm = new OSRM({'path': data_path, 'disable_feature_dataset': ['ROUTE_STEPS']});
var options = {
steps: true,
coordinates: three_test_coordinates.concat(three_test_coordinates),
};
osrm.trip(options, function(err, route) {
console.log(err)
assert.match(err.message, /DisabledDatasetException/);
});
});
test('trip: ok on disabled steps', function (assert) {
assert.plan(8);
var osrm = new OSRM({'path': data_path, 'disable_feature_dataset': ['ROUTE_STEPS']});
var options = {
steps: false,
overview: 'simplified',
annotations: true,
coordinates: three_test_coordinates.concat(three_test_coordinates),
};
osrm.trip(options, function(err, response) {
assert.ifError(err);
assert.ok(response.waypoints);
assert.ok(response.trips);
assert.equal(response.trips.length, 1);
assert.ok(response.trips[0].geometry, "trip has geometry");
assert.ok(response.trips[0].legs, "trip has legs");
assert.notok(response.trips[0].legs.every(l => { return l.steps.length > 0; }), 'every leg has steps');
assert.ok(response.trips[0].legs.every(l => { return l.annotation;}), 'every leg has annotations');
});
});