Merge pull request #889 from Project-OSRM/experimental/cuke_datastore

use osrm-datastore for testing, keep osrm-routed runnning
This commit is contained in:
Dennis Luxen 2014-10-15 15:41:38 +02:00
commit dfc81f65ee
37 changed files with 311 additions and 110 deletions

View File

@ -1,4 +1,4 @@
@routed @options @files
@routed @options @files @todo
Feature: osrm-routed command line options: files
# Normally when launching osrm-routed, it will keep running as a server until it's shut down.
# For testing program options, the --trial option is used, which causes osrm-routed to quit
@ -7,6 +7,11 @@ Feature: osrm-routed command line options: files
# The {base} part of the options to osrm-routed will be expanded to the actual base path of
# the preprocessed file.
# TODO
# Since we're not using osmr-datastore for all testing, osrm-routed is kept running.
# This means this test fails because osrm-routed is already running.
# It probably needs to be rewritten to first quit osrm-routed.
Background:
Given the profile "testbot"
And the node map

View File

@ -158,3 +158,19 @@ Given /^the data has been prepared$/ do
@process_error = e
end
end
Given /^osrm\-routed is stopped$/ do
begin
OSRMLoader.shutdown
rescue OSRMError => e
@process_error = e
end
end
Given /^data is loaded directly/ do
@load_method = 'directly'
end
Given /^data is loaded with datastore$/ do
@load_method = 'datastore'
end

View File

@ -1,7 +1,7 @@
When /^I request locate I should get$/ do |table|
reprocess
actual = []
OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
OSRMLoader.load(self,"#{@osm_file}.osrm") do
table.hashes.each_with_index do |row,ri|
in_node = find_node_by_name row['in']
raise "*** unknown in-node '#{row['in']}" unless in_node

View File

@ -1,7 +1,7 @@
When /^I request nearest I should get$/ do |table|
reprocess
actual = []
OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
OSRMLoader.load(self,"#{@osm_file}.osrm") do
table.hashes.each_with_index do |row,ri|
in_node = find_node_by_name row['in']
raise "*** unknown in-node '#{row['in']}" unless in_node

View File

@ -1,6 +1,6 @@
When(/^I run "osrm\-routed\s?(.*?)"$/) do |options|
begin
Timeout.timeout(1) { run_bin 'osrm-routed', options }
Timeout.timeout(SHUTDOWN_TIMEOUT) { run_bin 'osrm-routed', options }
rescue Timeout::Error
raise "*** osrm-routed didn't quit. Maybe the --trial option wasn't used?"
end
@ -14,6 +14,10 @@ When(/^I run "osrm\-prepare\s?(.*?)"$/) do |options|
run_bin 'osrm-prepare', options
end
When(/^I run "osrm\-datastore\s?(.*?)"$/) do |options|
run_bin 'osrm-datastore', options
end
Then /^it should exit with code (\d+)$/ do |code|
expect(@exit_code).to eq( code.to_i )
end

View File

@ -1,6 +1,6 @@
When /^I request \/(.*)$/ do |path|
reprocess
OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
OSRMLoader.load(self,"#{@osm_file}.osrm") do
@response = request_path path
end
end

View File

@ -44,7 +44,7 @@ Then /^routability should be$/ do |table|
if table.headers&["forw","backw","bothw"] == []
raise "*** routability tabel must contain either 'forw', 'backw' or 'bothw' column"
end
OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
OSRMLoader.load(self,"#{@osm_file}.osrm") do
table.hashes.each_with_index do |row,i|
output_row = row.dup
attempts = []

View File

@ -1,7 +1,7 @@
When /^I route I should get$/ do |table|
reprocess
actual = []
OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do
OSRMLoader.load(self,"#{@osm_file}.osrm") do
table.hashes.each_with_index do |row,ri|
if row['request']
got = {'request' => row['request'] }

View File

@ -11,6 +11,7 @@ class Location
end
end
def set_input_format format
raise '*** Input format must be eiter "osm" or "pbf"' unless ['pbf','osm'].include? format.to_s
@input_format = format.to_s
@ -21,7 +22,7 @@ def input_format
end
def sanitized_scenario_title
@sanitized_scenario_title ||= @scenario_title.gsub /[^0-9A-Za-z.\-]/, '_'
@sanitized_scenario_title ||= @scenario_title.to_s.gsub /[^0-9A-Za-z.\-]/, '_'
end
def set_grid_size meters
@ -225,13 +226,17 @@ def convert_osm_to_pbf
end
def extracted?
File.exist?("#{@osm_file}.osrm") &&
File.exist?("#{@osm_file}.osrm.names") &&
File.exist?("#{@osm_file}.osrm.restrictions")
Dir.chdir TEST_FOLDER do
File.exist?("#{@osm_file}.osrm") &&
File.exist?("#{@osm_file}.osrm.names") &&
File.exist?("#{@osm_file}.osrm.restrictions")
end
end
def prepared?
File.exist?("#{@osm_file}.osrm.hsgr")
Dir.chdir TEST_FOLDER do
File.exist?("#{@osm_file}.osrm.hsgr")
end
end
def write_timestamp

View File

@ -1,8 +1,8 @@
require 'rspec/expectations'
DEFAULT_PORT = 5000
DEFAULT_TIMEOUT = 2
ROOT_FOLDER = Dir.pwd
OSM_USER = 'osrm'
OSM_GENERATOR = 'osrm-test'
@ -17,6 +17,26 @@ PROFILES_PATH = File.join ROOT_FOLDER, 'profiles'
BIN_PATH = File.join ROOT_FOLDER, 'build'
DEFAULT_INPUT_FORMAT = 'osm'
DEFAULT_ORIGIN = [1,1]
LAUNCH_TIMEOUT = 1
SHUTDOWN_TIMEOUT = 10
DEFAULT_LOAD_METHOD = 'datastore'
OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
if ENV['OS']==/Windows.*/ then
TERMSIGNAL='TERM'
else
TERMSIGNAL=9
end
def log_time_and_run cmd
log_time cmd
`#{cmd}`
end
def log_time cmd
puts "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S:%L')}] #{cmd}"
end
puts "Ruby version #{RUBY_VERSION}"
@ -44,6 +64,7 @@ unless File.exists? TEST_FOLDER
raise "*** Test folder #{TEST_FOLDER} doesn't exist."
end
if ENV['OS']=~/Windows.*/ then
EXE='.exe'
QQ='"'
@ -53,5 +74,12 @@ else
end
AfterConfiguration do |config|
if OSRMLoader::OSRMBaseLoader.new.osrm_up?
raise "*** osrm-routed is already running."
end
clear_log_files
end
at_exit do
OSRMLoader::OSRMBaseLoader.new.shutdown
end

View File

@ -1,7 +1,9 @@
STRESS_TIMEOUT = 300
Before do |scenario|
# feature name
case scenario
when Cucumber::Ast::Scenario
@ -18,6 +20,7 @@ Before do |scenario|
@scenario_title = scenario.scenario_outline.name
end
@load_method = DEFAULT_LOAD_METHOD
@query_params = {}
@scenario_time = Time.now.strftime("%Y-%m-%dT%H:%m:%SZ")
reset_data
@ -25,6 +28,7 @@ Before do |scenario|
@has_logged_scenario_info = false
set_grid_size DEFAULT_GRID_SIZE
set_origin DEFAULT_ORIGIN
end
Around('@stress') do |scenario, block|

View File

@ -1,95 +1,136 @@
require 'socket'
require 'open3'
if ENV['OS']==/Windows.*/ then
TERMSIGNAL='TERM'
else
TERMSIGNAL=9
end
# Only one isntance of osrm-routed is ever launched, to avoid collisions.
# The default is to keep osrm-routed running and load data with datastore.
# however, osrm-routed it shut down and relaunched for each scenario thats
# loads data directly.
class OSRMLoader
OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
class OSRMBaseLoader
@@pid = nil
class OSRMBackgroundLauncher
def initialize input_file, &block
@input_file = input_file
Dir.chdir TEST_FOLDER do
begin
def launch
Timeout.timeout(LAUNCH_TIMEOUT) do
osrm_up
wait_for_connection
end
rescue Timeout::Error
raise RoutedError.new "Launching osrm-routed timed out."
end
def shutdown
Timeout.timeout(SHUTDOWN_TIMEOUT) do
osrm_down
end
rescue Timeout::Error
kill
raise RoutedError.new "Shutting down osrm-routed timed out."
end
def osrm_up?
if @@pid
begin
if Process.waitpid(@@pid, Process::WNOHANG) then
false
else
true
end
rescue Errno::ESRCH, Errno::ECHILD
false
end
end
end
def osrm_down
if @@pid
Process.kill TERMSIGNAL, @@pid
wait_for_shutdown
@@pid = nil
end
end
def kill
if @@pid
Process.kill 'KILL', @@pid
end
end
def wait_for_connection
while true
begin
socket = TCPSocket.new('127.0.0.1', OSRM_PORT)
return
rescue Errno::ECONNREFUSED
sleep 0.1
end
end
end
def wait_for_shutdown
while osrm_up?
sleep 0.01
end
end
end
# looading data directly when lauching osrm-routed:
# under this scheme, osmr-routed is launched and shutdown for each scenario,
# and osrm-datastore is not used
class OSRMDirectLoader < OSRMBaseLoader
def load world, input_file, &block
@world = world
@input_file = input_file
Dir.chdir TEST_FOLDER do
shutdown
launch
yield
ensure
shutdown
end
end
end
private
def launch
Timeout.timeout(OSRM_TIMEOUT) do
osrm_up
wait_for_connection
def osrm_up
return if @@pid
@@pid = Process.spawn("#{BIN_PATH}/osrm-routed #{@input_file} --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
Process.detach(@@pid) # avoid zombie processes
end
rescue Timeout::Error
raise RoutedError.new "Launching osrm-routed timed out."
end
def shutdown
Timeout.timeout(OSRM_TIMEOUT) do
osrm_down
end
rescue Timeout::Error
kill
raise RoutedError.new "Shutting down osrm-routed timed out."
end
def osrm_up?
if @pid
begin
if Process.waitpid(@pid, Process::WNOHANG) then
false
else
true
end
rescue Errno::ESRCH, Errno::ECHILD
false
# looading data with osrm-datastore:
# under this scheme, osmr-routed is launched once and kept running for all scenarios,
# and osrm-datastore is used to load data for each scenario
class OSRMDatastoreLoader < OSRMBaseLoader
def load world, input_file, &block
@world = world
@input_file = input_file
Dir.chdir TEST_FOLDER do
load_data
launch unless @@pid
yield
end
end
end
def osrm_up
return if osrm_up?
@pid = Process.spawn("#{BIN_PATH}/osrm-routed #{@input_file} --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
Process.detach(@pid) # avoid zombie processes
end
def load_data
run_bin "osrm-datastore", @input_file
end
def osrm_down
if @pid
Process.kill TERMSIGNAL, @pid
wait_for_shutdown
def osrm_up
return if osrm_up?
@@pid = Process.spawn("#{BIN_PATH}/osrm-routed --sharedmemory=1 --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE)
Process.detach(@@pid) # avoid zombie processes
end
end
def kill
if @pid
Process.kill 'KILL', @pid
def self.load world, input_file, &block
method = world.instance_variable_get "@load_method"
if method == 'datastore'
OSRMDatastoreLoader.new.load world, input_file, &block
elsif method == 'directly'
OSRMDirectLoader.new.load world, input_file, &block
else
raise "*** Unknown load method '#{method}'"
end
end
def wait_for_connection
while true
begin
socket = TCPSocket.new('127.0.0.1', OSRM_PORT)
return
rescue Errno::ECONNREFUSED
sleep 0.1
end
end
end
def wait_for_shutdown
while osrm_up?
sleep 0.1
end
end
end

View File

@ -11,7 +11,8 @@ def run_bin bin, options
opt.gsub! "{profile}", "#{PROFILES_PATH}/#{@profile}.lua"
end
@stdout = `#{QQ}#{BIN_PATH}/#{bin}#{EXE}#{QQ} #{opt} 2>error.log`
cmd = "#{QQ}#{BIN_PATH}/#{bin}#{EXE}#{QQ} #{opt} 2>error.log"
@stdout = `#{cmd}`
@stderr = File.read 'error.log'
@exit_code = $?.exitstatus
end

View File

@ -1,4 +1,4 @@
@routing @bad
@routing @bad @testbot
Feature: Handle bad data in a graceful manner
Background:

View File

@ -1,4 +1,4 @@
@routing @basic
@routing @basic @testbot
Feature: Basic Routing
Background:

View File

@ -1,4 +1,4 @@
@routing @bearing
@routing @bearing @testbot
Feature: Compass bearing
Background:

View File

@ -1,4 +1,4 @@
@routing @bearing_param @todo
@routing @bearing_param @todo @testbot
Feature: Bearing parameter
Background:

View File

@ -1,4 +1,4 @@
@routing @graph
@routing @graph @testbot
Feature: Geometry Compression
Background:

View File

@ -0,0 +1,31 @@
@routing @datastore @testbot
Feature: Temporary tests related to osrm-datastore
Background:
Given the profile "testbot"
Scenario: Scenario ab
Given the node map
| a | b |
And the ways
| nodes |
| ab |
When I route I should get
| from | to | route |
| a | b | ab |
| b | a | ab |
Scenario: Scenaria xy
Given the node map
| x | y |
And the ways
| nodes |
| xy |
When I route I should get
| from | to | route |
| x | y | xy |
| y | x | xy |

View File

@ -1,4 +1,4 @@
@routing @distance
@routing @distance @testbot
Feature: Distance calculation
Background:

View File

@ -1,4 +1,4 @@
@routing @fastest
@routing @fastest @testbot
Feature: Choosing fastest route
Background:

View File

@ -1,4 +1,4 @@
@routing
@routing @testbot
Feature: Retrieve geometry
Background: Use some profile

View File

@ -1,4 +1,4 @@
@routing @graph
@routing @graph @testbot
Feature: Basic Routing
#Test the input data descibed on https://github.com/DennisOSRM/Project-OSRM/wiki/Graph-representation

View File

@ -0,0 +1,63 @@
@routing @load @testbot
Feature: Ways of loading data
# Several scenarios that change between direct/datastore makes
# it easier to check that the test framework behaves as expected.
Background:
Given the profile "testbot"
Scenario: Load data with datastore - ab
Given data is loaded with datastore
Given the node map
| a | b |
And the ways
| nodes |
| ab |
When I route I should get
| from | to | route |
| a | b | ab |
| b | a | ab |
Scenario: Load data directly - st
Given data is loaded directly
Given the node map
| s | t |
And the ways
| nodes |
| st |
When I route I should get
| from | to | route |
| s | t | st |
| t | s | st |
Scenario: Load data datstore - xy
Given data is loaded with datastore
Given the node map
| x | y |
And the ways
| nodes |
| xy |
When I route I should get
| from | to | route |
| x | y | xy |
| y | x | xy |
Scenario: Load data directly - cd
Given data is loaded directly
Given the node map
| c | d |
And the ways
| nodes |
| cd |
When I route I should get
| from | to | route |
| c | d | cd |
| d | c | cd |

View File

@ -1,4 +1,4 @@
@routing @726
@routing @726 @testbot
Feature: Avoid weird loops caused by rounding errors
Background:

View File

@ -6,11 +6,12 @@ Feature: Testbot - oneways
Scenario: Routing on a oneway roundabout
Given the node map
| | | | v | | |
| | | d | c | | |
| x | e | | | b | |
| | | | | v | |
| x | | d | c | | |
| | e | | | b | |
| | f | | | a | |
| | | g | h | | |
| | | g | h | | y |
| | z | | | | |
And the ways
| nodes | oneway |
@ -23,6 +24,8 @@ Feature: Testbot - oneways
| gh | yes |
| ha | yes |
| vx | yes |
| vy | yes |
| yz | yes |
| xe | yes |
When I route I should get

View File

@ -1,4 +1,4 @@
@routing @origin
@routing @origin @testbot
Feature: Routing close to the [0,0] origin
Background:

View File

@ -1,4 +1,4 @@
@routing @penalty @signal
@routing @penalty @signal @testbot
Feature: Penalties
# Testbot uses a signal penalty of 7s.

View File

@ -1,4 +1,4 @@
@routing @planetary
@routing @planetary @testbot
Feature: Distance calculation
Scenario: Approximated Longitudinal distances at equator

View File

@ -1,4 +1,4 @@
@routing @projection
@routing @projection @testbot
Feature: Projection to nearest point on road
# Waypoints are projected perpendiculary onto the closest road

View File

@ -1,4 +1,4 @@
@routing @pbf
@routing @pbf @testbot
Feature: Importing protobuffer (.pbf) format
# Test normally read .osm, which is faster than .pbf files,
# since we don't need to use osmosis to first convert to .pbf

View File

@ -1,4 +1,4 @@
@routing @snap
@routing @snap @testbot
Feature: Snap start/end point to the nearest way
Background:

View File

@ -1,4 +1,4 @@
@routing @status
@routing @status @testbot
Feature: Status messages
Background:

View File

@ -1,4 +1,4 @@
@routing @time
@routing @time @testbot
Feature: Estimation of travel time
# Testbot speeds:
# Primary road: 36km/h = 36000m/3600s = 100m/10s

View File

@ -1,4 +1,4 @@
@routing @turns
@routing @turns @testbot
Feature: Turn directions/codes
Background:

View File

@ -1,4 +1,4 @@
@routing @utf
@routing @utf @testbot
Feature: Handling of UTF characters
Background:

View File

@ -1,4 +1,4 @@
@routing @uturn @via
@routing @uturn @via @testbot
Feature: U-turns at via points
Background: