]> git.openstreetmap.org Git - rails.git/blob - test/controllers/api/nodes_controller_test.rb
Update number of created relations in changeset
[rails.git] / test / controllers / api / nodes_controller_test.rb
1 require "test_helper"
2 require_relative "elements_test_helper"
3
4 module Api
5   class NodesControllerTest < ActionDispatch::IntegrationTest
6     include ElementsTestHelper
7
8     ##
9     # test all routes which lead to this controller
10     def test_routes
11       assert_routing(
12         { :path => "/api/0.6/nodes", :method => :get },
13         { :controller => "api/nodes", :action => "index" }
14       )
15       assert_routing(
16         { :path => "/api/0.6/nodes.json", :method => :get },
17         { :controller => "api/nodes", :action => "index", :format => "json" }
18       )
19       assert_routing(
20         { :path => "/api/0.6/nodes", :method => :post },
21         { :controller => "api/nodes", :action => "create" }
22       )
23       assert_routing(
24         { :path => "/api/0.6/node/1", :method => :get },
25         { :controller => "api/nodes", :action => "show", :id => "1" }
26       )
27       assert_routing(
28         { :path => "/api/0.6/node/1.json", :method => :get },
29         { :controller => "api/nodes", :action => "show", :id => "1", :format => "json" }
30       )
31       assert_routing(
32         { :path => "/api/0.6/node/1", :method => :put },
33         { :controller => "api/nodes", :action => "update", :id => "1" }
34       )
35       assert_routing(
36         { :path => "/api/0.6/node/1", :method => :delete },
37         { :controller => "api/nodes", :action => "destroy", :id => "1" }
38       )
39
40       assert_recognizes(
41         { :controller => "api/nodes", :action => "create" },
42         { :path => "/api/0.6/node/create", :method => :put }
43       )
44     end
45
46     ##
47     # test fetching multiple nodes
48     def test_index
49       node1 = create(:node)
50       node2 = create(:node, :deleted)
51       node3 = create(:node)
52       node4 = create(:node, :with_history, :version => 2)
53       node5 = create(:node, :deleted, :with_history, :version => 2)
54
55       # check error when no parameter provided
56       get api_nodes_path
57       assert_response :bad_request
58
59       # check error when no parameter value provided
60       get api_nodes_path(:nodes => "")
61       assert_response :bad_request
62
63       # test a working call
64       get api_nodes_path(:nodes => "#{node1.id},#{node2.id},#{node3.id},#{node4.id},#{node5.id}")
65       assert_response :success
66       assert_select "osm" do
67         assert_select "node", :count => 5
68         assert_select "node[id='#{node1.id}'][visible='true']", :count => 1
69         assert_select "node[id='#{node2.id}'][visible='false']", :count => 1
70         assert_select "node[id='#{node3.id}'][visible='true']", :count => 1
71         assert_select "node[id='#{node4.id}'][visible='true']", :count => 1
72         assert_select "node[id='#{node5.id}'][visible='false']", :count => 1
73       end
74
75       # test a working call with json format
76       get api_nodes_path(:nodes => "#{node1.id},#{node2.id},#{node3.id},#{node4.id},#{node5.id}", :format => "json")
77
78       js = ActiveSupport::JSON.decode(@response.body)
79       assert_not_nil js
80       assert_equal 5, js["elements"].count
81       assert_equal 5, (js["elements"].count { |a| a["type"] == "node" })
82       assert_equal 1, (js["elements"].count { |a| a["id"] == node1.id && a["visible"].nil? })
83       assert_equal 1, (js["elements"].count { |a| a["id"] == node2.id && a["visible"] == false })
84       assert_equal 1, (js["elements"].count { |a| a["id"] == node3.id && a["visible"].nil? })
85       assert_equal 1, (js["elements"].count { |a| a["id"] == node4.id && a["visible"].nil? })
86       assert_equal 1, (js["elements"].count { |a| a["id"] == node5.id && a["visible"] == false })
87
88       # check error when a non-existent node is included
89       get api_nodes_path(:nodes => "#{node1.id},#{node2.id},#{node3.id},#{node4.id},#{node5.id},0")
90       assert_response :not_found
91     end
92
93     def test_create_when_unauthorized
94       with_unchanging_request do |_headers, changeset|
95         osm = "<osm><node lat='0' lon='0' changeset='#{changeset.id}'/></osm>"
96
97         post api_nodes_path, :params => osm
98
99         assert_response :unauthorized
100       end
101     end
102
103     def test_create_by_private_user
104       with_unchanging_request([:data_public => false]) do |headers, changeset|
105         osm = "<osm><node lat='0' lon='0' changeset='#{changeset.id}'/></osm>"
106
107         post api_nodes_path, :params => osm, :headers => headers
108
109         assert_require_public_data "node create did not return forbidden status"
110       end
111     end
112
113     def test_create
114       with_request do |headers, changeset|
115         lat = rand(-50..50) + rand
116         lon = rand(-50..50) + rand
117
118         assert_difference "Node.count", 1 do
119           osm = "<osm><node lat='#{lat}' lon='#{lon}' changeset='#{changeset.id}'/></osm>"
120
121           post api_nodes_path, :params => osm, :headers => headers
122
123           assert_response :success, "node upload did not return success status"
124         end
125
126         created_node_id = @response.body
127         node = Node.find(created_node_id)
128         assert_in_delta lat * 10000000, node.latitude, 1, "saved node does not match requested latitude"
129         assert_in_delta lon * 10000000, node.longitude, 1, "saved node does not match requested longitude"
130         assert_equal changeset.id, node.changeset_id, "saved node does not belong to changeset that it was created in"
131         assert node.visible, "saved node is not visible"
132
133         changeset.reload
134         assert_equal 1, changeset.num_changes
135         assert_predicate changeset, :num_type_changes_in_sync?
136         assert_equal 1, changeset.num_created_nodes
137       end
138     end
139
140     def test_create_with_invalid_osm_structure
141       with_unchanging_request do |headers|
142         osm = "<create/>"
143
144         post api_nodes_path, :params => osm, :headers => headers
145
146         assert_response :bad_request, "node upload did not return bad_request status"
147         assert_equal "Cannot parse valid node from xml string <create/>. XML doesn't contain an osm/node element.", @response.body
148       end
149     end
150
151     def test_create_without_lat
152       with_unchanging_request do |headers, changeset|
153         osm = "<osm><node lon='3.23' changeset='#{changeset.id}'/></osm>"
154
155         post api_nodes_path, :params => osm, :headers => headers
156
157         assert_response :bad_request, "node upload did not return bad_request status"
158         assert_equal "Cannot parse valid node from xml string <node lon=\"3.23\" changeset=\"#{changeset.id}\"/>. lat missing", @response.body
159       end
160     end
161
162     def test_create_without_lon
163       with_unchanging_request do |headers, changeset|
164         osm = "<osm><node lat='3.434' changeset='#{changeset.id}'/></osm>"
165
166         post api_nodes_path, :params => osm, :headers => headers
167
168         assert_response :bad_request, "node upload did not return bad_request status"
169         assert_equal "Cannot parse valid node from xml string <node lat=\"3.434\" changeset=\"#{changeset.id}\"/>. lon missing", @response.body
170       end
171     end
172
173     def test_create_with_non_numeric_lat
174       with_unchanging_request do |headers, changeset|
175         osm = "<osm><node lat='abc' lon='3.23' changeset='#{changeset.id}'/></osm>"
176
177         post api_nodes_path, :params => osm, :headers => headers
178
179         assert_response :bad_request, "node upload did not return bad_request status"
180         assert_equal "Cannot parse valid node from xml string <node lat=\"abc\" lon=\"3.23\" changeset=\"#{changeset.id}\"/>. lat not a number", @response.body
181       end
182     end
183
184     def test_create_with_non_numeric_lon
185       with_unchanging_request do |headers, changeset|
186         osm = "<osm><node lat='3.434' lon='abc' changeset='#{changeset.id}'/></osm>"
187
188         post api_nodes_path, :params => osm, :headers => headers
189
190         assert_response :bad_request, "node upload did not return bad_request status"
191         assert_equal "Cannot parse valid node from xml string <node lat=\"3.434\" lon=\"abc\" changeset=\"#{changeset.id}\"/>. lon not a number", @response.body
192       end
193     end
194
195     def test_create_with_tag_too_long
196       with_unchanging_request do |headers, changeset|
197         osm = "<osm><node lat='3.434' lon='3.23' changeset='#{changeset.id}'><tag k='foo' v='#{'x' * 256}'/></node></osm>"
198
199         post api_nodes_path, :params => osm, :headers => headers
200
201         assert_response :bad_request, "node upload did not return bad_request status"
202         assert_match(/ v: is too long \(maximum is 255 characters\) /, @response.body)
203       end
204     end
205
206     ##
207     # try and put something into a string that the API might
208     # use unquoted and therefore allow code injection
209     def test_create_with_string_injection_by_private_user
210       with_unchanging_request([:data_public => false]) do |headers, changeset|
211         osm = <<~OSM
212           <osm>
213             <node lat='0' lon='0' changeset='#{changeset.id}'>
214               <tag k='\#{@user.inspect}' v='0'/>
215             </node>
216           </osm>
217         OSM
218
219         post api_nodes_path, :params => osm, :headers => headers
220
221         assert_require_public_data "Shouldn't be able to create with non-public user"
222       end
223     end
224
225     ##
226     # try and put something into a string that the API might
227     # use unquoted and therefore allow code injection
228     def test_create_with_string_injection
229       with_request do |headers, changeset|
230         assert_difference "Node.count", 1 do
231           osm = <<~OSM
232             <osm>
233               <node lat='0' lon='0' changeset='#{changeset.id}'>
234                 <tag k='\#{@user.inspect}' v='0'/>
235               </node>
236             </osm>
237           OSM
238
239           post api_nodes_path, :params => osm, :headers => headers
240
241           assert_response :success
242         end
243
244         created_node_id = @response.body
245         db_node = Node.find(created_node_id)
246
247         get api_node_path(created_node_id)
248
249         assert_response :success
250
251         api_node = Node.from_xml(@response.body)
252         assert_not_nil api_node, "downloaded node is nil, but shouldn't be"
253         assert_equal db_node.tags, api_node.tags, "tags are corrupted"
254         assert_includes api_node.tags, "\#{@user.inspect}"
255       end
256     end
257
258     def test_show_not_found
259       get api_node_path(0)
260       assert_response :not_found
261     end
262
263     def test_show_deleted
264       get api_node_path(create(:node, :deleted))
265       assert_response :gone
266     end
267
268     def test_show
269       node = create(:node, :timestamp => "2021-02-03T00:00:00Z")
270
271       get api_node_path(node)
272
273       assert_response :success
274       assert_not_nil @response.header["Last-Modified"]
275       assert_equal "2021-02-03T00:00:00Z", Time.parse(@response.header["Last-Modified"]).utc.xmlschema
276     end
277
278     def test_show_lat_lon_decimal_format
279       node = create(:node, :latitude => (0.00004 * OldNode::SCALE).to_i, :longitude => (0.00008 * OldNode::SCALE).to_i)
280
281       get api_node_path(node)
282
283       assert_match(/lat="0.0000400"/, response.body)
284       assert_match(/lon="0.0000800"/, response.body)
285     end
286
287     def test_destroy_when_unauthorized
288       with_unchanging(:node) do |node|
289         delete api_node_path(node)
290
291         assert_response :unauthorized
292       end
293     end
294
295     def test_destroy_in_closed_changeset_by_private_user
296       with_unchanging(:node) do |node|
297         with_unchanging_request([:data_public => false], [:closed]) do |headers, changeset|
298           osm_xml = xml_for_node node
299           osm_xml = update_changeset osm_xml, changeset.id
300
301           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
302
303           assert_require_public_data "non-public user shouldn't be able to delete node"
304         end
305       end
306     end
307
308     def test_destroy_in_missing_changeset_by_private_user
309       with_unchanging(:node) do |node|
310         with_unchanging_request([:data_public => false]) do |headers|
311           osm_xml = xml_for_node node
312           osm_xml = update_changeset osm_xml, 0
313
314           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
315
316           assert_require_public_data "shouldn't be able to delete node, when user's data is private"
317         end
318       end
319     end
320
321     def test_destroy_by_private_user
322       with_unchanging(:node) do |node|
323         with_unchanging_request([:data_public => false]) do |headers, changeset|
324           osm_xml = xml_for_node node
325           osm_xml = update_changeset osm_xml, changeset.id
326
327           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
328
329           assert_require_public_data "shouldn't be able to delete node when user's data isn't public'"
330         end
331       end
332     end
333
334     def test_destroy_deleted_node_by_private_user
335       with_unchanging(:node, :deleted) do |node|
336         with_unchanging_request([:data_public => false]) do |headers, changeset|
337           osm_xml = "<osm><node id='#{node.id}' changeset='#{changeset.id}' version='1' lat='0' lon='0'/></osm>"
338
339           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
340
341           assert_require_public_data
342         end
343       end
344     end
345
346     def test_destroy_missing_node_by_private_user
347       with_unchanging_request([:data_public => false]) do |headers|
348         delete api_node_path(0), :headers => headers
349
350         assert_require_public_data
351       end
352     end
353
354     def test_destroy_node_in_way_by_private_user
355       with_unchanging(:node) do |node|
356         create(:way_node, :node => node)
357
358         with_unchanging_request([:data_public => false]) do |headers, changeset|
359           osm_xml = xml_for_node node
360           osm_xml = update_changeset osm_xml, changeset.id
361
362           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
363
364           assert_require_public_data "shouldn't be able to delete a node used in a way (#{@response.body})"
365         end
366       end
367     end
368
369     def test_destroy_node_in_relation_by_private_user
370       with_unchanging(:node) do |node|
371         create(:relation_member, :member => node)
372
373         with_unchanging_request([:data_public => false]) do |headers, changeset|
374           osm_xml = xml_for_node node
375           osm_xml = update_changeset osm_xml, changeset.id
376
377           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
378
379           assert_require_public_data "shouldn't be able to delete a node used in a relation (#{@response.body})"
380         end
381       end
382     end
383
384     def test_destroy_in_closed_changeset
385       with_unchanging(:node) do |node|
386         with_unchanging_request([], [:closed]) do |headers, changeset|
387           osm_xml = xml_for_node node
388           osm_xml = update_changeset osm_xml, changeset.id
389
390           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
391
392           assert_response :conflict
393         end
394       end
395     end
396
397     def test_destroy_in_missing_changeset
398       with_unchanging(:node) do |node|
399         with_unchanging_request do |headers|
400           osm_xml = xml_for_node node
401           osm_xml = update_changeset osm_xml, 0
402
403           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
404
405           assert_response :conflict
406         end
407       end
408     end
409
410     def test_destroy_different_node
411       with_unchanging(:node) do |node|
412         with_unchanging(:node) do |other_node|
413           with_unchanging_request do |headers, changeset|
414             osm_xml = xml_for_node other_node
415             osm_xml = update_changeset osm_xml, changeset.id
416
417             delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
418
419             assert_response :bad_request, "should not be able to delete a node with a different ID from the XML"
420           end
421         end
422       end
423     end
424
425     def test_destroy_invalid_osm_structure
426       with_unchanging(:node) do |node|
427         with_unchanging_request do |headers|
428           osm = "<delete/>"
429
430           delete api_node_path(node), :params => osm, :headers => headers
431
432           assert_response :bad_request, "should not be able to delete a node without a valid XML payload"
433         end
434       end
435     end
436
437     def test_destroy
438       with_request do |headers, changeset|
439         node = create(:node)
440         osm_xml = xml_for_node node
441         osm_xml = update_changeset osm_xml, changeset.id
442
443         delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
444
445         assert_response :success
446
447         response_node_version = @response.body.to_i
448         assert_operator response_node_version, :>, node.version, "delete request should return a new version number for node"
449         node.reload
450         assert_not_predicate node, :visible?
451         assert_equal response_node_version, node.version
452       end
453     end
454
455     def test_destroy_twice
456       user = create(:user)
457       node = create(:node, :changeset => create(:changeset, :user => user))
458       osm_xml = xml_for_node node
459
460       delete api_node_path(node), :params => osm_xml.to_s, :headers => bearer_authorization_header(user)
461
462       assert_response :success
463
464       delete api_node_path(node), :params => osm_xml.to_s, :headers => bearer_authorization_header(user)
465
466       assert_response :gone
467     end
468
469     def test_destroy_deleted_node
470       with_unchanging(:node, :deleted) do |node|
471         with_unchanging_request do |headers, changeset|
472           osm = "<osm><node id='#{node.id}' changeset='#{changeset.id}' version='1' lat='0' lon='0'/></osm>"
473
474           delete api_node_path(node), :params => osm, :headers => headers
475
476           assert_response :gone
477         end
478       end
479     end
480
481     def test_destroy_missing_node
482       with_unchanging_request do |headers|
483         delete api_node_path(0), :headers => headers
484
485         assert_response :not_found
486       end
487     end
488
489     def test_destroy_node_in_ways
490       with_unchanging(:node) do |node|
491         way_node = create(:way_node, :node => node)
492         way_node2 = create(:way_node, :node => node)
493
494         with_unchanging_request do |headers, changeset|
495           osm_xml = xml_for_node node
496           osm_xml = update_changeset osm_xml, changeset.id
497
498           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
499
500           assert_response :precondition_failed, "shouldn't be able to delete a node used in a way (#{@response.body})"
501           assert_equal "Precondition failed: Node #{node.id} is still used by ways #{way_node.way.id},#{way_node2.way.id}.", @response.body
502         end
503       end
504     end
505
506     def test_destroy_node_in_relations
507       with_unchanging(:node) do |node|
508         relation_member = create(:relation_member, :member => node)
509         relation_member2 = create(:relation_member, :member => node)
510
511         with_unchanging_request do |headers, changeset|
512           osm_xml = xml_for_node node
513           osm_xml = update_changeset osm_xml, changeset.id
514
515           delete api_node_path(node), :params => osm_xml.to_s, :headers => headers
516
517           assert_response :precondition_failed, "shouldn't be able to delete a node used in a relation (#{@response.body})"
518           assert_equal "Precondition failed: Node #{node.id} is still used by relations #{relation_member.relation.id},#{relation_member2.relation.id}.", @response.body
519         end
520       end
521     end
522
523     def test_update_when_unauthorized
524       with_unchanging(:node) do |node|
525         osm_xml = xml_for_node node
526
527         put api_node_path(node), :params => osm_xml.to_s
528
529         assert_response :unauthorized
530       end
531     end
532
533     def test_update_in_changeset_of_other_user_by_private_user
534       with_unchanging(:node) do |node|
535         other_user = create(:user)
536
537         with_unchanging_request([:data_public => false], [:user => other_user]) do |headers, changeset|
538           osm_xml = xml_for_node node
539           osm_xml = update_changeset osm_xml, changeset.id
540
541           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
542
543           assert_require_public_data "update with other user's changeset should be forbidden when data isn't public"
544         end
545       end
546     end
547
548     def test_update_in_closed_changeset_by_private_user
549       with_unchanging(:node) do |node|
550         with_unchanging_request([:data_public => false], [:closed]) do |headers, changeset|
551           osm_xml = xml_for_node node
552           osm_xml = update_changeset osm_xml, changeset.id
553
554           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
555
556           assert_require_public_data "update with closed changeset should be forbidden, when data isn't public"
557         end
558       end
559     end
560
561     def test_update_in_missing_changeset_by_private_user
562       with_unchanging(:node) do |node|
563         with_unchanging_request([:data_public => false]) do |headers|
564           osm_xml = xml_for_node node
565           osm_xml = update_changeset osm_xml, 0
566
567           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
568
569           assert_require_public_data "update with changeset=0 should be forbidden, when data isn't public"
570         end
571       end
572     end
573
574     def test_update_with_lat_too_large_by_private_user
575       check_update_with_invalid_attr_value "lat", 91.0, :data_public => false
576     end
577
578     def test_update_with_lat_too_small_by_private_user
579       check_update_with_invalid_attr_value "lat", -91.0, :data_public => false
580     end
581
582     def test_update_with_lon_too_large_by_private_user
583       check_update_with_invalid_attr_value "lon", 181.0, :data_public => false
584     end
585
586     def test_update_with_lon_too_small_by_private_user
587       check_update_with_invalid_attr_value "lon", -181.0, :data_public => false
588     end
589
590     def test_update_by_private_user
591       with_unchanging(:node) do |node|
592         with_unchanging_request([:data_public => false]) do |headers, changeset|
593           osm_xml = xml_for_node node
594           osm_xml = update_changeset osm_xml, changeset.id
595
596           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
597
598           assert_require_public_data "should have failed with a forbidden when data isn't public"
599         end
600       end
601     end
602
603     def test_update_in_changeset_of_other_user
604       with_unchanging(:node) do |node|
605         other_user = create(:user)
606
607         with_unchanging_request([], [:user => other_user]) do |headers, changeset|
608           osm_xml = xml_for_node node
609           osm_xml = update_changeset osm_xml, changeset.id
610
611           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
612
613           assert_response :conflict, "update with other user's changeset should be rejected"
614         end
615       end
616     end
617
618     def test_update_in_closed_changeset
619       with_unchanging(:node) do |node|
620         with_unchanging_request([], [:closed]) do |headers, changeset|
621           osm_xml = xml_for_node node
622           osm_xml = update_changeset osm_xml, changeset.id
623
624           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
625
626           assert_response :conflict, "update with closed changeset should be rejected"
627         end
628       end
629     end
630
631     def test_update_in_missing_changeset
632       with_unchanging(:node) do |node|
633         with_unchanging_request do |headers|
634           osm_xml = xml_for_node node
635           osm_xml = update_changeset osm_xml, 0
636
637           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
638
639           assert_response :conflict, "update with changeset=0 should be rejected"
640         end
641       end
642     end
643
644     def test_update_with_lat_too_large
645       check_update_with_invalid_attr_value "lat", 91.0
646     end
647
648     def test_update_with_lat_too_small
649       check_update_with_invalid_attr_value "lat", -91.0
650     end
651
652     def test_update_with_lon_too_large
653       check_update_with_invalid_attr_value "lon", 181.0
654     end
655
656     def test_update_with_lon_too_small
657       check_update_with_invalid_attr_value "lon", -181.0
658     end
659
660     def test_update_with_version_behind
661       with_unchanging(:node, :version => 2) do |node|
662         with_unchanging_request do |headers, changeset|
663           osm_xml = xml_for_node node
664           osm_xml = xml_attr_rewrite osm_xml, "version", node.version - 1
665           osm_xml = update_changeset osm_xml, changeset.id
666
667           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
668
669           assert_response :conflict, "should have failed on old version number"
670         end
671       end
672     end
673
674     def test_update_with_version_ahead
675       with_unchanging(:node, :version => 2) do |node|
676         with_unchanging_request do |headers, changeset|
677           osm_xml = xml_for_node node
678           osm_xml = xml_attr_rewrite osm_xml, "version", node.version + 1
679           osm_xml = update_changeset osm_xml, changeset.id
680
681           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
682
683           assert_response :conflict, "should have failed on skipped version number"
684         end
685       end
686     end
687
688     def test_update_with_invalid_version
689       with_unchanging(:node) do |node|
690         with_unchanging_request do |headers, changeset|
691           osm_xml = xml_for_node node
692           osm_xml = xml_attr_rewrite osm_xml, "version", "p1r4t3s!"
693           osm_xml = update_changeset osm_xml, changeset.id
694
695           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
696
697           assert_response :conflict, "should not be able to put 'p1r4at3s!' in the version field"
698         end
699       end
700     end
701
702     def test_update_other_node
703       with_unchanging(:node) do |node|
704         with_unchanging(:node) do |other_node|
705           with_unchanging_request do |headers, changeset|
706             osm_xml = xml_for_node other_node
707             osm_xml = update_changeset osm_xml, changeset.id
708
709             put api_node_path(node), :params => osm_xml.to_s, :headers => headers
710
711             assert_response :bad_request, "should not be able to update a node with a different ID from the XML"
712           end
713         end
714       end
715     end
716
717     def test_update_with_invalid_osm_structure
718       with_unchanging(:node) do |node|
719         with_unchanging_request do |headers|
720           osm = "<update/>"
721
722           put api_node_path(node), :params => osm, :headers => headers
723
724           assert_response :bad_request, "should not be able to update a node with non-OSM XML doc."
725         end
726       end
727     end
728
729     def test_update
730       with_request do |headers, changeset|
731         node = create(:node)
732         osm_xml = xml_for_node node
733         osm_xml = update_changeset osm_xml, changeset.id
734
735         put api_node_path(node), :params => osm_xml.to_s, :headers => headers
736
737         assert_response :success, "a valid update request failed"
738       end
739     end
740
741     def test_update_with_duplicate_tags
742       with_unchanging(:node) do |node|
743         create(:node_tag, :node => node, :k => "key_to_duplicate", :v => "value_to_duplicate")
744
745         with_unchanging_request do |headers, changeset|
746           tag_xml = XML::Node.new("tag")
747           tag_xml["k"] = "key_to_duplicate"
748           tag_xml["v"] = "value_to_duplicate"
749
750           osm_xml = xml_for_node node
751           osm_xml.find("//osm/node").first << tag_xml
752           osm_xml = update_changeset osm_xml, changeset.id
753
754           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
755
756           assert_response :bad_request, "adding duplicate tags to a node should fail with 'bad request'"
757           assert_equal "Element node/#{node.id} has duplicate tags with key key_to_duplicate", @response.body
758         end
759       end
760     end
761
762     ##
763     # test initial rate limit
764     def test_initial_rate_limit
765       # create a user
766       user = create(:user)
767
768       # create a changeset that puts us near the initial rate limit
769       changeset = create(:changeset, :user => user,
770                                      :created_at => Time.now.utc - 5.minutes,
771                                      :num_changes => Settings.initial_changes_per_hour - 1)
772
773       # create authentication header
774       auth_header = bearer_authorization_header user
775
776       # try creating a node
777       xml = "<osm><node lat='0' lon='0' changeset='#{changeset.id}'/></osm>"
778       post api_nodes_path, :params => xml, :headers => auth_header
779       assert_response :success, "node create did not return success status"
780
781       # get the id of the node we created
782       nodeid = @response.body
783
784       # try updating the node, which should be rate limited
785       xml = "<osm><node id='#{nodeid}' version='1' lat='1' lon='1' changeset='#{changeset.id}'/></osm>"
786       put api_node_path(nodeid), :params => xml, :headers => auth_header
787       assert_response :too_many_requests, "node update did not hit rate limit"
788
789       # try deleting the node, which should be rate limited
790       xml = "<osm><node id='#{nodeid}' version='2' lat='1' lon='1' changeset='#{changeset.id}'/></osm>"
791       delete api_node_path(nodeid), :params => xml, :headers => auth_header
792       assert_response :too_many_requests, "node delete did not hit rate limit"
793
794       # try creating a node, which should be rate limited
795       xml = "<osm><node lat='0' lon='0' changeset='#{changeset.id}'/></osm>"
796       post api_nodes_path, :params => xml, :headers => auth_header
797       assert_response :too_many_requests, "node create did not hit rate limit"
798     end
799
800     ##
801     # test maximum rate limit
802     def test_maximum_rate_limit
803       # create a user
804       user = create(:user)
805
806       # create a changeset to establish our initial edit time
807       changeset = create(:changeset, :user => user,
808                                      :created_at => Time.now.utc - 28.days)
809
810       # create changeset to put us near the maximum rate limit
811       total_changes = Settings.max_changes_per_hour - 1
812       while total_changes.positive?
813         changes = [total_changes, Changeset::MAX_ELEMENTS].min
814         changeset = create(:changeset, :user => user,
815                                        :created_at => Time.now.utc - 5.minutes,
816                                        :num_changes => changes)
817         total_changes -= changes
818       end
819
820       # create authentication header
821       auth_header = bearer_authorization_header user
822
823       # try creating a node
824       xml = "<osm><node lat='0' lon='0' changeset='#{changeset.id}'/></osm>"
825       post api_nodes_path, :params => xml, :headers => auth_header
826       assert_response :success, "node create did not return success status"
827
828       # get the id of the node we created
829       nodeid = @response.body
830
831       # try updating the node, which should be rate limited
832       xml = "<osm><node id='#{nodeid}' version='1' lat='1' lon='1' changeset='#{changeset.id}'/></osm>"
833       put api_node_path(nodeid), :params => xml, :headers => auth_header
834       assert_response :too_many_requests, "node update did not hit rate limit"
835
836       # try deleting the node, which should be rate limited
837       xml = "<osm><node id='#{nodeid}' version='2' lat='1' lon='1' changeset='#{changeset.id}'/></osm>"
838       delete api_node_path(nodeid), :params => xml, :headers => auth_header
839       assert_response :too_many_requests, "node delete did not hit rate limit"
840
841       # try creating a node, which should be rate limited
842       xml = "<osm><node lat='0' lon='0' changeset='#{changeset.id}'/></osm>"
843       post api_nodes_path, :params => xml, :headers => auth_header
844       assert_response :too_many_requests, "node create did not hit rate limit"
845     end
846
847     private
848
849     def check_update_with_invalid_attr_value(name, value, data_public: true)
850       with_unchanging(:node) do |node|
851         with_unchanging_request([:data_public => data_public]) do |headers, changeset|
852           osm_xml = xml_for_node node
853           osm_xml = xml_attr_rewrite osm_xml, name, value
854           osm_xml = update_changeset osm_xml, changeset.id
855
856           put api_node_path(node), :params => osm_xml.to_s, :headers => headers
857
858           if data_public
859             assert_response :bad_request, "node at #{name}=#{value} should be rejected"
860           else
861             assert_require_public_data "node at #{name}=#{value} should be forbidden, when data isn't public"
862           end
863         end
864       end
865     end
866
867     def affected_models
868       [Node, NodeTag,
869        OldNode, OldNodeTag]
870     end
871
872     ##
873     # update an attribute in the node element
874     def xml_attr_rewrite(xml, name, value)
875       xml.find("//osm/node").first[name] = value.to_s
876       xml
877     end
878   end
879 end