1 # frozen_string_literal: true
 
   5 class RelationVersionsTest < ActionDispatch::IntegrationTest
 
   7   # test that, when tags are updated on a relation, the correct things
 
   8   # happen to the correct tables and the API gives sensible results.
 
   9   # this is to test a case that gregory marler noticed and posted to
 
  11   def test_update_relation_tags
 
  13     changeset = create(:changeset, :user => user)
 
  14     relation = create(:relation)
 
  15     create_list(:relation_tag, 4, :relation => relation)
 
  17     auth_header = bearer_authorization_header user
 
  19     get api_relation_path(relation)
 
  20     assert_response :success
 
  21     rel = xml_parse(@response.body)
 
  22     rel_id = rel.find("//osm/relation").first["id"].to_i
 
  24     # alter one of the tags
 
  25     tag = rel.find("//osm/relation/tag").first
 
  26     tag["v"] = "some changed value"
 
  27     update_changeset(rel, changeset.id)
 
  28     put api_relation_path(rel_id), :params => rel.to_s, :headers => auth_header
 
  29     assert_response :success, "can't update relation: #{@response.body}"
 
  30     new_version = @response.body.to_i
 
  32     # check that the downloaded tags are the same as the uploaded tags...
 
  33     get api_relation_path(rel_id)
 
  34     assert_tags_equal_response rel
 
  36     # check the original one in the current_* table again
 
  37     get api_relation_path(relation)
 
  38     assert_tags_equal_response rel
 
  40     # now check the version in the history
 
  41     get api_relation_version_path(relation, new_version)
 
  42     assert_tags_equal_response rel
 
  46   # test that, when tags are updated on a relation when using the diff
 
  47   # upload function, the correct things happen to the correct tables
 
  48   # and the API gives sensible results. this is to test a case that
 
  49   # gregory marler noticed and posted to josm-dev.
 
  50   def test_update_relation_tags_via_upload
 
  52     changeset = create(:changeset, :user => user)
 
  53     relation = create(:relation)
 
  54     create_list(:relation_tag, 4, :relation => relation)
 
  56     auth_header = bearer_authorization_header user
 
  58     get api_relation_path(relation)
 
  59     assert_response :success
 
  60     rel = xml_parse(@response.body)
 
  61     rel_id = rel.find("//osm/relation").first["id"].to_i
 
  63     # alter one of the tags
 
  64     tag = rel.find("//osm/relation/tag").first
 
  65     tag["v"] = "some changed value"
 
  66     update_changeset(rel, changeset.id)
 
  68     with_controller(Api::ChangesetsController.new) do
 
  69       doc = OSM::API.new.xml_doc
 
  70       change = XML::Node.new "osmChange"
 
  72       modify = XML::Node.new "modify"
 
  74       modify << doc.import(rel.find("//osm/relation").first)
 
  76       post api_changeset_upload_path(changeset), :params => doc.to_s, :headers => auth_header
 
  77       assert_response :success, "can't upload diff relation: #{@response.body}"
 
  78       new_version = xml_parse(@response.body).find("//diffResult/relation").first["new_version"].to_i
 
  81     # check that the downloaded tags are the same as the uploaded tags...
 
  82     get api_relation_path(rel_id)
 
  83     assert_tags_equal_response rel
 
  85     # check the original one in the current_* table again
 
  86     get api_relation_path(relation)
 
  87     assert_tags_equal_response rel
 
  89     # now check the version in the history
 
  90     get api_relation_version_path(relation, new_version)
 
  91     assert_tags_equal_response rel
 
  95   # check that relations are ordered
 
  96   def test_relation_member_ordering
 
  98     changeset = create(:changeset, :user => user)
 
 100     node2 = create(:node)
 
 101     node3 = create(:node)
 
 102     way1 = create(:way_with_nodes, :nodes_count => 2)
 
 103     way2 = create(:way_with_nodes, :nodes_count => 2)
 
 105     auth_header = bearer_authorization_header user
 
 109         <relation changeset='#{changeset.id}'>
 
 110         <member ref='#{node1.id}' type='node' role='first'/>
 
 111         <member ref='#{node2.id}' type='node' role='second'/>
 
 112         <member ref='#{way1.id}' type='way' role='third'/>
 
 113         <member ref='#{way2.id}' type='way' role='fourth'/>
 
 117     doc = XML::Parser.string(doc_str).parse
 
 119     post api_relations_path, :params => doc.to_s, :headers => auth_header
 
 120     assert_response :success, "can't create a relation: #{@response.body}"
 
 121     relation_id = @response.body.to_i
 
 123     # get it back and check the ordering
 
 124     get api_relation_path(relation_id)
 
 125     assert_members_equal_response doc
 
 127     # check the ordering in the history tables:
 
 128     get api_relation_version_path(relation_id, 1)
 
 129     assert_members_equal_response doc, "can't read back version 2 of the relation"
 
 131     # insert a member at the front
 
 132     new_member = XML::Node.new "member"
 
 133     new_member["ref"] = node3.id.to_s
 
 134     new_member["type"] = "node"
 
 135     new_member["role"] = "new first"
 
 136     doc.find("//osm/relation").first.child.prev = new_member
 
 137     # update the version, should be 1?
 
 138     doc.find("//osm/relation").first["id"] = relation_id.to_s
 
 139     doc.find("//osm/relation").first["version"] = 1.to_s
 
 141     # upload the next version of the relation
 
 142     put api_relation_path(relation_id), :params => doc.to_s, :headers => auth_header
 
 143     assert_response :success, "can't update relation: #{@response.body}"
 
 144     assert_equal 2, @response.body.to_i
 
 146     # get it back again and check the ordering again
 
 147     get api_relation_path(relation_id)
 
 148     assert_members_equal_response doc
 
 150     # check the ordering in the history tables:
 
 151     get api_relation_version_path(relation_id, 2)
 
 152     assert_members_equal_response doc, "can't read back version 2 of the relation"
 
 156   # check that relations can contain duplicate members
 
 157   def test_relation_member_duplicates
 
 158     private_user = create(:user, :data_public => false)
 
 160     changeset = create(:changeset, :user => user)
 
 161     node1 = create(:node)
 
 162     node2 = create(:node)
 
 166         <relation changeset='#{changeset.id}'>
 
 167         <member ref='#{node1.id}' type='node' role='forward'/>
 
 168         <member ref='#{node2.id}' type='node' role='forward'/>
 
 169         <member ref='#{node1.id}' type='node' role='forward'/>
 
 170         <member ref='#{node2.id}' type='node' role='forward'/>
 
 174     doc = XML::Parser.string(doc_str).parse
 
 176     ## First try with the private user
 
 177     auth_header = bearer_authorization_header private_user
 
 179     post api_relations_path, :params => doc.to_s, :headers => auth_header
 
 180     assert_response :forbidden
 
 182     ## Now try with the public user
 
 183     auth_header = bearer_authorization_header user
 
 185     post api_relations_path, :params => doc.to_s, :headers => auth_header
 
 186     assert_response :success, "can't create a relation: #{@response.body}"
 
 187     relation_id = @response.body.to_i
 
 189     # get it back and check the ordering
 
 190     get api_relation_path(relation_id)
 
 191     assert_members_equal_response doc
 
 193     # check the ordering in the history tables:
 
 194     get api_relation_version_path(relation_id, 1)
 
 195     assert_members_equal_response doc, "can't read back version 1 of the relation"
 
 199   # test that the ordering of elements in the history is the same as in current.
 
 200   def test_history_ordering
 
 202     changeset = create(:changeset, :user => user)
 
 203     node1 = create(:node)
 
 204     node2 = create(:node)
 
 205     node3 = create(:node)
 
 206     node4 = create(:node)
 
 210         <relation changeset='#{changeset.id}'>
 
 211         <member ref='#{node1.id}' type='node' role='forward'/>
 
 212         <member ref='#{node4.id}' type='node' role='forward'/>
 
 213         <member ref='#{node3.id}' type='node' role='forward'/>
 
 214         <member ref='#{node2.id}' type='node' role='forward'/>
 
 218     doc = XML::Parser.string(doc_str).parse
 
 219     auth_header = bearer_authorization_header user
 
 221     post api_relations_path, :params => doc.to_s, :headers => auth_header
 
 222     assert_response :success, "can't create a relation: #{@response.body}"
 
 223     relation_id = @response.body.to_i
 
 225     # check the ordering in the current tables:
 
 226     get api_relation_path(relation_id)
 
 227     assert_members_equal_response doc
 
 229     # check the ordering in the history tables:
 
 230     get api_relation_version_path(relation_id, 1)
 
 231     assert_members_equal_response doc, "can't read back version 1 of the relation"
 
 237   # assert that tags on relation document +rel+
 
 238   # are equal to tags in response
 
 239   def assert_tags_equal_response(rel)
 
 240     assert_response :success
 
 241     response_xml = xml_parse(@response.body)
 
 243     # turn the XML doc into tags hashes
 
 244     rel_tags = get_tags_as_hash(rel)
 
 245     response_tags = get_tags_as_hash(response_xml)
 
 247     assert_equal rel_tags, response_tags, "Tags should be identical."
 
 251   # checks that the XML document and the response have
 
 252   # members in the same order.
 
 253   def assert_members_equal_response(doc, response_message = "can't read back the relation")
 
 254     assert_response :success, "#{response_message}: #{@response.body}"
 
 255     new_doc = XML::Parser.string(@response.body).parse
 
 257     doc_members = doc.find("//osm/relation/member").collect do |m|
 
 258       [m["ref"].to_i, m["type"].to_sym, m["role"]]
 
 261     new_members = new_doc.find("//osm/relation/member").collect do |m|
 
 262       [m["ref"].to_i, m["type"].to_sym, m["role"]]
 
 265     assert_equal doc_members, new_members, "members are not equal - ordering is wrong? (#{doc}, #{@response.body})"
 
 269   # returns a k->v hash of tags from an xml doc
 
 270   def get_tags_as_hash(a)
 
 271     a.find("//osm/relation/tag").to_h do |tag|
 
 277   # update the changeset_id of a node element
 
 278   def update_changeset(xml, changeset_id)
 
 279     xml_attr_rewrite(xml, "changeset", changeset_id)
 
 283   # update an attribute in the node element
 
 284   def xml_attr_rewrite(xml, name, value)
 
 285     xml.find("//osm/relation").first[name] = value.to_s
 
 292     parser = XML::Parser.string(xml)