Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Directions api validator cli #1189

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions validator/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
package-lock.json

# This project
releases
14 changes: 14 additions & 0 deletions validator/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug configuration",
"program": "${workspaceFolder}/index.js download-all",
"args": [
"download", "5.6.0"
],
}
]
}
15 changes: 15 additions & 0 deletions validator/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

.DEFAULT_GOAL := default

default:
npm install
validator download-all

clean:
rm package-lock.json
rm -rf node_modules
rm -rf releases

.PHONY: all test clean
test:
npm test
31 changes: 31 additions & 0 deletions validator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

## Introduction
This project is made to validate any json response with all releases.

The command line interface is called "validator". Use it to download releases,

and then run json on the releases. Check out the Makefile to get started.

You can also use the scripts/all-releases.sh to run the validator on every release.

## Getting started
cd validator
npm install

## Examples
### Download and test a release
validator download 5.6.0

sh scripts/all-releases.sh ../services-directions-models/src/test/resources/directions_*

### Download all releases and test a json
validator download-all

sh scripts/all-releases.sh json/tokyo-2020-09-22.json

### Explore the releases
- validator list-services
- validator list-releases
- validator list-releases mapbox-sdk-geojson
- validator list-releases mapbox-sdk-directions-models
- rm -rf releases
1 change: 1 addition & 0 deletions validator/json/test-from-examples.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"routes":[{"weight_name":"auto","weight":113.233,"duration":96.031,"distance":1330.19,"legs":[{"steps":[{"voiceInstructions":[{"ssmlAnnouncement":"<speak><amazon:effect name=\"drc\"><prosody rate=\"1.08\">Drive southeast on Wybrzeże Kościuszkowskie for 1 mile.</prosody></amazon:effect></speak>","announcement":"Drive southeast on Wybrzeże Kościuszkowskie for 1 mile.","distanceAlongGeometry":1286.201},{"ssmlAnnouncement":"<speak><amazon:effect name=\"drc\"><prosody rate=\"1.08\">In a quarter mile, Take the exit on the left.</prosody></amazon:effect></speak>","announcement":"In a quarter mile, Take the exit on the left.","distanceAlongGeometry":402.336},{"ssmlAnnouncement":"<speak><amazon:effect name=\"drc\"><prosody rate=\"1.08\">Take the exit on the left. Then You will arrive at your destination.</prosody></amazon:effect></speak>","announcement":"Take the exit on the left. Then You will arrive at your destination.","distanceAlongGeometry":109.722}],"bannerInstructions":[{"primary":{"components":[{"type":"text","text":"Take the exit on the left"}],"type":"off ramp","modifier":"left","text":"Take the exit on the left"},"distanceAlongGeometry":1286.201}],"maneuver":{"type":"depart","instruction":"Drive southeast on Wybrzeże Kościuszkowskie.","bearing_after":139,"bearing_before":0,"location":[21.023726,52.244762]},"intersections":[{"entry":[true],"bearings":[139],"duration":4.191,"out":0,"weight":4.505,"geometry_index":0,"location":[21.023726,52.244762]},{"entry":[true,false],"in":1,"bearings":[129,312],"duration":12.024,"out":0,"weight":12.926,"geometry_index":4,"location":[21.024321,52.244392]},{"entry":[true,false],"classes":["tunnel"],"in":1,"bearings":[135,310],"duration":52.37,"turn_weight":5,"out":0,"weight":61.298,"geometry_index":10,"location":[21.026243,52.243465]},{"entry":[true,false],"in":1,"bearings":[170,347],"duration":7.786,"turn_weight":5,"out":0,"weight":13.37,"geometry_index":22,"location":[21.033167,52.238121]},{"bearings":[149,333],"entry":[true,false],"in":1,"out":0,"geometry_index":28,"location":[21.033546,52.237324]}],"weight":109.828,"duration":92.863,"distance":1286.201,"name":"Wybrzeże Kościuszkowskie","driving_side":"right","mode":"driving","geometry":"spwsbBy}dbg@pBwClEqHtE}IlE}J`C{FhCiHlI{UjQif@tJcV`HuPx\\cp@lbBoeDlOaWdOwVlo@}{@r_@_m@lKyL|IuJ`MuJxMkI`MoDvWgHfOmChGcB~DoAlEmBnCeBjGaFhLkLbRgVnv@egA"},{"voiceInstructions":[{"ssmlAnnouncement":"<speak><amazon:effect name=\"drc\"><prosody rate=\"1.08\">You have arrived at your destination.</prosody></amazon:effect></speak>","announcement":"You have arrived at your destination.","distanceAlongGeometry":43.988}],"bannerInstructions":[{"primary":{"components":[{"type":"text","text":"You have arrived at your destination"}],"type":"arrive","modifier":"straight","text":"You have arrived at your destination"},"distanceAlongGeometry":43.988}],"maneuver":{"type":"off ramp","instruction":"Take the exit on the left.","modifier":"slight left","bearing_after":130,"bearing_before":142,"location":[21.035288,52.235916]},"intersections":[{"bearings":[130,144,322],"entry":[true,true,false],"in":2,"out":0,"geometry_index":31,"location":[21.035288,52.235916]}],"weight":3.405,"duration":3.167,"distance":43.988,"name":"","driving_side":"right","mode":"driving","geometry":"wgfsbBmp{bg@jGgO`HcK"},{"voiceInstructions":[],"bannerInstructions":[],"maneuver":{"type":"arrive","instruction":"You have arrived at your destination.","bearing_after":0,"bearing_before":140,"location":[21.035742,52.235638]},"intersections":[{"bearings":[320],"entry":[true],"in":0,"geometry_index":33,"location":[21.035742,52.235638]}],"weight":0,"duration":0,"distance":0,"name":"","driving_side":"right","mode":"driving","geometry":"ivesbByl|bg@??"}],"duration":96.031,"annotation":{"congestion":["unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown","unknown"],"distance":[8.2,15.5,16.9,17.3,11.2,12.7,31.2,53.9,32.7,25.1,75.4,253.7,39.3,38.8,108.8,76.8,26.7,23.3,28.1,28.7,25.8,45.3,29.3,15.2,11,12.1,8.8,16.7,27.9,42.4,126.5,23.1,20.9]},"distance":1330.19,"weight":113.233,"summary":"Wybrzeże Kościuszkowskie"}],"geometry":"spwsbBy}dbg@pBwClEqHtE}IlE}J`C{FhCiHlI{UjQif@tJcV`HuPx\\cp@lbBoeDlOaWdOwVlo@}{@r_@_m@lKyL|IuJ`MuJxMkI`MoDvWgHfOmChGcB~DoAlEmBnCeBjGaFhLkLbRgVnv@egAjGgO`HcK","voiceLocale":"en-US"}],"waypoints":[{"distance":0.134,"name":"Wybrzeże Kościuszkowskie","location":[21.023726,52.244762]},{"distance":2.687,"name":"","location":[21.035742,52.235638]}],"code":"Ok","uuid":"pev23CwTyjeHXL5nzBGSMLq0aV5bG3xjuOUpPekqusN_H-pq9LTeaw=="}
1 change: 1 addition & 0 deletions validator/json/tokyo-2020-09-22.json

Large diffs are not rendered by default.

Binary file added validator/lib/gson-2.8.6.jar
Binary file not shown.
24 changes: 24 additions & 0 deletions validator/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "validator",
"version": "1.0.0",
"description": "",
"main": "index.mjs",
"bin": {
"validator": "./src/index.js"
},
"scripts": {
"test": "mocha"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"chai": "^4.2.0",
"expect.js": "^0.3.1",
"fetch-mock": "^9.10.7",
"java": "^0.12.1",
"mocha": "^8.1.3",
"node-fetch": "^2.6.1",
"yargs": "^16.0.3"
}
}
30 changes: 30 additions & 0 deletions validator/scripts/all-releases.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash

#
# This script helps run the validator. The validator loads jars and validates
# json on that loaded jar.
#
# The reason we loop through this is because the Node.js command line interface
# can only load one executable per run. If there is better way to clear the
# library then we could consider that and delete this script.
#

# This script requires a file with a DirectionsResponse in the form of json.
echo $#
if [[ $# -lt 1 ]]; then
echo "Provide a path to the json file"
exit 1
fi
JSON_FILE=$1

for var in "$@"; do
JSON_FILE=$var
echo Testing $JSON_FILE
# Validate the json with each release that has been downloaded.
# To download releases, use the validator command line interface
FILES=releases/*
for f in $FILES; do
release="${f:9}"
validator json $release $JSON_FILE
done
done
69 changes: 69 additions & 0 deletions validator/src/download.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const fetch = require("node-fetch");
const fs = require('fs')
const util = require('util')
const releases = require('./releases')

function downloadUrl(release, service) {
// https://dl.bintray.com/<SUBJECT_NAME>/<REPO_NAME>/<VERSION>/<FILE_PATH>
const path = `mapbox/mapbox/com/mapbox/mapboxsdk/${service}`
const query = `${release}/${service}-${release}.jar`
return `https://dl.bintray.com/${path}/${query}`
}

async function write(release, service, response) {
const releaseDirectory = releases.mkdir(release)
const relativePath = `${releaseDirectory}/${service}.jar`
if (!fs.existsSync(relativePath)) {
const streamPipeline = util.promisify(require('stream').pipeline)
await streamPipeline(response.body, fs.createWriteStream(relativePath))
}
};

async function downloadService(release, service) {
const releaseInfo = releases.info(release, service)
const url = downloadUrl(release, service)
if (releaseInfo.exists) {
return {
url:`${url}`,
service:`${service}`,
release:`${release}`,
result:"success"
};
}

const response = await fetch(url)
.then( response => {
if (response.ok) {
write(release, service, response);
}
const result = response.ok ? "success" : "retry"
console.log(`${url} ${response.status}`)
const downloadStatus = {
url:`${url}`,
service:`${service}`,
release:`${release}`,
result:`${result}`
};
return downloadStatus
})
.catch( error => {
return {
url:`${url}`,
service:`${service}`,
release:`${release}`,
result:"failure"
};
});

return response
};

module.exports = {
downloadRelease: async function(release) {
const sdkServices = downloadService(release, "mapbox-sdk-services")
const sdkGeojson = downloadService(release, "mapbox-sdk-geojson")
const directionsModels = downloadService(release, "mapbox-sdk-directions-models")
const directionsRefreshModels = downloadService(release, "mapbox-sdk-directions-refresh-models")
return await Promise.all([sdkServices, sdkGeojson, directionsModels, directionsRefreshModels]);
}
}
57 changes: 57 additions & 0 deletions validator/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env node

const releases = require('./releases')
const download = require('./download')
const runner = require('./runner')

const DEFAULT_SERVICE = "mapbox-sdk-services"

const argv = require('yargs')
.command('list-services', 'Request info on all available services', (argv) => {
releases.listServices(services => {
console.log(services)
});
})
.command('list-releases [service]', 'Request releases for a specific service', (argv) => {
argv.positional('service', {
describe: 'The service you want to know the releases available',
type: 'string',
default:DEFAULT_SERVICE
});
}, handler = (argv) => {
releases.listReleases(argv.service, release => {
console.log(release)
});
})
.command('download <release>', 'Download specific release', (argv) => {
argv.positional('release', {
describe: 'The release version',
type: 'string'
});
}, handler = (argv) => {
download.downloadRelease(argv.release);
})
.command('download-all', 'Download all the releases', (argv) => {
releases.listReleases(DEFAULT_SERVICE, releases => {
releases[0].versions.forEach(element => {
download.downloadRelease(element)
});
});
})
.command('json <release> <file>', 'Validate the contents of a json file', (argv) => {
argv.positional('release', {
describe: 'The release version',
type: 'string'
});
argv.positional('file', {
describe: 'Path to a json file',
type: 'string'
});
}, handler = (argv) => {
const result = runner.validateJson(argv.release, argv.file);
const resultsMessage = result.success ? "success" : `failure ${result.reason}`
console.log(`${result.release} ${resultsMessage}`);
})
.help()
.demandCommand(1)
.parse()
45 changes: 45 additions & 0 deletions validator/src/releases.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const fetch = require("node-fetch");
const fs = require('fs');

module.exports = {
listServices: function(callback) {
const servicesUrl = "https://api.bintray.com/search/packages/maven?g=com.mapbox.mapboxsdk"
fetch(servicesUrl, { method: 'GET' })
.then( response => response.json() )
.then( json => callback(json) )
.catch( error => console.error('Unable to list services:', error) );
},
listReleases: function(service, callback) {
const versionUrl = `https://api.bintray.com/search/packages/maven?g=com.mapbox.mapboxsdk&a=${service}`
fetch(versionUrl, { method: 'GET' })
.then( response => response.json() )
.then( json => callback(json) )
.catch( error => console.error('Unable to list release versions:', error) );
},
info: function(release, service) {
const releaseDirectory = this.mkdir(release)
const relativePath = `${releaseDirectory}/${service}.jar`
const exists = fs.existsSync(relativePath)
const result = {
release:`${release}`,
exists:exists
}
if (exists) {
const stats = fs.statSync(relativePath);
result.sizeMB = stats.size / 1000000.0
result.downloaded = stats.birthtime
}
return result
},
mkdir: function(release) {
const outputDirectory = "releases"
if (!fs.existsSync(outputDirectory)) {
fs.mkdirSync(outputDirectory);
}
const releaseDirectory = `${outputDirectory}/${release}`
if (!fs.existsSync(releaseDirectory)) {
fs.mkdirSync(releaseDirectory);
}
return `./${releaseDirectory}`
}
};
35 changes: 35 additions & 0 deletions validator/src/runner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const fs = require('fs')
const java = require('java');

function validateJsonData(release, data) {
const releaseDirectory = `releases/${release}`

java.classpath.push(`./${releaseDirectory}/mapbox-sdk-services.jar`);
java.classpath.push(`./${releaseDirectory}/mapbox-sdk-geojson.jar`);
java.classpath.push(`./${releaseDirectory}/mapbox-sdk-directions-models.jar`);
java.classpath.push(`./${releaseDirectory}/mapbox-sdk-directions-refresh-models.jar`);

// TODO there should be a better place to put this.
java.classpath.push("lib/gson-2.8.6.jar");

const result = {
release:`${release}`
}
try {
const directionStatic = java.import("com.mapbox.api.directions.v5.models.DirectionsResponse");
const fromJsonResult = directionStatic.fromJsonSync(data)
result.success=true
} catch (err) {
result.success=false
result.reason=`${err}`
}

return result
}

module.exports = {
validateJson: function(release, file) {
const data = fs.readFileSync(file, 'utf8');
return validateJsonData(release, data);
}
}
30 changes: 30 additions & 0 deletions validator/test/download.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const download = require('../src/download')

const chai = require('chai');
const assert = chai.assert
const should = chai.should();

describe('#downloadRelease()', function() {
context('should successfully download a release', function() {

it('should download results for 4 services', async function () {
const services = await download.downloadRelease('5.5.0')

services.should.be.an('array').to.have.lengthOf(4)
});

it('should return success for each result', async function() {
const services = await download.downloadRelease('5.5.0')

const success = services.every(value => value.result == "success")

assert.isTrue(success, `expecting result values to be 'retry' ${JSON.stringify(services)}`)
});
})
});


// "https://dl.bintray.com/mapbox/mapbox/com/mapbox/mapboxsdk/mapbox-sdk-services/5.4.0/mapbox-sdk-services-5.4.0.jar",
// "https://dl.bintray.com/mapbox/mapbox/com/mapbox/mapboxsdk/mapbox-sdk-geojson/5.4.0/mapbox-sdk-geojson-5.4.0.jar",
// "https://dl.bintray.com/mapbox/mapbox/com/mapbox/mapboxsdk/mapbox-sdk-directions-models/5.4.0/mapbox-sdk-directions-models-5.4.0.jar",
// "https://dl.bintray.com/mapbox/mapbox/com/mapbox/mapboxsdk/mapbox-sdk-directions-refresh-models/5.4.0/mapbox-sdk-directions-refresh-models-5.4.0.jar"