From 71b967d24308be1939e8290d4597847e526566c3 Mon Sep 17 00:00:00 2001 From: Emil Tin Date: Tue, 14 Oct 2014 15:35:14 +0200 Subject: [PATCH] test both datastore and direct data load --- features/step_definitions/data.rb | 16 ++ features/step_definitions/locate.rb | 2 +- features/step_definitions/nearest.rb | 2 +- features/step_definitions/requests.rb | 2 +- features/step_definitions/routability.rb | 2 +- features/step_definitions/routing.rb | 2 +- features/support/data.rb | 1 + features/support/env.rb | 18 ++- features/support/hooks.rb | 4 + features/support/launch.rb | 182 ++++++++++++++--------- features/testbot/load.feature | 63 ++++++++ 11 files changed, 214 insertions(+), 80 deletions(-) create mode 100644 features/testbot/load.feature diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb index e0985a4b1..f1e58bae2 100644 --- a/features/step_definitions/data.rb +++ b/features/step_definitions/data.rb @@ -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 diff --git a/features/step_definitions/locate.rb b/features/step_definitions/locate.rb index 26c52e2d0..ca04b7742 100644 --- a/features/step_definitions/locate.rb +++ b/features/step_definitions/locate.rb @@ -1,7 +1,7 @@ When /^I request locate I should get$/ do |table| reprocess actual = [] - OSRMLoader.load("#{@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 diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb index 030a8e5bc..3dd90dd55 100644 --- a/features/step_definitions/nearest.rb +++ b/features/step_definitions/nearest.rb @@ -1,7 +1,7 @@ When /^I request nearest I should get$/ do |table| reprocess actual = [] - OSRMLoader.load("#{@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 diff --git a/features/step_definitions/requests.rb b/features/step_definitions/requests.rb index b9f4d98f6..aec6ebbab 100644 --- a/features/step_definitions/requests.rb +++ b/features/step_definitions/requests.rb @@ -1,6 +1,6 @@ When /^I request \/(.*)$/ do |path| reprocess - OSRMLoader.load("#{@osm_file}.osrm") do + OSRMLoader.load(self,"#{@osm_file}.osrm") do @response = request_path path end end diff --git a/features/step_definitions/routability.rb b/features/step_definitions/routability.rb index e46d0d9ff..1496ad01f 100644 --- a/features/step_definitions/routability.rb +++ b/features/step_definitions/routability.rb @@ -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 - OSRMLoader.load("#{@osm_file}.osrm") do + OSRMLoader.load(self,"#{@osm_file}.osrm") do table.hashes.each_with_index do |row,i| output_row = row.dup attempts = [] diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb index 53a1b6fec..adf2f7a7a 100644 --- a/features/step_definitions/routing.rb +++ b/features/step_definitions/routing.rb @@ -1,7 +1,7 @@ When /^I route I should get$/ do |table| reprocess actual = [] - OSRMLoader.load("#{@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'] } diff --git a/features/support/data.rb b/features/support/data.rb index 76822811b..adb619204 100644 --- a/features/support/data.rb +++ b/features/support/data.rb @@ -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 diff --git a/features/support/env.rb b/features/support/env.rb index cb328d12b..a01341dd6 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,8 +1,8 @@ require 'rspec/expectations' + DEFAULT_PORT = 5000 DEFAULT_TIMEOUT = 2 - ROOT_FOLDER = Dir.pwd OSM_USER = 'osrm' OSM_GENERATOR = 'osrm-test' @@ -19,6 +19,14 @@ 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 @@ -31,8 +39,6 @@ def log_time cmd end - - puts "Ruby version #{RUBY_VERSION}" unless RUBY_VERSION.to_f >= 1.9 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." end + if ENV['OS']=~/Windows.*/ then EXE='.exe' QQ='"' @@ -67,9 +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.shutdown + OSRMLoader::OSRMBaseLoader.new.shutdown end diff --git a/features/support/hooks.rb b/features/support/hooks.rb index ff8f10ff1..337014246 100644 --- a/features/support/hooks.rb +++ b/features/support/hooks.rb @@ -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| diff --git a/features/support/launch.rb b/features/support/launch.rb index 7b85e0d57..11572a7ce 100644 --- a/features/support/launch.rb +++ b/features/support/launch.rb @@ -1,96 +1,136 @@ require 'socket' require 'open3' -if ENV['OS']==/Windows.*/ then - TERMSIGNAL='TERM' -else - TERMSIGNAL=9 -end - -OSRM_ROUTED_LOG_FILE = 'osrm-routed.log' - +# 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 - - @@pid = nil - - def self.load input_file, &block - @input_file = input_file - Dir.chdir TEST_FOLDER do - self.load_data - self.launch unless @@pid - yield - end - end - - def self.load_data - run_bin "osrm-datastore", @input_file - end - def self.launch - Timeout.timeout(LAUNCH_TIMEOUT) do - self.osrm_up - self.wait_for_connection - end - rescue Timeout::Error - raise RoutedError.new "Launching osrm-routed timed out." - end + class OSRMBaseLoader + @@pid = nil - def self.shutdown - Timeout.timeout(SHUTDOWN_TIMEOUT) do - self.osrm_down + 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 - rescue Timeout::Error - self.kill - raise RoutedError.new "Shutting down osrm-routed timed out." - end - def self.osrm_up? + 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 + begin + if Process.waitpid(@@pid, Process::WNOHANG) then + false + else + true + end + rescue Errno::ESRCH, Errno::ECHILD + false end - rescue Errno::ESRCH, Errno::ECHILD - false end end - end - def self.osrm_up - return if self.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 - - def self.osrm_down - if @@pid - Process.kill TERMSIGNAL, @@pid - self.wait_for_shutdown + def osrm_down + if @@pid + Process.kill TERMSIGNAL, @@pid + wait_for_shutdown + @@pid = nil + end end - end - def self.kill - if @@pid - Process.kill 'KILL', @@pid + def kill + if @@pid + Process.kill 'KILL', @@pid + end end - end - def self.wait_for_connection - while true - begin - socket = TCPSocket.new('127.0.0.1', OSRM_PORT) - return - rescue Errno::ECONNREFUSED + 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 - def self.wait_for_shutdown - while self.osrm_up? - sleep 0.1 + # 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 + 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 + + 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 diff --git a/features/testbot/load.feature b/features/testbot/load.feature new file mode 100644 index 000000000..cf5e470bd --- /dev/null +++ b/features/testbot/load.feature @@ -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 |