test both datastore and direct data load

This commit is contained in:
Emil Tin 2014-10-14 15:35:14 +02:00
parent 76fb0cb965
commit 71b967d243
11 changed files with 214 additions and 80 deletions

View File

@ -158,3 +158,19 @@ Given /^the data has been prepared$/ do
@process_error = e @process_error = e
end end
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| When /^I request locate I should get$/ do |table|
reprocess reprocess
actual = [] actual = []
OSRMLoader.load("#{@osm_file}.osrm") do OSRMLoader.load(self,"#{@osm_file}.osrm") do
table.hashes.each_with_index do |row,ri| table.hashes.each_with_index do |row,ri|
in_node = find_node_by_name row['in'] in_node = find_node_by_name row['in']
raise "*** unknown in-node '#{row['in']}" unless in_node raise "*** unknown in-node '#{row['in']}" unless in_node

View File

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

View File

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

View File

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

View File

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

View File

@ -11,6 +11,7 @@ class Location
end end
end end
def set_input_format format def set_input_format format
raise '*** Input format must be eiter "osm" or "pbf"' unless ['pbf','osm'].include? format.to_s raise '*** Input format must be eiter "osm" or "pbf"' unless ['pbf','osm'].include? format.to_s
@input_format = format.to_s @input_format = format.to_s

View File

@ -1,8 +1,8 @@
require 'rspec/expectations' require 'rspec/expectations'
DEFAULT_PORT = 5000 DEFAULT_PORT = 5000
DEFAULT_TIMEOUT = 2 DEFAULT_TIMEOUT = 2
ROOT_FOLDER = Dir.pwd ROOT_FOLDER = Dir.pwd
OSM_USER = 'osrm' OSM_USER = 'osrm'
OSM_GENERATOR = 'osrm-test' OSM_GENERATOR = 'osrm-test'
@ -19,6 +19,14 @@ DEFAULT_INPUT_FORMAT = 'osm'
DEFAULT_ORIGIN = [1,1] DEFAULT_ORIGIN = [1,1]
LAUNCH_TIMEOUT = 1 LAUNCH_TIMEOUT = 1
SHUTDOWN_TIMEOUT = 10 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 def log_time_and_run cmd
@ -31,8 +39,6 @@ def log_time cmd
end end
puts "Ruby version #{RUBY_VERSION}" puts "Ruby version #{RUBY_VERSION}"
unless RUBY_VERSION.to_f >= 1.9 unless RUBY_VERSION.to_f >= 1.9
raise "*** Please upgrade to Ruby 1.9.x to run the OSRM cucumber tests" raise "*** Please upgrade to Ruby 1.9.x to run the OSRM cucumber tests"
@ -58,6 +64,7 @@ unless File.exists? TEST_FOLDER
raise "*** Test folder #{TEST_FOLDER} doesn't exist." raise "*** Test folder #{TEST_FOLDER} doesn't exist."
end end
if ENV['OS']=~/Windows.*/ then if ENV['OS']=~/Windows.*/ then
EXE='.exe' EXE='.exe'
QQ='"' QQ='"'
@ -67,9 +74,12 @@ else
end end
AfterConfiguration do |config| AfterConfiguration do |config|
if OSRMLoader::OSRMBaseLoader.new.osrm_up?
raise "*** osrm-routed is already running."
end
clear_log_files clear_log_files
end end
at_exit do at_exit do
OSRMLoader.shutdown OSRMLoader::OSRMBaseLoader.new.shutdown
end end

View File

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

View File

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

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 |