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