]> git.openstreetmap.org Git - rails.git/blob - test/controllers/api/relations_controller_test.rb
Merge remote-tracking branch 'upstream/pull/6185'
[rails.git] / test / controllers / api / relations_controller_test.rb
1 require "test_helper"
2 require_relative "elements_test_helper"
3
4 module Api
5   class RelationsControllerTest < 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/relations", :method => :get },
13         { :controller => "api/relations", :action => "index" }
14       )
15       assert_routing(
16         { :path => "/api/0.6/relations.json", :method => :get },
17         { :controller => "api/relations", :action => "index", :format => "json" }
18       )
19       assert_routing(
20         { :path => "/api/0.6/relations", :method => :post },
21         { :controller => "api/relations", :action => "create" }
22       )
23       assert_routing(
24         { :path => "/api/0.6/relation/1", :method => :get },
25         { :controller => "api/relations", :action => "show", :id => "1" }
26       )
27       assert_routing(
28         { :path => "/api/0.6/relation/1.json", :method => :get },
29         { :controller => "api/relations", :action => "show", :id => "1", :format => "json" }
30       )
31       assert_routing(
32         { :path => "/api/0.6/relation/1/full", :method => :get },
33         { :controller => "api/relations", :action => "show", :full => true, :id => "1" }
34       )
35       assert_routing(
36         { :path => "/api/0.6/relation/1/full.json", :method => :get },
37         { :controller => "api/relations", :action => "show", :full => true, :id => "1", :format => "json" }
38       )
39       assert_routing(
40         { :path => "/api/0.6/relation/1", :method => :put },
41         { :controller => "api/relations", :action => "update", :id => "1" }
42       )
43       assert_routing(
44         { :path => "/api/0.6/relation/1", :method => :delete },
45         { :controller => "api/relations", :action => "destroy", :id => "1" }
46       )
47
48       assert_recognizes(
49         { :controller => "api/relations", :action => "create" },
50         { :path => "/api/0.6/relation/create", :method => :put }
51       )
52     end
53
54     ##
55     # test fetching multiple relations
56     def test_index
57       relation1 = create(:relation)
58       relation2 = create(:relation, :deleted)
59       relation3 = create(:relation, :with_history, :version => 2)
60       relation4 = create(:relation, :with_history, :version => 2)
61       relation4.old_relations.find_by(:version => 1).redact!(create(:redaction))
62
63       # check error when no parameter provided
64       get api_relations_path
65       assert_response :bad_request
66
67       # check error when no parameter value provided
68       get api_relations_path(:relations => "")
69       assert_response :bad_request
70
71       # test a working call
72       get api_relations_path(:relations => "#{relation1.id},#{relation2.id},#{relation3.id},#{relation4.id}")
73       assert_response :success
74       assert_select "osm" do
75         assert_select "relation", :count => 4
76         assert_select "relation[id='#{relation1.id}'][visible='true']", :count => 1
77         assert_select "relation[id='#{relation2.id}'][visible='false']", :count => 1
78         assert_select "relation[id='#{relation3.id}'][visible='true']", :count => 1
79         assert_select "relation[id='#{relation4.id}'][visible='true']", :count => 1
80       end
81
82       # test a working call with json format
83       get api_relations_path(:relations => "#{relation1.id},#{relation2.id},#{relation3.id},#{relation4.id}", :format => "json")
84
85       js = ActiveSupport::JSON.decode(@response.body)
86       assert_not_nil js
87       assert_equal 4, js["elements"].count
88       assert_equal 4, (js["elements"].count { |a| a["type"] == "relation" })
89       assert_equal 1, (js["elements"].count { |a| a["id"] == relation1.id && a["visible"].nil? })
90       assert_equal 1, (js["elements"].count { |a| a["id"] == relation2.id && a["visible"] == false })
91       assert_equal 1, (js["elements"].count { |a| a["id"] == relation3.id && a["visible"].nil? })
92       assert_equal 1, (js["elements"].count { |a| a["id"] == relation4.id && a["visible"].nil? })
93
94       # check error when a non-existent relation is included
95       get api_relations_path(:relations => "#{relation1.id},#{relation2.id},#{relation3.id},#{relation4.id},0")
96       assert_response :not_found
97     end
98
99     # -------------------------------------
100     # Test showing relations.
101     # -------------------------------------
102
103     def test_show_not_found
104       get api_relation_path(0)
105       assert_response :not_found
106     end
107
108     def test_show_deleted
109       get api_relation_path(create(:relation, :deleted))
110       assert_response :gone
111     end
112
113     def test_show
114       relation = create(:relation, :timestamp => "2021-02-03T00:00:00Z")
115       node = create(:node, :timestamp => "2021-04-05T00:00:00Z")
116       create(:relation_member, :relation => relation, :member => node)
117
118       get api_relation_path(relation)
119
120       assert_response :success
121       assert_not_nil @response.header["Last-Modified"]
122       assert_equal "2021-02-03T00:00:00Z", Time.parse(@response.header["Last-Modified"]).utc.xmlschema
123       assert_dom "node", :count => 0
124       assert_dom "relation", :count => 1 do
125         assert_dom "> @id", :text => relation.id.to_s
126       end
127     end
128
129     def test_full_not_found
130       get api_relation_path(999999, :full => true)
131       assert_response :not_found
132     end
133
134     def test_full_deleted
135       get api_relation_path(create(:relation, :deleted), :full => true)
136       assert_response :gone
137     end
138
139     def test_full_empty
140       relation = create(:relation)
141
142       get api_relation_path(relation, :full => true)
143
144       assert_response :success
145       assert_dom "relation", :count => 1 do
146         assert_dom "> @id", :text => relation.id.to_s
147       end
148     end
149
150     def test_full_with_node_member
151       relation = create(:relation)
152       node = create(:node)
153       create(:relation_member, :relation => relation, :member => node)
154
155       get api_relation_path(relation, :full => true)
156
157       assert_response :success
158       assert_dom "node", :count => 1 do
159         assert_dom "> @id", :text => node.id.to_s
160       end
161       assert_dom "relation", :count => 1 do
162         assert_dom "> @id", :text => relation.id.to_s
163       end
164     end
165
166     def test_full_with_way_member
167       relation = create(:relation)
168       way = create(:way_with_nodes)
169       create(:relation_member, :relation => relation, :member => way)
170
171       get api_relation_path(relation, :full => true)
172
173       assert_response :success
174       assert_dom "node", :count => 1 do
175         assert_dom "> @id", :text => way.nodes[0].id.to_s
176       end
177       assert_dom "way", :count => 1 do
178         assert_dom "> @id", :text => way.id.to_s
179       end
180       assert_dom "relation", :count => 1 do
181         assert_dom "> @id", :text => relation.id.to_s
182       end
183     end
184
185     def test_full_with_node_member_json
186       relation = create(:relation)
187       node = create(:node)
188       create(:relation_member, :relation => relation, :member => node)
189
190       get api_relation_path(relation, :full => true, :format => "json")
191
192       assert_response :success
193       js = ActiveSupport::JSON.decode(@response.body)
194       assert_not_nil js
195       assert_equal 2, js["elements"].count
196
197       js_relations = js["elements"].filter { |e| e["type"] == "relation" }
198       assert_equal 1, js_relations.count
199       assert_equal relation.id, js_relations[0]["id"]
200       assert_equal 1, js_relations[0]["members"].count
201       assert_equal "node", js_relations[0]["members"][0]["type"]
202       assert_equal node.id, js_relations[0]["members"][0]["ref"]
203
204       js_nodes = js["elements"].filter { |e| e["type"] == "node" }
205       assert_equal 1, js_nodes.count
206       assert_equal node.id, js_nodes[0]["id"]
207     end
208
209     # -------------------------------------
210     # Test creating relations.
211     # -------------------------------------
212
213     def test_create_without_members_by_private_user
214       with_unchanging_request([:data_public => false]) do |headers, changeset|
215         osm = <<~OSM
216           <osm>
217             <relation changeset='#{changeset.id}'>
218               <tag k='test' v='yes' />
219             </relation>
220           </osm>
221         OSM
222
223         post api_relations_path, :params => osm, :headers => headers
224
225         assert_response :forbidden, "relation upload should have failed with forbidden"
226       end
227     end
228
229     def test_create_with_node_member_with_role_by_private_user
230       node = create(:node)
231
232       with_unchanging_request([:data_public => false]) do |headers, changeset|
233         osm = <<~OSM
234           <osm>
235             <relation changeset='#{changeset.id}'>
236               <member ref='#{node.id}' type='node' role='some'/>
237               <tag k='test' v='yes' />
238             </relation>
239           </osm>
240         OSM
241
242         post api_relations_path, :params => osm, :headers => headers
243
244         assert_response :forbidden, "relation upload did not return forbidden status"
245       end
246     end
247
248     def test_create_with_node_member_without_role_by_private_user
249       node = create(:node)
250
251       with_unchanging_request([:data_public => false]) do |headers, changeset|
252         osm = <<~OSM
253           <osm>
254             <relation changeset='#{changeset.id}'>
255               <member ref='#{node.id}' type='node'/>
256               <tag k='test' v='yes' />
257             </relation>
258           </osm>
259         OSM
260
261         post api_relations_path, :params => osm, :headers => headers
262
263         assert_response :forbidden, "relation upload did not return forbidden status"
264       end
265     end
266
267     def test_create_with_node_and_way_members_by_private_user
268       node = create(:node)
269       way = create(:way_with_nodes, :nodes_count => 2)
270
271       with_unchanging_request([:data_public => false]) do |headers, changeset|
272         osm = <<~OSM
273           <osm>
274             <relation changeset='#{changeset.id}'>
275               <member type='node' ref='#{node.id}' role='some'/>
276               <member type='way' ref='#{way.id}' role='other'/>
277               <tag k='test' v='yes' />
278             </relation>
279           </osm>
280         OSM
281
282         post api_relations_path, :params => osm, :headers => headers
283
284         assert_response :forbidden, "relation upload did not return success status"
285       end
286     end
287
288     def test_create_without_members
289       with_request do |headers, changeset|
290         assert_difference "Relation.count" => 1,
291                           "RelationMember.count" => 0 do
292           osm = <<~OSM
293             <osm>
294               <relation changeset='#{changeset.id}'>
295                 <tag k='test' v='yes' />
296               </relation>
297             </osm>
298           OSM
299
300           post api_relations_path, :params => osm, :headers => headers
301
302           assert_response :success, "relation upload did not return success status"
303         end
304
305         created_relation_id = @response.body
306         relation = Relation.find(created_relation_id)
307         assert_empty relation.members
308         assert_equal({ "test" => "yes" }, relation.tags)
309         assert_equal changeset.id, relation.changeset_id, "saved relation does not belong in the changeset it was assigned to"
310         assert relation.visible, "saved relation is not visible"
311       end
312     end
313
314     def test_create_with_node_member_with_role
315       node = create(:node)
316
317       with_request do |headers, changeset|
318         assert_difference "Relation.count" => 1,
319                           "RelationMember.count" => 1 do
320           osm = <<~OSM
321             <osm>
322               <relation changeset='#{changeset.id}'>
323                 <member ref='#{node.id}' type='node' role='some'/>
324                 <tag k='test' v='yes' />
325               </relation>
326             </osm>
327           OSM
328
329           post api_relations_path, :params => osm, :headers => headers
330
331           assert_response :success, "relation upload did not return success status"
332         end
333
334         created_relation_id = @response.body
335         relation = Relation.find(created_relation_id)
336         assert_equal [["Node", node.id, "some"]], relation.members
337         assert_equal({ "test" => "yes" }, relation.tags)
338         assert_equal changeset.id, relation.changeset_id, "saved relation does not belong in the changeset it was assigned to"
339         assert relation.visible, "saved relation is not visible"
340       end
341     end
342
343     def test_create_with_node_member_without_role
344       node = create(:node)
345
346       with_request do |headers, changeset|
347         assert_difference "Relation.count" => 1,
348                           "RelationMember.count" => 1 do
349           osm = <<~OSM
350             <osm>
351               <relation changeset='#{changeset.id}'>
352                 <member ref='#{node.id}' type='node'/>
353                 <tag k='test' v='yes' />
354               </relation>
355             </osm>
356           OSM
357
358           post api_relations_path, :params => osm, :headers => headers
359
360           assert_response :success, "relation upload did not return success status"
361         end
362
363         created_relation_id = @response.body
364         relation = Relation.find(created_relation_id)
365         assert_equal [["Node", node.id, ""]], relation.members
366         assert_equal({ "test" => "yes" }, relation.tags)
367         assert_equal changeset.id, relation.changeset_id, "saved relation does not belong in the changeset it was assigned to"
368         assert relation.visible, "saved relation is not visible"
369       end
370     end
371
372     def test_create_with_node_and_way_members
373       node = create(:node)
374       way = create(:way_with_nodes, :nodes_count => 2)
375
376       with_request do |headers, changeset|
377         assert_difference "Relation.count" => 1,
378                           "RelationMember.count" => 2 do
379           osm = <<~OSM
380             <osm>
381               <relation changeset='#{changeset.id}'>
382                 <member type='node' ref='#{node.id}' role='some'/>
383                 <member type='way' ref='#{way.id}' role='other'/>
384                 <tag k='test' v='yes' />
385               </relation>
386             </osm>
387           OSM
388
389           post api_relations_path, :params => osm, :headers => headers
390
391           assert_response :success, "relation upload did not return success status"
392         end
393
394         created_relation_id = @response.body
395         relation = Relation.find(created_relation_id)
396         assert_equal [["Node", node.id, "some"],
397                       ["Way", way.id, "other"]], relation.members
398         assert_equal({ "test" => "yes" }, relation.tags)
399         assert_equal changeset.id, relation.changeset_id, "saved relation does not belong in the changeset it was assigned to"
400         assert relation.visible, "saved relation is not visible"
401       end
402     end
403
404     def test_create_with_missing_node_member
405       with_unchanging_request do |headers, changeset|
406         osm = <<~OSM
407           <osm>
408             <relation changeset='#{changeset.id}'>
409               <member type='node' ref='0'/>
410             </relation>
411           </osm>
412         OSM
413
414         post api_relations_path, :params => osm, :headers => headers
415
416         assert_response :precondition_failed, "relation upload with invalid node did not return 'precondition failed'"
417         assert_equal "Precondition failed: Relation with id  cannot be saved due to Node with id 0", @response.body
418       end
419     end
420
421     def test_create_with_invalid_member_type
422       node = create(:node)
423
424       with_unchanging_request do |headers, changeset|
425         osm = <<~OSM
426           <osm>
427             <relation changeset='#{changeset.id}'>
428               <member type='type' ref='#{node.id}' role=''/>
429             </relation>
430           </osm>
431         OSM
432
433         post api_relations_path, :params => osm, :headers => headers
434
435         assert_response :bad_request
436         assert_match(/Cannot parse valid relation from xml string/, @response.body)
437         assert_match(/The type is not allowed only, /, @response.body)
438       end
439     end
440
441     def test_create_and_show
442       user = create(:user)
443       changeset = create(:changeset, :user => user)
444
445       osm = <<~OSM
446         <osm>
447           <relation changeset='#{changeset.id}'/>
448         </osm>
449       OSM
450
451       post api_relations_path, :params => osm, :headers => bearer_authorization_header(user)
452
453       assert_response :success, "relation upload did not return success status"
454
455       created_relation_id = @response.body
456
457       get api_relation_path(created_relation_id)
458
459       assert_response :success
460     end
461
462     # ------------------------------------
463     # Test updating relations
464     # ------------------------------------
465
466     def test_update
467       relation = create(:relation)
468
469       with_request do |headers, changeset|
470         osm_xml = xml_for_relation relation
471         osm_xml = update_changeset osm_xml, changeset.id
472
473         put api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
474
475         assert_response :success
476
477         relation.reload
478         assert_equal 2, relation.version
479
480         changeset.reload
481         assert_equal 1, changeset.num_changes
482       end
483     end
484
485     def test_update_other_relation
486       with_unchanging(:relation) do |relation|
487         with_unchanging(:relation) do |other_relation|
488           with_unchanging_request do |headers, changeset|
489             osm_xml = xml_for_relation other_relation
490             osm_xml = update_changeset osm_xml, changeset.id
491
492             put api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
493
494             assert_response :bad_request
495           end
496         end
497       end
498     end
499
500     # -------------------------------------
501     # Test deleting relations.
502     # -------------------------------------
503
504     def test_destroy_when_unauthorized
505       with_unchanging(:relation) do |relation|
506         delete api_relation_path(relation)
507
508         assert_response :unauthorized
509       end
510     end
511
512     def test_destroy_without_payload_by_private_user
513       with_unchanging(:relation) do |relation|
514         with_unchanging_request([:data_public => false]) do |headers|
515           delete api_relation_path(relation), :headers => headers
516
517           assert_response :forbidden
518         end
519       end
520     end
521
522     def test_destroy_without_changeset_id_by_private_user
523       with_unchanging(:relation) do |relation|
524         with_unchanging_request([:data_public => false]) do |headers|
525           osm = "<osm><relation id='#{relation.id}' version='#{relation.version}'/></osm>"
526
527           delete api_relation_path(relation), :params => osm, :headers => headers
528
529           assert_response :forbidden
530         end
531       end
532     end
533
534     def test_destroy_in_closed_changeset_by_private_user
535       with_unchanging(:relation) do |relation|
536         with_unchanging_request([:data_public => false], [:closed]) do |headers, changeset|
537           osm_xml = xml_for_relation relation
538           osm_xml = update_changeset osm_xml, changeset.id
539
540           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
541
542           assert_response :forbidden
543         end
544       end
545     end
546
547     def test_destroy_in_missing_changeset_by_private_user
548       with_unchanging(:relation) do |relation|
549         with_unchanging_request([:data_public => false]) do |headers|
550           osm_xml = xml_for_relation relation
551           osm_xml = update_changeset osm_xml, 0
552
553           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
554
555           assert_response :forbidden
556         end
557       end
558     end
559
560     def test_destroy_relation_used_by_other_relation_by_private_user
561       with_unchanging(:relation) do |relation|
562         create(:relation_member, :member => relation)
563
564         with_unchanging_request([:data_public => false]) do |headers, changeset|
565           osm_xml = xml_for_relation relation
566           osm_xml = update_changeset osm_xml, changeset.id
567
568           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
569
570           assert_response :forbidden
571         end
572       end
573     end
574
575     def test_destroy_by_private_user
576       with_unchanging(:relation) do |relation|
577         with_unchanging_request([:data_public => false]) do |headers, changeset|
578           osm_xml = xml_for_relation relation
579           osm_xml = update_changeset osm_xml, changeset.id
580
581           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
582
583           assert_response :forbidden
584         end
585       end
586     end
587
588     def test_destroy_deleted_relation_by_private_user
589       with_unchanging(:relation, :deleted) do |relation|
590         with_unchanging_request([:data_public => false]) do |headers, changeset|
591           osm_xml = xml_for_relation relation
592           osm_xml = update_changeset osm_xml, changeset.id
593
594           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
595
596           assert_response :forbidden
597         end
598       end
599     end
600
601     def test_destroy_missing_relation_by_private_user
602       with_unchanging_request([:data_public => false]) do |headers|
603         delete api_relation_path(0), :headers => headers
604
605         assert_response :forbidden
606       end
607     end
608
609     def test_destroy_without_payload
610       with_unchanging(:relation) do |relation|
611         with_unchanging_request do |headers|
612           delete api_relation_path(relation), :headers => headers
613
614           assert_response :bad_request
615         end
616       end
617     end
618
619     def test_destroy_without_changeset_id
620       with_unchanging(:relation) do |relation|
621         with_unchanging_request do |headers|
622           osm = "<osm><relation id='#{relation.id}' version='#{relation.version}'/></osm>"
623
624           delete api_relation_path(relation), :params => osm, :headers => headers
625
626           assert_response :bad_request
627           assert_match(/Changeset id is missing/, @response.body)
628         end
629       end
630     end
631
632     def test_destroy_in_closed_changeset
633       with_unchanging(:relation) do |relation|
634         with_unchanging_request([], [:closed]) do |headers, changeset|
635           osm_xml = xml_for_relation relation
636           osm_xml = update_changeset osm_xml, changeset.id
637
638           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
639
640           assert_response :conflict
641         end
642       end
643     end
644
645     def test_destroy_in_missing_changeset
646       with_unchanging(:relation) do |relation|
647         with_unchanging_request do |headers|
648           osm_xml = xml_for_relation relation
649           osm_xml = update_changeset osm_xml, 0
650
651           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
652
653           assert_response :conflict
654         end
655       end
656     end
657
658     def test_destroy_in_changeset_of_other_user
659       with_unchanging(:relation) do |relation|
660         other_user = create(:user)
661
662         with_unchanging_request([], [:user => other_user]) do |headers, changeset|
663           osm_xml = xml_for_relation relation
664           osm_xml = update_changeset osm_xml, changeset.id
665
666           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
667
668           assert_response :conflict, "shouldn't be able to delete a relation in a changeset owned by someone else (#{@response.body})"
669         end
670       end
671     end
672
673     def test_destroy_other_relation
674       with_unchanging(:relation) do |relation|
675         with_unchanging(:relation) do |other_relation|
676           with_unchanging_request do |headers, changeset|
677             osm_xml = xml_for_relation other_relation
678             osm_xml = update_changeset osm_xml, changeset.id
679
680             delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
681
682             assert_response :bad_request, "shouldn't be able to delete a relation when payload is different to the url"
683           end
684         end
685       end
686     end
687
688     def test_destroy_relation_used_by_other_relation
689       with_unchanging(:relation) do |relation|
690         super_relation = create(:relation)
691         create(:relation_member, :relation => super_relation, :member => relation)
692
693         with_unchanging_request do |headers, changeset|
694           osm_xml = xml_for_relation relation
695           osm_xml = update_changeset osm_xml, changeset.id
696
697           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
698
699           assert_response :precondition_failed, "shouldn't be able to delete a relation used in a relation (#{@response.body})"
700           assert_equal "Precondition failed: The relation #{relation.id} is used in relation #{super_relation.id}.", @response.body
701         end
702       end
703     end
704
705     def test_destroy
706       relation = create(:relation)
707       create_list(:relation_tag, 4, :relation => relation)
708
709       with_request do |headers, changeset|
710         osm_xml = xml_for_relation relation
711         osm_xml = update_changeset osm_xml, changeset.id
712
713         delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
714
715         assert_response :success
716         assert_operator @response.body.to_i, :>, relation.version, "delete request should return a new version number for relation"
717       end
718     end
719
720     def test_destroy_deleted_relation
721       with_unchanging(:relation, :deleted) do |relation|
722         with_unchanging_request do |headers, changeset|
723           osm_xml = xml_for_relation relation
724           osm_xml = update_changeset osm_xml, changeset.id
725
726           delete api_relation_path(relation), :params => osm_xml.to_s, :headers => headers
727
728           assert_response :gone
729         end
730       end
731     end
732
733     def test_destroy_super_relation_then_used_relation
734       used_relation = create(:relation)
735       super_relation = create(:relation)
736       create(:relation_member, :relation => super_relation, :member => used_relation)
737
738       with_request do |headers, changeset|
739         osm_xml = xml_for_relation super_relation
740         osm_xml = update_changeset osm_xml, changeset.id
741
742         delete api_relation_path(super_relation), :params => osm_xml.to_s, :headers => headers
743
744         assert_response :success
745       end
746
747       with_request do |headers, changeset|
748         osm_xml = xml_for_relation used_relation
749         osm_xml = update_changeset osm_xml, changeset.id
750
751         delete api_relation_path(used_relation), :params => osm_xml.to_s, :headers => headers
752
753         assert_response :success, "should be able to delete a relation used in an old relation (#{@response.body})"
754       end
755     end
756
757     def test_destroy_missing_relation
758       with_unchanging_request do |headers|
759         delete api_relation_path(0), :headers => headers
760
761         assert_response :not_found
762       end
763     end
764
765     ##
766     # test initial rate limit
767     def test_initial_rate_limit
768       # create a user
769       user = create(:user)
770
771       # create some nodes
772       node1 = create(:node)
773       node2 = create(:node)
774
775       # create a changeset that puts us near the initial rate limit
776       changeset = create(:changeset, :user => user,
777                                      :created_at => Time.now.utc - 5.minutes,
778                                      :num_changes => Settings.initial_changes_per_hour - 1)
779
780       # create authentication header
781       auth_header = bearer_authorization_header user
782
783       # try creating a relation
784       xml = <<~OSM
785         <osm>
786           <relation changeset='#{changeset.id}'>
787             <member ref='#{node1.id}' type='node' role='some'/>
788             <member ref='#{node2.id}' type='node' role='some'/>
789           </relation>
790         </osm>
791       OSM
792       post api_relations_path, :params => xml, :headers => auth_header
793       assert_response :success, "relation create did not return success status"
794
795       # get the id of the relation we created
796       relationid = @response.body
797
798       # try updating the relation, which should be rate limited
799       xml = <<~OSM
800         <osm>
801           <relation id='#{relationid}' version='1' changeset='#{changeset.id}'>
802             <member ref='#{node2.id}' type='node' role='some'/>
803             <member ref='#{node1.id}' type='node' role='some'/>
804           </relation>
805         </osm>
806       OSM
807       put api_relation_path(relationid), :params => xml, :headers => auth_header
808       assert_response :too_many_requests, "relation update did not hit rate limit"
809
810       # try deleting the relation, which should be rate limited
811       xml = "<osm><relation id='#{relationid}' version='2' changeset='#{changeset.id}'/></osm>"
812       delete api_relation_path(relationid), :params => xml, :headers => auth_header
813       assert_response :too_many_requests, "relation delete did not hit rate limit"
814
815       # try creating a relation, which should be rate limited
816       xml = <<~OSM
817         <osm>
818           <relation changeset='#{changeset.id}'>
819             <member ref='#{node1.id}' type='node' role='some'/>
820             <member ref='#{node2.id}' type='node' role='some'/>
821           </relation>
822         </osm>
823       OSM
824       post api_relations_path, :params => xml, :headers => auth_header
825       assert_response :too_many_requests, "relation create did not hit rate limit"
826     end
827
828     ##
829     # test maximum rate limit
830     def test_maximum_rate_limit
831       # create a user
832       user = create(:user)
833
834       # create some nodes
835       node1 = create(:node)
836       node2 = create(:node)
837
838       # create a changeset to establish our initial edit time
839       changeset = create(:changeset, :user => user,
840                                      :created_at => Time.now.utc - 28.days)
841
842       # create changeset to put us near the maximum rate limit
843       total_changes = Settings.max_changes_per_hour - 1
844       while total_changes.positive?
845         changes = [total_changes, Changeset::MAX_ELEMENTS].min
846         changeset = create(:changeset, :user => user,
847                                        :created_at => Time.now.utc - 5.minutes,
848                                        :num_changes => changes)
849         total_changes -= changes
850       end
851
852       # create authentication header
853       auth_header = bearer_authorization_header user
854
855       # try creating a relation
856       xml = <<~OSM
857         <osm>
858           <relation changeset='#{changeset.id}'>
859             <member ref='#{node1.id}' type='node' role='some'/>
860             <member ref='#{node2.id}' type='node' role='some'/>
861           </relation>
862         </osm>
863       OSM
864       post api_relations_path, :params => xml, :headers => auth_header
865       assert_response :success, "relation create did not return success status"
866
867       # get the id of the relation we created
868       relationid = @response.body
869
870       # try updating the relation, which should be rate limited
871       xml = <<~OSM
872         <osm>
873           <relation id='#{relationid}' version='1' changeset='#{changeset.id}'>
874             <member ref='#{node2.id}' type='node' role='some'/>
875             <member ref='#{node1.id}' type='node' role='some'/>
876           </relation>
877         </osm>
878       OSM
879       put api_relation_path(relationid), :params => xml, :headers => auth_header
880       assert_response :too_many_requests, "relation update did not hit rate limit"
881
882       # try deleting the relation, which should be rate limited
883       xml = "<osm><relation id='#{relationid}' version='2' changeset='#{changeset.id}'/></osm>"
884       delete api_relation_path(relationid), :params => xml, :headers => auth_header
885       assert_response :too_many_requests, "relation delete did not hit rate limit"
886
887       # try creating a relation, which should be rate limited
888       xml = <<~OSM
889         <osm>
890           <relation changeset='#{changeset.id}'>
891             <member ref='#{node1.id}' type='node' role='some'/>
892             <member ref='#{node2.id}' type='node' role='some'/>
893           </relation>
894         </osm>
895       OSM
896       post api_relations_path, :params => xml, :headers => auth_header
897       assert_response :too_many_requests, "relation create did not hit rate limit"
898     end
899
900     private
901
902     def affected_models
903       [Relation, RelationTag, RelationMember,
904        OldRelation, OldRelationTag, OldRelationMember]
905     end
906
907     ##
908     # update an attribute in the node element
909     def xml_attr_rewrite(xml, name, value)
910       xml.find("//osm/relation").first[name] = value.to_s
911       xml
912     end
913   end
914 end