require 'spec_helper' include Rosemary describe Node do before do WebMock.disable_net_connect! end let(:changeset) { Changeset.new(:id => 1) } let(:osm) { Api.new } def stub_changeset_lookup 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 def stub_node_lookup 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 def request_url "http://www.openstreetmap.org/api/0.6/node/1234" end def stubbed_request 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 expect(node.class).to eql Node expect(node.tags.size).to eql 3 expect(node.tags['name']).to eql 'The rose' expect(node['name']).to eql 'The rose' node.add_tags('wheelchair' => 'yes') expect(node['wheelchair']).to eql 'yes' end it "should raise a Unavailable, when api times out" do stubbed_request.to_timeout expect { node = osm.find_node(1234) }.to raise_exception(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'}) expect { node = osm.find_node(1234) }.to raise_exception(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'}) node = osm.find_node(1234) expect(node).to be_nil end end describe 'with BasicAuthClient' do let :osm do Api.new(BasicAuthClient.new('a_username', 'a_password')) end def stub_user_lookup 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) { Node.new } let (:expected_body) { expected_node = node.dup expected_node.changeset = changeset.id expected_node.to_xml } def request_url "http://a_username:a_password@www.openstreetmap.org/api/0.6/node/create" end def stubbed_request stub_request(:put, request_url) end before do stub_user_lookup end it "should create a new Node from given attributes" do stubbed_request.with(:body => expected_body). to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'}) new_id = osm.create(node, changeset) end it "should raise a Unavailable, when api times out" do stubbed_request.to_timeout expect { new_id = osm.create(node, changeset) }.to raise_exception(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'}) expect { new_id = osm.save(node, changeset) }.to raise_exception(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'}) expect { new_id = osm.save(node, changeset) }.to raise_exception(Conflict) end it "should not allow to create a node when no authentication client is given" do osm = Api.new expect { osm.save(node, changeset) }.to raise_exception(CredentialsMissing) end it "should set a changeset" do stubbed_request.to_return(:status => 200, :body => '123', :headers => {'Content-Type' => 'text/plain'}) node.changeset = nil osm.save(node, changeset) expect(node.changeset).to eql changeset.id end end describe '#update:' do let :node do osm.find_node 123 end before do 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' expect(node).to receive(:changeset=) new_version = osm.save(node, changeset) expect(new_version).to eql 43 end it "should set a changeset" 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.changeset = nil osm.save(node, changeset) expect(node.changeset).to eql changeset.id 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 = Node.new osm.destroy(node, changeset) 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'}) expect(node).to receive(:changeset=) new_version = osm.destroy(node, changeset) expect(new_version).to 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'}) expect { response = osm.destroy(node, changeset) expect(response).to eql "Version does not match current database version" }.to raise_exception 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'}) expect { response = osm.destroy(node, changeset) expect(response).to eql "Node cannot be found" }.to raise_exception 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'}) expect { response = osm.destroy(node, changeset) expect(response).to eql "Node has been deleted in this changeset" }.to raise_exception 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'}) expect { response = osm.destroy(node, changeset) expect(response).to eql "Node has been deleted" }.to raise_exception 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'}) expect { response = osm.destroy(node, changeset) expect(response).to eql "Node 123 is still used by way 456" }.to raise_exception Precondition end it "should set the changeset 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.changeset = nil new_version = osm.destroy(node, changeset) expect(node.changeset).to eql changeset.id 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 Api.new(OauthClient.new(access_token)) end def stub_user_lookup 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 Node.new end def request_url "http://www.openstreetmap.org/api/0.6/node/create" end def stubbed_request 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'}) expect(node.id).to be_nil new_id = osm.save(node, changeset) end it "should raise a Unavailable, when api times out" do stubbed_request.to_timeout expect { new_id = osm.save(node, changeset) }.to raise_exception(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'}) expect { new_id = osm.save(node, changeset) }.to raise_exception(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'}) expect { new_id = osm.save(node, changeset) }.to raise_exception(Conflict) end it "should not allow to create a node when no authentication client is given" do osm = Api.new expect { osm.save(node, changeset) }.to raise_exception(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' expect(node).to receive(:changeset=) new_version = osm.save(node, changeset) expect(new_version).to 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'}) expect(node).to receive(:changeset=) expect { # Delete is not implemented using oauth new_version = osm.destroy(node, changeset) }.to raise_exception(NotImplemented) end end end end