1 # frozen_string_literal: true
 
   4 require_relative "elements_test_helper"
 
   7   class WaysControllerTest < ActionDispatch::IntegrationTest
 
   8     include ElementsTestHelper
 
  11     # test all routes which lead to this controller
 
  14         { :path => "/api/0.6/ways", :method => :get },
 
  15         { :controller => "api/ways", :action => "index" }
 
  18         { :path => "/api/0.6/ways.json", :method => :get },
 
  19         { :controller => "api/ways", :action => "index", :format => "json" }
 
  22         { :path => "/api/0.6/ways", :method => :post },
 
  23         { :controller => "api/ways", :action => "create" }
 
  26         { :path => "/api/0.6/way/1", :method => :get },
 
  27         { :controller => "api/ways", :action => "show", :id => "1" }
 
  30         { :path => "/api/0.6/way/1.json", :method => :get },
 
  31         { :controller => "api/ways", :action => "show", :id => "1", :format => "json" }
 
  34         { :path => "/api/0.6/way/1/full", :method => :get },
 
  35         { :controller => "api/ways", :action => "show", :full => true, :id => "1" }
 
  38         { :path => "/api/0.6/way/1/full.json", :method => :get },
 
  39         { :controller => "api/ways", :action => "show", :full => true, :id => "1", :format => "json" }
 
  42         { :path => "/api/0.6/way/1", :method => :put },
 
  43         { :controller => "api/ways", :action => "update", :id => "1" }
 
  46         { :path => "/api/0.6/way/1", :method => :delete },
 
  47         { :controller => "api/ways", :action => "destroy", :id => "1" }
 
  51         { :controller => "api/ways", :action => "create" },
 
  52         { :path => "/api/0.6/way/create", :method => :put }
 
  57     # test fetching multiple ways
 
  60       way2 = create(:way, :deleted)
 
  64       # check error when no parameter provided
 
  66       assert_response :bad_request
 
  68       # check error when no parameter value provided
 
  69       get api_ways_path(:ways => "")
 
  70       assert_response :bad_request
 
  73       get api_ways_path(:ways => "#{way1.id},#{way2.id},#{way3.id},#{way4.id}")
 
  74       assert_response :success
 
  75       assert_select "osm" do
 
  76         assert_select "way", :count => 4
 
  77         assert_select "way[id='#{way1.id}'][visible='true']", :count => 1
 
  78         assert_select "way[id='#{way2.id}'][visible='false']", :count => 1
 
  79         assert_select "way[id='#{way3.id}'][visible='true']", :count => 1
 
  80         assert_select "way[id='#{way4.id}'][visible='true']", :count => 1
 
  83       # test a working call with json format
 
  84       get api_ways_path(:ways => "#{way1.id},#{way2.id},#{way3.id},#{way4.id}", :format => "json")
 
  86       js = ActiveSupport::JSON.decode(@response.body)
 
  88       assert_equal 4, js["elements"].count
 
  89       assert_equal(4, js["elements"].count { |a| a["type"] == "way" })
 
  90       assert_equal(1, js["elements"].count { |a| a["id"] == way1.id && a["visible"].nil? })
 
  91       assert_equal(1, js["elements"].count { |a| a["id"] == way2.id && a["visible"] == false })
 
  92       assert_equal(1, js["elements"].count { |a| a["id"] == way3.id && a["visible"].nil? })
 
  93       assert_equal(1, js["elements"].count { |a| a["id"] == way4.id && a["visible"].nil? })
 
  95       # check error when a non-existent way is included
 
  96       get api_ways_path(:ways => "#{way1.id},#{way2.id},#{way3.id},#{way4.id},0")
 
  97       assert_response :not_found
 
 100     # -------------------------------------
 
 102     # -------------------------------------
 
 104     def test_show_not_found
 
 106       assert_response :not_found
 
 109     def test_show_deleted
 
 110       get api_way_path(create(:way, :deleted))
 
 111       assert_response :gone
 
 115       way = create(:way, :timestamp => "2021-02-03T00:00:00Z")
 
 116       node = create(:node, :timestamp => "2021-04-05T00:00:00Z")
 
 117       create(:way_node, :way => way, :node => node)
 
 119       get api_way_path(way)
 
 121       assert_response :success
 
 122       assert_not_nil @response.header["Last-Modified"]
 
 123       assert_equal "2021-02-03T00:00:00Z", Time.parse(@response.header["Last-Modified"]).utc.xmlschema
 
 127       way = create(:way_with_nodes, :nodes_count => 3)
 
 129       get api_way_path(way, :format => "json")
 
 131       assert_response :success
 
 133       js = ActiveSupport::JSON.decode(@response.body)
 
 135       assert_equal 1, js["elements"].count
 
 136       js_ways = js["elements"].filter { |e| e["type"] == "way" }
 
 137       assert_equal 1, js_ways.count
 
 138       assert_equal way.id, js_ways[0]["id"]
 
 139       assert_equal 1, js_ways[0]["version"]
 
 143     # check the "full" mode
 
 145       way = create(:way_with_nodes, :nodes_count => 3)
 
 147       get api_way_path(way, :full => true)
 
 149       assert_response :success
 
 151       # Check the way is correctly returned
 
 152       assert_select "osm way[id='#{way.id}'][version='1'][visible='true']", 1
 
 154       # check that each node in the way appears once in the output as a
 
 155       # reference and as the node element.
 
 156       way.nodes.each do |n|
 
 157         assert_select "osm way nd[ref='#{n.id}']", 1
 
 158         assert_select "osm node[id='#{n.id}'][version='1'][lat='#{format('%<lat>.7f', :lat => n.lat)}'][lon='#{format('%<lon>.7f', :lon => n.lon)}']", 1
 
 162     def test_show_full_json
 
 163       way = create(:way_with_nodes, :nodes_count => 3)
 
 165       get api_way_path(way, :full => true, :format => "json")
 
 167       assert_response :success
 
 169       # Check the way is correctly returned
 
 170       js = ActiveSupport::JSON.decode(@response.body)
 
 172       assert_equal 4, js["elements"].count
 
 173       js_ways = js["elements"].filter { |e| e["type"] == "way" }
 
 174       assert_equal 1, js_ways.count
 
 175       assert_equal way.id, js_ways[0]["id"]
 
 176       assert_equal 1, js_ways[0]["version"]
 
 178       # check that each node in the way appears once in the output as a
 
 179       # reference and as the node element.
 
 180       js_nodes = js["elements"].filter { |e| e["type"] == "node" }
 
 181       assert_equal 3, js_nodes.count
 
 183       way.nodes.each_with_index do |n, i|
 
 184         assert_equal n.id, js_ways[0]["nodes"][i]
 
 185         js_nodes_with_id = js_nodes.filter { |e| e["id"] == n.id }
 
 186         assert_equal 1, js_nodes_with_id.count
 
 187         assert_equal n.id, js_nodes_with_id[0]["id"]
 
 188         assert_equal 1, js_nodes_with_id[0]["version"]
 
 189         assert_equal n.lat, js_nodes_with_id[0]["lat"]
 
 190         assert_equal n.lon, js_nodes_with_id[0]["lon"]
 
 194     def test_show_full_deleted
 
 195       way = create(:way, :deleted)
 
 197       get api_way_path(way, :full => true)
 
 199       assert_response :gone
 
 202     # -------------------------------------
 
 203     # Test creating ways.
 
 204     # -------------------------------------
 
 206     def test_create_by_private_user
 
 207       node1 = create(:node)
 
 208       node2 = create(:node)
 
 210       with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 213             <way changeset='#{changeset.id}'>
 
 214               <nd ref='#{node1.id}'/>
 
 215               <nd ref='#{node2.id}'/>
 
 216               <tag k='test' v='yes' />
 
 221         post api_ways_path, :params => osm, :headers => headers
 
 223         assert_response :forbidden, "way upload did not return forbidden status"
 
 228       node1 = create(:node)
 
 229       node2 = create(:node)
 
 231       with_request do |headers, changeset|
 
 232         assert_difference "Way.count" => 1,
 
 233                           "WayNode.count" => 2 do
 
 236               <way changeset='#{changeset.id}'>
 
 237                 <nd ref='#{node1.id}'/>
 
 238                 <nd ref='#{node2.id}'/>
 
 239                 <tag k='test' v='yes' />
 
 244           post api_ways_path, :params => osm, :headers => headers
 
 246           assert_response :success, "way upload did not return success status"
 
 249         created_way_id = @response.body
 
 250         way = Way.find(created_way_id)
 
 251         assert_equal [node1, node2], way.nodes
 
 252         assert_equal changeset.id, way.changeset_id, "saved way does not belong to the correct changeset"
 
 253         assert way.visible, "saved way is not visible"
 
 256         assert_equal 1, changeset.num_changes
 
 257         assert_predicate changeset, :num_type_changes_in_sync?
 
 258         assert_equal 1, changeset.num_created_ways
 
 262     def test_create_in_missing_changeset
 
 263       node1 = create(:node)
 
 264       node2 = create(:node)
 
 266       with_unchanging_request do |headers|
 
 270               <nd ref='#{node1.id}'/>
 
 271               <nd ref='#{node2.id}'/>
 
 276         post api_ways_path, :params => osm, :headers => headers
 
 278         assert_response :conflict
 
 282     def test_create_with_missing_node_by_private_user
 
 283       with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 286             <way changeset='#{changeset.id}'>
 
 292         post api_ways_path, :params => osm, :headers => headers
 
 294         assert_response :forbidden, "way upload with invalid node using a private user did not return 'forbidden'"
 
 298     def test_create_without_nodes_by_private_user
 
 299       with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 302             <way changeset='#{changeset.id}' />
 
 306         post api_ways_path, :params => osm, :headers => headers
 
 308         assert_response :forbidden, "way upload with no node using a private user did not return 'forbidden'"
 
 312     def test_create_in_closed_changeset_by_private_user
 
 315       with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 318             <way changeset='#{changeset.id}'>
 
 319               <nd ref='#{node.id}'/>
 
 324         post api_ways_path, :params => osm, :headers => headers
 
 326         assert_response :forbidden, "way upload to closed changeset with a private user did not return 'forbidden'"
 
 330     def test_create_with_missing_node
 
 331       with_unchanging_request do |headers, changeset|
 
 334             <way changeset='#{changeset.id}'>
 
 340         post api_ways_path, :params => osm, :headers => headers
 
 342         assert_response :precondition_failed, "way upload with invalid node did not return 'precondition failed'"
 
 343         assert_equal "Precondition failed: Way  requires the nodes with id in (0), which either do not exist, or are not visible.", @response.body
 
 347     def test_create_without_nodes
 
 348       with_unchanging_request do |headers, changeset|
 
 351             <way changeset='#{changeset.id}' />
 
 355         post api_ways_path, :params => osm, :headers => headers
 
 357         assert_response :precondition_failed, "way upload with no node did not return 'precondition failed'"
 
 358         assert_equal "Precondition failed: Cannot create way: data is invalid.", @response.body
 
 362     def test_create_in_closed_changeset
 
 365       with_unchanging_request([], [:closed]) do |headers, changeset|
 
 368             <way changeset='#{changeset.id}'>
 
 369               <nd ref='#{node.id}'/>
 
 374         post api_ways_path, :params => osm, :headers => headers
 
 376         assert_response :conflict, "way upload to closed changeset did not return 'conflict'"
 
 380     def test_create_with_tag_too_long
 
 383       with_unchanging_request do |headers, changeset|
 
 386             <way changeset='#{changeset.id}'>
 
 387               <nd ref='#{node.id}'/>
 
 388               <tag k='foo' v='#{'x' * 256}'/>
 
 393         post api_ways_path, :params => osm, :headers => headers
 
 395         assert_response :bad_request, "way upload to with too long tag did not return 'bad_request'"
 
 399     def test_create_with_duplicate_tags_by_private_user
 
 402       with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 405             <way changeset='#{changeset.id}'>
 
 406               <nd ref='#{node.id}'/>
 
 407               <tag k='addr:housenumber' v='1'/>
 
 408               <tag k='addr:housenumber' v='2'/>
 
 413         post api_ways_path, :params => osm, :headers => headers
 
 415         assert_response :forbidden, "adding new duplicate tags to a way with a non-public user should fail with 'forbidden'"
 
 419     def test_create_with_duplicate_tags
 
 422       with_unchanging_request do |headers, changeset|
 
 425             <way changeset='#{changeset.id}'>
 
 426               <nd ref='#{node.id}'/>
 
 427               <tag k='addr:housenumber' v='1'/>
 
 428               <tag k='addr:housenumber' v='2'/>
 
 433         post api_ways_path, :params => osm, :headers => headers
 
 435         assert_response :bad_request, "adding new duplicate tags to a way should fail with 'bad request'"
 
 436         assert_equal "Element way/ has duplicate tags with key addr:housenumber", @response.body
 
 440     def test_create_race_condition
 
 442       changeset = create(:changeset, :user => user)
 
 444       auth_header = bearer_authorization_header user
 
 446       concurrency_level = 16
 
 448       threads = Array.new(concurrency_level) do
 
 452               <way changeset='#{changeset.id}'>
 
 453                 <nd ref='#{node.id}'/>
 
 457           post path, :params => osm, :headers => auth_header
 
 463       assert_equal concurrency_level, changeset.num_changes
 
 464       assert_predicate changeset, :num_type_changes_in_sync?
 
 465       assert_equal concurrency_level, changeset.num_created_ways
 
 468     # -------------------------------------
 
 469     # Test deleting ways.
 
 470     # -------------------------------------
 
 472     def test_destroy_when_unauthorized
 
 473       with_unchanging(:way) do |way|
 
 474         delete api_way_path(way)
 
 476         assert_response :unauthorized
 
 480     def test_destroy_without_payload_by_private_user
 
 481       with_unchanging(:way) do |way|
 
 482         with_unchanging_request([:data_public => false]) do |headers|
 
 483           delete api_way_path(way), :headers => headers
 
 485           assert_response :forbidden
 
 490     def test_destroy_without_changeset_id_by_private_user
 
 491       with_unchanging(:way) do |way|
 
 492         with_unchanging_request([:data_public => false]) do |headers|
 
 493           osm = "<osm><way id='#{way.id}'/></osm>"
 
 495           delete api_way_path(way), :params => osm, :headers => headers
 
 497           assert_response :forbidden
 
 502     def test_destroy_in_closed_changeset_by_private_user
 
 503       with_unchanging(:way) do |way|
 
 504         with_unchanging_request([:data_public => false], [:closed]) do |headers, changeset|
 
 505           osm_xml = xml_for_way way
 
 506           osm_xml = update_changeset osm_xml, changeset.id
 
 508           delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 510           assert_response :forbidden
 
 515     def test_destroy_in_missing_changeset_by_private_user
 
 516       with_unchanging(:way) do |way|
 
 517         with_unchanging_request([:data_public => false]) do |headers|
 
 518           osm_xml = xml_for_way way
 
 519           osm_xml = update_changeset osm_xml, 0
 
 521           delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 523           assert_response :forbidden
 
 528     def test_destroy_by_private_user
 
 529       with_unchanging(:way) do |way|
 
 530         with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 531           osm_xml = xml_for_way way
 
 532           osm_xml = update_changeset osm_xml, changeset.id
 
 534           delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 536           assert_response :forbidden
 
 541     def test_destroy_deleted_way_by_private_user
 
 542       with_unchanging(:way, :deleted) do |way|
 
 543         with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 544           osm_xml = xml_for_way way
 
 545           osm_xml = update_changeset osm_xml, changeset.id
 
 547           delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 549           assert_response :forbidden
 
 554     def test_destroy_way_in_relation_by_private_user
 
 555       with_unchanging(:way) do |way|
 
 556         create(:relation_member, :member => way)
 
 558         with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 559           osm_xml = xml_for_way way
 
 560           osm_xml = update_changeset osm_xml, changeset.id
 
 562           delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 564           assert_response :forbidden, "shouldn't be able to delete a way used in a relation (#{@response.body}), when done by a private user"
 
 569     def test_destroy_missing_way_by_private_user
 
 570       with_unchanging_request([:data_public => false]) do |headers|
 
 571         delete api_way_path(0), :headers => headers
 
 573         assert_response :forbidden
 
 577     def test_destroy_without_payload
 
 578       with_unchanging(:way) do |way|
 
 579         with_unchanging_request do |headers|
 
 580           delete api_way_path(way), :headers => headers
 
 582           assert_response :bad_request
 
 587     def test_destroy_without_changeset_id
 
 588       with_unchanging(:way) do |way|
 
 589         with_unchanging_request do |headers|
 
 590           osm = "<osm><way id='#{way.id}'/></osm>"
 
 592           delete api_way_path(way), :params => osm, :headers => headers
 
 594           assert_response :bad_request
 
 599     def test_destroy_in_closed_changeset
 
 600       with_unchanging(:way) do |way|
 
 601         with_unchanging_request([], [:closed]) do |headers, changeset|
 
 602           osm_xml = xml_for_way way
 
 603           osm_xml = update_changeset osm_xml, changeset.id
 
 605           delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 607           assert_response :conflict
 
 612     def test_destroy_in_missing_changeset
 
 613       with_unchanging(:way) do |way|
 
 614         with_unchanging_request do |headers|
 
 615           osm_xml = xml_for_way way
 
 616           osm_xml = update_changeset osm_xml, 0
 
 618           delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 620           assert_response :conflict
 
 628       with_request do |headers, changeset|
 
 629         osm_xml = xml_for_way way
 
 630         osm_xml = update_changeset osm_xml, changeset.id
 
 632         delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 634         assert_response :success
 
 636         response_way_version = @response.body.to_i
 
 637         assert_operator response_way_version, :>, way.version, "delete request should return a new version number for way"
 
 639         assert_not_predicate way, :visible?
 
 640         assert_equal response_way_version, way.version
 
 643         assert_equal 1, changeset.num_changes
 
 644         assert_predicate changeset, :num_type_changes_in_sync?
 
 645         assert_equal 1, changeset.num_deleted_ways
 
 649     def test_destroy_deleted_way
 
 650       with_unchanging(:way, :deleted) do |way|
 
 651         with_unchanging_request do |headers, changeset|
 
 652           osm_xml = xml_for_way way
 
 653           osm_xml = update_changeset osm_xml, changeset.id
 
 655           delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 657           assert_response :gone
 
 662     def test_destroy_way_in_relation
 
 663       with_unchanging(:way) do |way|
 
 664         relation_member = create(:relation_member, :member => way)
 
 666         with_unchanging_request do |headers, changeset|
 
 667           osm_xml = xml_for_way way
 
 668           osm_xml = update_changeset osm_xml, changeset.id
 
 670           delete api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 672           assert_response :precondition_failed, "shouldn't be able to delete a way used in a relation (#{@response.body})"
 
 673           assert_equal "Precondition failed: Way #{way.id} is still used by relations #{relation_member.relation.id}.", @response.body
 
 678     def test_destroy_missing_way_with_payload
 
 679       with_unchanging(:way) do |way|
 
 680         with_unchanging_request do |headers, changeset|
 
 681           osm_xml = xml_for_way way
 
 682           osm_xml = update_changeset osm_xml, changeset.id
 
 684           delete api_way_path(0), :params => osm_xml.to_s, :headers => headers
 
 686           assert_response :not_found
 
 691     # -------------------------------------
 
 692     # Test updating ways.
 
 693     # -------------------------------------
 
 695     def test_update_when_unauthorized
 
 696       with_unchanging(:way_with_nodes) do |way|
 
 697         osm_xml = xml_for_way way
 
 699         put api_way_path(way), :params => osm_xml.to_s
 
 701         assert_response :unauthorized
 
 705     def test_update_in_changeset_of_other_user_by_private_user
 
 706       with_unchanging(:way_with_nodes) do |way|
 
 707         other_user = create(:user)
 
 709         with_unchanging_request([:data_public => false], [:user => other_user]) do |headers, changeset|
 
 710           osm_xml = xml_for_way way
 
 711           osm_xml = update_changeset osm_xml, changeset.id
 
 713           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 715           assert_require_public_data "update with other user's changeset should be forbidden when date isn't public"
 
 720     def test_update_in_closed_changeset_by_private_user
 
 721       with_unchanging(:way_with_nodes) do |way|
 
 722         with_unchanging_request([:data_public => false], [:closed]) do |headers, changeset|
 
 723           osm_xml = xml_for_way way
 
 724           osm_xml = update_changeset osm_xml, changeset.id
 
 726           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 728           assert_require_public_data "update with closed changeset should be forbidden, when data isn't public"
 
 733     def test_update_in_missing_changeset_by_private_user
 
 734       with_unchanging(:way_with_nodes) do |way|
 
 735         with_unchanging_request([:data_public => false]) do |headers|
 
 736           osm_xml = xml_for_way way
 
 737           osm_xml = update_changeset osm_xml, 0
 
 739           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 741           assert_require_public_data "update with changeset=0 should be forbidden, when data isn't public"
 
 746     def test_update_with_missing_node_by_private_user
 
 747       with_unchanging(:way) do |way|
 
 749         create(:way_node, :way => way, :node => node)
 
 751         with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 752           osm_xml = xml_for_way way
 
 753           osm_xml = xml_replace_node osm_xml, node.id, 9999
 
 754           osm_xml = update_changeset osm_xml, changeset.id
 
 756           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 758           assert_require_public_data "way with non-existent node should be forbidden, when data isn't public"
 
 763     def test_update_with_deleted_node_by_private_user
 
 764       with_unchanging(:way) do |way|
 
 766         deleted_node = create(:node, :deleted)
 
 767         create(:way_node, :way => way, :node => node)
 
 769         with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 770           osm_xml = xml_for_way way
 
 771           osm_xml = xml_replace_node osm_xml, node.id, deleted_node.id
 
 772           osm_xml = update_changeset osm_xml, changeset.id
 
 774           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 776           assert_require_public_data "way with deleted node should be forbidden, when data isn't public"
 
 781     def test_update_by_private_user
 
 782       with_unchanging(:way_with_nodes) do |way|
 
 783         with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 784           osm_xml = xml_for_way way
 
 785           osm_xml = update_changeset osm_xml, changeset.id
 
 787           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 789           assert_require_public_data "should have failed with a forbidden when data isn't public"
 
 794     def test_update_in_changeset_of_other_user
 
 795       with_unchanging(:way_with_nodes) do |way|
 
 796         other_user = create(:user)
 
 798         with_unchanging_request([], [:user => other_user]) do |headers, changeset|
 
 799           osm_xml = xml_for_way way
 
 800           osm_xml = update_changeset osm_xml, changeset.id
 
 802           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 804           assert_response :conflict, "update with other user's changeset should be rejected"
 
 809     def test_update_in_closed_changeset
 
 810       with_unchanging(:way_with_nodes) do |way|
 
 811         with_unchanging_request([], [:closed]) do |headers, changeset|
 
 812           osm_xml = xml_for_way way
 
 813           osm_xml = update_changeset osm_xml, changeset.id
 
 815           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 817           assert_response :conflict, "update with closed changeset should be rejected"
 
 822     def test_update_in_missing_changeset
 
 823       with_unchanging(:way_with_nodes) do |way|
 
 824         with_unchanging_request do |headers|
 
 825           osm_xml = xml_for_way way
 
 826           osm_xml = update_changeset osm_xml, 0
 
 828           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 830           assert_response :conflict, "update with changeset=0 should be rejected"
 
 835     def test_update_with_missing_node
 
 836       with_unchanging(:way) do |way|
 
 838         create(:way_node, :way => way, :node => node)
 
 840         with_unchanging_request do |headers, changeset|
 
 841           osm_xml = xml_for_way way
 
 842           osm_xml = xml_replace_node osm_xml, node.id, 9999
 
 843           osm_xml = update_changeset osm_xml, changeset.id
 
 845           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 847           assert_response :precondition_failed, "way with non-existent node should be rejected"
 
 852     def test_update_with_deleted_node
 
 853       with_unchanging(:way) do |way|
 
 855         deleted_node = create(:node, :deleted)
 
 856         create(:way_node, :way => way, :node => node)
 
 858         with_unchanging_request do |headers, changeset|
 
 859           osm_xml = xml_for_way way
 
 860           osm_xml = xml_replace_node osm_xml, node.id, deleted_node.id
 
 861           osm_xml = update_changeset osm_xml, changeset.id
 
 863           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 865           assert_response :precondition_failed, "way with deleted node should be rejected"
 
 870     def test_update_with_version_behind
 
 871       with_unchanging(:way_with_nodes, :version => 2) do |way|
 
 872         with_unchanging_request do |headers, changeset|
 
 873           osm_xml = xml_for_way way
 
 874           osm_xml = xml_attr_rewrite osm_xml, "version", way.version - 1
 
 875           osm_xml = update_changeset osm_xml, changeset.id
 
 877           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 879           assert_response :conflict, "should have failed on old version number"
 
 884     def test_update_with_version_ahead
 
 885       with_unchanging(:way_with_nodes, :version => 2) do |way|
 
 886         with_unchanging_request do |headers, changeset|
 
 887           osm_xml = xml_for_way way
 
 888           osm_xml = xml_attr_rewrite osm_xml, "version", way.version + 1
 
 889           osm_xml = update_changeset osm_xml, changeset.id
 
 891           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 893           assert_response :conflict, "should have failed on skipped version number"
 
 898     def test_update_with_invalid_version
 
 899       with_unchanging(:way_with_nodes) do |way|
 
 900         with_unchanging_request do |headers, changeset|
 
 901           osm_xml = xml_for_way way
 
 902           osm_xml = xml_attr_rewrite osm_xml, "version", "p1r4t3s!"
 
 903           osm_xml = update_changeset osm_xml, changeset.id
 
 905           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 907           assert_response :conflict, "should not be able to put 'p1r4at3s!' in the version field"
 
 912     def test_update_other_way
 
 913       with_unchanging(:way_with_nodes) do |way|
 
 914         with_unchanging(:way_with_nodes) do |other_way|
 
 915           with_unchanging_request do |headers, changeset|
 
 916             osm_xml = xml_for_way other_way
 
 917             osm_xml = update_changeset osm_xml, changeset.id
 
 919             put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 921             assert_response :bad_request, "should not be able to update a way with a different ID from the XML"
 
 927     def test_update_with_invalid_osm_structure
 
 928       with_unchanging(:way_with_nodes) do |way|
 
 929         with_unchanging_request do |headers|
 
 932           put api_way_path(way), :params => osm, :headers => headers
 
 934           assert_response :bad_request, "should not be able to update a way with non-OSM XML doc."
 
 940       way = create(:way_with_nodes)
 
 942       with_request do |headers, changeset|
 
 943         osm_xml = xml_for_way way
 
 944         osm_xml = update_changeset osm_xml, changeset.id
 
 946         put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 948         assert_response :success, "a valid update request failed"
 
 951         assert_equal 1, changeset.num_changes
 
 952         assert_predicate changeset, :num_type_changes_in_sync?
 
 953         assert_equal 1, changeset.num_modified_ways
 
 957     def test_update_with_new_tags_by_private_user
 
 958       with_unchanging(:way_with_nodes, :nodes_count => 2) do |way|
 
 959         with_unchanging_request([:data_public => false]) do |headers, changeset|
 
 960           tag_xml = XML::Node.new("tag")
 
 964           osm_xml = xml_for_way way
 
 965           osm_xml.find("//osm/way").first << tag_xml
 
 966           osm_xml = update_changeset osm_xml, changeset.id
 
 968           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 970           assert_response :forbidden, "adding a tag to a way for a non-public should fail with 'forbidden'"
 
 975     def test_update_with_new_tags
 
 976       way = create(:way_with_nodes, :nodes_count => 2)
 
 978       with_request do |headers, changeset|
 
 979         tag_xml = XML::Node.new("tag")
 
 983         osm_xml = xml_for_way way
 
 984         osm_xml.find("//osm/way").first << tag_xml
 
 985         osm_xml = update_changeset osm_xml, changeset.id
 
 987         put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
 989         assert_response :success, "adding a new tag to a way should succeed"
 
 990         assert_equal way.version + 1, @response.body.to_i
 
 993         assert_equal 1, changeset.num_changes
 
 994         assert_predicate changeset, :num_type_changes_in_sync?
 
 995         assert_equal 1, changeset.num_modified_ways
 
 999     def test_update_with_duplicated_existing_tags_by_private_user
 
1000       with_unchanging(:way_with_nodes) do |way|
 
1001         create(:way_tag, :way => way, :k => "key_to_duplicate", :v => "value_to_duplicate")
 
1003         with_unchanging_request([:data_public => false]) do |headers, changeset|
 
1004           tag_xml = XML::Node.new("tag")
 
1005           tag_xml["k"] = "key_to_duplicate"
 
1006           tag_xml["v"] = "value_to_duplicate"
 
1008           osm_xml = xml_for_way way
 
1009           osm_xml.find("//osm/way").first << tag_xml
 
1010           osm_xml = update_changeset osm_xml, changeset.id
 
1012           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
1014           assert_response :forbidden, "adding a duplicate tag to a way for a non-public should fail with 'forbidden'"
 
1019     def test_update_with_duplicated_existing_tags
 
1020       with_unchanging(:way_with_nodes) do |way|
 
1021         create(:way_tag, :way => way, :k => "key_to_duplicate", :v => "value_to_duplicate")
 
1023         with_unchanging_request do |headers, changeset|
 
1024           tag_xml = XML::Node.new("tag")
 
1025           tag_xml["k"] = "key_to_duplicate"
 
1026           tag_xml["v"] = "value_to_duplicate"
 
1028           osm_xml = xml_for_way way
 
1029           osm_xml.find("//osm/way").first << tag_xml
 
1030           osm_xml = update_changeset osm_xml, changeset.id
 
1032           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
1034           assert_response :bad_request, "adding a duplicate tag to a way should fail with 'bad request'"
 
1035           assert_equal "Element way/#{way.id} has duplicate tags with key key_to_duplicate", @response.body
 
1040     def test_update_with_new_duplicate_tags_by_private_user
 
1041       with_unchanging(:way_with_nodes) do |way|
 
1042         with_unchanging_request([:data_public => false]) do |headers, changeset|
 
1043           tag_xml = XML::Node.new("tag")
 
1044           tag_xml["k"] = "i_am_a_duplicate"
 
1045           tag_xml["v"] = "foobar"
 
1047           osm_xml = xml_for_way way
 
1048           osm_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
 
1049           osm_xml = update_changeset osm_xml, changeset.id
 
1051           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
1053           assert_response :forbidden, "adding new duplicate tags to a way using a non-public user should fail with 'forbidden'"
 
1058     def test_update_with_new_duplicate_tags
 
1059       with_unchanging(:way_with_nodes) do |way|
 
1060         with_unchanging_request do |headers, changeset|
 
1061           tag_xml = XML::Node.new("tag")
 
1062           tag_xml["k"] = "i_am_a_duplicate"
 
1063           tag_xml["v"] = "foobar"
 
1065           osm_xml = xml_for_way way
 
1066           osm_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
 
1067           osm_xml = update_changeset osm_xml, changeset.id
 
1069           put api_way_path(way), :params => osm_xml.to_s, :headers => headers
 
1071           assert_response :bad_request, "adding new duplicate tags to a way should fail with 'bad request'"
 
1072           assert_equal "Element way/#{way.id} has duplicate tags with key i_am_a_duplicate", @response.body
 
1078     # test initial rate limit
 
1079     def test_initial_rate_limit
 
1081       user = create(:user)
 
1084       node1 = create(:node)
 
1085       node2 = create(:node)
 
1087       # create a changeset that puts us near the initial rate limit
 
1088       changeset = create(:changeset, :user => user,
 
1089                                      :created_at => Time.now.utc - 5.minutes,
 
1090                                      :num_changes => Settings.initial_changes_per_hour - 1)
 
1092       # create authentication header
 
1093       auth_header = bearer_authorization_header user
 
1095       # try creating a way
 
1098           <way changeset='#{changeset.id}'>
 
1099             <nd ref='#{node1.id}'/>
 
1100             <nd ref='#{node2.id}'/>
 
1104       post api_ways_path, :params => xml, :headers => auth_header
 
1105       assert_response :success, "way create did not return success status"
 
1107       # get the id of the way we created
 
1108       wayid = @response.body
 
1110       # try updating the way, which should be rate limited
 
1113           <way id='#{wayid}' version='1' changeset='#{changeset.id}'>
 
1114             <nd ref='#{node2.id}'/>
 
1115             <nd ref='#{node1.id}'/>
 
1119       put api_way_path(wayid), :params => xml, :headers => auth_header
 
1120       assert_response :too_many_requests, "way update did not hit rate limit"
 
1122       # try deleting the way, which should be rate limited
 
1123       xml = "<osm><way id='#{wayid}' version='2' changeset='#{changeset.id}'/></osm>"
 
1124       delete api_way_path(wayid), :params => xml, :headers => auth_header
 
1125       assert_response :too_many_requests, "way delete did not hit rate limit"
 
1127       # try creating a way, which should be rate limited
 
1130           <way changeset='#{changeset.id}'>
 
1131             <nd ref='#{node1.id}'/>
 
1132             <nd ref='#{node2.id}'/>
 
1136       post api_ways_path, :params => xml, :headers => auth_header
 
1137       assert_response :too_many_requests, "way create did not hit rate limit"
 
1141     # test maximum rate limit
 
1142     def test_maximum_rate_limit
 
1144       user = create(:user)
 
1147       node1 = create(:node)
 
1148       node2 = create(:node)
 
1150       # create a changeset to establish our initial edit time
 
1151       changeset = create(:changeset, :user => user,
 
1152                                      :created_at => Time.now.utc - 28.days)
 
1154       # create changeset to put us near the maximum rate limit
 
1155       total_changes = Settings.max_changes_per_hour - 1
 
1156       while total_changes.positive?
 
1157         changes = [total_changes, Changeset::MAX_ELEMENTS].min
 
1158         changeset = create(:changeset, :user => user,
 
1159                                        :created_at => Time.now.utc - 5.minutes,
 
1160                                        :num_changes => changes)
 
1161         total_changes -= changes
 
1164       # create authentication header
 
1165       auth_header = bearer_authorization_header user
 
1167       # try creating a way
 
1170           <way changeset='#{changeset.id}'>
 
1171             <nd ref='#{node1.id}'/>
 
1172             <nd ref='#{node2.id}'/>
 
1176       post api_ways_path, :params => xml, :headers => auth_header
 
1177       assert_response :success, "way create did not return success status"
 
1179       # get the id of the way we created
 
1180       wayid = @response.body
 
1182       # try updating the way, which should be rate limited
 
1185           <way id='#{wayid}' version='1' changeset='#{changeset.id}'>
 
1186             <nd ref='#{node2.id}'/>
 
1187             <nd ref='#{node1.id}'/>
 
1191       put api_way_path(wayid), :params => xml, :headers => auth_header
 
1192       assert_response :too_many_requests, "way update did not hit rate limit"
 
1194       # try deleting the way, which should be rate limited
 
1195       xml = "<osm><way id='#{wayid}' version='2' changeset='#{changeset.id}'/></osm>"
 
1196       delete api_way_path(wayid), :params => xml, :headers => auth_header
 
1197       assert_response :too_many_requests, "way delete did not hit rate limit"
 
1199       # try creating a way, which should be rate limited
 
1202           <way changeset='#{changeset.id}'>
 
1203             <nd ref='#{node1.id}'/>
 
1204             <nd ref='#{node2.id}'/>
 
1208       post api_ways_path, :params => xml, :headers => auth_header
 
1209       assert_response :too_many_requests, "way create did not hit rate limit"
 
1215       [Way, WayNode, WayTag,
 
1216        OldWay, OldWayNode, OldWayTag]
 
1220     # update an attribute in the way element
 
1221     def xml_attr_rewrite(xml, name, value)
 
1222       xml.find("//osm/way").first[name] = value.to_s
 
1227     # replace a node in a way element
 
1228     def xml_replace_node(xml, old_node, new_node)
 
1229       xml.find("//osm/way/nd[@ref='#{old_node}']").first["ref"] = new_node.to_s