source: subversion/sites/rails_port/test/functional/node_controller_test.rb @ 14769

Last change on this file since 14769 was 14769, checked in by Shaun McDonald, 10 years ago

Make node update work with the new require data public to edit policy. Added convenience testing method for the require data public. Add 2 new fixtures that are owned by the public user.

File size: 13.4 KB
Line 
1require File.dirname(__FILE__) + '/../test_helper'
2
3class NodeControllerTest < ActionController::TestCase
4  api_fixtures
5
6  def test_create
7    # cannot read password from fixture as it is stored as MD5 digest
8    basic_authorization(users(:normal_user).email, "test")
9   
10    # create a node with random lat/lon
11    lat = rand(100)-50 + rand
12    lon = rand(100)-50 + rand
13    # normal user has a changeset open, so we'll use that.
14    changeset = changesets(:normal_user_first_change)
15    # create a minimal xml file
16    content("<osm><node lat='#{lat}' lon='#{lon}' changeset='#{changeset.id}'/></osm>")
17    put :create
18    # hope for success
19    assert_response :success, "node upload did not return success status"
20
21    # read id of created node and search for it
22    nodeid = @response.body
23    checknode = Node.find(nodeid)
24    assert_not_nil checknode, "uploaded node not found in data base after upload"
25    # compare values
26    assert_in_delta lat * 10000000, checknode.latitude, 1, "saved node does not match requested latitude"
27    assert_in_delta lon * 10000000, checknode.longitude, 1, "saved node does not match requested longitude"
28    assert_equal changesets(:normal_user_first_change).id, checknode.changeset_id, "saved node does not belong to changeset that it was created in"
29    assert_equal true, checknode.visible, "saved node is not visible"
30  end
31
32  def test_create_invalid_xml
33    # Initial setup
34    basic_authorization(users(:normal_user).email, "test")
35    # normal user has a changeset open, so we'll use that.
36    changeset = changesets(:normal_user_first_change)
37    lat = 3.434
38    lon = 3.23
39   
40    # test that the upload is rejected when no lat is supplied
41    # create a minimal xml file
42    content("<osm><node lon='#{lon}' changeset='#{changeset.id}'/></osm>")
43    put :create
44    # hope for success
45    assert_response :bad_request, "node upload did not return bad_request status"
46    assert_equal 'Cannot parse valid node from xml string <node lon="3.23" changeset="1"/>. lat missing', @response.body
47
48    # test that the upload is rejected when no lon is supplied
49    # create a minimal xml file
50    content("<osm><node lat='#{lat}' changeset='#{changeset.id}'/></osm>")
51    put :create
52    # hope for success
53    assert_response :bad_request, "node upload did not return bad_request status"
54    assert_equal 'Cannot parse valid node from xml string <node lat="3.434" changeset="1"/>. lon missing', @response.body
55
56  end
57
58  def test_read
59    # check that a visible node is returned properly
60    get :read, :id => current_nodes(:visible_node).id
61    assert_response :success
62
63    # check that an invisible node is not returned
64    get :read, :id => current_nodes(:invisible_node).id
65    assert_response :gone
66
67    # check chat a non-existent node is not returned
68    get :read, :id => 0
69    assert_response :not_found
70  end
71
72  # this tests deletion restrictions - basic deletion is tested in the unit
73  # tests for node!
74  def test_delete
75    # first try to delete node without auth
76    delete :delete, :id => current_nodes(:visible_node).id
77    assert_response :unauthorized
78
79    # now set auth
80    basic_authorization(users(:normal_user).email, "test"); 
81
82    # try to delete with an invalid (closed) changeset
83    content update_changeset(current_nodes(:visible_node).to_xml,
84                             changesets(:normal_user_closed_change).id)
85    delete :delete, :id => current_nodes(:visible_node).id
86    assert_response :conflict
87
88    # try to delete with an invalid (non-existent) changeset
89    content update_changeset(current_nodes(:visible_node).to_xml,0)
90    delete :delete, :id => current_nodes(:visible_node).id
91    assert_response :conflict
92
93    # valid delete now takes a payload
94    content(nodes(:visible_node).to_xml)
95    delete :delete, :id => current_nodes(:visible_node).id
96    assert_response :success
97
98    # valid delete should return the new version number, which should
99    # be greater than the old version number
100    assert @response.body.to_i > current_nodes(:visible_node).version,
101       "delete request should return a new version number for node"
102
103    # this won't work since the node is already deleted
104    content(nodes(:invisible_node).to_xml)
105    delete :delete, :id => current_nodes(:invisible_node).id
106    assert_response :gone
107
108    # this won't work since the node never existed
109    delete :delete, :id => 0
110    assert_response :not_found
111
112    ## these test whether nodes which are in-use can be deleted:
113    # in a way...
114    content(nodes(:used_node_1).to_xml)
115    delete :delete, :id => current_nodes(:used_node_1).id
116    assert_response :precondition_failed,
117       "shouldn't be able to delete a node used in a way (#{@response.body})"
118
119    # in a relation...
120    content(nodes(:node_used_by_relationship).to_xml)
121    delete :delete, :id => current_nodes(:node_used_by_relationship).id
122    assert_response :precondition_failed,
123       "shouldn't be able to delete a node used in a relation (#{@response.body})"
124  end
125
126  ##
127  # tests whether the API works and prevents incorrect use while trying
128  # to update nodes.
129  def test_update
130    ## First test with no user credentials
131    # try and update a node without authorisation
132    # first try to delete node without auth
133    content current_nodes(:visible_node).to_xml
134    put :update, :id => current_nodes(:visible_node).id
135    assert_response :unauthorized
136   
137   
138   
139    ## Second test with the private user
140   
141    # setup auth
142    basic_authorization(users(:normal_user).email, "test")
143
144    ## trying to break changesets
145
146    # try and update in someone else's changeset
147    content update_changeset(current_nodes(:visible_node).to_xml,
148                             changesets(:public_user_first_change).id)
149    put :update, :id => current_nodes(:visible_node).id
150    assert_require_public_data "update with other user's changeset should be forbidden when date isn't public"
151
152    # try and update in a closed changeset
153    content update_changeset(current_nodes(:visible_node).to_xml,
154                             changesets(:normal_user_closed_change).id)
155    put :update, :id => current_nodes(:visible_node).id
156    assert_require_public_data "update with closed changeset should be forbidden, when data isn't public"
157
158    # try and update in a non-existant changeset
159    content update_changeset(current_nodes(:visible_node).to_xml, 0)
160    put :update, :id => current_nodes(:visible_node).id
161    assert_require_public_data("update with changeset=0 should be forbidden, when data isn't public")
162
163    ## try and submit invalid updates
164    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lat', 91.0);
165    put :update, :id => current_nodes(:visible_node).id
166    assert_require_public_data "node at lat=91 should be forbidden, when data isn't public"
167
168    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lat', -91.0);
169    put :update, :id => current_nodes(:visible_node).id
170    assert_require_public_data "node at lat=-91 should be forbidden, when data isn't public"
171   
172    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lon', 181.0);
173    put :update, :id => current_nodes(:visible_node).id
174    assert_require_public_data "node at lon=181 should be forbidden, when data isn't public"
175
176    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lon', -181.0);
177    put :update, :id => current_nodes(:visible_node).id
178    assert_require_public_data "node at lon=-181 should be forbidden, when data isn't public"
179   
180    ## finally, produce a good request which should work
181    content current_nodes(:visible_node).to_xml
182    put :update, :id => current_nodes(:visible_node).id
183    assert_require_public_data "should have failed with a forbidden when data isn't public"
184
185   
186   
187   
188    ## Finally test with the public user
189   
190    # try and update a node without authorisation
191    # first try to delete node without auth
192    content current_nodes(:visible_node).to_xml
193    put :update, :id => current_nodes(:visible_node).id
194    assert_response :forbidden
195   
196    # setup auth
197    basic_authorization(users(:public_user).email, "test")
198
199    ## trying to break changesets
200
201    # try and update in someone else's changeset
202    content update_changeset(current_nodes(:visible_node).to_xml,
203                              changesets(:normal_user_first_change).id)
204    put :update, :id => current_nodes(:visible_node).id
205    assert_response :conflict, "update with other user's changeset should be rejected"
206
207    # try and update in a closed changeset
208    content update_changeset(current_nodes(:visible_node).to_xml,
209                             changesets(:normal_user_closed_change).id)
210    put :update, :id => current_nodes(:visible_node).id
211    assert_response :conflict, "update with closed changeset should be rejected"
212
213    # try and update in a non-existant changeset
214    content update_changeset(current_nodes(:visible_node).to_xml, 0)
215    put :update, :id => current_nodes(:visible_node).id
216    assert_response :conflict, "update with changeset=0 should be rejected"
217
218    ## try and submit invalid updates
219    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lat', 91.0);
220    put :update, :id => current_nodes(:visible_node).id
221    assert_response :bad_request, "node at lat=91 should be rejected"
222
223    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lat', -91.0);
224    put :update, :id => current_nodes(:visible_node).id
225    assert_response :bad_request, "node at lat=-91 should be rejected"
226   
227    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lon', 181.0);
228    put :update, :id => current_nodes(:visible_node).id
229    assert_response :bad_request, "node at lon=181 should be rejected"
230
231    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 'lon', -181.0);
232    put :update, :id => current_nodes(:visible_node).id
233    assert_response :bad_request, "node at lon=-181 should be rejected"
234
235    ## next, attack the versioning
236    current_node_version = current_nodes(:visible_node).version
237
238    # try and submit a version behind
239    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 
240                             'version', current_node_version - 1);
241    put :update, :id => current_nodes(:visible_node).id
242    assert_response :conflict, "should have failed on old version number"
243   
244    # try and submit a version ahead
245    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 
246                             'version', current_node_version + 1);
247    put :update, :id => current_nodes(:visible_node).id
248    assert_response :conflict, "should have failed on skipped version number"
249
250    # try and submit total crap in the version field
251    content xml_attr_rewrite(current_nodes(:visible_node).to_xml, 
252                             'version', 'p1r4t3s!');
253    put :update, :id => current_nodes(:visible_node).id
254    assert_response :conflict, 
255       "should not be able to put 'p1r4at3s!' in the version field"
256   
257    ## finally, produce a good request which should work
258    content current_nodes(:public_visible_node).to_xml
259    put :update, :id => current_nodes(:public_visible_node).id
260    assert_response :success, "a valid update request failed"
261  end
262
263  ##
264  # test adding tags to a node
265  def test_duplicate_tags
266    # setup auth
267    basic_authorization(users(:normal_user).email, "test")
268
269    # add an identical tag to the node
270    tag_xml = XML::Node.new("tag")
271    tag_xml['k'] = current_node_tags(:t1).k
272    tag_xml['v'] = current_node_tags(:t1).v
273
274    # add the tag into the existing xml
275    node_xml = current_nodes(:visible_node).to_xml
276    node_xml.find("//osm/node").first << tag_xml
277
278    # try and upload it
279    content node_xml
280    put :update, :id => current_nodes(:visible_node).id
281    assert_response :bad_request, 
282      "adding duplicate tags to a node should fail with 'bad request'"
283    assert_equal "Element node/#{current_nodes(:visible_node).id} has duplicate tags with key #{current_node_tags(:t1).k}.", @response.body
284  end
285
286  # test whether string injection is possible
287  def test_string_injection
288    basic_authorization(users(:normal_user).email, "test")
289    changeset_id = changesets(:normal_user_first_change).id
290
291    # try and put something into a string that the API might
292    # use unquoted and therefore allow code injection...
293    content "<osm><node lat='0' lon='0' changeset='#{changeset_id}'>" +
294      '<tag k="#{@user.inspect}" v="0"/>' +
295      '</node></osm>'
296    put :create
297    assert_response :success
298    nodeid = @response.body
299
300    # find the node in the database
301    checknode = Node.find(nodeid)
302    assert_not_nil checknode, "node not found in data base after upload"
303   
304    # and grab it using the api
305    get :read, :id => nodeid
306    assert_response :success
307    apinode = Node.from_xml(@response.body)
308    assert_not_nil apinode, "downloaded node is nil, but shouldn't be"
309   
310    # check the tags are not corrupted
311    assert_equal checknode.tags, apinode.tags
312    assert apinode.tags.include?('#{@user.inspect}')
313  end
314
315  def basic_authorization(user, pass)
316    @request.env["HTTP_AUTHORIZATION"] = "Basic %s" % Base64.encode64("#{user}:#{pass}")
317  end
318
319  def content(c)
320    @request.env["RAW_POST_DATA"] = c.to_s
321  end
322
323  ##
324  # update the changeset_id of a node element
325  def update_changeset(xml, changeset_id)
326    xml_attr_rewrite(xml, 'changeset', changeset_id)
327  end
328
329  ##
330  # update an attribute in the node element
331  def xml_attr_rewrite(xml, name, value)
332    xml.find("//osm/node").first[name] = value.to_s
333    return xml
334  end
335
336  ##
337  # parse some xml
338  def xml_parse(xml)
339    parser = XML::Parser.string(xml)
340    parser.parse
341  end
342end
Note: See TracBrowser for help on using the repository browser.