Merge 18542d1df1 into b44e36e7ba
This commit is contained in:
commit
1ece534826
15
.gitignore
vendored
15
.gitignore
vendored
@ -1,3 +1,13 @@
|
||||
# Test folder #
|
||||
###################
|
||||
test/speedprofile.ini
|
||||
test/data/*.osrm
|
||||
test/data/*.osrm.*
|
||||
test/data/denmark.osm.pbf
|
||||
test/data/regh.osm.pbf
|
||||
test/data/test.osm
|
||||
test/data/test.osm.pbf
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
@ -6,6 +16,9 @@
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
osrm-extract
|
||||
osrm-prepare
|
||||
osrm-routed
|
||||
|
||||
# Packages #
|
||||
############
|
||||
@ -70,4 +83,4 @@ win/*.suo
|
||||
win/Debug/
|
||||
win/Release/
|
||||
win/bin/
|
||||
win/bin-debug/
|
||||
win/bin-debug/
|
||||
|
||||
@ -210,10 +210,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( w.direction == _Way::opposite ){
|
||||
std::reverse( w.path.begin(), w.path.end() );
|
||||
}
|
||||
|
||||
for(vector< NodeID >::size_type n = 0; n < w.path.size()-1; ++n) {
|
||||
externalMemory->allEdges.push_back(_Edge(w.path[n], w.path[n+1], w.type, w.direction, w.speed, w.nameID, w.roundabout, highway == settings.excludeFromGrid));
|
||||
externalMemory->usedNodeIDs.push_back(w.path[n]);
|
||||
|
||||
@ -122,15 +122,15 @@ public:
|
||||
_forwardHeap2->Clear();
|
||||
//insert new starting nodes into forward heap, adjusted by previous distances.
|
||||
if(searchFrom1stStartNode) {
|
||||
_forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, distance1-phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
_forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode, distance2-phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
_forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
_forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
// INFO("1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode << " with weight " << phantomNodePair.startPhantom.weight1);
|
||||
// } else {
|
||||
// INFO("Skipping first start node");
|
||||
}
|
||||
if(phantomNodePair.startPhantom.isBidirected() && searchFrom2ndStartNode) {
|
||||
_forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, distance1-phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
_forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, distance2-phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
_forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
_forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
// INFO("1)forw insert " << phantomNodePair.startPhantom.edgeBasedNode+1 << " with weight " << distance1-phantomNodePair.startPhantom.weight1);
|
||||
// INFO("2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode+1 << " with weight " << distance2-phantomNodePair.startPhantom.weight1);
|
||||
// } else if(!searchFrom2ndStartNode) {
|
||||
|
||||
125
Rakefile
Normal file
125
Rakefile
Normal file
@ -0,0 +1,125 @@
|
||||
require 'OSM/StreamParser'
|
||||
|
||||
#$:.unshift(File.dirname(__FILE__) + '/../../lib')
|
||||
require 'cucumber/rake/task'
|
||||
|
||||
Cucumber::Rake::Task.new do |t|
|
||||
t.cucumber_opts = %w{--format pretty}
|
||||
end
|
||||
|
||||
areas = {
|
||||
:test => {},
|
||||
: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 = ENV['area'] ? ENV['area'].to_s.to_sym : :test
|
||||
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]
|
||||
|
||||
|
||||
desc "Rebuild and run tests"
|
||||
task :default => [:build, :cucumber]
|
||||
|
||||
desc "Build using Scons"
|
||||
task :build do
|
||||
system "scons"
|
||||
end
|
||||
|
||||
namespace :data do
|
||||
desc "Download OSM data"
|
||||
task :download do
|
||||
raise "Error while downloading data." unless system "curl http://download.geofabrik.de/osm/europe/#{osm_data_country}.osm.pbf -o test/data/#{osm_data_country}.osm.pbf"
|
||||
if osm_data_area_bbox
|
||||
raise "Error while cropping data." unless system "osmosis --read-pbf file=test/data/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=test/data/#{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=test/data/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=test/data/#{osm_data_area_name}.osm.pbf omitmetadata=true"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Reprocess OSM data"
|
||||
task :process do
|
||||
Dir.chdir "test" do #we must be in the test_folder folder to use the speedprofile.ini in that folder
|
||||
raise "Error while extracting data." unless system "./osrm-extract data/#{osm_data_area_name}.osm.pbf"
|
||||
puts
|
||||
raise "Error while preparing data." unless system "./osrm-prepare data/#{osm_data_area_name}.osrm #{osm_data_area_name}.osrm.restrictions"
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
desc "Convert test file to protobuffer format"
|
||||
task :protofy do
|
||||
Dir.chdir "test" do
|
||||
system "osmosis --read-xml data/test.osm --write-pbf data/test.osm.pbf omitmetadata=true"
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
desc "Delete preprocessing files"
|
||||
task :clean do
|
||||
File.delete *Dir.glob('test/data/*.osrm')
|
||||
File.delete *Dir.glob('test/data/*.osrm.*')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
desc "Launch the routing server"
|
||||
task :run do
|
||||
Dir.chdir "test" do
|
||||
system "./osrm-routed"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Run all test"
|
||||
task :test do
|
||||
system "cucumber --tags @syn"
|
||||
puts
|
||||
end
|
||||
|
||||
desc "Prepare test data"
|
||||
task :prep => ['data:protofy', 'data:process'] do
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
class OSMTestParserCallbacks < OSM::Callbacks
|
||||
attr_accessor :locations
|
||||
|
||||
def initialize
|
||||
@locations = {}
|
||||
end
|
||||
def node(node)
|
||||
puts node
|
||||
@locations[node.name] = [node.lat,node.lon]
|
||||
end
|
||||
|
||||
def way(way)
|
||||
puts way
|
||||
end
|
||||
|
||||
def relation(relation)
|
||||
puts relation
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
task :read do
|
||||
Dir.chdir "test" do
|
||||
file = 'data/test.osm'
|
||||
callbacks = OSMTestParserCallbacks.new
|
||||
parser = OSM::StreamParser.new(:filename => file, :callbacks => callbacks)
|
||||
parser.parse
|
||||
puts callbacks.locations
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
130
SConstruct
130
SConstruct
@ -49,49 +49,72 @@ def CheckProtobuf(context, version):
|
||||
context.Result(ret)
|
||||
return ret
|
||||
|
||||
|
||||
AddOption('--cxx', dest='cxx', type='string', nargs=1, action='store', metavar='STRING', help='C++ Compiler')
|
||||
AddOption('--stxxlroot', dest='stxxlroot', type='string', nargs=1, action='store', metavar='STRING', help='root directory of STXXL')
|
||||
AddOption('--verbosity', dest='verbosity', type='string', nargs=1, action='store', metavar='STRING', help='make Scons talking')
|
||||
AddOption('--buildconfiguration', dest='buildconfiguration', type='string', nargs=1, action='store', metavar='STRING', help='debug or release')
|
||||
env = Environment(ENV = {'PATH' : os.environ['PATH']} ,COMPILER = GetOption('cxx'))
|
||||
if sys.platform.startswith("freebsd"):
|
||||
env.ParseConfig('pkg-config --cflags --libs protobuf')
|
||||
|
||||
env = Environment( ENV = {'PATH' : os.environ['PATH']} ,COMPILER = GetOption('cxx'))
|
||||
conf = Configure(env, custom_tests = { 'CheckBoost' : CheckBoost, 'CheckProtobuf' : CheckProtobuf })
|
||||
|
||||
|
||||
if GetOption('cxx') is None:
|
||||
#default Compiler
|
||||
print 'Using default C++ Compiler: ', env['CXX']
|
||||
else:
|
||||
env.Replace(CXX = GetOption('cxx'))
|
||||
print 'Using user supplied C++ Compiler: ', env['CXX']
|
||||
if GetOption('stxxlroot') is not None:
|
||||
env.Append(CPPPATH = GetOption('stxxlroot')+'/include')
|
||||
env.Append(LIBPATH = GetOption('stxxlroot')+'/lib')
|
||||
print 'STXXLROOT = ', GetOption('stxxlroot')
|
||||
if sys.platform == 'win32':
|
||||
#SCons really wants to use Microsoft compiler
|
||||
print "Compiling is not yet supported on Windows"
|
||||
Exit(-1)
|
||||
else: #Mac OS X
|
||||
if sys.platform == 'darwin':
|
||||
print "Compiling is experimental on Mac"
|
||||
env.Append(CPPPATH = ['/opt/local/include/', '/opt/local/include/libxml2'])
|
||||
env.Append(LIBPATH = ['/opt/local/lib'])
|
||||
elif sys.platform.startswith('freebsd'):
|
||||
env.Append(CPPPATH = ['/usr/local/include', '/usr/local/include/libxml2'])
|
||||
env.Append(LIBPATH = ['/usr/local/lib'])
|
||||
else:
|
||||
env.Append(CPPPATH = ['/usr/include', '/usr/include/include', '/usr/include/libxml2/'])
|
||||
|
||||
if GetOption('buildconfiguration') == 'debug':
|
||||
env.Append(CCFLAGS = ['-Wall', '-g3', '-rdynamic'])
|
||||
else:
|
||||
env.Append(CCFLAGS = ['-O3', '-DNDEBUG', '-march=native'])
|
||||
#print "Compiling with: ", env['CXX']
|
||||
conf = Configure(env, custom_tests = { 'CheckBoost' : CheckBoost, 'CheckProtobuf' : CheckProtobuf })
|
||||
if not conf.CheckHeader('omp.h'):
|
||||
print "Compiler does not support OpenMP. Exiting"
|
||||
if sys.platform == 'darwin':
|
||||
print "Continuing because we are on Mac. This might be fatal."
|
||||
else:
|
||||
env.Append(CCFLAGS = ['-O3', '-DNDEBUG'])
|
||||
|
||||
|
||||
if sys.platform == 'darwin': #Mac OS X
|
||||
env.Append(CPPPATH = ['/usr/include/libxml2'] ) #comes with os x
|
||||
#assume dependencies are installed with homebrew, and call out get folder locations
|
||||
import subprocess
|
||||
stxxl_prefix = subprocess.check_output(["brew", "--prefix", "libstxxl"]).strip()
|
||||
env.Append(CPPPATH = [stxxl_prefix+"/include"] )
|
||||
env.Append(LIBPATH = [stxxl_prefix+"/lib"] )
|
||||
|
||||
boost_prefix = subprocess.check_output(["brew", "--prefix", "boost"]).strip()
|
||||
env.Append(CPPPATH = [boost_prefix+"/include"] )
|
||||
env.Append(LIBPATH = [boost_prefix+"/lib"] )
|
||||
|
||||
#libxml2_prefix = subprocess.check_output(["brew", "--prefix", "libxml2"]).strip()
|
||||
#env.Append(CPPPATH = [libxml2_prefix+"/include"] )
|
||||
#env.Append(LIBPATH = [libxml2_prefix+"/lib"] )
|
||||
|
||||
elif sys.platform.startswith("freebsd"):
|
||||
env.ParseConfig('pkg-config --cflags --libs protobuf')
|
||||
env.Append(CPPPATH = ['/usr/local/include', '/usr/local/include/libxml2'])
|
||||
env.Append(LIBPATH = ['/usr/local/lib'])
|
||||
if GetOption('stxxlroot') is not None:
|
||||
env.Append(CPPPATH = GetOption('stxxlroot')+'/include')
|
||||
env.Append(LIBPATH = GetOption('stxxlroot')+'/lib')
|
||||
print 'STXXLROOT = ', GetOption('stxxlroot')
|
||||
if GetOption('buildconfiguration') != 'debug':
|
||||
env.Append(CCFLAGS = ['-march=native'])
|
||||
#print "Compiling with: ", env['CXX']
|
||||
env.Append(CCFLAGS = ['-fopenmp'])
|
||||
env.Append(LINKFLAGS = ['-fopenmp'])
|
||||
elif sys.platform == 'win32':
|
||||
#SCons really wants to use Microsoft compiler
|
||||
print "Compiling is not yet supported on Windows"
|
||||
Exit(-1)
|
||||
else:
|
||||
print "Unknown platform.."
|
||||
env.Append(CPPPATH = ['/usr/include', '/usr/include/include', '/usr/include/libxml2/'])
|
||||
|
||||
|
||||
if sys.platform != 'darwin':
|
||||
if not conf.CheckHeader('omp.h'):
|
||||
print "Compiler does not support OpenMP. Exiting"
|
||||
Exit(-1)
|
||||
|
||||
if not conf.CheckLibWithHeader('bz2', 'bzlib.h', 'CXX'):
|
||||
print "bz2 library not found. Exiting"
|
||||
Exit(-1)
|
||||
@ -132,9 +155,6 @@ if not conf.CheckLibWithHeader('Magick++', 'ImageMagick/Magick++.h', 'CXX'):
|
||||
if not (conf.CheckBoost('1.41')):
|
||||
print 'Boost version >= 1.41 needed'
|
||||
Exit(-1);
|
||||
if not conf.CheckLib('boost_system', language="C++"):
|
||||
print "boost_system library not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckLibWithHeader('boost_thread', 'boost/thread.hpp', 'CXX'):
|
||||
if not conf.CheckLibWithHeader('boost_thread-mt', 'boost/thread.hpp', 'CXX'):
|
||||
print "boost thread library not found. Exiting"
|
||||
@ -144,14 +164,21 @@ if not conf.CheckLibWithHeader('boost_thread', 'boost/thread.hpp', 'CXX'):
|
||||
env.Append(CCFLAGS = ' -lboost_thread-mt')
|
||||
env.Append(LINKFLAGS = ' -lboost_thread-mt')
|
||||
if not conf.CheckLibWithHeader('boost_regex', 'boost/regex.hpp', 'CXX'):
|
||||
print "boost/regex.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/array.hpp'):
|
||||
print "boost/thread.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckCXXHeader('boost/asio.hpp'):
|
||||
print "boost/thread.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
if not conf.CheckLibWithHeader('boost_regex-mt', 'boost/regex.hpp', 'CXX'):
|
||||
print "boost/regex.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
else:
|
||||
print "using boost_regex -mt"
|
||||
env.Append(CCFLAGS = ' -lboost_regex-mt')
|
||||
env.Append(LINKFLAGS = ' -lboost_regex-mt')
|
||||
if not conf.CheckLib('boost_system', language="C++"):
|
||||
if not conf.CheckLib('boost_system-mt', language="C++"):
|
||||
print "boost_system library not found. Exiting"
|
||||
Exit(-1)
|
||||
else:
|
||||
print "using boost -mt"
|
||||
env.Append(CCFLAGS = ' -lboost_system-mt')
|
||||
env.Append(LINKFLAGS = ' -lboost_system-mt')
|
||||
if not conf.CheckCXXHeader('boost/bind.hpp'):
|
||||
print "boost/bind.hpp not found. Exiting"
|
||||
Exit(-1)
|
||||
@ -194,18 +221,27 @@ if not conf.CheckCXXHeader('boost/tuple/tuple.hpp'):
|
||||
if not conf.CheckCXXHeader('boost/unordered_map.hpp'):
|
||||
print "boost thread header not found. Exiting"
|
||||
Exit(-1)
|
||||
#if os.sysconf('SC_NPROCESSORS_ONLN') > 1:
|
||||
# env.Append(CCFLAGS = ' -D_GLIBCXX_PARALLEL');
|
||||
if not (conf.CheckBoost('1.41')):
|
||||
print 'Boost version >= 1.41 needed'
|
||||
Exit(-1);
|
||||
#check for protobuf 2.3.0, else rebuild proto files
|
||||
if not (conf.CheckProtobuf('2.3.0')):
|
||||
print 'libprotobuf version >= 2.3.0 needed'
|
||||
Exit(-1);
|
||||
if not (env.Detect('protoc')):
|
||||
print 'protobuffer compiler not found'
|
||||
|
||||
|
||||
protobld = Builder(action = 'protoc -I=DataStructures/pbf-proto --cpp_out=DataStructures/pbf-proto $SOURCE')
|
||||
env.Append(BUILDERS = {'Protobuf' : protobld})
|
||||
env.Protobuf('DataStructures/pbf-proto/fileformat.proto')
|
||||
env.Protobuf('DataStructures/pbf-proto/osmformat.proto')
|
||||
env.Append(CCFLAGS = ['-fopenmp'])
|
||||
env.Append(LINKFLAGS = ['-fopenmp'])
|
||||
#env.Append(LINKFLAGS = ['-lboost_system'])
|
||||
|
||||
env.Program(target = 'osrm-extract', source = ["extractor.cpp", Glob('DataStructures/pbf-proto/*.pb.cc'), Glob('Util/*.cpp')])
|
||||
env.Program(target = 'osrm-prepare', source = ["createHierarchy.cpp", 'Contractor/EdgeBasedGraphFactory.cpp', Glob('Util/SRTMLookup/*.cpp')])
|
||||
env.Append(CCFLAGS = ['-lboost_regex', '-lboost_iostreams', '-lbz2', '-lz', '-lprotobuf'])
|
||||
env.Append(LINKFLAGS = ['-lboost_system'])
|
||||
env.Program(target = 'osrm-routed', source = ["routed.cpp", 'Descriptors/DescriptionFactory.cpp'], CCFLAGS = ['-DROUTED'])
|
||||
env.Program(target = 'test/osrm-extract', source = ["extractor.cpp", 'DataStructures/pbf-proto/fileformat.pb.cc', 'DataStructures/pbf-proto/osmformat.pb.cc'])
|
||||
env.Program(target = 'test/osrm-prepare', source = ["createHierarchy.cpp", 'Contractor/EdgeBasedGraphFactory.cpp'])
|
||||
env.Program(target = 'test/osrm-routed', source = ["routed.cpp", 'Descriptors/DescriptionFactory.cpp'])
|
||||
env = conf.Finish()
|
||||
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
Threads = 4
|
||||
SRTM = /opt/storage/srtm/Eurasia
|
||||
@ -79,7 +79,7 @@ int main (int argc, char *argv[]) {
|
||||
INFO("Loading SRTM from/to " << SRTM_ROOT);
|
||||
omp_set_num_threads(numberOfThreads);
|
||||
|
||||
INFO("preprocessing data from input file " << argv[2] << " using STL "
|
||||
INFO("preprocessing data from input file " << argv[1] << " using STL "
|
||||
#ifdef _GLIBCXX_PARALLEL
|
||||
"parallel (GCC)"
|
||||
#else
|
||||
|
||||
@ -1 +0,0 @@
|
||||
Memory = 2
|
||||
25
features/0_process.feature
Normal file
25
features/0_process.feature
Normal file
@ -0,0 +1,25 @@
|
||||
@process
|
||||
Feature: Preprocessing OpenStreetMap data
|
||||
In order to enable efficient routing
|
||||
As the OSRM server
|
||||
I want to be able to preprocess OpenStreetMap data
|
||||
|
||||
Scenario: Processing OpenStreetMap data using bicycle profile
|
||||
Given I am in the test folder
|
||||
And the data file "data/kbh.osm.pbf" is present
|
||||
And the "bicycle" speedprofile is used
|
||||
|
||||
When I run the extractor with "./osrm-extract data/kbh.osm.pbf"
|
||||
Then the response should include "extracting data from input file data/kbh.osm.pbf"
|
||||
And the response should include 'Using profile "bicycle"'
|
||||
And the response should include "[extractor] finished"
|
||||
And I should see the file "data/kbh.osrm"
|
||||
And I should see the file "data/kbh.osrm.names"
|
||||
And I should see the file "data/kbh.osrm.restrictions"
|
||||
|
||||
When I run the preprocessor with "./osrm-prepare data/kbh.osrm data/kbh.osrm.restrictions"
|
||||
Then the response should include "finished preprocessing"
|
||||
And I should see the file "data/kbh.osrm.hsgr"
|
||||
And I should see the file "data/kbh.osrm.nodes"
|
||||
And I should see the file "data/kbh.osrm.ramIndex"
|
||||
And I should see the file "data/kbh.osrm.fileIndex"
|
||||
13
features/1_launch.feature
Normal file
13
features/1_launch.feature
Normal file
@ -0,0 +1,13 @@
|
||||
@launch
|
||||
Feature: Launching OSRM server
|
||||
In order to handle routing request
|
||||
As a user
|
||||
I want to launch the OSRM server
|
||||
|
||||
Scenario: Launching the OSRM server
|
||||
Given I am in the test folder
|
||||
And the preprocessed files for "data/kbh" are present and up to date
|
||||
When I start the server with "./osrm-routed"
|
||||
Then a process called "osrm-routed" should be running
|
||||
And I should see "running and waiting for requests" on the terminal
|
||||
|
||||
100
features/basic.feature
Normal file
100
features/basic.feature
Normal file
@ -0,0 +1,100 @@
|
||||
@routing @basic
|
||||
Feature: Basic Routing
|
||||
|
||||
Scenario Outline: Smallest possible datasat
|
||||
Given the nodes
|
||||
| a | b |
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
|
||||
When I route between "<from>" and "<to>"
|
||||
Then "<route>" should be returned
|
||||
|
||||
Examples:
|
||||
| from | to | route |
|
||||
| a | b | ab |
|
||||
| b | a | ba |
|
||||
|
||||
Scenario Outline: Smallest possible datasat
|
||||
Given the nodes
|
||||
| a | b |
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
|
||||
When I route between "<from>" and "<to>"
|
||||
Then "<route>" should be returned
|
||||
|
||||
Examples:
|
||||
| from | to | route |
|
||||
| a | b | ab |
|
||||
| b | a | ba |
|
||||
|
||||
Scenario Outline: Connected ways
|
||||
Given the nodes
|
||||
| a | | c |
|
||||
| | b | |
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
|
||||
When I route between "<from>" and "<to>"
|
||||
Then "<route>" should be returned
|
||||
|
||||
Examples:
|
||||
| from | to | route |
|
||||
| a | c | abc |
|
||||
| c | a | cba |
|
||||
| a | b | ab |
|
||||
| b | a | ba |
|
||||
| b | c | bc |
|
||||
| c | b | cb |
|
||||
|
||||
Scenario Outline: Unconnected ways
|
||||
Given the nodes
|
||||
| a | b |
|
||||
| c | d |
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| cd |
|
||||
|
||||
When I route between "<from>" and "<to>"
|
||||
Then "<route>" should be returned
|
||||
|
||||
Examples:
|
||||
| from | to | route |
|
||||
| a | b | ab |
|
||||
| b | a | ba |
|
||||
| c | d | cd |
|
||||
| d | c | dc |
|
||||
| a | c | |
|
||||
| c | a | |
|
||||
| b | d | |
|
||||
| d | c | |
|
||||
| a | d | |
|
||||
| d | a | |
|
||||
|
||||
Scenario Outline: Pick the fastest way type
|
||||
Given the nodes
|
||||
| a | s |
|
||||
| p | b |
|
||||
|
||||
And the ways
|
||||
| nodes | highway |
|
||||
| apb | primary |
|
||||
| asb | secondary |
|
||||
|
||||
When I route between "<from>" and "<to>"
|
||||
Then "<route>" should be returned
|
||||
|
||||
Examples:
|
||||
| from | to | route |
|
||||
| a | b | apb |
|
||||
| b | a | bpa |
|
||||
5
features/bicycle.feature
Normal file
5
features/bicycle.feature
Normal file
@ -0,0 +1,5 @@
|
||||
@routing @bicycle
|
||||
Feature: Bicycle Routing from A to B
|
||||
To enable bicycle routing
|
||||
OSRM should handle all relevant bicycle tags
|
||||
|
||||
37
features/kbh.feature
Normal file
37
features/kbh.feature
Normal file
@ -0,0 +1,37 @@
|
||||
@routing
|
||||
Feature: Real-world routing test in the Copenhagen area
|
||||
|
||||
Scenario: Phantom shortcut
|
||||
When I request a route from 55.662740149207,12.576105114488& to 55.665753800212,12.575547215013
|
||||
Then I should get a route
|
||||
And the distance should be close to 450m
|
||||
|
||||
Scenario: Start and stop markers should snap to closest streets
|
||||
When I request a route from 55.6634,12.5724 to 55.6649,12.5742
|
||||
Then I should get a route
|
||||
And the route should stay on "Islands Brygge"
|
||||
And the distance should be close to 200m
|
||||
|
||||
Scenario: Crossing roundabout at Amalienborg
|
||||
When I request a route from 55.683797649183,12.593940686704 to 55.6842149924,12.592476200581
|
||||
Then I should get a route
|
||||
And the distance should be close to 150m
|
||||
|
||||
Scenario: Requesting invalid routes
|
||||
When I request a route from 0,0 to 0,0
|
||||
Then I should not get a route
|
||||
And no error should be reported in terminal
|
||||
|
||||
Scenario: Dont flicker
|
||||
When I request a route from 55.658833555366,12.592788454378 to 55.663871808364,12.583497282355
|
||||
Then I should get a route
|
||||
And the route should follow "Amagerfælledvej, Njalsgade, Artillerivej"
|
||||
And no error should be reported in terminal
|
||||
When I request a route from 55.658821450674,12.592466589296 to 55.663871808364,12.583497282355
|
||||
Then I should get a route
|
||||
And the route should follow "Kaj Munks Vej, Tom Kristensens Vej, Ørestads Boulevard, Njalsgade, Artillerivej"
|
||||
And no error should be reported in terminal
|
||||
When I request a route from 55.658857764739,12.592058893525 to 55.663871808364,12.583497282355
|
||||
Then I should get a route
|
||||
And the route should follow "Kaj Munks Vej, Tom Kristensens Vej, Ørestads Boulevard, Njalsgade, Artillerivej"
|
||||
And no error should be reported in terminal
|
||||
96
features/oneways.feature
Normal file
96
features/oneways.feature
Normal file
@ -0,0 +1,96 @@
|
||||
@routing @oneways
|
||||
Feature: Oneway streets
|
||||
Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing
|
||||
|
||||
Scenario: Implied oneways
|
||||
Given the speedprofile "car"
|
||||
Then routability should be
|
||||
| highway | junction | forw | backw |
|
||||
| motorway | | x | x |
|
||||
| motorway_link | | x | |
|
||||
| trunk | | x | x |
|
||||
| trunk_link | | x | |
|
||||
| primary | roundabout | x | |
|
||||
|
||||
Scenario: Overriding implied oneways
|
||||
Given the defaults
|
||||
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 | | -1 | | x |
|
||||
| trunk_link | | -1 | | x |
|
||||
| primary | roundabout | -1 | | x |
|
||||
|
||||
Scenario: Handle various oneway tag values
|
||||
Given the defaults
|
||||
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: Disabling oneways in speedprofile
|
||||
Given 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 |
|
||||
|
||||
Scenario: Oneways and bicycles
|
||||
Given the defaults
|
||||
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 | |
|
||||
| motorway | | | yes | x | |
|
||||
| motorway_link | | | 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 |
|
||||
| motorway | | | no | x | x |
|
||||
| motorway_link | | | no | x | x |
|
||||
| primary | roundabout | | no | x | x |
|
||||
| primary | | | -1 | | x |
|
||||
| primary | | yes | -1 | | x |
|
||||
| primary | | no | -1 | | x |
|
||||
| primary | | -1 | -1 | | x |
|
||||
| motorway | | | -1 | | x |
|
||||
| motorway_link | | | -1 | | x |
|
||||
| primary | roundabout | | -1 | | x |
|
||||
|
||||
Scenario: Cars should not be affected by bicycle tags
|
||||
Given the speedprofile settings
|
||||
| accessTag | motorcar |
|
||||
|
||||
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 | |
|
||||
65
features/other.feature
Normal file
65
features/other.feature
Normal file
@ -0,0 +1,65 @@
|
||||
@other
|
||||
Feature: Other stuff
|
||||
|
||||
Scenario: No left turn when crossing a oneway street
|
||||
When I request a route from 55.689741159238,12.574720202639 to 55.689741159232,12.57455927015
|
||||
Then I should get a route
|
||||
And the route should start at "Sølvgade"
|
||||
And the route should end at "Øster Farimagsgade"
|
||||
And the route should not include "Sølvgade, Øster Farimagsgade"
|
||||
And no error should be reported in terminal
|
||||
|
||||
Scenario: No left turn at T-junction: Don't turn left from side road into main road
|
||||
When I request a route from 55.66442995717,12.549384056343 to 55.664218154805,12.5502638209
|
||||
Then I should get a route
|
||||
And the route should start at "Sigerstedgade"
|
||||
And the route should end at "Ingerslevsgade"
|
||||
And the route should not include "Sigerstedgade, Ingerslevsgade"
|
||||
And there should be more than 1 turn
|
||||
|
||||
Scenario: No left turn at T-junction: OK to turn right from side road into main road
|
||||
When I request a route from 55.66442995717,12.549384056343 to 55.664060815164,12.548944174065
|
||||
Then I should get a route
|
||||
And the route should start at "Sigerstedgade"
|
||||
And the route should end at "Ingerslevsgade"
|
||||
And the route should include "Sigerstedgade, Ingerslevsgade"
|
||||
And there should be 1 turn
|
||||
|
||||
Scenario: No left turn at T-junction: OK to go straight on main road
|
||||
When I request a route from 55.66419092299,12.550333558335 to 55.664060815164,12.548944174065
|
||||
Then I should get a route
|
||||
And the route should stay on "Ingerslevsgade"
|
||||
|
||||
Scenario: No left turn at T-junction: OK to turn right from main road into side road
|
||||
When I request a route from 55.664060815164,12.548944174065 to 55.66442995717,12.549384056343
|
||||
Then I should get a route
|
||||
And the route should start at "Ingerslevsgade"
|
||||
And the route should end at "Sigerstedgade"
|
||||
And the route should include "Ingerslevsgade, Sigerstedgade"
|
||||
And there should be 1 turn
|
||||
|
||||
Scenario: No left turn at T-junction: OK to turn left from main road into side road
|
||||
When I request a route from 55.664218154805,12.5502638209 to 55.66442995717,12.549384056343
|
||||
Then I should get a route
|
||||
And the route should start at "Ingerslevsgade"
|
||||
And the route should end at "Sigerstedgade"
|
||||
And the route should include "Ingerslevsgade, Sigerstedgade"
|
||||
And there should be 1 turn
|
||||
|
||||
|
||||
|
||||
Scenario: oneway:bicycle
|
||||
When I request a route from 55.673168935147,12.563557740441 to 55.67380116846,12.563107129324&
|
||||
Then I should get a route
|
||||
And the route should follow "Banegårdspladsen"
|
||||
And there should not be any turns
|
||||
And the distance should be close to 80m
|
||||
|
||||
Scenario: cycleway=opposite_lane
|
||||
When I request a route from 55.689126237262,12.553137305887 to 55.688666612359,12.55296564451
|
||||
Then I should get a route
|
||||
And the route should follow "Kapelvej"
|
||||
And there should not be any turns
|
||||
And the distance should be close to 50m
|
||||
|
||||
|
||||
25
features/outlines.feature
Normal file
25
features/outlines.feature
Normal file
@ -0,0 +1,25 @@
|
||||
@outlines
|
||||
Feature: Outlines
|
||||
Scenario outlines is another way to test routes... not sure which method is best?
|
||||
|
||||
Scenario Outline: ways
|
||||
Given the nodes
|
||||
| a | | c |
|
||||
| | b | |
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ab |
|
||||
| bc |
|
||||
|
||||
When I route from "<from>" to "<to>"
|
||||
Then I should get the route "<route>"
|
||||
|
||||
Examples:
|
||||
| from | to | route |
|
||||
| a | c | abc |
|
||||
| c | a | cba |
|
||||
| a | b | ab |
|
||||
| b | a | ba |
|
||||
| b | c | bc |
|
||||
| c | b | cb |
|
||||
30
features/restrictions.feature
Normal file
30
features/restrictions.feature
Normal file
@ -0,0 +1,30 @@
|
||||
@routing @restrictions
|
||||
Feature: Turn restrictions
|
||||
Handle turn restrictions as defined by http://wiki.openstreetmap.org/wiki/Relation:restriction
|
||||
|
||||
Scenario Outline: No left turn at T-junction
|
||||
Given the nodes
|
||||
| a | j | b |
|
||||
| | s | |
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| aj |
|
||||
| jb |
|
||||
| sj |
|
||||
|
||||
And the relations
|
||||
| from | to | via | restriction |
|
||||
| sj | ja | j | no_left_turn |
|
||||
|
||||
When I route between "<from>" and "<to>"
|
||||
Then "<route>" should be returned
|
||||
|
||||
Examples:
|
||||
| from | to | route |
|
||||
| a | b | ajb |
|
||||
| a | s | ajs |
|
||||
| b | a | bja |
|
||||
| b | s | bjs |
|
||||
| s | a | |
|
||||
| s | b | sjb |
|
||||
96
features/step_definitions/launch.rb
Normal file
96
features/step_definitions/launch.rb
Normal file
@ -0,0 +1,96 @@
|
||||
require 'pathname'
|
||||
require 'json'
|
||||
require 'open4'
|
||||
require "net/http"
|
||||
require "uri"
|
||||
|
||||
$stdout.sync = true
|
||||
$server_pipe = nil
|
||||
$server_running = false
|
||||
|
||||
def read_terminal
|
||||
return $server_pipe.read_nonblock 10000 rescue nil
|
||||
end
|
||||
|
||||
def running?
|
||||
`ps -eo command | grep #{@test_folder}/osrm-running$`.size != 0
|
||||
end
|
||||
|
||||
def launch cmd = "./osrm-routed"
|
||||
$server_pipe = IO.popen(cmd)
|
||||
sleep 2 # so the daemon has a chance to boot
|
||||
|
||||
at_exit do
|
||||
if $server_pipe
|
||||
Process.kill("KILL", $server_pipe.pid) # clean up the daemon when the tests finish
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def kill
|
||||
if $server_pipe
|
||||
Process.kill("KILL", $server_pipe.pid)
|
||||
$server_pipe = nil
|
||||
sleep 2 # so the daemon has a chance to quit
|
||||
end
|
||||
end
|
||||
|
||||
Given /^I am in the test folder$/ do
|
||||
@root = Pathname.new(File.dirname(__FILE__)).parent.parent.expand_path
|
||||
@test_folder = "#{@root}/test"
|
||||
Dir.chdir @test_folder
|
||||
end
|
||||
|
||||
Given /^the server is configured for bike routing$/ do
|
||||
pending # express the regexp above with the code you wish you had
|
||||
end
|
||||
|
||||
Given /^the "([^"]*)" speedprofile is used$/ do |profile|
|
||||
FileUtils.cp "speedprofiles/#{profile}.ini", "speedprofile.ini"
|
||||
end
|
||||
|
||||
Then /^the response should include "([^"]*)"$/ do |string|
|
||||
@response.include?(string).should_not == nil
|
||||
end
|
||||
|
||||
Then /^the response should include '([^']*)'$/ do |string|
|
||||
@response.include?(string).should_not == nil
|
||||
end
|
||||
|
||||
Given /^the server is running$/ do
|
||||
unless $server_running
|
||||
step 'a process called "osrm-routed" should be running'
|
||||
@server_running = true
|
||||
end
|
||||
end
|
||||
|
||||
When /^I start the server with "([^']*)"$/ do |cmd|
|
||||
launch cmd
|
||||
end
|
||||
|
||||
When /^I stop the server$/ do
|
||||
kill
|
||||
end
|
||||
|
||||
Then /^a process called "([^']*)" should be running$/ do |daemon|
|
||||
#puts `ps -eo command | grep #{@test_folder}/#{daemon}`
|
||||
`ps -eo command | grep #{@test_folder}/#{daemon}`.size.should > 0
|
||||
end
|
||||
|
||||
Then /^a process called "([^']*)" should not be running$/ do |daemon|
|
||||
`ps -eo command | grep #{@test_folder}/#{daemon}$`.size.should == 0
|
||||
end
|
||||
|
||||
Then /^a process called "([^']*)" is not running$/ do |daemon|
|
||||
step "a process called \"#{daemon}\" should not be running"
|
||||
end
|
||||
|
||||
|
||||
Then /^I should see "([^']*)" on the terminal$/ do |string|
|
||||
out = read_terminal
|
||||
out.should =~ /#{string}/
|
||||
end
|
||||
|
||||
Then /^no error should be reported in terminal$/ do
|
||||
read_terminal.should_not =~ /error/
|
||||
end
|
||||
77
features/step_definitions/processing.rb
Normal file
77
features/step_definitions/processing.rb
Normal file
@ -0,0 +1,77 @@
|
||||
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
|
||||
|
||||
def way(way)
|
||||
end
|
||||
|
||||
def relation(relation)
|
||||
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
|
||||
234
features/step_definitions/routing.rb
Normal file
234
features/step_definitions/routing.rb
Normal file
@ -0,0 +1,234 @@
|
||||
|
||||
|
||||
def request_route a,b
|
||||
uri = URI.parse "http://localhost:5000/viaroute&start=#{a}&dest=#{b}&output=json&geomformat=cmp"
|
||||
#puts "routing: #{uri}"
|
||||
Net::HTTP.get_response uri
|
||||
rescue Errno::ECONNREFUSED => e
|
||||
raise "*** osrm-routed is not running."
|
||||
rescue Timeout::Error
|
||||
raise "*** osrm-routed didn't respond."
|
||||
end
|
||||
|
||||
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|
|
||||
computed_route.should == sanitize_route(route)
|
||||
end
|
||||
|
||||
Then /^the route should not follow "([^"]*)"$/ do |route|
|
||||
computed_route.should_not == sanitize_route(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
|
||||
|
||||
def parse_response response
|
||||
if response.code == "200" && response.body.empty? == false
|
||||
json = JSON.parse response.body
|
||||
#puts response.body
|
||||
if json['status'] == 0
|
||||
route = json['route_instructions'].map { |r| r[1] }.reject(&:empty?).join(', ')
|
||||
if route.empty?
|
||||
"Empty route: #{json['route_instructions']}"
|
||||
else
|
||||
route
|
||||
end
|
||||
elsif json['status'] == 207
|
||||
nil #no route found
|
||||
else
|
||||
"Status: #{json['status']}"
|
||||
end
|
||||
else
|
||||
"HTTP: #{response.code}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
When /^I route I should get$/ do |table|
|
||||
actual = []
|
||||
reprocess_if_needed
|
||||
Dir.chdir 'test' do
|
||||
launch
|
||||
table.hashes.each do |row|
|
||||
from_node = @name_node_hash[ row['from'] ]
|
||||
to_node = @name_node_hash[ row['to'] ]
|
||||
route = parse_response( request_route("#{from_node.lon},#{from_node.lat}", "#{to_node.lat},#{to_node.lat}") )
|
||||
actual << { 'from' => row['from'].dup, 'to' => row['to'].dup, 'route' => route }
|
||||
end
|
||||
kill
|
||||
end
|
||||
table.diff! actual
|
||||
end
|
||||
|
||||
When /^I route on tagged ways I should get $/ do |table|
|
||||
pending
|
||||
end
|
||||
|
||||
When /^I route between "([^"]*)" and "([^"]*)"$/ do |from,to|
|
||||
end
|
||||
|
||||
Then /^"([^"]*)" should be returned$/ do |route|
|
||||
end
|
||||
|
||||
def build_ways_from_table table
|
||||
#add one unconnected way for each row
|
||||
table.hashes.each_with_index do |row,ri|
|
||||
#two nodes...
|
||||
node1 = OSM::Node.new nil, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+0*ZOOM, ORIGIN[1]-ri*ZOOM
|
||||
node2 = OSM::Node.new nil, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+1*ZOOM, ORIGIN[1]-ri*ZOOM
|
||||
node1.uid = OSM_UID
|
||||
node2.uid = OSM_UID
|
||||
osm_db << node1
|
||||
osm_db << node2
|
||||
|
||||
#...with a way between them
|
||||
way = OSM::Way.new -ri-1, OSM_USER, OSM_TIMESTAMP
|
||||
way.uid = OSM_UID
|
||||
tags = row.dup
|
||||
tags.delete 'forw'
|
||||
tags.delete 'backw'
|
||||
tags.reject! { |k,v| v=='' }
|
||||
way << tags
|
||||
way << node1
|
||||
way << node2
|
||||
osm_db << way
|
||||
end
|
||||
Dir.chdir TEST_FOLDER do
|
||||
write_osm
|
||||
end
|
||||
must_reprocess
|
||||
end
|
||||
|
||||
Then /^routability should be$/ do |table|
|
||||
build_ways_from_table table
|
||||
reprocess_if_needed
|
||||
actual = [ table.column_names ]
|
||||
Dir.chdir 'test' do
|
||||
launch
|
||||
p "#{ORIGIN[0]+0*ZOOM},#{ORIGIN[1]-0*ZOOM}", "#{ORIGIN[0]+1*ZOOM},#{ORIGIN[1]-0*ZOOM}"
|
||||
p request_route("#{ORIGIN[0]+0*ZOOM},#{ORIGIN[1]-0*ZOOM}", "#{ORIGIN[0]+1*ZOOM},#{ORIGIN[1]-0*ZOOM}").body
|
||||
kill
|
||||
end
|
||||
table.diff! actual
|
||||
end
|
||||
183
features/step_definitions/test_data.rb
Normal file
183
features/step_definitions/test_data.rb
Normal file
@ -0,0 +1,183 @@
|
||||
require 'OSM/objects' #osmlib gem
|
||||
require 'OSM/Database'
|
||||
require 'builder'
|
||||
|
||||
OSM_USER = 'osrm'
|
||||
OSM_TIMESTAMP = '2012-01-01T00:00:00Z'
|
||||
OSM_GENERATOR = 'osrm-test'
|
||||
OSM_UID = 1
|
||||
TEST_FOLDER = 'test'
|
||||
DATA_FOLDER = 'data'
|
||||
OSM_FILE = 'test'
|
||||
LOG_FILE = 'test.log'
|
||||
|
||||
DEFAULT_SPEEDPROFILE = 'bicycle'
|
||||
|
||||
ORIGIN = [1,1]
|
||||
ZOOM = 0.001
|
||||
|
||||
def must_reprocess
|
||||
@must_reprocess = true
|
||||
end
|
||||
|
||||
def must_reprocess?
|
||||
@must_reprocess ||= true
|
||||
end
|
||||
|
||||
def reprocess_if_needed
|
||||
if must_reprocess?
|
||||
raise "*** osrm-routed is running. Please stop it before running tests." if running?
|
||||
#puts "Reprocessing: #{@osm_db.nodes.size} nodes, #{@name_way_hash.size} ways, #{@relations.size} relations... "
|
||||
|
||||
Dir.chdir TEST_FOLDER do
|
||||
write_speedprofile
|
||||
write_osm
|
||||
reprocess
|
||||
end
|
||||
@must_reprocess = false
|
||||
end
|
||||
end
|
||||
|
||||
def reprocess
|
||||
file = "#{DATA_FOLDER}/#{OSM_FILE}"
|
||||
raise "*** osrm-extract failed. Please see test.log for more info." unless system "./osrm-extract #{file}.osm.pbf 1>>#{LOG_FILE} 2>>#{LOG_FILE}"
|
||||
raise "*** osrm-prepare failed. Please see test.log for more info." unless system "./osrm-prepare #{file}.osrm #{file}.restrictions 1>>#{LOG_FILE} 2>>#{LOG_FILE}"
|
||||
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
|
||||
osm_db.clear
|
||||
name_node_hash.clear
|
||||
name_way_hash.clear
|
||||
must_reprocess
|
||||
reset_speedprofile
|
||||
end
|
||||
|
||||
def clear_data_files
|
||||
File.delete *Dir.glob("#{DATA_FOLDER}/test.*")
|
||||
end
|
||||
|
||||
def clear_log
|
||||
File.delete *Dir.glob("*.log")
|
||||
end
|
||||
|
||||
def speedprofile
|
||||
@speedprofile ||= reset_speedprofile
|
||||
end
|
||||
|
||||
def reset_speedprofile
|
||||
@speedprofile = {}
|
||||
read_speedprofile DEFAULT_SPEEDPROFILE
|
||||
end
|
||||
|
||||
def read_speedprofile profile
|
||||
@speedprofile = {}
|
||||
s = File.read "test/speedprofiles/#{profile}.ini"
|
||||
s.scan /(.*)=(.*)/ do |option|
|
||||
@speedprofile[option[0].strip] = option[1].strip
|
||||
end
|
||||
end
|
||||
|
||||
def dump_speedprofile
|
||||
"[default]\n" + @speedprofile.map { |k,v| "\t#{k} = #{v}" }.join("\n")
|
||||
end
|
||||
|
||||
def write_speedprofile
|
||||
File.open( 'speedprofile.ini', 'w') {|f| f.write( dump_speedprofile ) }
|
||||
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 write_osm
|
||||
xml = ''
|
||||
doc = Builder::XmlMarkup.new :indent => 2, :target => xml
|
||||
doc.instruct!
|
||||
osm_db.to_xml doc, OSM_GENERATOR
|
||||
|
||||
#write .oms file
|
||||
file = "#{DATA_FOLDER}/#{OSM_FILE}"
|
||||
File.open( "#{file}.osm", 'w') {|f| f.write(xml) }
|
||||
|
||||
#convert from .osm to .osm.pbf, which is the format osrm reads
|
||||
#convert. redirect stdout and stderr to a log file avoid output in the cucumber console
|
||||
unless system "osmosis --read-xml #{file}.osm --write-pbf #{file}.osm.pbf omitmetadata=true 1>>#{LOG_FILE} 2>>#{LOG_FILE}"
|
||||
raise "Failed to convert to proto buffer format. Please see #{file}.log for more info."
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
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?
|
||||
node = OSM::Node.new nil, 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|
|
||||
must_reprocess
|
||||
table.hashes.each do |row|
|
||||
name = row.delete 'nodes'
|
||||
way = OSM::Way.new nil, OSM_USER, OSM_TIMESTAMP
|
||||
defaults = { 'highway' => 'primary' }
|
||||
way << defaults.merge( 'name' => name ).merge(row)
|
||||
way.uid = OSM_UID
|
||||
name.each_char { |c| way << find_node_by_name(c) }
|
||||
osm_db << way
|
||||
name_way_hash[name] = way
|
||||
end
|
||||
end
|
||||
|
||||
Given /^the relations$/ do |table|
|
||||
must_reprocess
|
||||
table.hashes.each do |row|
|
||||
relation = OSM::Relation.new nil, OSM_USER, OSM_TIMESTAMP
|
||||
relation << { :type => :restriction, :restriction => 'no_left_turn' }
|
||||
relation << OSM::Member.new( 'way', find_way_by_name(row['from']).id, 'from' )
|
||||
relation << OSM::Member.new( 'way', find_way_by_name(row['to']).id, 'to' )
|
||||
relation << OSM::Member.new( 'node', find_node_by_name(row['via']).id, 'via' )
|
||||
relation.uid = OSM_UID
|
||||
osm_db << relation
|
||||
end
|
||||
end
|
||||
|
||||
Given /^the defaults$/ do
|
||||
end
|
||||
3
features/support/hooks.rb
Normal file
3
features/support/hooks.rb
Normal file
@ -0,0 +1,3 @@
|
||||
Before do
|
||||
reset_data
|
||||
end
|
||||
10
server.ini
10
server.ini
@ -2,8 +2,8 @@ Threads = 8
|
||||
IP = 0.0.0.0
|
||||
Port = 5000
|
||||
|
||||
hsgrData=/opt/osm/germany.osrm.hsgr
|
||||
nodesData=/opt/osm/germany.osrm.nodes
|
||||
ramIndex=/opt/osm/germany.osrm.ramIndex
|
||||
fileIndex=/opt/osm/germany.osrm.fileIndex
|
||||
namesData=/opt/osm/germany.osrm.names
|
||||
hsgrData=data/kbh.osrm.hsgr
|
||||
nodesData=data/kbh.osrm.nodes
|
||||
ramIndex=data/kbh.osrm.ramIndex
|
||||
fileIndex=data/kbh.osrm.fileIndex
|
||||
namesData=data/kbh.osrm.names
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
[car]
|
||||
motorway = 110
|
||||
motorway_link = 90
|
||||
trunk = 90
|
||||
trunk_link = 70
|
||||
primary = 70
|
||||
primary_link = 60
|
||||
secondary = 60
|
||||
secondary_link = 50
|
||||
tertiary = 55
|
||||
unclassified = 25
|
||||
residential = 40
|
||||
living_street = 10
|
||||
service = 30
|
||||
ferry = 5
|
||||
pier = 5
|
||||
obeyBollards = yes
|
||||
obeyOneways = yes
|
||||
useRestrictions = yes
|
||||
accessTag = motorcar
|
||||
excludeFromGrid = ferry
|
||||
defaultSpeed = 50
|
||||
trafficLightPenalty = 15
|
||||
[bike]
|
||||
trunk = 16
|
||||
trunk_link = 16
|
||||
primary = 16
|
||||
primary_link = 16
|
||||
secondary = 16
|
||||
secondary_link = 16
|
||||
tertiary = 16
|
||||
unclassified = 16
|
||||
residential = 16
|
||||
living_street = 16
|
||||
service = 16
|
||||
track = 16
|
||||
cycleway = 16
|
||||
path = 16
|
||||
ferry = 5
|
||||
pier = 5
|
||||
obeyOneways = yes
|
||||
useRestrictions = no
|
||||
accessTag = bicycle
|
||||
excludeFromGrid = ferry
|
||||
defaultSpeed = 5
|
||||
trafficLightPenalty = 15
|
||||
obeyBollards = no
|
||||
|
||||
2
test/contractor.ini
Normal file
2
test/contractor.ini
Normal file
@ -0,0 +1,2 @@
|
||||
Threads = 4
|
||||
SRTM = data/srtm/Eurasia
|
||||
BIN
test/data/kbh.osm.pbf
Normal file
BIN
test/data/kbh.osm.pbf
Normal file
Binary file not shown.
1
test/extractor.ini
Normal file
1
test/extractor.ini
Normal file
@ -0,0 +1 @@
|
||||
Memory = 1
|
||||
9
test/server.ini
Normal file
9
test/server.ini
Normal file
@ -0,0 +1,9 @@
|
||||
Threads = 8
|
||||
IP = 0.0.0.0
|
||||
Port = 5000
|
||||
|
||||
hsgrData=data/test.osrm.hsgr
|
||||
nodesData=data/test.osrm.nodes
|
||||
ramIndex=data/test.osrm.ramIndex
|
||||
fileIndex=data/test.osrm.fileIndex
|
||||
namesData=data/test.osrm.names
|
||||
28
test/speedprofiles/bicycle.ini
Normal file
28
test/speedprofiles/bicycle.ini
Normal file
@ -0,0 +1,28 @@
|
||||
[bicycle]
|
||||
cycleway = 19
|
||||
trunk = 19
|
||||
trunk_link = 19
|
||||
primary = 19
|
||||
primary_link = 19
|
||||
secondary = 17
|
||||
secondary_link = 17
|
||||
tertiary = 15
|
||||
residential = 15
|
||||
unclassified = 15
|
||||
living_street = 13
|
||||
service = 12
|
||||
track = 12
|
||||
path = 12
|
||||
footway = 10
|
||||
pedestrian = 5
|
||||
pier = 5
|
||||
steps = 3
|
||||
ferry = 5
|
||||
obeyOneways = yes
|
||||
useRestrictions = yes
|
||||
accessTag = bicycle
|
||||
excludeFromGrid = ferry
|
||||
defaultSpeed = 17
|
||||
obeyBollards = no
|
||||
trafficLightPenalty = 20
|
||||
|
||||
22
test/speedprofiles/car.ini
Normal file
22
test/speedprofiles/car.ini
Normal file
@ -0,0 +1,22 @@
|
||||
[car]
|
||||
motorway = 110
|
||||
motorway_link = 90
|
||||
trunk = 90
|
||||
trunk_link = 70
|
||||
primary = 70
|
||||
primary_link = 60
|
||||
secondary = 60
|
||||
secondary_link = 50
|
||||
tertiary = 55
|
||||
unclassified = 25
|
||||
residential = 40
|
||||
living_street = 10
|
||||
service = 30
|
||||
ferry = 5
|
||||
pier = 5
|
||||
barrier = bollard
|
||||
obeyOneways = yes
|
||||
useRestrictions = yes
|
||||
accessTag = motorcar
|
||||
excludeFromGrid = ferry
|
||||
defaultSpeed = 50
|
||||
20
test/speedprofiles/default.ini
Normal file
20
test/speedprofiles/default.ini
Normal file
@ -0,0 +1,20 @@
|
||||
[default]
|
||||
accessTag = motorcar
|
||||
defaultSpeed = 50
|
||||
|
||||
barrier = bollard
|
||||
|
||||
motorway = 110
|
||||
motorway_link = 90
|
||||
trunk = 90
|
||||
trunk_link = 70
|
||||
primary = 70
|
||||
primary_link = 60
|
||||
secondary = 60
|
||||
secondary_link = 50
|
||||
tertiary = 40
|
||||
residential = 30
|
||||
living_street = 25
|
||||
service = 25
|
||||
unclassified = 25
|
||||
|
||||
25
test/speedprofiles/ebike.ini
Normal file
25
test/speedprofiles/ebike.ini
Normal file
@ -0,0 +1,25 @@
|
||||
[ebike]
|
||||
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
|
||||
ferry = 5
|
||||
pier = 5
|
||||
pedestrian = 5
|
||||
footway = 5
|
||||
steps = 3
|
||||
obeyOneways = yes
|
||||
useRestrictions = no
|
||||
accessTag = bicycle
|
||||
excludeFromGrid = ferry
|
||||
defaultSpeed = 25
|
||||
Loading…
Reference in New Issue
Block a user