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)