Make the first 3 nearest/pick.feature scenarios pass

This commit is contained in:
Dennis 2024-05-31 21:07:10 +02:00
parent 59cbb08c0e
commit 5cf37a0c7c
No known key found for this signature in database
GPG Key ID: 6937EAEA33A3FA5D
9 changed files with 122 additions and 29 deletions

8
Cargo.lock generated
View File

@ -548,6 +548,12 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "help"
version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5d2c6714f78261bbacbd07338eb21943fa5a25c67760287aecb6aefbec89062"
[[package]]
name = "humantime"
version = "2.1.0"
@ -740,6 +746,8 @@ dependencies = [
"cucumber",
"futures",
"geo-types",
"help",
"serde",
"serde_json",
"ureq",
"xml-builder",

View File

@ -10,6 +10,8 @@ clap = "4.5.4"
cucumber = "0.21.0"
futures = "0.3.30"
geo-types = "0.7.13"
help = "0.0.0"
serde = { version = "1.0.203", features = ["serde_derive"] }
serde_json = "1.0.117"
ureq = "2.9.7"
xml-builder = "0.5.2"

View File

@ -7,6 +7,7 @@
#include "util/json_container.hpp"
#include <boost/format.hpp>
#include <iostream>
namespace osrm::server::service
{
@ -30,11 +31,11 @@ std::string getWrongOptionHelp(const engine::api::NearestParameters &parameters)
return help;
}
} // namespace
engine::Status NearestService::RunQuery(std::size_t prefix_length,
std::string &query,
osrm::engine::api::ResultT &result)
{
std::cout << "running query: " << query << "\n";
result = util::json::Object();
auto &json_result = std::get<util::json::Object>(result);

View File

@ -1,4 +1,8 @@
use std::{collections::VecDeque, fs, path::{Path, PathBuf}};
use std::{
collections::VecDeque,
fs,
path::{Path, PathBuf},
};
// TODO: port into toolbox-rs
pub struct LexicographicFileWalker {

View File

@ -1,4 +1,5 @@
pub mod lexicographic_file_walker;
pub mod nearest_response;
pub mod osm;
pub mod osm_db;
pub mod osrm_world;

View File

@ -0,0 +1,23 @@
use geo_types::{point, Point};
use serde::Deserialize;
#[derive(Deserialize, Debug)]
pub struct Waypoint {
hint: String,
nodes: Vec<u64>,
distance: f64,
name: String,
location: [f64; 2],
}
impl Waypoint {
pub fn location(&self) -> Point {
point!(self.location)
}
}
#[derive(Deserialize, Debug)]
pub struct NearestResponse {
code: String,
pub waypoints: Vec<Waypoint>,
}

View File

@ -1,5 +1,5 @@
use xml_builder::{XMLBuilder, XMLElement, XMLVersion};
use super::osm::{OSMNode, OSMWay};
use xml_builder::{XMLBuilder, XMLElement, XMLVersion};
// TODO: better error handling in XML creation
#[derive(Debug, Default)]
@ -124,4 +124,4 @@ mod tests {
println!("{actual}");
assert_eq!(actual, expected);
}
}
}

View File

@ -1,6 +1,6 @@
use std::{collections::HashMap, fs::File, path::PathBuf};
use crate::Point;
use cucumber::World;
use std::{collections::HashMap, fs::File, path::PathBuf};
use super::{osm::OSMNode, osm_db::OSMDb};
@ -58,10 +58,17 @@ impl OSRMWorld {
pub fn get_location(&self, name: char) -> Point {
match name {
// TODO: move lookup to world
'0'..='9' => self.known_locations.get(&name).expect("test case specifies unknown location: {name}"),
'a'..='z' => self.known_osm_nodes.get(&name).expect("test case specifies unknown osm node: {name}"),
'0'..='9' => self
.known_locations
.get(&name)
.expect("test case specifies unknown location: {name}"),
'a'..='z' => self
.known_osm_nodes
.get(&name)
.expect("test case specifies unknown osm node: {name}"),
_ => unreachable!("nodes have to be name in [0-9][a-z]"),
}.clone()
}
.clone()
}
pub fn add_location(&mut self, name: char, location: Point) {
@ -70,4 +77,4 @@ impl OSRMWorld {
}
self.known_locations.insert(name, location);
}
}
}

View File

@ -6,20 +6,20 @@ use crate::common::osrm_world::OSRMWorld;
use cheap_ruler::CheapRuler;
use clap::Parser;
use common::lexicographic_file_walker::LexicographicFileWalker;
use common::nearest_response::NearestResponse;
use common::osm::OSMWay;
use serde_json::Value;
use ureq::Agent;
use core::panic;
use std::time::Duration;
use cucumber::{self, gherkin::Step, given, when, World};
use futures::{future, FutureExt};
use geo_types::{point, Point};
use std::fmt::Display;
use std::fmt::{format, Display};
use std::fs::{create_dir_all, File};
use std::io::{Read, Write};
use std::io::{BufRead, BufReader, Read, Write};
use std::path::PathBuf;
use std::process::Command;
use std::process::{Command, Stdio};
use std::time::Duration;
use std::{env, fs};
use ureq::Agent;
const DEFAULT_ORIGIN: [f64; 2] = [1., 1.]; // TODO: move to world?
const DEFAULT_GRID_SIZE: f64 = 100.; // TODO: move to world?
@ -192,18 +192,38 @@ fn request_nearest(world: &mut OSRMWorld, step: &Step) {
let data_path = cache_path.join(world.scenario_id.to_owned() + ".osrm");
println!("{routed_path:?} {}", data_path.to_str().unwrap());
let handle = Command::new(routed_path)
// TODO: move the child handling into a convenience struct
let mut handle = Command::new(routed_path)
.arg(data_path.to_str().unwrap())
.stdout(Stdio::piped())
.spawn();
if let Err(e) = handle {
panic!("{e}");
let child = match &mut handle {
Ok(o) => o,
Err(e) => panic!("cannot access handle: {e}"),
};
let mut running = false;
if let Some(output) = &mut child.stdout {
let mut reader = BufReader::new(output);
let mut line = String::new();
while let Ok(count) = reader.read_line(&mut line) {
println!("count: {count} ->{line}");
if line.contains("running and waiting for requests") {
running = true;
break;
}
}
}
if !running {
panic! {"routed not started"}
}
let agent: Agent = ureq::AgentBuilder::new()
.timeout_read(Duration::from_secs(5))
.timeout_write(Duration::from_secs(5))
.build();
.timeout_read(Duration::from_secs(5))
.timeout_write(Duration::from_secs(5))
.build();
// parse and run test cases
for (query, expected) in test_cases {
@ -213,23 +233,50 @@ fn request_nearest(world: &mut OSRMWorld, step: &Step) {
println!("{query_location:?} => {expected_location:?}");
// run queries
// "http://localhost:5000/nearest/v1/testbot/1.0008984512067491,1.0"
let url = format!("http://localhost:5000/nearest/v1/{}/{},{}", world.profile, query_location.x(), query_location.y());
let body: String = agent.get(&url)
.call().unwrap()
.into_string().unwrap();
let url = format!(
"http://localhost:5000/nearest/v1/{}/{},{}",
world.profile,
query_location.x(),
query_location.y()
);
let call = agent.get(&url).call();
let v: Value = serde_json::from_str(&body).unwrap();
let result_location = point!{ x: v["location"][0].as_f64().unwrap(), y: v["location"][1].as_f64().unwrap()};
assert_eq!(result_location, expected_location)
let body = match call {
Ok(response) => response.into_string().expect("response not parseable"),
Err(e) => panic!("http error: {e}"),
};
println!("body: {body}");
let v: NearestResponse = match serde_json::from_str(&body) {
Ok(v) => v,
Err(e) => panic!("parsing error {e}"),
};
let result_location = v.waypoints[0].location();
// assert_eq!(result_location, expected_location)
assert!(approx_equal(result_location.x(), expected_location.x(), 5));
assert!(approx_equal(result_location.y(), expected_location.y(), 5));
// println!("{body}");
// check results
}
if let Err(e) = handle.expect("osrm-routed died unexpectedly").kill() {
if let Err(e) = child.kill() {
panic!("shutdown failed: {e}");
}
}
// matchLocation (got, want) {
// if (got == null || want == null) return false;
// return this.match(got[0], util.format('%d ~0.0025%', want.lon)) &&
// this.match(got[1], util.format('%d ~0.0025%', want.lat));
// }
pub fn approx_equal(a: f64, b: f64, dp: u8) -> bool {
let p = 10f64.powi(-(dp as i32));
(a - b).abs() < p
}
// TODO: move to different file
fn get_file_as_byte_vec(path: &PathBuf) -> Vec<u8> {
println!("opening {path:?}");