Adds the cucumber test framework referenced in issues #26, #95, #114

This commit is contained in:
Emil Tin 2012-02-14 17:21:07 +01:00 committed by DennisOSRM
parent 84b35f47a1
commit eeea5b0e81
28 changed files with 1818 additions and 1 deletions

4
.gitignore vendored
View File

@ -71,3 +71,7 @@ win/Debug/
win/Release/
win/bin/
win/bin-debug/
/osrm-extract
/osrm-routed
/osrm-prepare
/nohup.out

6
Gemfile Normal file
View File

@ -0,0 +1,6 @@
source "http://rubygems.org"
gem "cucumber"
gem "rake"
gem "osmlib-base"
gem "sys-proctable"

27
Gemfile.lock Normal file
View File

@ -0,0 +1,27 @@
GEM
remote: http://rubygems.org/
specs:
builder (3.0.0)
cucumber (1.1.4)
builder (>= 2.1.2)
diff-lcs (>= 1.1.2)
gherkin (~> 2.7.1)
json (>= 1.4.6)
term-ansicolor (>= 1.0.6)
diff-lcs (1.1.3)
gherkin (2.7.6)
json (>= 1.4.6)
json (1.6.5)
osmlib-base (0.1.4)
rake (0.9.2.2)
sys-proctable (0.9.1)
term-ansicolor (1.0.7)
PLATFORMS
ruby
DEPENDENCIES
cucumber
osmlib-base
rake
sys-proctable

181
Rakefile Normal file
View File

@ -0,0 +1,181 @@
require 'OSM/StreamParser'
require 'socket'
require 'digest/sha1'
require 'cucumber/rake/task'
require 'sys/proctable'
SANDBOX = 'sandbox'
DATA_FOLDER = 'osm_data'
Cucumber::Rake::Task.new do |t|
t.cucumber_opts = %w{--format pretty}
end
areas = {
:kbh => { :country => 'denmark', :bbox => 'top=55.6972 left=12.5222 right=12.624 bottom=55.6376' },
:frd => { :country => 'denmark', :bbox => 'top=55.7007 left=12.4765 bottom=55.6576 right=12.5698' },
:regh => { :country => 'denmark', :bbox => 'top=56.164 left=11.792 bottom=55.403 right=12.731' },
:dk => { :country => 'denmark', :bbox => nil },
:skaane => { :counry => 'sweden', :bbox => 'top=56.55 left=12.4 bottom=55.3 right=14.6' }
}
osm_data_area_name = ARGV[1] ? ARGV[1].to_s.to_sym : :kbh
raise "Unknown data area." unless areas[osm_data_area_name]
osm_data_country = areas[osm_data_area_name][:country]
osm_data_area_bbox = areas[osm_data_area_name][:bbox]
task osm_data_area_name.to_sym {} #define empty task to prevent rake from whining. will break if area has same name as a task
def each_process name, &block
Sys::ProcTable.ps do |process|
if process.comm.strip == name.strip
yield process.pid.to_i, process.state.strip
end
end
end
def up?
find_pid('osrm-routed') != nil
end
def find_pid name
each_process(name) { |pid,state| return pid.to_i }
return nil
end
def wait_for_shutdown name
timeout = 10
(timeout*10).times do
return if find_pid(name) == nil
sleep 0.1
end
raise "*** Could not terminate #{name}."
end
def write_server_ini osm_file
s=<<-EOF
Threads = 1
IP = 0.0.0.0
Port = 5000
hsgrData=#{DATA_FOLDER}/#{osm_file}.osrm.hsgr
nodesData=#{DATA_FOLDER}/#{osm_file}.osrm.nodes
ramIndex=#{DATA_FOLDER}/#{osm_file}.osrm.ramIndex
fileIndex=#{DATA_FOLDER}/#{osm_file}.osrm.fileIndex
namesData=#{DATA_FOLDER}/#{osm_file}.osrm.names
EOF
File.open( 'server.ini', 'w') {|f| f.write( s ) }
end
desc "Rebuild and run tests."
task :default => [:build, :cucumber]
desc "Build using SConsstruct."
task :build do
system "scons"
end
desc "Setup config files."
task :setup do
Dir.mkdir "#{SANDBOX}/#{DATA_FOLDER}" unless File.exist? "#{SANDBOX}/#{DATA_FOLDER}"
['server.ini','speedprofile.ini','extractor.ini','contractor.ini'].each do |file|
unless File.exist? "#{SANDBOX}/#{file}"
puts "Copying #{file} template to sandbox/#{file}"
FileUtils.cp file, "#{SANDBOX}/#{file}"
end
end
end
desc "Download OSM data."
task :download => :setup do
puts "Downloading..."
raise "Error while downloading data." unless system "curl http://download.geofabrik.de/osm/europe/#{osm_data_country}.osm.pbf -o #{SANDBOX}/#{DATA_FOLDER}/#{osm_data_country}.osm.pbf"
if osm_data_area_bbox
puts "Cropping and converting to protobuffer..."
raise "Error while cropping data." unless system "osmosis --read-pbf file=#{SANDBOX}/#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{SANDBOX}/#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
end
end
desc "Crop OSM data"
task :crop do
if osm_data_area_bbox
raise "Error while cropping data." unless system "osmosis --read-pbf file=#{SANDBOX}/#{DATA_FOLDER}/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=#{SANDBOX}/#{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf omitmetadata=true"
end
end
desc "Reprocess OSM data."
task :process => :setup do
Dir.chdir SANDBOX do
raise "Error while extracting data." unless system "../osrm-extract #{DATA_FOLDER}/#{osm_data_area_name}.osm.pbf"
puts
raise "Error while preparing data." unless system "../osrm-prepare #{DATA_FOLDER}/#{osm_data_area_name}.osrm #{DATA_FOLDER}/#{osm_data_area_name}.osrm.restrictions"
puts
end
end
desc "Delete preprocessing files."
task :clean do
File.delete *Dir.glob("#{SANDBOX}/#{DATA_FOLDER}/*.osrm")
File.delete *Dir.glob("#{SANDBOX}/#{DATA_FOLDER}/*.osrm.*")
end
desc "Run all cucumber test"
task :test do
system "cucumber"
puts
end
desc "Run the routing server in the terminal. Press Ctrl-C to stop."
task :run => :setup do
Dir.chdir SANDBOX do
write_server_ini osm_data_area_name
system "../osrm-routed"
end
end
desc "Launch the routing server in the background. Use rake:down to stop it."
task :up => :setup do
Dir.chdir SANDBOX do
abort("Already up.") if up?
write_server_ini osm_data_area_name
pipe = IO.popen('../osrm-routed 1>>osrm-routed.log 2>>osrm-routed.log')
timeout = 5
(timeout*10).times do
begin
socket = TCPSocket.new('localhost', 5000)
socket.puts 'ping'
rescue Errno::ECONNREFUSED
sleep 0.1
end
end
end
end
desc "Stop the routing server."
task :down do
pid = find_pid 'osrm-routed'
abort("Already down.") unless pid
Process.kill 'TERM', pid
end
desc "Kill all osrm-extract, osrm-prepare and osrm-routed processes."
task :kill do
each_process('osrm-routed') { |pid,state| Process.kill 'KILL', pid }
each_process('osrm-prepare') { |pid,state| Process.kill 'KILL', pid }
each_process('osrm-extract') { |pid,state| Process.kill 'KILL', pid }
wait_for_shutdown 'osrm-routed'
wait_for_shutdown 'osrm-prepare'
wait_for_shutdown 'osrm-extract'
end
desc "Get PIDs of all osrm-extract, osrm-prepare and osrm-routed processes."
task :pid do
each_process 'osrm-routed' do |pid,state|
puts "#{pid}\t#{state}"
end
end

55
features/access.feature Normal file
View File

@ -0,0 +1,55 @@
@routing @access
Feature: Oneway streets
Basic accessability of various way types.
Scenario: Basic access for cars
Given the speedprofile "car"
Then routability should be
| highway | forw |
| motorway | x |
| motorway_link | x |
| trunk | x |
| trunk_link | x |
| primary | x |
| secondary | x |
| tertiary | x |
| residential | x |
| service | x |
| unclassified | x |
| living_street | x |
| road | x |
| track | |
| path | |
| footway | |
| pedestrian | |
| steps | |
| pier | |
| cycleway | |
| bridleway | |
Scenario: Basic access for bicycles
Bikes are allowed on footways etc because you can pull your bike at a lower speed.
Given the speedprofile "bicycle"
Then routability should be
| highway | forw |
| motorway | |
| motorway_link | |
| trunk | |
| trunk_link | |
| primary | x |
| secondary | x |
| tertiary | x |
| residential | x |
| service | x |
| unclassified | x |
| living_street | x |
| road | x |
| track | x |
| path | x |
| footway | x |
| pedestrian | x |
| steps | x |
| pier | x |
| cycleway | x |
| bridleway | |

55
features/bad.feature Normal file
View File

@ -0,0 +1,55 @@
@routing @bad
Feature: Handle bad data in a graceful manner
Scenario: Empty dataset
Given the nodes
| a | b |
Given the ways
| nodes |
When I route I should get
| from | to | route |
| a | b | |
Scenario: Start/end point at the same location
Given the nodes
| a | b |
| 1 | 2 |
Given the ways
| nodes |
| ab |
When I route I should get
| from | to | route |
| a | a | |
| b | b | |
| 1 | 1 | |
| 2 | 2 | |
Scenario: Start/end point far outside data area
Given the nodes
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1 |
| a | b | | | | | | | | | | | | | | | | | | | | | | | | | | | 2 |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | 3 |
Given the ways
| nodes |
| ab |
When I route I should get
| from | to | route |
| 1 | a | ab |
| 2 | a | ab |
| 3 | a | ab |
| 1 | b | |
| 2 | b | |
| 3 | b | |
| 1 | 2 | |
| 1 | 3 | |
| 2 | 1 | |
| 2 | 3 | |
| 3 | 1 | |
| 3 | 2 | |

136
features/basic.feature Normal file
View File

@ -0,0 +1,136 @@
@routing @basic
Feature: Basic Routing
@smallest
Scenario: A single way with two nodes
Given the nodes
| a | b |
And the ways
| nodes |
| ab |
When I route I should get
| from | to | route |
| a | b | ab |
| b | a | ab |
Scenario: Routing in between two nodes of way
Given the nodes
| a | b | 1 | 2 | c | d |
And the ways
| nodes |
| abcd |
When I route I should get
| from | to | route |
| 1 | 2 | abcd |
| 2 | 1 | abcd |
Scenario: Routing between the middle nodes of way
Given the nodes
| a | b | c | d | e | f |
And the ways
| nodes |
| abcdef |
When I route I should get
| from | to | route |
| b | c | abcdef |
| b | d | abcdef |
| b | e | abcdef |
| c | b | abcdef |
| c | d | abcdef |
| c | e | abcdef |
| d | b | abcdef |
| d | c | abcdef |
| d | e | abcdef |
| e | b | abcdef |
| e | c | abcdef |
| e | d | abcdef |
Scenario: Two ways connected in a straight line
Given the nodes
| a | b | c |
And the ways
| nodes |
| ab |
| bc |
When I route I should get
| from | to | route |
| a | c | ab,bc |
| c | a | bc,ab |
| a | b | ab |
| b | a | ab |
| b | c | bc |
| c | b | bc |
Scenario: 2 unconnected parallel ways
Given the nodes
| a | b |
| c | d |
And the ways
| nodes |
| ab |
| cd |
When I route I should get
| from | to | route |
| a | b | ab |
| b | a | ab |
| c | d | cd |
| d | c | cd |
| a | c | |
| c | a | |
| b | d | |
| d | b | |
| a | d | |
| d | a | |
Scenario: 3 ways connected in a triangle
Given the nodes
| a | | b |
| | | |
| | c | |
And the ways
| nodes |
| ab |
| bc |
| ca |
When I route I should get
| from | to | route |
| a | b | ab |
| a | c | ca |
| b | c | bc |
| b | a | ab |
| c | a | ca |
| c | b | bc |
Scenario: To ways connected at a 45 degree angle
Given the nodes
| a | | |
| b | | |
| c | d | e |
And the ways
| nodes |
| abc |
| cde |
When I route I should get
| from | to | route |
| b | d | abc,cde |
| a | e | abc,cde |
| a | c | abc |
| c | a | abc |
| c | e | cde |
| e | c | cde |

27
features/ferry.feature Normal file
View File

@ -0,0 +1,27 @@
@routing @ferry
Feature: Handle ferry routes
Scenario: Use a ferry route
Given the nodes
| a | b | c | | |
| | | d | | |
| | | e | f | g |
And the ways
| nodes | highway | route | bicycle |
| abc | primary | | |
| cde | | ferry | yes |
| efg | primary | | |
When I route I should get
| from | to | route |
| a | g | abc,cde,efg |
| b | f | abc,cde,efg |
| e | c | cde |
| e | b | cde,abc |
| e | a | cde,abc |
| c | e | cde |
| c | f | cde,efg |
| c | g | cde,efg |

166
features/oneway.feature Normal file
View File

@ -0,0 +1,166 @@
@routing @oneway
Feature: Oneway streets
Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing
Scenario: Simple oneway
Given the speedprofile "car"
Then routability should be
| highway | oneway | forw | backw |
| primary | yes | x | |
Scenario: Simple reverse oneway
Given the speedprofile "car"
Then routability should be
| highway | oneway | forw | backw |
| primary | -1 | | x |
Scenario: Around the Block
Given the nodes
| a | b |
| d | c |
And the ways
| nodes | oneway |
| ab | yes |
| bc | |
| cd | |
| da | |
When I route I should get
| from | to | route |
| a | b | ab |
| b | a | bc,cd,da |
Scenario: Avoid oneway traps
Given the nodes
| | x | |
| a | b | c |
| | y | |
And the ways
| nodes | oneway |
| abc | |
| bx | yes |
| yb | -1 |
When I route I should get
| from | to | route |
| b | x | |
| b | y | |
Scenario: Handle various oneway tag values
Given the speedprofile "bicycle"
Then routability should be
| highway | oneway | forw | backw |
| primary | | x | x |
| primary | nonsense | x | x |
| primary | no | x | x |
| primary | false | x | x |
| primary | 0 | x | x |
| primary | yes | x | |
| primary | true | x | |
| primary | 1 | x | |
| primary | -1 | | x |
Scenario: Implied oneways
Given the speedprofile "car"
Then routability should be
| highway | junction | forw | backw |
| motorway | | x | |
| motorway_link | | x | |
| trunk | | x | x |
| trunk_link | | x | x |
| primary | | x | x |
| primary_link | | x | x |
| secondary | | x | x |
| secondary_link | | x | x |
| tertiary | | x | x |
| tertiary_link | | x | x |
| residential | | x | x |
| primary | roundabout | x | |
| secondary | roundabout | x | |
| tertiary | roundabout | x | |
| residential | roundabout | x | |
Scenario: Overriding implied oneways
Given the speedprofile "car"
Then routability should be
| highway | junction | oneway | forw | backw |
| motorway_link | | no | x | x |
| trunk_link | | no | x | x |
| primary | roundabout | no | x | x |
| motorway_link | | yes | x | |
| trunk_link | | yes | x | |
| primary | roundabout | yes | x | |
| motorway_link | | -1 | | x |
| trunk_link | | -1 | | x |
| primary | roundabout | -1 | | x |
Scenario: Disabling oneways in speedprofile
Given the speedprofile "car"
And the speedprofile settings
| obeyOneways | no |
Then routability should be
| highway | junction | oneway | forw | backw |
| primary | | yes | x | x |
| primary | | true | x | x |
| primary | | 1 | x | x |
| primary | | -1 | x | x |
| motorway_link | | | x | x |
| trunk_link | | | x | x |
| primary | roundabout | | x | x |
@bicycle
Scenario: Oneway:bicycle should override normal oneways tags
Given the speedprofile "bicycle"
Then routability should be
| highway | junction | oneway | oneway:bicycle | forw | backw |
| primary | | | yes | x | |
| primary | | yes | yes | x | |
| primary | | no | yes | x | |
| primary | | -1 | yes | x | |
| primary | roundabout | | yes | x | |
| primary | | | no | x | x |
| primary | | yes | no | x | x |
| primary | | no | no | x | x |
| primary | | -1 | no | x | x |
| primary | roundabout | | no | x | x |
| primary | | | -1 | | x |
| primary | | yes | -1 | | x |
| primary | | no | -1 | | x |
| primary | | -1 | -1 | | x |
| primary | roundabout | | -1 | | x |
@bicycle
Scenario: Bicycles and contra flow
Given the speedprofile "bicycle"
Then routability should be
| highway | oneway | cycleway | forw | backw |
| primary | yes | opposite | x | x |
| primary | yes | opposite_track | x | x |
| primary | yes | opposite_lane | x | x |
| primary | -1 | opposite | x | x |
| primary | -1 | opposite_track | x | x |
| primary | -1 | opposite_lane | x | x |
| primary | no | opposite | x | x |
| primary | no | opposite_track | x | x |
| primary | no | opposite_lane | x | x |
@bicycle
Scenario: Cars should not be affected by bicycle tags
Given the speedprofile "car"
Then routability should be
| highway | junction | oneway | oneway:bicycle | forw | backw |
| primary | | yes | yes | x | |
| primary | | yes | no | x | |
| primary | | yes | -1 | x | |
| primary | | no | yes | x | x |
| primary | | no | no | x | x |
| primary | | no | -1 | x | x |
| primary | | -1 | yes | | x |
| primary | | -1 | no | | x |
| primary | | -1 | -1 | | x |
| primary | roundabout | | yes | x | |
| primary | roundabout | | no | x | |
| primary | roundabout | | -1 | x | |

View File

@ -0,0 +1,95 @@
@routing @restrictions
Feature: Turn restrictions
Handle turn restrictions as defined by http://wiki.openstreetmap.org/wiki/Relation:restriction
How this plays with u-turns can be tricky.
Scenario: No left turn
Given the nodes
| | t | |
| a | j | b |
| | s | |
And the ways
| nodes |
| bj |
| aj |
| sj |
| tj |
And the relations
| from | to | via | restriction |
| sj | aj | j | no_left_turn |
When I route I should get
| from | to | route |
| s | a | |
| s | b | sj,jb |
| s | t | sj,tj |
| a | b | aj,bj |
| a | a | aj,sj |
| a | t | aj,tj |
| b | b | jb,aj |
| b | s | bj,sj |
| b | t | bj,tj |
Scenario: No left turn, go counter-clockwise around the block instead
Given the nodes
| x | t | |
| a | j | b |
| | s | |
And the ways
| nodes |
| bj |
| aj |
| sj |
| tj |
| axt |
And the relations
| from | to | via | restriction |
| sj | aj | j | no_left_turn |
When I route I should get
| from | to | route |
| s | a | sj,tj,axt |
| s | b | sj,jb |
| s | t | sj,tj |
| a | b | aj,bj |
| a | a | aj,sj |
| a | t | aj,tj |
| b | b | jb,aj |
| b | s | bj,sj |
| b | t | bj,tj |
Scenario: No left turn, go clockwise around the block instead
Given the nodes
| | | t | |
| z | a | j | b |
| x | | s | |
And the ways
| nodes |
| bj |
| aj |
| sj |
| tj |
| sxza |
And the relations
| from | to | via | restriction |
| sj | aj | j | no_left_turn |
When I route I should get
| from | to | route |
| s | a | sxza |
| s | b | sj,jb |
| s | t | sj,tj |
| a | b | aj,bj |
| a | a | aj,sj |
| a | t | aj,tj |
| b | b | jb,aj |
| b | s | bj,sj |
| b | t | bj,tj |

86
features/snap.feature Normal file
View File

@ -0,0 +1,86 @@
@routing @snap
Feature: Snap start/end point to the nearest way
Scenario: Snap to nearest protruding oneway
Given the nodes
| | 1 | | 2 | |
| 8 | | n | | 3 |
| | w | c | e | |
| 7 | | s | | 4 |
| | 6 | | 5 | |
And the ways
| nodes |
| nc |
| ec |
| sc |
| wc |
When I route I should get
| from | to | route |
| 1 | c | nc |
| 2 | c | nc |
| 3 | c | ec |
| 4 | c | ec |
| 5 | c | sc |
| 6 | c | sc |
| 7 | c | wc |
| 8 | c | wc |
Scenario: Snap to nearest edge of a square
Given the nodes
| 4 | 5 | 6 | 7 |
| 3 | a | | u |
| 2 | | | |
| 1 | d | | b |
And the ways
| nodes |
| aub |
| adb |
When I route I should get
| from | to | route |
| 1 | b | adb |
| 2 | b | adb |
| 6 | b | aub |
| 7 | b | aub |
Scenario: Snap to edge right under start/end point
Given the nodes
| d | e | f | g |
| c | | | h |
| b | | | i |
| a | l | k | j |
And the ways
| nodes |
| abcd |
| defg |
| ghij |
| jkla |
When I route I should get
| from | to | route |
| a | b | abcd |
| a | c | abcd |
| a | d | abcd |
| a | e | abcd |
| a | f | abcd |
| a | g | abcd |
| a | h | jkla |
| a | i | jkla |
| a | j | jkla |
| a | k | jkla |
| a | l | jkla |
| b | a | abcd |
| b | c | abcd |
| b | d | abcd |
| b | e | abcd |
| b | f | abcd |
| b | g | abcd |
| b | h | jkla |
| b | i | jkla |
| b | j | jkla |
| b | k | jkla |
| b | l | jkla |

View File

@ -0,0 +1,73 @@
Given /^the speedprofile "([^"]*)"$/ do |profile|
read_speedprofile profile
end
Given /^the speedprofile settings$/ do |table|
table.raw.each do |row|
speedprofile[ row[0] ] = row[1]
end
end
Given /^the nodes$/ do |table|
table.raw.each_with_index do |row,ri|
row.each_with_index do |name,ci|
unless name.empty?
raise "*** node invalid name '#{name}', must be single characters" unless name.size == 1
raise "*** invalid node name '#{name}', must me alphanumeric" unless name.match /[a-z0-9]/
raise "*** duplicate node '#{name}'" if name_node_hash[name]
node = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+ci*ZOOM, ORIGIN[1]-ri*ZOOM
node << { :name => name }
node.uid = OSM_UID
osm_db << node
name_node_hash[name] = node
end
end
end
end
Given /^the ways$/ do |table|
table.hashes.each do |row|
name = row.delete 'nodes'
raise "*** duplicate way '#{name}'" if name_way_hash[name]
way = OSM::Way.new make_osm_id, OSM_USER, OSM_TIMESTAMP
defaults = { 'highway' => 'primary' }
way << defaults.merge( 'name' => name ).merge(row)
way.uid = OSM_UID
name.each_char do |c|
raise "*** node invalid name '#{c}', must be single characters" unless c.size == 1
raise "*** ways cannot use numbered nodes, '#{name}'" unless c.match /[a-z]/
node = find_node_by_name(c)
raise "*** unknown node '#{c}'" unless node
way << node
end
osm_db << way
name_way_hash[name] = way
end
end
Given /^the relations$/ do |table|
table.hashes.each do |row|
relation = OSM::Relation.new make_osm_id, OSM_USER, OSM_TIMESTAMP
relation << { :type => :restriction, :restriction => 'no_left_turn' }
from_way = find_way_by_name(row['from'])
raise "*** unknown way '#{row['from']}'" unless from_way
to_way = find_way_by_name(row['to'])
raise "*** unknown way '#{row['to']}'" unless to_way
relation << OSM::Member.new( 'way', from_way.id, 'from' )
relation << OSM::Member.new( 'way', to_way.id, 'to' )
c = row['via']
unless c.empty?
raise "*** node invalid name '#{c}', must be single characters" unless c.size == 1
raise "*** via node cannot use numbered nodes, '#{c}'" unless c.match /[a-z]/
via_node = find_node_by_name(c)
raise "*** unknown node '#{row['via']}'" unless via_node
relation << OSM::Member.new( 'node', via_node.id, 'via' )
end
relation.uid = OSM_UID
osm_db << relation
end
end
Given /^the defaults$/ do
end

View File

@ -0,0 +1,72 @@
require 'OSM/StreamParser'
class OSMTestParserCallbacks < OSM::Callbacks
@@locations = nil
def self.locations
if @@locations
@@locations
else
#parse the test file, so we can later reference nodes and ways by name in tests
@@locations = {}
file = 'test/data/test.osm'
callbacks = OSMTestParserCallbacks.new
parser = OSM::StreamParser.new(:filename => file, :callbacks => callbacks)
parser.parse
puts @@locations
end
end
def node(node)
@@locations[node.name] = [node.lat,node.lon]
end
end
Given /^the OSM file contains$/ do |string|
file = 'data/test.osm'
File.open( file, 'w') {|f| f.write(string) }
#convert from .osm to .osm.pbf, which is the format osrm reads
system "osmosis --read-xml data/test.osm --write-pbf data/test.osm.pbf omitmetadata=true"
end
Given /^the speedprofile contains$/ do |string|
File.open( 'speedprofile.ini', 'w') {|f| f.write(string) }
end
Given /^the data file "([^"]*)" is present$/ do |file|
File.exists?(file).should == true
end
When /^I run the extractor with "([^"]*)"$/ do |cmd|
@response = `#{cmd}`
#Dir.chdir @test_folder do
# @response = IO.popen([cmd, :err=>[:child, :out]]) { |ls_io| ls_result_with_error = ls_io.read }
#end
end
When /^I run the preprocessor with "([^"]*)"$/ do |cmd|
@response = `#{cmd}`
end
Given /^the preprocessed files for "([^"]*)" are present and up to date$/ do |area|
File.exists?("#{area}.osrm").should == true
File.exists?("#{area}.osrm.names").should == true
File.exists?("#{area}.osrm.restrictions").should == true
File.exists?("#{area}.osrm.hsgr").should == true
File.exists?("#{area}.osrm.nodes").should == true
File.exists?("#{area}.osrm.ramIndex").should == true
File.exists?("#{area}.osrm.fileIndex").should == true
end
Then /^I should see the file "([^"]*)"$/ do |file|
File.exists?(file).should == true
end
When /^preprocessed files for "([^"]*)" has been removed$/ do |file|
FileUtils.rm_r Dir["#{file}.*"], :secure => true
end

View File

@ -0,0 +1,221 @@
When /^I request a route from ([^"]+) to ([^"]+)$/ do |a,b|
@response = request_route a,b
#puts @response.body
#@response
end
When /^I request a route from "([^"]*)" to "([^"]*)"$/ do |a,b|
locations = OSMTestParserCallbacks.locations
raise "Locations hash is empty. To reference nodes by name, please preprocess the test file earlier in the test." unless locations
raise "Unknown node: #{a}" unless locations[a]
raise "Unknown node: #{b}" unless locations[b]
@response = request_route "#{locations[a][0]},#{locations[a][1]}", "#{locations[b][0]},#{locations[b][1]}"
end
Then /^I should get a response/ do
@response.code.should == "200"
@response.body.should_not == nil
@response.body.should_not == ''
end
Then /^response should be valid JSON$/ do
@json = JSON.parse @response.body
end
Then /^response should be well-formed$/ do
@json['version'].class.should == Float
@json['status'].class.should == Fixnum
@json['status_message'].class.should == String
@json['route_summary'].class.should == Hash
@json['route_geometry'].class.should == String
@json['route_instructions'].class.should == Array
@json['via_points'].class.should == Array
@json['transactionId'].class.should == String
end
Then /^a route should be found$/ do
@json['status'].should == 0
@json['status_message'].should == "Found route between points"
end
Then /^no route should be found$/ do
@json['status'].should == 207
@json['status_message'].should == "Cannot find route between points"
end
Then /^I should get a valid response$/ do
step "I should get a response"
step "response should be valid JSON"
step "response should be well-formed"
#step "no error should be reported in terminal"
end
Then /^I should get a route$/ do
step "I should get a valid response"
step "a route should be found"
#puts @response.body
end
Then /^I should not get a route$/ do
step "I should get a valid response"
step "no route should be found"
end
Then /^the route should start at "([^']*)"$/ do |name|
@json['route_summary']['start_point'].should == name
end
Then /^the route should end at "([^']*)"$/ do |name|
@json['route_summary']['end_point'].should == name
end
Then /^distance should be between (\d+) and (\d+)$/ do |min,max|
@json['route_summary']['total_distance'].to_i.should >= min.to_i
@json['route_summary']['total_distance'].to_i.should <= max.to_i
end
Then /^the distance should be close to (\d+)m$/ do |d|
@json['route_summary']['total_distance'].to_i.should >= d.to_i*0.95
@json['route_summary']['total_distance'].to_i.should <= d.to_i/0.95
end
Then /^number of instructions should be (\d+)$/ do |n|
@json['route_instructions'].size.should == n
end
Then /^there should be 1 turn$/ do
step 'there should be 1 turns'
end
Then /^there should be (\d+) turns$/ do |n|
@json['route_instructions'].map {|t| t.first}.select {|t| t =~ /^Turn/ }.size.should == n.to_i
end
Then /^there should be more than (\d+) turn$/ do |n|
@json['route_instructions'].map {|t| t.first}.select {|t| t =~ /^Turn/ }.size.should > n.to_i
end
Then /^there should not be any turns$/ do
(@json['route_instructions'].size-1).should == 0
end
def sanitize_route route
route.split(',').map{|w| w.strip}.reject(&:empty?).join(', ')
end
def computed_route
@json['route_instructions'].map { |r| r[1] }.reject(&:empty?).join(', ')
end
Then /^the route should follow "([^"]*)"$/ do |route|
sanitize_route(route).should == computed_route
end
Then /^the route should not follow "([^"]*)"$/ do |route|
sanitize_route(route).should_not == computed_route
end
Then /^the route should include "([^"]*)"$/ do |route|
sanitize_route(route).should =~ /#{computed_route}/
end
Then /^the route should not include "([^"]*)"$/ do |route|
sanitize_route(route).should_not =~ /#{computed_route}/
end
Then /^the route should stay on "([^"]*)"$/ do |way|
step "the route should start at \"#{way}\""
step "the route should end at \"#{way}\""
step "the route should follow \"#{way}\""
step "there should not be any turns"
end
When /^I route between "([^"]*)" and "([^"]*)"$/ do |from,to|
reprocess
Dir.chdir 'test' do
from_node = name_node_hash[from]
to_node = name_node_hash[to]
a = "#{from_node.lon},#{from_node.lat}"
b = "#{to_node.lon},#{to_node.lat}"
@route = parse_response( request_route(a,b) )
end
end
Then /^"([^"]*)" should be returned$/ do |route|
@route.should == route.split(',').join(',')
end
Then /^routability should be$/ do |table|
osrm_kill
build_ways_from_table table
reprocess
actual = []
if table.headers&["forw","backw"] == []
raise "*** routability tabel must contain either 'forw' or 'backw' column"
end
OSRMLauncher.new do
table.hashes.each_with_index do |row,i|
got = row.dup
attempts = []
if table.headers.include? 'forw'
response = request_route("#{ORIGIN[1]},#{ORIGIN[0]+(1+WAY_SPACING*i)*ZOOM}","#{ORIGIN[1]},#{ORIGIN[0]+(2+WAY_SPACING*i)*ZOOM}")
got['forw'] = route_status response
if got['forw'] != row['forw']
json = JSON.parse(response.body)
attempts << { :attempt => 'Forward', :query => @query, :response => response }
end
end
if table.headers.include? 'backw'
response = request_route("#{ORIGIN[1]},#{ORIGIN[0]+(2+WAY_SPACING*i)*ZOOM}","#{ORIGIN[1]},#{ORIGIN[0]+(1+WAY_SPACING*i)*ZOOM}")
got['backw'] = route_status response
if got['backw'] != row['backw']
attempts << { :attempt => 'Backward', :query => @query, :response => response }
end
end
if got != row
log_fail row,got,attempts
end
actual << got
end
end
table.diff! actual
end
When /^I route I should get$/ do |table|
osrm_kill
reprocess
actual = []
OSRMLauncher.new do
table.hashes.each_with_index do |row,ri|
from_node = @name_node_hash[ row['from'] ]
raise "*** unknown from-node '#{row['from']}" unless from_node
to_node = @name_node_hash[ row['to'] ]
raise "*** unknown to-node '#{row['to']}" unless to_node
response = request_route("#{from_node.lat},#{from_node.lon}", "#{to_node.lat},#{to_node.lon}")
if response.code == "200" && response.body.empty? == false
json = JSON.parse response.body
if json['status'] == 0
instructions = way_list json['route_instructions']
end
end
got = {'from' => row['from'], 'to' => row['to'] }
if table.headers.include? 'start'
got['start'] = instructions ? json['route_summary']['start_point'] : nil
end
if table.headers.include? 'end'
got['end'] = instructions ? json['route_summary']['end_point'] : nil
end
if table.headers.include? 'route'
got['route'] = (instructions || '').strip
end
if got['route'] != row['route'] || got['start'] != row['start'] || got['end'] != row['end']
failed = { :attempt => 'Backward', :query => @query, :response => response }
log_fail row,got,[failed]
end
actual << got
end
end
table.diff! actual
end

View File

@ -0,0 +1,41 @@
def speedprofile
@speedprofile ||= reset_speedprofile
end
def reset_speedprofile
@speedprofile = {}
read_speedprofile DEFAULT_SPEEDPROFILE
end
def read_speedprofile profile
@speedprofile = {}
@speedprofile_str = nil
s = File.read "speedprofiles/#{profile}.ini"
s.scan /(.*)=(.*)/ do |option|
@speedprofile[option[0].strip] = option[1].strip
end
end
def speedprofile_str
@speedprofile_str ||= "[Scenario: #{@scenario_title}]\n" + @speedprofile.map { |k,v| " #{k} = #{v}" }.join("\n")
end
def write_speedprofile
File.open( 'speedprofile.ini', 'w') {|f| f.write( speedprofile_str ) }
end
def write_server_ini
s=<<-EOF
Threads = 1
IP = 0.0.0.0
Port = 5000
hsgrData=#{@osm_file}.osrm.hsgr
nodesData=#{@osm_file}.osrm.nodes
ramIndex=#{@osm_file}.osrm.ramIndex
fileIndex=#{@osm_file}.osrm.fileIndex
namesData=#{@osm_file}.osrm.names
EOF
File.open( 'server.ini', 'w') {|f| f.write( s ) }
end

189
features/support/data.rb Normal file
View File

@ -0,0 +1,189 @@
require 'OSM/objects' #osmlib gem
require 'OSM/Database'
require 'builder'
OSM_USER = 'osrm'
OSM_GENERATOR = 'osrm-test'
OSM_UID = 1
TEST_FOLDER = 'test'
DATA_FOLDER = 'cache'
PREPROCESS_LOG_FILE = 'preprocessing.log'
LOG_FILE = 'fail.log'
OSM_TIMESTAMP = '2000-00-00T00:00:00Z'
DEFAULT_SPEEDPROFILE = 'bicycle'
WAY_SPACING = 10
ORIGIN = [1,1]
NODE_SPACING = 100 #meters
ZOOM = 0.001*(NODE_SPACING.to_f/111.0)
def build_ways_from_table table
#add one unconnected way for each row
table.hashes.each_with_index do |row,ri|
#NOTE:
#currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4
#this is relatated to the fact that a oneway deadend doesn't make a lot of sense
#if we stack ways on different x coordinates, outability tests get messed up, because osrm might pick a neighboring way if the one test can't be used.
#instead we place all lines as a string on the same y coordinate. this prevents using neightboring ways.
#a few nodes...
node1 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+(0+WAY_SPACING*ri)*ZOOM, ORIGIN[1]
node2 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+(1+WAY_SPACING*ri)*ZOOM, ORIGIN[1]
node3 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+(2+WAY_SPACING*ri)*ZOOM, ORIGIN[1]
node4 = OSM::Node.new make_osm_id, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+(3+WAY_SPACING*ri)*ZOOM, ORIGIN[1]
node1.uid = OSM_UID
node2.uid = OSM_UID
node3.uid = OSM_UID
node4.uid = OSM_UID
node1 << { :name => "a#{ri}" }
node2 << { :name => "b#{ri}" }
node3 << { :name => "c#{ri}" }
node4 << { :name => "d#{ri}" }
osm_db << node1
osm_db << node2
osm_db << node3
osm_db << node4
#...with a way between them
way = OSM::Way.new make_osm_id, OSM_USER, OSM_TIMESTAMP
way.uid = OSM_UID
way << node1
way << node2
way << node3
way << node4
tags = row.dup
tags.delete 'forw'
tags.delete 'backw'
tags['name'] = "abcd#{ri}"
tags.reject! { |k,v| v=='' }
way << tags
osm_db << way
end
end
def find_node_by_name s
name_node_hash[s.to_s]
end
def find_way_by_name s
name_way_hash[s.to_s] || name_way_hash[s.to_s.reverse]
end
def reset_data
Dir.chdir TEST_FOLDER do
#clear_log
#clear_data_files
end
reset_speedprofile
reset_osm
@fingerprint = nil
end
def make_osm_id
@osm_id = @osm_id+1
end
def reset_osm
osm_db.clear
name_node_hash.clear
name_way_hash.clear
@osm_str = nil
@osm_hash = nil
##ID -1 causes trouble, so add a few nodes to avoid it
#node = OSM::Node.new nil, OSM_USER, OSM_TIMESTAMP, 0,0
#node = OSM::Node.new nil, OSM_USER, OSM_TIMESTAMP, 0,0
@osm_id = 0
end
def clear_data_files
File.delete *Dir.glob("#{DATA_FOLDER}/test.*")
end
def clear_log
File.delete *Dir.glob("*.log")
end
def osm_db
@osm_db ||= OSM::Database.new
end
def name_node_hash
@name_node_hash ||= {}
end
def name_way_hash
@name_way_hash ||= {}
end
def osm_str
return @osm_str if @osm_str
@osm_str = ''
doc = Builder::XmlMarkup.new :indent => 2, :target => @osm_str
doc.instruct!
osm_db.to_xml doc, OSM_GENERATOR
@osm_str
end
def write_osm
#write .oms file if needed
Dir.mkdir DATA_FOLDER unless File.exist? DATA_FOLDER
@osm_file = "#{DATA_FOLDER}/#{fingerprint}"
unless File.exist?("#{@osm_file}.osm")
File.open( "#{@osm_file}.osm", 'w') {|f| f.write(osm_str) }
end
end
def convert_osm_to_pbf
unless File.exist?("#{@osm_file}.osm.pbf")
log_preprocess_info
log "== Converting #{@osm_file}.osm to protobuffer format...", :preprocess
#redirect stdout and stderr to a log file avoid output in the cucumber console
unless system "osmosis --read-xml #{@osm_file}.osm --write-pbf #{@osm_file}.osm.pbf omitmetadata=true 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE}"
raise "Failed to convert to proto buffer format. Please see #{hash}.log for more info."
end
log '', :preprocess
end
end
def extracted?
File.exist?("#{@osm_file}.osrm") &&
File.exist?("#{@osm_file}.osrm.names") &&
File.exist?("#{@osm_file}.osrm.restrictions")
end
def prepared?
base = "#{DATA_FOLDER}/#{fingerprint}"
File.exist?("#{base}.osrm.hsgr")
end
def reprocess
Dir.chdir TEST_FOLDER do
write_speedprofile
write_osm
convert_osm_to_pbf
unless extracted?
log_preprocess_info
log "== Extracting #{@osm_file}.osm...", :preprocess
unless system "../osrm-extract #{@osm_file}.osm.pbf 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE}"
log "*** Exited with code #{$?.exitstatus}.", :preprocess
raise "*** osrm-extract exited with code #{$?.exitstatus}. The file preprocess.log might contain more info."
end
log '', :preprocess
end
unless prepared?
log_preprocess_info
log "== Preparing #{@osm_file}.osm...", :preprocess
unless system "../osrm-prepare #{@osm_file}.osrm #{@osm_file}.restrictions 1>>#{PREPROCESS_LOG_FILE} 2>>#{PREPROCESS_LOG_FILE}"
log "*** Exited with code #{$?.exitstatus}.", :preprocess
raise "*** osrm-prepare exited with code #{$?.exitstatus}. The file preprocess.log might contain more info."
end
log '', :preprocess
end
log_preprocess_done
write_server_ini
end
end

38
features/support/hash.rb Normal file
View File

@ -0,0 +1,38 @@
require 'digest/sha1'
def hash_of_file path
hash = Digest::SHA1.new
open(path,'r') do |io|
while !io.eof
buf = io.readpartial 1024
hash.update buf
end
end
return hash.hexdigest
end
def speedprofile_hash
@speedprofile_hash ||= Digest::SHA1.hexdigest speedprofile_str
end
def osm_hash
@osm_hash ||= Digest::SHA1.hexdigest osm_str
end
def osm_hash
@osm_hash ||= Digest::SHA1.hexdigest osm_str
end
def bin_extract_hash
@bin_hash ||= hash_of_file '../osrm-extract'
end
def bin_prepare_hash
@bin_hash ||= hash_of_file '../osrm-prepare'
end
#combine state of data, speedprofile and binaries into a hash that identifies the exact test scenario
def fingerprint
@fingerprint ||= Digest::SHA1.hexdigest "#{bin_extract_hash}-#{bin_prepare_hash}-#{speedprofile_hash}-#{osm_hash}"
end

17
features/support/hooks.rb Normal file
View File

@ -0,0 +1,17 @@
Before do |scenario|
@scenario_title = scenario.title
@scenario_time = Time.now.strftime("%Y-%m-%dT%H:%m:%SZ")
reset_data
@has_logged_preprocess_info = false
@has_logged_scenario_info = false
end
Around('@routing') do |scenario, block|
Timeout.timeout(10) do
block.call
end
end
After do
osrm_kill
end

View File

@ -0,0 +1,71 @@
require 'socket'
require 'sys/proctable'
class OSRMLauncher
def initialize &block
Dir.chdir TEST_FOLDER do
osrm_up
yield
osrm_down
end
end
end
def each_process name, &block
Sys::ProcTable.ps do |process|
if process.comm.strip == name.strip
yield process.pid.to_i, process.state.strip
end
end
end
def osrm_up?
find_pid('osrm-routed') != nil
end
def find_pid name
each_process(name) { |pid,state| return pid.to_i }
return nil
end
def osrm_up
return if osrm_up?
pipe = IO.popen('../osrm-routed 1>>osrm-routed.log 2>>osrm-routed.log')
timeout = 5
(timeout*10).times do
begin
socket = TCPSocket.new('localhost', 5000)
socket.puts 'ping'
rescue Errno::ECONNREFUSED
sleep 0.1
end
end
sleep 0.1
end
def osrm_down
each_process('osrm-routed') { |pid,state| Process.kill 'TERM', pid }
each_process('osrm-prepare') { |pid,state| Process.kill 'TERM', pid }
each_process('osrm-extract') { |pid,state| Process.kill 'TERM', pid }
wait_for_shutdown 'osrm-routed'
wait_for_shutdown 'osrm-prepare'
wait_for_shutdown 'osrm-extract'
end
def osrm_kill
each_process('osrm-routed') { |pid,state| Process.kill 'KILL', pid }
each_process('osrm-prepare') { |pid,state| Process.kill 'KILL', pid }
each_process('osrm-extract') { |pid,state| Process.kill 'KILL', pid }
wait_for_shutdown 'osrm-routed'
wait_for_shutdown 'osrm-prepare'
wait_for_shutdown 'osrm-extract'
end
def wait_for_shutdown name
timeout = 10
(timeout*10).times do
return if find_pid(name) == nil
sleep 0.1
end
raise "*** Could not terminate #{name}."
end

66
features/support/log.rb Normal file
View File

@ -0,0 +1,66 @@
def log s='', type=nil
if type == :preprocess
file = PREPROCESS_LOG_FILE
else
file = LOG_FILE
end
File.open(file, 'a') {|f| f.write("#{s}\n") }
end
def log_scenario_fail_info
return if @has_logged_scenario_info
log "========================================="
log "Failed scenario: #{@scenario_title}"
log "Time: #{@scenario_time}"
log
log '```xml' #so output can be posted directly to github comment fields
log osm_str.strip
log '```'
log
log speedprofile_str
log
@has_logged_scenario_info = true
end
def log_fail expected,actual,failed
log_scenario_fail_info
log "== "
log "Expected: #{expected}"
log "Got: #{actual}"
log
failed.each do |fail|
log "Attempt: #{fail[:attempt]}"
log "Query: #{fail[:query]}"
log "Response: #{fail[:response].body}"
log
end
end
def log_preprocess_info
return if @has_logged_preprocess_info
log "=========================================", :preprocess
log "Preprocessing data for scenario: #{@scenario_title}", :preprocess
log "Time: #{@scenario_time}", :preprocess
log '', :preprocess
log "== OSM data:", :preprocess
log '```xml', :preprocess #so output can be posted directly to github comment fields
log osm_str, :preprocess
log '```', :preprocess
log '', :preprocess
log "== Speed profile:", :preprocess
log speedprofile_str.strip, :preprocess
log '', :preprocess
@has_logged_preprocess_info = true
end
def log_preprocess str
log_preprocess_info
log str, :preprocess
end
def log_preprocess_done
end

View File

@ -0,0 +1,14 @@
#monkey-patch osmlib to fix a bug
module OSM
class Way
def to_xml(xml)
xml.way(attributes) do
nodes.each do |node|
xml.nd(:ref => node)
end
tags.to_xml(xml)
end
end
end
end

68
features/support/route.rb Normal file
View File

@ -0,0 +1,68 @@
require 'net/http'
def request_route a,b
@query = "http://localhost:5000/viaroute&start=#{a}&dest=#{b}&output=json&geomformat=cmp"
#log @query
uri = URI.parse @query
Net::HTTP.get_response uri
rescue Errno::ECONNREFUSED => e
raise "*** osrm-routed is not running."
rescue Timeout::Error
raise "*** osrm-routed did not respond."
end
def parse_response response
if response.code == "200" && response.body.empty? == false
json = JSON.parse response.body
if json['status'] == 0
route = way_list json['route_instructions']
if route.empty?
"Empty route: #{json['route_instructions']}"
else
"Route: #{route}"
end
elsif json['status'] == 207
"No route"
else
"Status: #{json['status']}"
end
else
"HTTP: #{response.code}"
end
end
def got_route? response
if response.code == "200" && !response.body.empty?
json = JSON.parse response.body
if json['status'] == 0
return way_list( json['route_instructions']).empty? == false
end
end
false
end
def route_status response
if response.code == "200" && !response.body.empty?
json = JSON.parse response.body
if json['status'] == 0
if way_list( json['route_instructions']).empty?
return 'Empty route'
else
return 'x'
end
elsif json['status'] == 207
''
else
"Status #{json['status']}"
end
else
"HTTP #{response.code}"
end
end
def way_list instructions
instructions.
#reject { |i| i[2]<=1 }. #FIXME temporary hack to ignore instructions with length==0
map { |r| r[1] }.
reject(&:empty?).join(',')
end

29
features/weight.feature Normal file
View File

@ -0,0 +1,29 @@
@routing @weight
Feature: Choosing route based on length, speed, etc
Scenario: Pick the geometrically shortest route, way types being equal
Given the nodes
| | s | |
| | t | |
| a | | b |
And the ways
| nodes |
| atb |
| asb |
When I route I should get
| from | to | route |
| a | b | atb |
| a | b | atb |
Scenario: Pick the fastest way type, lengths being equal
Given the nodes
| a | s |
| p | b |
And the ways
| nodes | highway |
| apb | primary |
| asb | secondary |

27
speedprofiles/bicycle.ini Normal file
View File

@ -0,0 +1,27 @@
[bicycle]
accessTag = bicycle
defaultSpeed = 17
obeyOneways = yes
useRestrictions = yes
obeyBollards = no
cycleway = 19
primary = 19
primary_link = 19
secondary = 17
secondary_link = 17
tertiary = 15
residential = 15
unclassified = 15
living_street = 13
road = 13
service = 12
track = 12
path = 12
footway = 10
pedestrian = 5
pier = 5
steps = 3
ferry = 5
excludeFromGrid = ferry

23
speedprofiles/car.ini Normal file
View File

@ -0,0 +1,23 @@
[car]
accessTag = motorcar
defaultSpeed = 50
obeyOneways = yes
useRestrictions = yes
barrier = bollard
motorway = 100
motorway_link = 90
trunk = 90
trunk_link = 70
primary = 70
primary_link = 60
secondary = 60
secondary_link = 50
tertiary = 50
tertiary_link = 40
road = 40
residential = 40
unclassified = 30
service = 20
living_street = 10

26
speedprofiles/ebiki.ini Normal file
View File

@ -0,0 +1,26 @@
[ebike]
accessTag = bicycle
obeyOneways = yes
defaultSpeed = 25
useRestrictions = no
cycleway = 25
trunk = 25
trunk_link = 25
primary = 25
primary_link = 25
secondary = 25
secondary_link = 25
tertiary = 25
unclassified = 25
residential = 25
living_street = 20
service = 20
track = 20
path = 15
pier = 5
pedestrian = 5
footway = 5
ferry = 5
excludeFromGrid = ferry

3
test/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/server.ini
/cache
/speedprofile.ini

1
test/.stxxl Normal file
View File

@ -0,0 +1 @@
disk=/tmp/stxxl,1,syscall