]> git.openstreetmap.org Git - rails.git/blob - test/integration/relation_versions_test.rb
Merge remote-tracking branch 'upstream/pull/6154'
[rails.git] / test / integration / relation_versions_test.rb
1 require "test_helper"
2
3 class RelationVersionsTest < ActionDispatch::IntegrationTest
4   ##
5   # test that, when tags are updated on a relation, the correct things
6   # happen to the correct tables and the API gives sensible results.
7   # this is to test a case that gregory marler noticed and posted to
8   # josm-dev.
9   def test_update_relation_tags
10     user = create(:user)
11     changeset = create(:changeset, :user => user)
12     relation = create(:relation)
13     create_list(:relation_tag, 4, :relation => relation)
14
15     auth_header = bearer_authorization_header user
16
17     get api_relation_path(relation)
18     assert_response :success
19     rel = xml_parse(@response.body)
20     rel_id = rel.find("//osm/relation").first["id"].to_i
21
22     # alter one of the tags
23     tag = rel.find("//osm/relation/tag").first
24     tag["v"] = "some changed value"
25     update_changeset(rel, changeset.id)
26     put api_relation_path(rel_id), :params => rel.to_s, :headers => auth_header
27     assert_response :success, "can't update relation: #{@response.body}"
28     new_version = @response.body.to_i
29
30     # check that the downloaded tags are the same as the uploaded tags...
31     get api_relation_path(rel_id)
32     assert_tags_equal_response rel
33
34     # check the original one in the current_* table again
35     get api_relation_path(relation)
36     assert_tags_equal_response rel
37
38     # now check the version in the history
39     get api_relation_version_path(relation, new_version)
40     assert_tags_equal_response rel
41   end
42
43   ##
44   # test that, when tags are updated on a relation when using the diff
45   # upload function, the correct things happen to the correct tables
46   # and the API gives sensible results. this is to test a case that
47   # gregory marler noticed and posted to josm-dev.
48   def test_update_relation_tags_via_upload
49     user = create(:user)
50     changeset = create(:changeset, :user => user)
51     relation = create(:relation)
52     create_list(:relation_tag, 4, :relation => relation)
53
54     auth_header = bearer_authorization_header user
55
56     get api_relation_path(relation)
57     assert_response :success
58     rel = xml_parse(@response.body)
59     rel_id = rel.find("//osm/relation").first["id"].to_i
60
61     # alter one of the tags
62     tag = rel.find("//osm/relation/tag").first
63     tag["v"] = "some changed value"
64     update_changeset(rel, changeset.id)
65     new_version = nil
66     with_controller(Api::ChangesetsController.new) do
67       doc = OSM::API.new.xml_doc
68       change = XML::Node.new "osmChange"
69       doc.root = change
70       modify = XML::Node.new "modify"
71       change << modify
72       modify << doc.import(rel.find("//osm/relation").first)
73
74       post api_changeset_upload_path(changeset), :params => doc.to_s, :headers => auth_header
75       assert_response :success, "can't upload diff relation: #{@response.body}"
76       new_version = xml_parse(@response.body).find("//diffResult/relation").first["new_version"].to_i
77     end
78
79     # check that the downloaded tags are the same as the uploaded tags...
80     get api_relation_path(rel_id)
81     assert_tags_equal_response rel
82
83     # check the original one in the current_* table again
84     get api_relation_path(relation)
85     assert_tags_equal_response rel
86
87     # now check the version in the history
88     get api_relation_version_path(relation, new_version)
89     assert_tags_equal_response rel
90   end
91
92   ##
93   # check that relations are ordered
94   def test_relation_member_ordering
95     user = create(:user)
96     changeset = create(:changeset, :user => user)
97     node1 = create(:node)
98     node2 = create(:node)
99     node3 = create(:node)
100     way1 = create(:way_with_nodes, :nodes_count => 2)
101     way2 = create(:way_with_nodes, :nodes_count => 2)
102
103     auth_header = bearer_authorization_header user
104
105     doc_str = <<~OSM
106       <osm>
107         <relation changeset='#{changeset.id}'>
108         <member ref='#{node1.id}' type='node' role='first'/>
109         <member ref='#{node2.id}' type='node' role='second'/>
110         <member ref='#{way1.id}' type='way' role='third'/>
111         <member ref='#{way2.id}' type='way' role='fourth'/>
112         </relation>
113       </osm>
114     OSM
115     doc = XML::Parser.string(doc_str).parse
116
117     post api_relations_path, :params => doc.to_s, :headers => auth_header
118     assert_response :success, "can't create a relation: #{@response.body}"
119     relation_id = @response.body.to_i
120
121     # get it back and check the ordering
122     get api_relation_path(relation_id)
123     assert_members_equal_response doc
124
125     # check the ordering in the history tables:
126     get api_relation_version_path(relation_id, 1)
127     assert_members_equal_response doc, "can't read back version 2 of the relation"
128
129     # insert a member at the front
130     new_member = XML::Node.new "member"
131     new_member["ref"] = node3.id.to_s
132     new_member["type"] = "node"
133     new_member["role"] = "new first"
134     doc.find("//osm/relation").first.child.prev = new_member
135     # update the version, should be 1?
136     doc.find("//osm/relation").first["id"] = relation_id.to_s
137     doc.find("//osm/relation").first["version"] = 1.to_s
138
139     # upload the next version of the relation
140     put api_relation_path(relation_id), :params => doc.to_s, :headers => auth_header
141     assert_response :success, "can't update relation: #{@response.body}"
142     assert_equal 2, @response.body.to_i
143
144     # get it back again and check the ordering again
145     get api_relation_path(relation_id)
146     assert_members_equal_response doc
147
148     # check the ordering in the history tables:
149     get api_relation_version_path(relation_id, 2)
150     assert_members_equal_response doc, "can't read back version 2 of the relation"
151   end
152
153   ##
154   # check that relations can contain duplicate members
155   def test_relation_member_duplicates
156     private_user = create(:user, :data_public => false)
157     user = create(:user)
158     changeset = create(:changeset, :user => user)
159     node1 = create(:node)
160     node2 = create(:node)
161
162     doc_str = <<~OSM
163       <osm>
164         <relation changeset='#{changeset.id}'>
165         <member ref='#{node1.id}' type='node' role='forward'/>
166         <member ref='#{node2.id}' type='node' role='forward'/>
167         <member ref='#{node1.id}' type='node' role='forward'/>
168         <member ref='#{node2.id}' type='node' role='forward'/>
169         </relation>
170       </osm>
171     OSM
172     doc = XML::Parser.string(doc_str).parse
173
174     ## First try with the private user
175     auth_header = bearer_authorization_header private_user
176
177     post api_relations_path, :params => doc.to_s, :headers => auth_header
178     assert_response :forbidden
179
180     ## Now try with the public user
181     auth_header = bearer_authorization_header user
182
183     post api_relations_path, :params => doc.to_s, :headers => auth_header
184     assert_response :success, "can't create a relation: #{@response.body}"
185     relation_id = @response.body.to_i
186
187     # get it back and check the ordering
188     get api_relation_path(relation_id)
189     assert_members_equal_response doc
190
191     # check the ordering in the history tables:
192     get api_relation_version_path(relation_id, 1)
193     assert_members_equal_response doc, "can't read back version 1 of the relation"
194   end
195
196   ##
197   # test that the ordering of elements in the history is the same as in current.
198   def test_history_ordering
199     user = create(:user)
200     changeset = create(:changeset, :user => user)
201     node1 = create(:node)
202     node2 = create(:node)
203     node3 = create(:node)
204     node4 = create(:node)
205
206     doc_str = <<~OSM
207       <osm>
208         <relation changeset='#{changeset.id}'>
209         <member ref='#{node1.id}' type='node' role='forward'/>
210         <member ref='#{node4.id}' type='node' role='forward'/>
211         <member ref='#{node3.id}' type='node' role='forward'/>
212         <member ref='#{node2.id}' type='node' role='forward'/>
213         </relation>
214       </osm>
215     OSM
216     doc = XML::Parser.string(doc_str).parse
217     auth_header = bearer_authorization_header user
218
219     post api_relations_path, :params => doc.to_s, :headers => auth_header
220     assert_response :success, "can't create a relation: #{@response.body}"
221     relation_id = @response.body.to_i
222
223     # check the ordering in the current tables:
224     get api_relation_path(relation_id)
225     assert_members_equal_response doc
226
227     # check the ordering in the history tables:
228     get api_relation_version_path(relation_id, 1)
229     assert_members_equal_response doc, "can't read back version 1 of the relation"
230   end
231
232   private
233
234   ##
235   # assert that tags on relation document +rel+
236   # are equal to tags in response
237   def assert_tags_equal_response(rel)
238     assert_response :success
239     response_xml = xml_parse(@response.body)
240
241     # turn the XML doc into tags hashes
242     rel_tags = get_tags_as_hash(rel)
243     response_tags = get_tags_as_hash(response_xml)
244
245     assert_equal rel_tags, response_tags, "Tags should be identical."
246   end
247
248   ##
249   # checks that the XML document and the response have
250   # members in the same order.
251   def assert_members_equal_response(doc, response_message = "can't read back the relation")
252     assert_response :success, "#{response_message}: #{@response.body}"
253     new_doc = XML::Parser.string(@response.body).parse
254
255     doc_members = doc.find("//osm/relation/member").collect do |m|
256       [m["ref"].to_i, m["type"].to_sym, m["role"]]
257     end
258
259     new_members = new_doc.find("//osm/relation/member").collect do |m|
260       [m["ref"].to_i, m["type"].to_sym, m["role"]]
261     end
262
263     assert_equal doc_members, new_members, "members are not equal - ordering is wrong? (#{doc}, #{@response.body})"
264   end
265
266   ##
267   # returns a k->v hash of tags from an xml doc
268   def get_tags_as_hash(a)
269     a.find("//osm/relation/tag").to_h do |tag|
270       [tag["k"], tag["v"]]
271     end
272   end
273
274   ##
275   # update the changeset_id of a node element
276   def update_changeset(xml, changeset_id)
277     xml_attr_rewrite(xml, "changeset", changeset_id)
278   end
279
280   ##
281   # update an attribute in the node element
282   def xml_attr_rewrite(xml, name, value)
283     xml.find("//osm/relation").first[name] = value.to_s
284     xml
285   end
286
287   ##
288   # parse some xml
289   def xml_parse(xml)
290     parser = XML::Parser.string(xml)
291     parser.parse
292   end
293 end