]> git.openstreetmap.org Git - rails.git/blob - test/controllers/old_nodes_controller_test.rb
Merge remote-tracking branch 'upstream/pull/2061'
[rails.git] / test / controllers / old_nodes_controller_test.rb
1 require "test_helper"
2
3 class OldNodesControllerTest < ActionController::TestCase
4   #
5   # TODO: test history
6   #
7
8   ##
9   # test all routes which lead to this controller
10   def test_routes
11     assert_routing(
12       { :path => "/api/0.6/node/1/history", :method => :get },
13       { :controller => "old_nodes", :action => "history", :id => "1" }
14     )
15     assert_routing(
16       { :path => "/api/0.6/node/1/2", :method => :get },
17       { :controller => "old_nodes", :action => "version", :id => "1", :version => "2" }
18     )
19     assert_routing(
20       { :path => "/api/0.6/node/1/2/redact", :method => :post },
21       { :controller => "old_nodes", :action => "redact", :id => "1", :version => "2" }
22     )
23   end
24
25   ##
26   # test the version call by submitting several revisions of a new node
27   # to the API and ensuring that later calls to version return the
28   # matching versions of the object.
29   #
30   ##
31   # FIXME: Move this test to being an integration test since it spans multiple controllers
32   def test_version
33     private_user = create(:user, :data_public => false)
34     private_node = create(:node, :with_history, :version => 4, :changeset => create(:changeset, :user => private_user))
35     user = create(:user)
36     node = create(:node, :with_history, :version => 4, :changeset => create(:changeset, :user => user))
37     create_list(:node_tag, 2, :node => node)
38     # Ensure that the current tags are propagated to the history too
39     propagate_tags(node, node.old_nodes.last)
40
41     ## First try this with a non-public user
42     basic_authorization private_user.email, "test"
43
44     # setup a simple XML node
45     xml_doc = private_node.to_xml
46     xml_node = xml_doc.find("//osm/node").first
47     nodeid = private_node.id
48
49     # keep a hash of the versions => string, as we'll need something
50     # to test against later
51     versions = {}
52
53     # save a version for later checking
54     versions[xml_node["version"]] = xml_doc.to_s
55
56     # randomly move the node about
57     3.times do
58       # move the node somewhere else
59       xml_node["lat"] = precision(rand * 180 - 90).to_s
60       xml_node["lon"] = precision(rand * 360 - 180).to_s
61       with_controller(NodesController.new) do
62         content xml_doc
63         put :update, :params => { :id => nodeid }
64         assert_response :forbidden, "Should have rejected node update"
65         xml_node["version"] = @response.body.to_s
66       end
67       # save a version for later checking
68       versions[xml_node["version"]] = xml_doc.to_s
69     end
70
71     # add a bunch of random tags
72     3.times do
73       xml_tag = XML::Node.new("tag")
74       xml_tag["k"] = random_string
75       xml_tag["v"] = random_string
76       xml_node << xml_tag
77       with_controller(NodesController.new) do
78         content xml_doc
79         put :update, :params => { :id => nodeid }
80         assert_response :forbidden,
81                         "should have rejected node #{nodeid} (#{@response.body}) with forbidden"
82         xml_node["version"] = @response.body.to_s
83       end
84       # save a version for later checking
85       versions[xml_node["version"]] = xml_doc.to_s
86     end
87
88     # probably should check that they didn't get written to the database
89
90     ## Now do it with the public user
91     basic_authorization user.email, "test"
92
93     # setup a simple XML node
94
95     xml_doc = node.to_xml
96     xml_node = xml_doc.find("//osm/node").first
97     nodeid = node.id
98
99     # keep a hash of the versions => string, as we'll need something
100     # to test against later
101     versions = {}
102
103     # save a version for later checking
104     versions[xml_node["version"]] = xml_doc.to_s
105
106     # randomly move the node about
107     3.times do
108       # move the node somewhere else
109       xml_node["lat"] = precision(rand * 180 - 90).to_s
110       xml_node["lon"] = precision(rand * 360 - 180).to_s
111       with_controller(NodesController.new) do
112         content xml_doc
113         put :update, :params => { :id => nodeid }
114         assert_response :success
115         xml_node["version"] = @response.body.to_s
116       end
117       # save a version for later checking
118       versions[xml_node["version"]] = xml_doc.to_s
119     end
120
121     # add a bunch of random tags
122     3.times do
123       xml_tag = XML::Node.new("tag")
124       xml_tag["k"] = random_string
125       xml_tag["v"] = random_string
126       xml_node << xml_tag
127       with_controller(NodesController.new) do
128         content xml_doc
129         put :update, :params => { :id => nodeid }
130         assert_response :success,
131                         "couldn't update node #{nodeid} (#{@response.body})"
132         xml_node["version"] = @response.body.to_s
133       end
134       # save a version for later checking
135       versions[xml_node["version"]] = xml_doc.to_s
136     end
137
138     # check all the versions
139     versions.each_key do |key|
140       get :version, :params => { :id => nodeid, :version => key.to_i }
141
142       assert_response :success,
143                       "couldn't get version #{key.to_i} of node #{nodeid}"
144
145       check_node = Node.from_xml(versions[key])
146       api_node = Node.from_xml(@response.body.to_s)
147
148       assert_nodes_are_equal check_node, api_node
149     end
150   end
151
152   def test_not_found_version
153     check_not_found_id_version(70000, 312344)
154     check_not_found_id_version(-1, -13)
155     check_not_found_id_version(create(:node).id, 24354)
156     check_not_found_id_version(24356, create(:node).version)
157   end
158
159   def check_not_found_id_version(id, version)
160     get :version, :params => { :id => id, :version => version }
161     assert_response :not_found
162   rescue ActionController::UrlGenerationError => ex
163     assert_match(/No route matches/, ex.to_s)
164   end
165
166   ##
167   # Test that getting the current version is identical to picking
168   # that version with the version URI call.
169   def test_current_version
170     node = create(:node, :with_history)
171     used_node = create(:node, :with_history)
172     create(:way_node, :node => used_node)
173     node_used_by_relationship = create(:node, :with_history)
174     create(:relation_member, :member => node_used_by_relationship)
175     node_with_versions = create(:node, :with_history, :version => 4)
176
177     create(:node_tag, :node => node)
178     create(:node_tag, :node => used_node)
179     create(:node_tag, :node => node_used_by_relationship)
180     create(:node_tag, :node => node_with_versions)
181     propagate_tags(node, node.old_nodes.last)
182     propagate_tags(used_node, used_node.old_nodes.last)
183     propagate_tags(node_used_by_relationship, node_used_by_relationship.old_nodes.last)
184     propagate_tags(node_with_versions, node_with_versions.old_nodes.last)
185
186     check_current_version(node)
187     check_current_version(used_node)
188     check_current_version(node_used_by_relationship)
189     check_current_version(node_with_versions)
190   end
191
192   ##
193   # test the redaction of an old version of a node, while not being
194   # authorised.
195   def test_redact_node_unauthorised
196     node = create(:node, :with_history, :version => 4)
197     node_v3 = node.old_nodes.find_by(:version => 3)
198
199     do_redact_node(node_v3,
200                    create(:redaction))
201     assert_response :unauthorized, "should need to be authenticated to redact."
202   end
203
204   ##
205   # test the redaction of an old version of a node, while being
206   # authorised as a normal user.
207   def test_redact_node_normal_user
208     basic_authorization create(:user).email, "test"
209
210     node = create(:node, :with_history, :version => 4)
211     node_v3 = node.old_nodes.find_by(:version => 3)
212
213     do_redact_node(node_v3,
214                    create(:redaction))
215     assert_response :forbidden, "should need to be moderator to redact."
216   end
217
218   ##
219   # test that, even as moderator, the current version of a node
220   # can't be redacted.
221   def test_redact_node_current_version
222     basic_authorization create(:moderator_user).email, "test"
223
224     node = create(:node, :with_history, :version => 4)
225     node_v4 = node.old_nodes.find_by(:version => 4)
226
227     do_redact_node(node_v4,
228                    create(:redaction))
229     assert_response :bad_request, "shouldn't be OK to redact current version as moderator."
230   end
231
232   ##
233   # test that redacted nodes aren't visible, regardless of
234   # authorisation except as moderator...
235   def test_version_redacted
236     node = create(:node, :with_history, :version => 2)
237     node_v1 = node.old_nodes.find_by(:version => 1)
238     node_v1.redact!(create(:redaction))
239
240     get :version, :params => { :id => node_v1.node_id, :version => node_v1.version }
241     assert_response :forbidden, "Redacted node shouldn't be visible via the version API."
242
243     # not even to a logged-in user
244     basic_authorization create(:user).email, "test"
245     get :version, :params => { :id => node_v1.node_id, :version => node_v1.version }
246     assert_response :forbidden, "Redacted node shouldn't be visible via the version API, even when logged in."
247   end
248
249   ##
250   # test that redacted nodes aren't visible in the history
251   def test_history_redacted
252     node = create(:node, :with_history, :version => 2)
253     node_v1 = node.old_nodes.find_by(:version => 1)
254     node_v1.redact!(create(:redaction))
255
256     get :history, :params => { :id => node_v1.node_id }
257     assert_response :success, "Redaction shouldn't have stopped history working."
258     assert_select "osm node[id='#{node_v1.node_id}'][version='#{node_v1.version}']", 0, "redacted node #{node_v1.node_id} version #{node_v1.version} shouldn't be present in the history."
259
260     # not even to a logged-in user
261     basic_authorization create(:user).email, "test"
262     get :history, :params => { :id => node_v1.node_id }
263     assert_response :success, "Redaction shouldn't have stopped history working."
264     assert_select "osm node[id='#{node_v1.node_id}'][version='#{node_v1.version}']", 0, "redacted node #{node_v1.node_id} version #{node_v1.version} shouldn't be present in the history, even when logged in."
265   end
266
267   ##
268   # test the redaction of an old version of a node, while being
269   # authorised as a moderator.
270   def test_redact_node_moderator
271     node = create(:node, :with_history, :version => 4)
272     node_v3 = node.old_nodes.find_by(:version => 3)
273     basic_authorization create(:moderator_user).email, "test"
274
275     do_redact_node(node_v3, create(:redaction))
276     assert_response :success, "should be OK to redact old version as moderator."
277
278     # check moderator can still see the redacted data, when passing
279     # the appropriate flag
280     get :version, :params => { :id => node_v3.node_id, :version => node_v3.version }
281     assert_response :forbidden, "After redaction, node should be gone for moderator, when flag not passed."
282     get :version, :params => { :id => node_v3.node_id, :version => node_v3.version, :show_redactions => "true" }
283     assert_response :success, "After redaction, node should not be gone for moderator, when flag passed."
284
285     # and when accessed via history
286     get :history, :params => { :id => node_v3.node_id }
287     assert_response :success, "Redaction shouldn't have stopped history working."
288     assert_select "osm node[id='#{node_v3.node_id}'][version='#{node_v3.version}']", 0, "node #{node_v3.node_id} version #{node_v3.version} should not be present in the history for moderators when not passing flag."
289     get :history, :params => { :id => node_v3.node_id, :show_redactions => "true" }
290     assert_response :success, "Redaction shouldn't have stopped history working."
291     assert_select "osm node[id='#{node_v3.node_id}'][version='#{node_v3.version}']", 1, "node #{node_v3.node_id} version #{node_v3.version} should still be present in the history for moderators when passing flag."
292   end
293
294   # testing that if the moderator drops auth, he can't see the
295   # redacted stuff any more.
296   def test_redact_node_is_redacted
297     node = create(:node, :with_history, :version => 4)
298     node_v3 = node.old_nodes.find_by(:version => 3)
299     basic_authorization create(:moderator_user).email, "test"
300
301     do_redact_node(node_v3, create(:redaction))
302     assert_response :success, "should be OK to redact old version as moderator."
303
304     # re-auth as non-moderator
305     basic_authorization create(:user).email, "test"
306
307     # check can't see the redacted data
308     get :version, :params => { :id => node_v3.node_id, :version => node_v3.version }
309     assert_response :forbidden, "Redacted node shouldn't be visible via the version API."
310
311     # and when accessed via history
312     get :history, :params => { :id => node_v3.node_id }
313     assert_response :success, "Redaction shouldn't have stopped history working."
314     assert_select "osm node[id='#{node_v3.node_id}'][version='#{node_v3.version}']", 0, "redacted node #{node_v3.node_id} version #{node_v3.version} shouldn't be present in the history."
315   end
316
317   ##
318   # test the unredaction of an old version of a node, while not being
319   # authorised.
320   def test_unredact_node_unauthorised
321     node = create(:node, :with_history, :version => 2)
322     node_v1 = node.old_nodes.find_by(:version => 1)
323     node_v1.redact!(create(:redaction))
324
325     post :redact, :params => { :id => node_v1.node_id, :version => node_v1.version }
326     assert_response :unauthorized, "should need to be authenticated to unredact."
327   end
328
329   ##
330   # test the unredaction of an old version of a node, while being
331   # authorised as a normal user.
332   def test_unredact_node_normal_user
333     user = create(:user)
334     node = create(:node, :with_history, :version => 2)
335     node_v1 = node.old_nodes.find_by(:version => 1)
336     node_v1.redact!(create(:redaction))
337
338     basic_authorization user.email, "test"
339
340     post :redact, :params => { :id => node_v1.node_id, :version => node_v1.version }
341     assert_response :forbidden, "should need to be moderator to unredact."
342   end
343
344   ##
345   # test the unredaction of an old version of a node, while being
346   # authorised as a moderator.
347   def test_unredact_node_moderator
348     moderator_user = create(:moderator_user)
349     node = create(:node, :with_history, :version => 2)
350     node_v1 = node.old_nodes.find_by(:version => 1)
351     node_v1.redact!(create(:redaction))
352
353     basic_authorization moderator_user.email, "test"
354
355     post :redact, :params => { :id => node_v1.node_id, :version => node_v1.version }
356     assert_response :success, "should be OK to unredact old version as moderator."
357
358     # check moderator can now see the redacted data, when not
359     # passing the aspecial flag
360     get :version, :params => { :id => node_v1.node_id, :version => node_v1.version }
361     assert_response :success, "After unredaction, node should not be gone for moderator."
362
363     # and when accessed via history
364     get :history, :params => { :id => node_v1.node_id }
365     assert_response :success, "Unredaction shouldn't have stopped history working."
366     assert_select "osm node[id='#{node_v1.node_id}'][version='#{node_v1.version}']", 1, "node #{node_v1.node_id} version #{node_v1.version} should now be present in the history for moderators without passing flag."
367
368     basic_authorization create(:user).email, "test"
369
370     # check normal user can now see the redacted data
371     get :version, :params => { :id => node_v1.node_id, :version => node_v1.version }
372     assert_response :success, "After unredaction, node should be visible to normal users."
373
374     # and when accessed via history
375     get :history, :params => { :id => node_v1.node_id }
376     assert_response :success, "Unredaction shouldn't have stopped history working."
377     assert_select "osm node[id='#{node_v1.node_id}'][version='#{node_v1.version}']", 1, "node #{node_v1.node_id} version #{node_v1.version} should now be present in the history for normal users without passing flag."
378   end
379
380   private
381
382   def do_redact_node(node, redaction)
383     get :version, :params => { :id => node.node_id, :version => node.version }
384     assert_response :success, "should be able to get version #{node.version} of node #{node.node_id}."
385
386     # now redact it
387     post :redact, :params => { :id => node.node_id, :version => node.version, :redaction => redaction.id }
388   end
389
390   def check_current_version(node_id)
391     # get the current version of the node
392     current_node = with_controller(NodesController.new) do
393       get :read, :params => { :id => node_id }
394       assert_response :success, "cant get current node #{node_id}"
395       Node.from_xml(@response.body)
396     end
397     assert_not_nil current_node, "getting node #{node_id} returned nil"
398
399     # get the "old" version of the node from the old_node interface
400     get :version, :params => { :id => node_id, :version => current_node.version }
401     assert_response :success, "cant get old node #{node_id}, v#{current_node.version}"
402     old_node = Node.from_xml(@response.body)
403
404     # check the nodes are the same
405     assert_nodes_are_equal current_node, old_node
406   end
407
408   ##
409   # returns a 16 character long string with some nasty characters in it.
410   # this ought to stress-test the tag handling as well as the versioning.
411   def random_string
412     letters = [["!", '"', "$", "&", ";", "@"],
413                ("a".."z").to_a,
414                ("A".."Z").to_a,
415                ("0".."9").to_a].flatten
416     (1..16).map { |_i| letters[rand(letters.length)] }.join
417   end
418
419   ##
420   # truncate a floating point number to the scale that it is stored in
421   # the database. otherwise rounding errors can produce failing unit
422   # tests when they shouldn't.
423   def precision(f)
424     (f * GeoRecord::SCALE).round.to_f / GeoRecord::SCALE
425   end
426
427   def propagate_tags(node, old_node)
428     node.tags.each do |k, v|
429       create(:old_node_tag, :old_node => old_node, :k => k, :v => v)
430     end
431   end
432 end