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