- ##
- # tests whether the API works and prevents incorrect use while trying
- # to update ways.
- def test_update
- private_user = create(:user, :data_public => false)
- private_way = create(:way, :changeset => create(:changeset, :user => private_user))
- user = create(:user)
- way = create(:way, :changeset => create(:changeset, :user => user))
- node = create(:node)
- create(:way_node, :way => private_way, :node => node)
- create(:way_node, :way => way, :node => node)
-
- ## First test with no user credentials
- # try and update a way without authorisation
- content way.to_xml
- put :update, :params => { :id => way.id }
- assert_response :unauthorized
-
- ## Second test with the private user
-
- # setup auth
- basic_authorization private_user.email, "test"
-
- ## trying to break changesets
-
- # try and update in someone else's changeset
- content update_changeset(private_way.to_xml,
- create(:changeset).id)
- put :update, :params => { :id => private_way.id }
- assert_require_public_data "update with other user's changeset should be forbidden when date isn't public"
-
- # try and update in a closed changeset
- content update_changeset(private_way.to_xml,
- create(:changeset, :closed, :user => private_user).id)
- put :update, :params => { :id => private_way.id }
- assert_require_public_data "update with closed changeset should be forbidden, when data isn't public"
-
- # try and update in a non-existant changeset
- content update_changeset(private_way.to_xml, 0)
- put :update, :params => { :id => private_way.id }
- assert_require_public_data("update with changeset=0 should be forbidden, when data isn't public")
-
- ## try and submit invalid updates
- content xml_replace_node(private_way.to_xml, node.id, 9999)
- put :update, :params => { :id => private_way.id }
- assert_require_public_data "way with non-existent node should be forbidden, when data isn't public"
-
- content xml_replace_node(private_way.to_xml, node.id, create(:node, :deleted).id)
- put :update, :params => { :id => private_way.id }
- assert_require_public_data "way with deleted node should be forbidden, when data isn't public"
-
- ## finally, produce a good request which will still not work
- content private_way.to_xml
- put :update, :params => { :id => private_way.id }
- assert_require_public_data "should have failed with a forbidden when data isn't public"
-
- ## Finally test with the public user
-
- # setup auth
- basic_authorization user.email, "test"
-
- ## trying to break changesets
-
- # try and update in someone else's changeset
- content update_changeset(way.to_xml,
- create(:changeset).id)
- put :update, :params => { :id => way.id }
- assert_response :conflict, "update with other user's changeset should be rejected"
-
- # try and update in a closed changeset
- content update_changeset(way.to_xml,
- create(:changeset, :closed, :user => user).id)
- put :update, :params => { :id => way.id }
- assert_response :conflict, "update with closed changeset should be rejected"
-
- # try and update in a non-existant changeset
- content update_changeset(way.to_xml, 0)
- put :update, :params => { :id => way.id }
- assert_response :conflict, "update with changeset=0 should be rejected"
-
- ## try and submit invalid updates
- content xml_replace_node(way.to_xml, node.id, 9999)
- put :update, :params => { :id => way.id }
- assert_response :precondition_failed, "way with non-existent node should be rejected"
-
- content xml_replace_node(way.to_xml, node.id, create(:node, :deleted).id)
- put :update, :params => { :id => way.id }
- assert_response :precondition_failed, "way with deleted node should be rejected"
-
- ## next, attack the versioning
- current_way_version = way.version
-
- # try and submit a version behind
- content xml_attr_rewrite(way.to_xml,
- "version", current_way_version - 1)
- put :update, :params => { :id => way.id }
- assert_response :conflict, "should have failed on old version number"
-
- # try and submit a version ahead
- content xml_attr_rewrite(way.to_xml,
- "version", current_way_version + 1)
- put :update, :params => { :id => way.id }
- assert_response :conflict, "should have failed on skipped version number"
-
- # try and submit total crap in the version field
- content xml_attr_rewrite(way.to_xml,
- "version", "p1r4t3s!")
- put :update, :params => { :id => way.id }
- assert_response :conflict,
- "should not be able to put 'p1r4at3s!' in the version field"
-
- ## try an update with the wrong ID
- content create(:way).to_xml
- put :update, :params => { :id => way.id }
- assert_response :bad_request,
- "should not be able to update a way with a different ID from the XML"
-
- ## try an update with a minimal valid XML doc which isn't a well-formed OSM doc.
- content "<update/>"
- put :update, :params => { :id => way.id }
- assert_response :bad_request,
- "should not be able to update a way with non-OSM XML doc."
-
- ## finally, produce a good request which should work
- content way.to_xml
- put :update, :params => { :id => way.id }
- assert_response :success, "a valid update request failed"
- end
-
- # ------------------------------------------------------------
- # test tags handling
- # ------------------------------------------------------------
-
- ##
- # Try adding a new tag to a way
- def test_add_tags
- private_user = create(:user, :data_public => false)
- private_way = create(:way_with_nodes, :nodes_count => 2, :changeset => create(:changeset, :user => private_user))
- user = create(:user)
- way = create(:way_with_nodes, :nodes_count => 2, :changeset => create(:changeset, :user => user))
-
- ## Try with the non-public user
- # setup auth
- basic_authorization private_user.email, "test"
-
- # add an identical tag to the way
- tag_xml = XML::Node.new("tag")
- tag_xml["k"] = "new"
- tag_xml["v"] = "yes"
-
- # add the tag into the existing xml
- way_xml = private_way.to_xml
- way_xml.find("//osm/way").first << tag_xml
-
- # try and upload it
- content way_xml
- put :update, :params => { :id => private_way.id }
- assert_response :forbidden,
- "adding a duplicate tag to a way for a non-public should fail with 'forbidden'"
-
- ## Now try with the public user
- # setup auth
- basic_authorization user.email, "test"
-
- # add an identical tag to the way
- tag_xml = XML::Node.new("tag")
- tag_xml["k"] = "new"
- tag_xml["v"] = "yes"
-
- # add the tag into the existing xml
- way_xml = way.to_xml
- way_xml.find("//osm/way").first << tag_xml
-
- # try and upload it
- content way_xml
- put :update, :params => { :id => way.id }
- assert_response :success,
- "adding a new tag to a way should succeed"
- assert_equal way.version + 1, @response.body.to_i
- end
-
- ##
- # Try adding a duplicate of an existing tag to a way
- def test_add_duplicate_tags
- private_user = create(:user, :data_public => false)
- private_way = create(:way, :changeset => create(:changeset, :user => private_user))
- private_existing_tag = create(:way_tag, :way => private_way)
- user = create(:user)
- way = create(:way, :changeset => create(:changeset, :user => user))
- existing_tag = create(:way_tag, :way => way)
-
- ## Try with the non-public user
- # setup auth
- basic_authorization private_user.email, "test"
-
- # add an identical tag to the way
- tag_xml = XML::Node.new("tag")
- tag_xml["k"] = private_existing_tag.k
- tag_xml["v"] = private_existing_tag.v
-
- # add the tag into the existing xml
- way_xml = private_way.to_xml
- way_xml.find("//osm/way").first << tag_xml
-
- # try and upload it
- content way_xml
- put :update, :params => { :id => private_way.id }
- assert_response :forbidden,
- "adding a duplicate tag to a way for a non-public should fail with 'forbidden'"
-
- ## Now try with the public user
- # setup auth
- basic_authorization user.email, "test"
-
- # add an identical tag to the way
- tag_xml = XML::Node.new("tag")
- tag_xml["k"] = existing_tag.k
- tag_xml["v"] = existing_tag.v
-
- # add the tag into the existing xml
- way_xml = way.to_xml
- way_xml.find("//osm/way").first << tag_xml
-
- # try and upload it
- content way_xml
- put :update, :params => { :id => way.id }
- assert_response :bad_request,
- "adding a duplicate tag to a way should fail with 'bad request'"
- assert_equal "Element way/#{way.id} has duplicate tags with key #{existing_tag.k}", @response.body
- end
-
- ##
- # Try adding a new duplicate tags to a way
- def test_new_duplicate_tags
- private_user = create(:user, :data_public => false)
- private_way = create(:way, :changeset => create(:changeset, :user => private_user))
- user = create(:user)
- way = create(:way, :changeset => create(:changeset, :user => user))
-
- ## First test with the non-public user so should be rejected
- # setup auth
- basic_authorization private_user.email, "test"
-
- # create duplicate tag
- tag_xml = XML::Node.new("tag")
- tag_xml["k"] = "i_am_a_duplicate"
- tag_xml["v"] = "foobar"
-
- # add the tag into the existing xml
- way_xml = private_way.to_xml
-
- # add two copies of the tag
- way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
-
- # try and upload it
- content way_xml
- put :update, :params => { :id => private_way.id }
- assert_response :forbidden,
- "adding new duplicate tags to a way using a non-public user should fail with 'forbidden'"
-
- ## Now test with the public user
- # setup auth
- basic_authorization user.email, "test"
-
- # create duplicate tag
- tag_xml = XML::Node.new("tag")
- tag_xml["k"] = "i_am_a_duplicate"
- tag_xml["v"] = "foobar"
-
- # add the tag into the existing xml
- way_xml = way.to_xml
-
- # add two copies of the tag
- way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
-
- # try and upload it
- content way_xml
- put :update, :params => { :id => way.id }
- assert_response :bad_request,
- "adding new duplicate tags to a way should fail with 'bad request'"
- assert_equal "Element way/#{way.id} has duplicate tags with key i_am_a_duplicate", @response.body
- end
-
- ##
- # Try adding a new duplicate tags to a way.
- # But be a bit subtle - use unicode decoding ambiguities to use different
- # binary strings which have the same decoding.
- def test_invalid_duplicate_tags
- private_user = create(:user, :data_public => false)
- private_changeset = create(:changeset, :user => private_user)
- user = create(:user)
- changeset = create(:changeset, :user => user)
-
- ## First make sure that you can't with a non-public user
- # setup auth
- basic_authorization private_user.email, "test"
-
- # add the tag into the existing xml
- way_str = "<osm><way changeset='#{private_changeset.id}'>"
- way_str << "<tag k='addr:housenumber' v='1'/>"
- way_str << "<tag k='addr:housenumber' v='2'/>"
- way_str << "</way></osm>"
-
- # try and upload it
- content way_str
- put :create
- assert_response :forbidden,
- "adding new duplicate tags to a way with a non-public user should fail with 'forbidden'"
-
- ## Now do it with a public user
- # setup auth
- basic_authorization user.email, "test"
-
- # add the tag into the existing xml
- way_str = "<osm><way changeset='#{changeset.id}'>"
- way_str << "<tag k='addr:housenumber' v='1'/>"
- way_str << "<tag k='addr:housenumber' v='2'/>"
- way_str << "</way></osm>"
-
- # try and upload it
- content way_str
- put :create
- assert_response :bad_request,
- "adding new duplicate tags to a way should fail with 'bad request'"
- assert_equal "Element way/ has duplicate tags with key addr:housenumber", @response.body
- end
-
- ##
- # test that a call to ways_for_node returns all ways that contain the node
- # and none that don't.
- def test_ways_for_node
- node = create(:node)
- way1 = create(:way)
- way2 = create(:way)
- create(:way_node, :way => way1, :node => node)
- create(:way_node, :way => way2, :node => node)
- # create an unrelated way
- create(:way_with_nodes, :nodes_count => 2)
- # create a way which used to use the node
- way3_v1 = create(:old_way, :version => 1)
- _way3_v2 = create(:old_way, :current_way => way3_v1.current_way, :version => 2)
- create(:old_way_node, :old_way => way3_v1, :node => node)
-
- get :ways_for_node, :params => { :id => node.id }
- assert_response :success
- ways_xml = XML::Parser.string(@response.body).parse
- assert_not_nil ways_xml, "failed to parse ways_for_node response"
-
- # check that the set of IDs match expectations
- expected_way_ids = [way1.id,
- way2.id]
- found_way_ids = ways_xml.find("//osm/way").collect { |w| w["id"].to_i }
- assert_equal expected_way_ids.sort, found_way_ids.sort,
- "expected ways for node #{node.id} did not match found"
-
- # check the full ways to ensure we're not missing anything
- expected_way_ids.each do |id|
- way_xml = ways_xml.find("//osm/way[@id='#{id}']").first
- assert_ways_are_equal(Way.find(id),
- Way.from_xml_node(way_xml))