mirror of
https://gitlab.com/mobicoop/v3/service/matcher.git
synced 2026-01-01 07:52:41 +00:00
almost full coverage for graphhopper georouter
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
import { Geodesic } from '@modules/geography/infrastructure/geodesic';
|
||||
|
||||
describe('Matcher geodesic', () => {
|
||||
it('should be defined', () => {
|
||||
const geodesic: Geodesic = new Geodesic();
|
||||
expect(geodesic).toBeDefined();
|
||||
});
|
||||
it('should get inverse values', () => {
|
||||
const geodesic: Geodesic = new Geodesic();
|
||||
const inv = geodesic.inverse(0, 0, 1, 1);
|
||||
expect(Math.round(inv.azimuth)).toBe(45);
|
||||
expect(Math.round(inv.distance)).toBe(156900);
|
||||
});
|
||||
});
|
||||
@@ -1,33 +1,259 @@
|
||||
import { DefaultParamsProviderPort } from '@modules/geography/core/application/ports/default-params-provider.port';
|
||||
import { GeodesicPort } from '@modules/geography/core/application/ports/geodesic.port';
|
||||
import {
|
||||
Path,
|
||||
PathType,
|
||||
Route,
|
||||
} from '@modules/geography/core/domain/route.types';
|
||||
import { PARAMS_PROVIDER } from '@modules/geography/geography.di-tokens';
|
||||
GeorouterUnavailableException,
|
||||
RouteNotFoundException,
|
||||
} from '@modules/geography/core/domain/route.errors';
|
||||
import { PathType, Route } from '@modules/geography/core/domain/route.types';
|
||||
import {
|
||||
GEODESIC,
|
||||
PARAMS_PROVIDER,
|
||||
} from '@modules/geography/geography.di-tokens';
|
||||
import { GraphhopperGeorouter } from '@modules/geography/infrastructure/graphhopper-georouter';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AxiosError } from 'axios';
|
||||
import { of, throwError } from 'rxjs';
|
||||
|
||||
const driverPath: Path = {
|
||||
type: PathType.DRIVER,
|
||||
points: [
|
||||
{
|
||||
lon: 6,
|
||||
lat: 47,
|
||||
},
|
||||
{
|
||||
lon: 6.1,
|
||||
lat: 47.1,
|
||||
},
|
||||
{
|
||||
lon: 6.2,
|
||||
lat: 47.2,
|
||||
},
|
||||
],
|
||||
const mockHttpService = {
|
||||
get: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => {
|
||||
return throwError(
|
||||
() => new AxiosError('Axios error', AxiosError.ERR_BAD_REQUEST),
|
||||
);
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
return throwError(() => 'Router unavailable');
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
return of({
|
||||
status: 200,
|
||||
data: {
|
||||
paths: [
|
||||
{
|
||||
distance: 50000,
|
||||
time: 1800000,
|
||||
snapped_waypoints: {
|
||||
coordinates: [
|
||||
[0, 0],
|
||||
[10, 10],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
return of({
|
||||
status: 200,
|
||||
data: {
|
||||
paths: [
|
||||
{
|
||||
distance: 50000,
|
||||
time: 1800000,
|
||||
points: {
|
||||
coordinates: [
|
||||
[0, 0],
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[5, 5],
|
||||
[6, 6],
|
||||
[7, 7],
|
||||
[8, 8],
|
||||
[9, 9],
|
||||
[10, 10],
|
||||
],
|
||||
},
|
||||
snapped_waypoints: {
|
||||
coordinates: [
|
||||
[0, 0],
|
||||
[10, 10],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
return of({
|
||||
status: 200,
|
||||
data: {
|
||||
paths: [
|
||||
{
|
||||
distance: 50000,
|
||||
time: 1800000,
|
||||
points: {
|
||||
coordinates: [
|
||||
[0, 0],
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[5, 5],
|
||||
[6, 6],
|
||||
[7, 7],
|
||||
[8, 8],
|
||||
[9, 9],
|
||||
[10, 10],
|
||||
],
|
||||
},
|
||||
details: {
|
||||
time: [
|
||||
[0, 1, 180000],
|
||||
[1, 2, 180000],
|
||||
[2, 3, 180000],
|
||||
[3, 4, 180000],
|
||||
[4, 5, 180000],
|
||||
[5, 6, 180000],
|
||||
[6, 7, 180000],
|
||||
[7, 9, 360000],
|
||||
[9, 10, 180000],
|
||||
],
|
||||
},
|
||||
snapped_waypoints: {
|
||||
coordinates: [
|
||||
[0, 0],
|
||||
[10, 10],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
return of({
|
||||
status: 200,
|
||||
data: {
|
||||
paths: [
|
||||
{
|
||||
distance: 50000,
|
||||
time: 1800000,
|
||||
points: {
|
||||
coordinates: [
|
||||
[0, 0],
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[7, 7],
|
||||
[8, 8],
|
||||
[9, 9],
|
||||
[10, 10],
|
||||
],
|
||||
},
|
||||
snapped_waypoints: {
|
||||
coordinates: [
|
||||
[0, 0],
|
||||
[5, 5],
|
||||
[10, 10],
|
||||
],
|
||||
},
|
||||
details: {
|
||||
time: [
|
||||
[0, 1, 180000],
|
||||
[1, 2, 180000],
|
||||
[2, 3, 180000],
|
||||
[3, 4, 180000],
|
||||
[4, 7, 540000],
|
||||
[7, 9, 360000],
|
||||
[9, 10, 180000],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
return of({
|
||||
status: 200,
|
||||
data: {
|
||||
paths: [
|
||||
{
|
||||
distance: 50000,
|
||||
time: 1800000,
|
||||
points: {
|
||||
coordinates: [
|
||||
[0, 0],
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
[4, 4],
|
||||
[5, 5],
|
||||
[6, 6],
|
||||
[7, 7],
|
||||
[8, 8],
|
||||
[9, 9],
|
||||
[10, 10],
|
||||
],
|
||||
},
|
||||
snapped_waypoints: {
|
||||
coordinates: [
|
||||
[0, 0],
|
||||
[5, 5],
|
||||
[10, 10],
|
||||
],
|
||||
},
|
||||
details: {
|
||||
time: [
|
||||
[0, 1, 180000],
|
||||
[1, 2, 180000],
|
||||
[2, 3, 180000],
|
||||
[3, 4, 180000],
|
||||
[4, 7, 540000],
|
||||
[7, 9, 360000],
|
||||
[9, 10, 180000],
|
||||
],
|
||||
},
|
||||
instructions: [
|
||||
{
|
||||
distance: 25000,
|
||||
sign: 0,
|
||||
interval: [0, 5],
|
||||
text: 'Some instructions',
|
||||
time: 900000,
|
||||
},
|
||||
{
|
||||
distance: 0,
|
||||
sign: 5,
|
||||
interval: [5, 5],
|
||||
text: 'Waypoint 1',
|
||||
time: 0,
|
||||
},
|
||||
{
|
||||
distance: 25000,
|
||||
sign: 2,
|
||||
interval: [5, 10],
|
||||
text: 'Some instructions',
|
||||
time: 900000,
|
||||
},
|
||||
{
|
||||
distance: 0.0,
|
||||
sign: 4,
|
||||
interval: [10, 10],
|
||||
text: 'Arrive at destination',
|
||||
time: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
}),
|
||||
};
|
||||
|
||||
const mockHttpService = {};
|
||||
const mockGeodesic: GeodesicPort = {
|
||||
inverse: jest.fn().mockImplementation(() => ({
|
||||
azimuth: 45,
|
||||
distance: 50000,
|
||||
})),
|
||||
};
|
||||
|
||||
const mockDefaultParamsProvider: DefaultParamsProviderPort = {
|
||||
getParams: jest.fn().mockImplementation(() => ({
|
||||
@@ -51,6 +277,10 @@ describe('Graphhopper Georouter', () => {
|
||||
provide: PARAMS_PROVIDER,
|
||||
useValue: mockDefaultParamsProvider,
|
||||
},
|
||||
{
|
||||
provide: GEODESIC,
|
||||
useValue: mockGeodesic,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
@@ -62,13 +292,209 @@ describe('Graphhopper Georouter', () => {
|
||||
expect(graphhopperGeorouter).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return basic driver routes', async () => {
|
||||
const paths: Path[] = [driverPath];
|
||||
const driverRoutes: Route[] = await graphhopperGeorouter.routes(paths, {
|
||||
detailedDistance: false,
|
||||
detailedDuration: false,
|
||||
points: true,
|
||||
});
|
||||
expect(driverRoutes.length).toBe(1);
|
||||
it('should fail if route is not found', async () => {
|
||||
await expect(
|
||||
graphhopperGeorouter.routes(
|
||||
[
|
||||
{
|
||||
type: PathType.DRIVER,
|
||||
points: [
|
||||
{
|
||||
lon: 0,
|
||||
lat: 0,
|
||||
},
|
||||
{
|
||||
lon: 1,
|
||||
lat: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
{
|
||||
detailedDistance: false,
|
||||
detailedDuration: false,
|
||||
points: false,
|
||||
},
|
||||
),
|
||||
).rejects.toBeInstanceOf(RouteNotFoundException);
|
||||
});
|
||||
|
||||
it('should fail if georouter is unavailable', async () => {
|
||||
await expect(
|
||||
graphhopperGeorouter.routes(
|
||||
[
|
||||
{
|
||||
type: PathType.DRIVER,
|
||||
points: [
|
||||
{
|
||||
lon: 0,
|
||||
lat: 0,
|
||||
},
|
||||
{
|
||||
lon: 1,
|
||||
lat: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
{
|
||||
detailedDistance: false,
|
||||
detailedDuration: false,
|
||||
points: false,
|
||||
},
|
||||
),
|
||||
).rejects.toBeInstanceOf(GeorouterUnavailableException);
|
||||
});
|
||||
|
||||
it('should create a basic route', async () => {
|
||||
const routes: Route[] = await graphhopperGeorouter.routes(
|
||||
[
|
||||
{
|
||||
type: PathType.DRIVER,
|
||||
points: [
|
||||
{
|
||||
lon: 0,
|
||||
lat: 0,
|
||||
},
|
||||
{
|
||||
lon: 10,
|
||||
lat: 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
{
|
||||
detailedDistance: false,
|
||||
detailedDuration: false,
|
||||
points: false,
|
||||
},
|
||||
);
|
||||
expect(routes).toHaveLength(1);
|
||||
expect(routes[0].distance).toBe(50000);
|
||||
});
|
||||
|
||||
it('should create one route with points', async () => {
|
||||
const routes = await graphhopperGeorouter.routes(
|
||||
[
|
||||
{
|
||||
type: PathType.DRIVER,
|
||||
points: [
|
||||
{
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
{
|
||||
lat: 10,
|
||||
lon: 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
{
|
||||
detailedDistance: false,
|
||||
detailedDuration: false,
|
||||
points: true,
|
||||
},
|
||||
);
|
||||
expect(routes).toHaveLength(1);
|
||||
expect(routes[0].distance).toBe(50000);
|
||||
expect(routes[0].duration).toBe(1800);
|
||||
expect(routes[0].fwdAzimuth).toBe(45);
|
||||
expect(routes[0].backAzimuth).toBe(225);
|
||||
expect(routes[0].points).toHaveLength(11);
|
||||
});
|
||||
|
||||
it('should create one route with points and time', async () => {
|
||||
const routes = await graphhopperGeorouter.routes(
|
||||
[
|
||||
{
|
||||
type: PathType.DRIVER,
|
||||
points: [
|
||||
{
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
{
|
||||
lat: 10,
|
||||
lon: 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
{
|
||||
detailedDistance: false,
|
||||
detailedDuration: true,
|
||||
points: true,
|
||||
},
|
||||
);
|
||||
expect(routes).toHaveLength(1);
|
||||
expect(routes[0].spacetimeWaypoints).toHaveLength(2);
|
||||
expect(routes[0].spacetimeWaypoints[1].duration).toBe(1800);
|
||||
expect(routes[0].spacetimeWaypoints[1].distance).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should create one route with points and missed waypoints extrapolations', async () => {
|
||||
const routes = await graphhopperGeorouter.routes(
|
||||
[
|
||||
{
|
||||
type: PathType.DRIVER,
|
||||
points: [
|
||||
{
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
{
|
||||
lat: 5,
|
||||
lon: 5,
|
||||
},
|
||||
{
|
||||
lat: 10,
|
||||
lon: 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
{
|
||||
detailedDistance: false,
|
||||
detailedDuration: true,
|
||||
points: true,
|
||||
},
|
||||
);
|
||||
expect(routes).toHaveLength(1);
|
||||
expect(routes[0].spacetimeWaypoints).toHaveLength(3);
|
||||
expect(routes[0].distance).toBe(50000);
|
||||
expect(routes[0].duration).toBe(1800);
|
||||
expect(routes[0].fwdAzimuth).toBe(45);
|
||||
expect(routes[0].backAzimuth).toBe(225);
|
||||
expect(routes[0].points.length).toBe(9);
|
||||
});
|
||||
|
||||
it('should create one route with points, time and distance', async () => {
|
||||
const routes = await graphhopperGeorouter.routes(
|
||||
[
|
||||
{
|
||||
type: PathType.DRIVER,
|
||||
points: [
|
||||
{
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
},
|
||||
{
|
||||
lat: 10,
|
||||
lon: 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
{
|
||||
detailedDistance: true,
|
||||
detailedDuration: true,
|
||||
points: true,
|
||||
},
|
||||
);
|
||||
expect(routes).toHaveLength(1);
|
||||
expect(routes[0].spacetimeWaypoints.length).toBe(3);
|
||||
expect(routes[0].spacetimeWaypoints[1].duration).toBe(990);
|
||||
expect(routes[0].spacetimeWaypoints[1].distance).toBe(25000);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user