4 class OldNodesControllerTest < ActionController::TestCase
10 # test all routes which lead to this controller
13 { :path => "/api/0.6/node/1/history", :method => :get },
14 { :controller => "api/old_nodes", :action => "history", :id => "1", :format => "xml" }
17 { :path => "/api/0.6/node/1/2", :method => :get },
18 { :controller => "api/old_nodes", :action => "version", :id => "1", :version => "2", :format => "xml" }
21 { :path => "/api/0.6/node/1/2/redact", :method => :post },
22 { :controller => "api/old_nodes", :action => "redact", :id => "1", :version => "2" }
27 # test the version call by submitting several revisions of a new node
28 # to the API and ensuring that later calls to version return the
29 # matching versions of the object.
32 # FIXME: Move this test to being an integration test since it spans multiple controllers
34 private_user = create(:user, :data_public => false)
35 private_node = create(:node, :with_history, :version => 4, :changeset => create(:changeset, :user => private_user))
37 node = create(:node, :with_history, :version => 4, :changeset => create(:changeset, :user => user))
38 create_list(:node_tag, 2, :node => node)
39 # Ensure that the current tags are propagated to the history too
40 propagate_tags(node, node.old_nodes.last)
42 ## First try this with a non-public user
43 basic_authorization private_user.email, "test"
45 # setup a simple XML node
46 xml_doc = private_node.to_xml
47 xml_node = xml_doc.find("//osm/node").first
48 nodeid = private_node.id
50 # keep a hash of the versions => string, as we'll need something
51 # to test against later
54 # save a version for later checking
55 versions[xml_node["version"]] = xml_doc.to_s
57 # randomly move the node about
59 # move the node somewhere else
60 xml_node["lat"] = precision(rand * 180 - 90).to_s
61 xml_node["lon"] = precision(rand * 360 - 180).to_s
62 with_controller(NodesController.new) do
63 put :update, :params => { :id => nodeid }, :body => xml_doc.to_s
64 assert_response :forbidden, "Should have rejected node update"
65 xml_node["version"] = @response.body.to_s
67 # save a version for later checking
68 versions[xml_node["version"]] = xml_doc.to_s
71 # add a bunch of random tags
73 xml_tag = XML::Node.new("tag")
74 xml_tag["k"] = random_string
75 xml_tag["v"] = random_string
77 with_controller(NodesController.new) do
78 put :update, :params => { :id => nodeid }, :body => xml_doc.to_s
79 assert_response :forbidden,
80 "should have rejected node #{nodeid} (#{@response.body}) with forbidden"
81 xml_node["version"] = @response.body.to_s
83 # save a version for later checking
84 versions[xml_node["version"]] = xml_doc.to_s
87 # probably should check that they didn't get written to the database
89 ## Now do it with the public user
90 basic_authorization user.email, "test"
92 # setup a simple XML node
95 xml_node = xml_doc.find("//osm/node").first
98 # keep a hash of the versions => string, as we'll need something
99 # to test against later
102 # save a version for later checking
103 versions[xml_node["version"]] = xml_doc.to_s
105 # randomly move the node about
107 # move the node somewhere else
108 xml_node["lat"] = precision(rand * 180 - 90).to_s
109 xml_node["lon"] = precision(rand * 360 - 180).to_s
110 with_controller(NodesController.new) do
111 put :update, :params => { :id => nodeid }, :body => xml_doc.to_s
112 assert_response :success
113 xml_node["version"] = @response.body.to_s
115 # save a version for later checking
116 versions[xml_node["version"]] = xml_doc.to_s
119 # add a bunch of random tags
121 xml_tag = XML::Node.new("tag")
122 xml_tag["k"] = random_string
123 xml_tag["v"] = random_string
125 with_controller(NodesController.new) do
126 put :update, :params => { :id => nodeid }, :body => xml_doc.to_s
127 assert_response :success,
128 "couldn't update node #{nodeid} (#{@response.body})"
129 xml_node["version"] = @response.body.to_s
131 # save a version for later checking
132 versions[xml_node["version"]] = xml_doc.to_s
135 # check all the versions
136 versions.each_key do |key|
137 get :version, :params => { :id => nodeid, :version => key.to_i }, :format => :xml
139 assert_response :success,
140 "couldn't get version #{key.to_i} of node #{nodeid}"
142 check_node = Node.from_xml(versions[key])
143 api_node = Node.from_xml(@response.body.to_s)
145 assert_nodes_are_equal check_node, api_node
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(create(:node).id, 24354)
153 check_not_found_id_version(24356, create(:node).version)
156 def check_not_found_id_version(id, version)
157 get :version, :params => { :id => id, :version => version }, :format => :xml
158 assert_response :not_found
159 rescue ActionController::UrlGenerationError => e
160 assert_match(/No route matches/, e.to_s)
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 node = create(:node, :with_history)
168 used_node = create(:node, :with_history)
169 create(:way_node, :node => used_node)
170 node_used_by_relationship = create(:node, :with_history)
171 create(:relation_member, :member => node_used_by_relationship)
172 node_with_versions = create(:node, :with_history, :version => 4)
174 create(:node_tag, :node => node)
175 create(:node_tag, :node => used_node)
176 create(:node_tag, :node => node_used_by_relationship)
177 create(:node_tag, :node => node_with_versions)
178 propagate_tags(node, node.old_nodes.last)
179 propagate_tags(used_node, used_node.old_nodes.last)
180 propagate_tags(node_used_by_relationship, node_used_by_relationship.old_nodes.last)
181 propagate_tags(node_with_versions, node_with_versions.old_nodes.last)
183 check_current_version(node)
184 check_current_version(used_node)
185 check_current_version(node_used_by_relationship)
186 check_current_version(node_with_versions)
190 # test the redaction of an old version of a node, while not being
192 def test_redact_node_unauthorised
193 node = create(:node, :with_history, :version => 4)
194 node_v3 = node.old_nodes.find_by(:version => 3)
196 do_redact_node(node_v3,
198 assert_response :unauthorized, "should need to be authenticated to redact."
202 # test the redaction of an old version of a node, while being
203 # authorised as a normal user.
204 def test_redact_node_normal_user
205 basic_authorization create(:user).email, "test"
207 node = create(:node, :with_history, :version => 4)
208 node_v3 = node.old_nodes.find_by(:version => 3)
210 do_redact_node(node_v3,
212 assert_response :forbidden, "should need to be moderator to redact."
216 # test that, even as moderator, the current version of a node
218 def test_redact_node_current_version
219 basic_authorization create(:moderator_user).email, "test"
221 node = create(:node, :with_history, :version => 4)
222 node_v4 = node.old_nodes.find_by(:version => 4)
224 do_redact_node(node_v4,
226 assert_response :bad_request, "shouldn't be OK to redact current version as moderator."
230 # test that redacted nodes aren't visible, regardless of
231 # authorisation except as moderator...
232 def test_version_redacted
233 node = create(:node, :with_history, :version => 2)
234 node_v1 = node.old_nodes.find_by(:version => 1)
235 node_v1.redact!(create(:redaction))
237 get :version, :params => { :id => node_v1.node_id, :version => node_v1.version }, :format => :xml
238 assert_response :forbidden, "Redacted node shouldn't be visible via the version API."
240 # not even to a logged-in user
241 basic_authorization create(:user).email, "test"
242 get :version, :params => { :id => node_v1.node_id, :version => node_v1.version }, :format => :xml
243 assert_response :forbidden, "Redacted node shouldn't be visible via the version API, even when logged in."
247 # test that redacted nodes aren't visible in the history
248 def test_history_redacted
249 node = create(:node, :with_history, :version => 2)
250 node_v1 = node.old_nodes.find_by(:version => 1)
251 node_v1.redact!(create(:redaction))
253 get :history, :params => { :id => node_v1.node_id }, :format => :xml
254 assert_response :success, "Redaction shouldn't have stopped history working."
255 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."
257 # not even to a logged-in user
258 basic_authorization create(:user).email, "test"
259 get :history, :params => { :id => node_v1.node_id }, :format => :xml
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, even when logged in."
265 # test the redaction of an old version of a node, while being
266 # authorised as a moderator.
267 def test_redact_node_moderator
268 node = create(:node, :with_history, :version => 4)
269 node_v3 = node.old_nodes.find_by(:version => 3)
270 basic_authorization create(:moderator_user).email, "test"
272 do_redact_node(node_v3, create(:redaction))
273 assert_response :success, "should be OK to redact old version as moderator."
275 # check moderator can still see the redacted data, when passing
276 # the appropriate flag
277 get :version, :params => { :id => node_v3.node_id, :version => node_v3.version }, :format => :xml
278 assert_response :forbidden, "After redaction, node should be gone for moderator, when flag not passed."
279 get :version, :params => { :id => node_v3.node_id, :version => node_v3.version, :show_redactions => "true" }, :format => :xml
280 assert_response :success, "After redaction, node should not be gone for moderator, when flag passed."
282 # and when accessed via history
283 get :history, :params => { :id => node_v3.node_id }, :format => :xml
284 assert_response :success, "Redaction shouldn't have stopped history working."
285 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."
286 get :history, :params => { :id => node_v3.node_id, :show_redactions => "true" }, :format => :xml
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}']", 1, "node #{node_v3.node_id} version #{node_v3.version} should still be present in the history for moderators when passing flag."
291 # testing that if the moderator drops auth, he can't see the
292 # redacted stuff any more.
293 def test_redact_node_is_redacted
294 node = create(:node, :with_history, :version => 4)
295 node_v3 = node.old_nodes.find_by(:version => 3)
296 basic_authorization create(:moderator_user).email, "test"
298 do_redact_node(node_v3, create(:redaction))
299 assert_response :success, "should be OK to redact old version as moderator."
301 # re-auth as non-moderator
302 basic_authorization create(:user).email, "test"
304 # check can't see the redacted data
305 get :version, :params => { :id => node_v3.node_id, :version => node_v3.version }, :format => :xml
306 assert_response :forbidden, "Redacted node shouldn't be visible via the version API."
308 # and when accessed via history
309 get :history, :params => { :id => node_v3.node_id }, :format => :xml
310 assert_response :success, "Redaction shouldn't have stopped history working."
311 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 # test the unredaction of an old version of a node, while not being
317 def test_unredact_node_unauthorised
318 node = create(:node, :with_history, :version => 2)
319 node_v1 = node.old_nodes.find_by(:version => 1)
320 node_v1.redact!(create(:redaction))
322 post :redact, :params => { :id => node_v1.node_id, :version => node_v1.version }
323 assert_response :unauthorized, "should need to be authenticated to unredact."
327 # test the unredaction of an old version of a node, while being
328 # authorised as a normal user.
329 def test_unredact_node_normal_user
331 node = create(:node, :with_history, :version => 2)
332 node_v1 = node.old_nodes.find_by(:version => 1)
333 node_v1.redact!(create(:redaction))
335 basic_authorization user.email, "test"
337 post :redact, :params => { :id => node_v1.node_id, :version => node_v1.version }
338 assert_response :forbidden, "should need to be moderator to unredact."
342 # test the unredaction of an old version of a node, while being
343 # authorised as a moderator.
344 def test_unredact_node_moderator
345 moderator_user = create(:moderator_user)
346 node = create(:node, :with_history, :version => 2)
347 node_v1 = node.old_nodes.find_by(:version => 1)
348 node_v1.redact!(create(:redaction))
350 basic_authorization moderator_user.email, "test"
352 post :redact, :params => { :id => node_v1.node_id, :version => node_v1.version }
353 assert_response :success, "should be OK to unredact old version as moderator."
355 # check moderator can now see the redacted data, when not
356 # passing the aspecial flag
357 get :version, :params => { :id => node_v1.node_id, :version => node_v1.version }, :format => :xml
358 assert_response :success, "After unredaction, node should not be gone for moderator."
360 # and when accessed via history
361 get :history, :params => { :id => node_v1.node_id }, :format => :xml
362 assert_response :success, "Unredaction shouldn't have stopped history working."
363 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."
365 basic_authorization create(:user).email, "test"
367 # check normal user can now see the redacted data
368 get :version, :params => { :id => node_v1.node_id, :version => node_v1.version }, :format => :xml
369 assert_response :success, "After unredaction, node should be visible to normal users."
371 # and when accessed via history
372 get :history, :params => { :id => node_v1.node_id }, :format => :xml
373 assert_response :success, "Unredaction shouldn't have stopped history working."
374 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."
379 def do_redact_node(node, redaction)
380 get :version, :params => { :id => node.node_id, :version => node.version }, :format => :xml
381 assert_response :success, "should be able to get version #{node.version} of node #{node.node_id}."
384 post :redact, :params => { :id => node.node_id, :version => node.version, :redaction => redaction.id }
387 def check_current_version(node_id)
388 # get the current version of the node
389 current_node = with_controller(NodesController.new) do
390 get :show, :params => { :id => node_id }, :format => :xml
391 assert_response :success, "cant get current node #{node_id}"
392 Node.from_xml(@response.body)
394 assert_not_nil current_node, "getting node #{node_id} returned nil"
396 # get the "old" version of the node from the old_node interface
397 get :version, :params => { :id => node_id, :version => current_node.version }, :format => :xml
398 assert_response :success, "cant get old node #{node_id}, v#{current_node.version}"
399 old_node = Node.from_xml(@response.body)
401 # check the nodes are the same
402 assert_nodes_are_equal current_node, old_node
406 # returns a 16 character long string with some nasty characters in it.
407 # this ought to stress-test the tag handling as well as the versioning.
409 letters = [["!", '"', "$", "&", ";", "@"],
412 ("0".."9").to_a].flatten
413 (1..16).map { |_i| letters[rand(letters.length)] }.join
417 # truncate a floating point number to the scale that it is stored in
418 # the database. otherwise rounding errors can produce failing unit
419 # tests when they shouldn't.
421 (f * GeoRecord::SCALE).round.to_f / GeoRecord::SCALE
424 def propagate_tags(node, old_node)
425 node.tags.each do |k, v|
426 create(:old_node_tag, :old_node => old_node, :k => k, :v => v)