]> git.openstreetmap.org Git - rails.git/blob - test/integration/relation_versions_test.rb
Add frozen_string_literal comments to ruby files
[rails.git] / test / integration / relation_versions_test.rb
1 # frozen_string_literal: true
2
3 require "test_helper"
4
5 class RelationVersionsTest < ActionDispatch::IntegrationTest
6   ##
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
10   # josm-dev.
11   def test_update_relation_tags
12     user = create(:user)
13     changeset = create(:changeset, :user => user)
14     relation = create(:relation)
15     create_list(:relation_tag, 4, :relation => relation)
16
17     auth_header = bearer_authorization_header user
18
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
23
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
31
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
35
36     # check the original one in the current_* table again
37     get api_relation_path(relation)
38     assert_tags_equal_response rel
39
40     # now check the version in the history
41     get api_relation_version_path(relation, new_version)
42     assert_tags_equal_response rel
43   end
44
45   ##
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
51     user = create(:user)
52     changeset = create(:changeset, :user => user)
53     relation = create(:relation)
54     create_list(:relation_tag, 4, :relation => relation)
55
56     auth_header = bearer_authorization_header user
57
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
62
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)
67     new_version = nil
68     with_controller(Api::ChangesetsController.new) do
69       doc = OSM::API.new.xml_doc
70       change = XML::Node.new "osmChange"
71       doc.root = change
72       modify = XML::Node.new "modify"
73       change << modify
74       modify << doc.import(rel.find("//osm/relation").first)
75
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
79     end
80
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
84
85     # check the original one in the current_* table again
86     get api_relation_path(relation)
87     assert_tags_equal_response rel
88
89     # now check the version in the history
90     get api_relation_version_path(relation, new_version)
91     assert_tags_equal_response rel
92   end
93
94   ##
95   # check that relations are ordered
96   def test_relation_member_ordering
97     user = create(:user)
98     changeset = create(:changeset, :user => user)
99     node1 = create(:node)
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)
104
105     auth_header = bearer_authorization_header user
106
107     doc_str = <<~OSM
108       <osm>
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'/>
114         </relation>
115       </osm>
116     OSM
117     doc = XML::Parser.string(doc_str).parse
118
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
122
123     # get it back and check the ordering
124     get api_relation_path(relation_id)
125     assert_members_equal_response doc
126
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"
130
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
140
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
145
146     # get it back again and check the ordering again
147     get api_relation_path(relation_id)
148     assert_members_equal_response doc
149
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"
153   end
154
155   ##
156   # check that relations can contain duplicate members
157   def test_relation_member_duplicates
158     private_user = create(:user, :data_public => false)
159     user = create(:user)
160     changeset = create(:changeset, :user => user)
161     node1 = create(:node)
162     node2 = create(:node)
163
164     doc_str = <<~OSM
165       <osm>
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'/>
171         </relation>
172       </osm>
173     OSM
174     doc = XML::Parser.string(doc_str).parse
175
176     ## First try with the private user
177     auth_header = bearer_authorization_header private_user
178
179     post api_relations_path, :params => doc.to_s, :headers => auth_header
180     assert_response :forbidden
181
182     ## Now try with the public user
183     auth_header = bearer_authorization_header user
184
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
188
189     # get it back and check the ordering
190     get api_relation_path(relation_id)
191     assert_members_equal_response doc
192
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"
196   end
197
198   ##
199   # test that the ordering of elements in the history is the same as in current.
200   def test_history_ordering
201     user = create(:user)
202     changeset = create(:changeset, :user => user)
203     node1 = create(:node)
204     node2 = create(:node)
205     node3 = create(:node)
206     node4 = create(:node)
207
208     doc_str = <<~OSM
209       <osm>
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'/>
215         </relation>
216       </osm>
217     OSM
218     doc = XML::Parser.string(doc_str).parse
219     auth_header = bearer_authorization_header user
220
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
224
225     # check the ordering in the current tables:
226     get api_relation_path(relation_id)
227     assert_members_equal_response doc
228
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"
232   end
233
234   private
235
236   ##
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)
242
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)
246
247     assert_equal rel_tags, response_tags, "Tags should be identical."
248   end
249
250   ##
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
256
257     doc_members = doc.find("//osm/relation/member").collect do |m|
258       [m["ref"].to_i, m["type"].to_sym, m["role"]]
259     end
260
261     new_members = new_doc.find("//osm/relation/member").collect do |m|
262       [m["ref"].to_i, m["type"].to_sym, m["role"]]
263     end
264
265     assert_equal doc_members, new_members, "members are not equal - ordering is wrong? (#{doc}, #{@response.body})"
266   end
267
268   ##
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|
272       [tag["k"], tag["v"]]
273     end
274   end
275
276   ##
277   # update the changeset_id of a node element
278   def update_changeset(xml, changeset_id)
279     xml_attr_rewrite(xml, "changeset", changeset_id)
280   end
281
282   ##
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
286     xml
287   end
288
289   ##
290   # parse some xml
291   def xml_parse(xml)
292     parser = XML::Parser.string(xml)
293     parser.parse
294   end
295 end