require 'spec_helper' describe Rosemary::Node do before do WebMock.disable_net_connect! end let :osm do Rosemary::Api.new end let :stub_changeset_lookup do stub_request(:get, "http://www.openstreetmap.org/api/0.6/changesets?open=true&user=1234").to_return(:status => 200, :body => valid_fake_changeset, :headers => {'Content-Type' => 'application/xml'} ) end let :stub_node_lookup do stub_request(:get, "http://www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => valid_fake_node, :headers => {'Content-Type' => 'application/xml'}) end def valid_fake_node node=<<-EOF EOF end def valid_fake_user user=<<-EOF The description of your profile de-DE de en-US en EOF end def valid_fake_changeset changeset=<<-EOF EOF end describe '#find:' do let :request_url do "http://www.openstreetmap.org/api/0.6/node/1234" end let :stubbed_request do stub_request(:get, request_url) end it "should build a Node from API response via get_object" do stubbed_request.to_return(:status => 200, :body => valid_fake_node, :headers => {'Content-Type' => 'application/xml'}) node = osm.find_node 1234 assert_requested :get, request_url, :times => 1 node.class.should eql Rosemary::Node node.tags.size.should eql 3 node.tags['name'].should eql 'The rose' node['name'].should eql 'The rose' node.add_tags('wheelchair' => 'yes') node['wheelchair'].should eql 'yes' end it "should raise a Unavailable, when api times out" do stubbed_request.to_timeout lambda { node = osm.find_node(1234) }.should raise_error(Rosemary::Unavailable) end it "should raise an Gone error, when a node has been deleted" do stubbed_request.to_return(:status => 410, :body => '', :headers => {'Content-Type' => 'text/plain'}) lambda { node = osm.find_node(1234) }.should raise_error(Rosemary::Gone) end it "should raise an NotFound error, when a node cannot be found" do stubbed_request.to_return(:status => 404, :body => '', :headers => {'Content-Type' => 'text/plain'}) lambda { node = osm.find_node(1234) }.should raise_error(Rosemary::NotFound) end end describe 'with BasicAuthClient' do let :osm do Rosemary::Api.new(Rosemary::BasicAuthClient.new('a_username', 'a_password')) end let :stub_user_lookup do stub_request(:get, "http://a_username:a_password@www.openstreetmap.org/api/0.6/user/details").to_return(:status => 200, :body => valid_fake_user, :headers => {'Content-Type' => 'application/xml'} ) end describe '#create:' do let :node do Rosemary::Node.new end let :request_url do "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/create" end let :stubbed_request do stub_request(:put, request_url) end before do stub_changeset_lookup stub_user_lookup end it "should create a new Node from given attributes" do stubbed_request.to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'}) node.id.should be_nil new_id = osm.save(node) end it "should raise a Unavailable, when api times out" do stubbed_request.to_timeout lambda { new_id = osm.save(node) }.should raise_error(Rosemary::Unavailable) end it "should not create a Node with invalid xml but raise BadRequest" do stubbed_request.to_return(:status => 400, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'}) lambda { new_id = osm.save(node) }.should raise_error(Rosemary::BadRequest) end it "should not allow to create a node when a changeset has been closed" do stubbed_request.to_return(:status => 409, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'}) lambda { new_id = osm.save(node) }.should raise_error(Rosemary::Conflict) end it "should not allow to create a node when no authentication client is given" do osm = Rosemary::Api.new lambda { osm.save(node) }.should raise_error(Rosemary::CredentialsMissing) end end describe '#update:' do let :node do osm.find_node 123 end before do stub_changeset_lookup stub_user_lookup stub_node_lookup end it "should save a edited node" do stub_request(:put, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => '43', :headers => {'Content-Type' => 'text/plain'}) node.tags['amenity'] = 'restaurant' node.tags['name'] = 'Il Tramonto' node.should_receive(:changeset=) new_version = osm.save(node) new_version.should eql 43 end end describe '#delete:' do let :node do osm.find_node 123 end before do stub_changeset_lookup stub_user_lookup stub_node_lookup end it "should not delete an node with missing id" do node = Rosemary::Node.new osm.destroy(node) end it "should delete an existing node" do stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => '43', :headers => {'Content-Type' => 'text/plain'}) node.should_receive(:changeset=) new_version = osm.destroy(node) new_version.should eql 43 # new version number end it "should raise an error if node to be deleted is still part of a way" do stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 400, :body => 'Version does not match current database version', :headers => {'Content-Type' => 'text/plain'}) lambda { response = osm.destroy(node) response.should eql "Version does not match current database version" }.should raise_error Rosemary::BadRequest end it "should raise an error if node cannot be found" do stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 404, :body => 'Node cannot be found', :headers => {'Content-Type' => 'text/plain'}) lambda { response = osm.destroy(node) response.should eql "Node cannot be found" }.should raise_error Rosemary::NotFound end it "should raise an error if there is a conflict" do stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 409, :body => 'Node has been deleted in this changeset', :headers => {'Content-Type' => 'text/plain'}) lambda { response = osm.destroy(node) response.should eql "Node has been deleted in this changeset" }.should raise_error Rosemary::Conflict end it "should raise an error if the node is already delted" do stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 410, :body => 'Node has been deleted', :headers => {'Content-Type' => 'text/plain'}) lambda { response = osm.destroy(node) response.should eql "Node has been deleted" }.should raise_error Rosemary::Gone end it "should raise an error if the node is part of a way" do stub_request(:delete, "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/123").to_return(:status => 412, :body => 'Node 123 is still used by way 456', :headers => {'Content-Type' => 'text/plain'}) lambda { response = osm.destroy(node) response.should eql "Node 123 is still used by way 456" }.should raise_error Rosemary::Precondition end end end describe 'with OauthClient' do let :consumer do OAuth::Consumer.new( 'a_key', 'a_secret', { :site => 'http://www.openstreetmap.org', :request_token_path => '/oauth/request_token', :access_token_path => '/oauth/access_token', :authorize_path => '/oauth/authorize' } ) end let :access_token do OAuth::AccessToken.new(consumer, 'a_token', 'a_secret') end let :osm do Rosemary::Api.new(Rosemary::OauthClient.new(access_token)) end let :stub_user_lookup do stub_request(:get, "http://www.openstreetmap.org/api/0.6/user/details").to_return(:status => 200, :body => valid_fake_user, :headers => {'Content-Type' => 'application/xml'} ) end describe '#create:' do let :node do Rosemary::Node.new end let :request_url do "http://www.openstreetmap.org/api/0.6/node/create" end let :stubbed_request do stub_request(:put, request_url) end before do stub_changeset_lookup stub_user_lookup end it "should create a new Node from given attributes" do stubbed_request.to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'}) node.id.should be_nil new_id = osm.save(node) end it "should raise a Unavailable, when api times out" do stubbed_request.to_timeout lambda { new_id = osm.save(node) }.should raise_error(Rosemary::Unavailable) end it "should not create a Node with invalid xml but raise BadRequest" do stubbed_request.to_return(:status => 400, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'}) lambda { new_id = osm.save(node) }.should raise_error(Rosemary::BadRequest) end it "should not allow to create a node when a changeset has been closed" do stubbed_request.to_return(:status => 409, :body => 'The given node is invalid', :headers => {'Content-Type' => 'text/plain'}) lambda { new_id = osm.save(node) }.should raise_error(Rosemary::Conflict) end it "should not allow to create a node when no authentication client is given" do osm = Rosemary::Api.new lambda { osm.save(node) }.should raise_error(Rosemary::CredentialsMissing) end end describe '#update:' do let :node do osm.find_node 123 end before do stub_changeset_lookup stub_user_lookup stub_node_lookup end it "should save a edited node" do stub_request(:put, "http://www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => '43', :headers => {'Content-Type' => 'text/plain'}) node.tags['amenity'] = 'restaurant' node.tags['name'] = 'Il Tramonto' node.should_receive(:changeset=) new_version = osm.save(node) new_version.should eql 43 end end describe '#delete:' do let :node do osm.find_node 123 end before do stub_changeset_lookup stub_user_lookup stub_node_lookup end it "should delete an existing node" do stub_request(:delete, "http://www.openstreetmap.org/api/0.6/node/123").to_return(:status => 200, :body => '43', :headers => {'Content-Type' => 'text/plain'}) node.should_receive(:changeset=) lambda { # Delete is not implemented using oauth new_version = osm.destroy(node) }.should raise_error(Rosemary::NotImplemented) end end end end