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