4   class WaysControllerTest < ActionDispatch::IntegrationTest
 
   6     # test all routes which lead to this controller
 
   9         { :path => "/api/0.6/ways", :method => :get },
 
  10         { :controller => "api/ways", :action => "index" }
 
  13         { :path => "/api/0.6/ways.json", :method => :get },
 
  14         { :controller => "api/ways", :action => "index", :format => "json" }
 
  17         { :path => "/api/0.6/ways", :method => :post },
 
  18         { :controller => "api/ways", :action => "create" }
 
  21         { :path => "/api/0.6/way/1", :method => :get },
 
  22         { :controller => "api/ways", :action => "show", :id => "1" }
 
  25         { :path => "/api/0.6/way/1.json", :method => :get },
 
  26         { :controller => "api/ways", :action => "show", :id => "1", :format => "json" }
 
  29         { :path => "/api/0.6/way/1/full", :method => :get },
 
  30         { :controller => "api/ways", :action => "show", :full => true, :id => "1" }
 
  33         { :path => "/api/0.6/way/1/full.json", :method => :get },
 
  34         { :controller => "api/ways", :action => "show", :full => true, :id => "1", :format => "json" }
 
  37         { :path => "/api/0.6/way/1", :method => :put },
 
  38         { :controller => "api/ways", :action => "update", :id => "1" }
 
  41         { :path => "/api/0.6/way/1", :method => :delete },
 
  42         { :controller => "api/ways", :action => "destroy", :id => "1" }
 
  46         { :controller => "api/ways", :action => "create" },
 
  47         { :path => "/api/0.6/way/create", :method => :put }
 
  52     # test fetching multiple ways
 
  55       way2 = create(:way, :deleted)
 
  59       # check error when no parameter provided
 
  61       assert_response :bad_request
 
  63       # check error when no parameter value provided
 
  64       get api_ways_path(:ways => "")
 
  65       assert_response :bad_request
 
  68       get api_ways_path(:ways => "#{way1.id},#{way2.id},#{way3.id},#{way4.id}")
 
  69       assert_response :success
 
  70       assert_select "osm" do
 
  71         assert_select "way", :count => 4
 
  72         assert_select "way[id='#{way1.id}'][visible='true']", :count => 1
 
  73         assert_select "way[id='#{way2.id}'][visible='false']", :count => 1
 
  74         assert_select "way[id='#{way3.id}'][visible='true']", :count => 1
 
  75         assert_select "way[id='#{way4.id}'][visible='true']", :count => 1
 
  78       # test a working call with json format
 
  79       get api_ways_path(:ways => "#{way1.id},#{way2.id},#{way3.id},#{way4.id}", :format => "json")
 
  81       js = ActiveSupport::JSON.decode(@response.body)
 
  83       assert_equal 4, js["elements"].count
 
  84       assert_equal 4, (js["elements"].count { |a| a["type"] == "way" })
 
  85       assert_equal 1, (js["elements"].count { |a| a["id"] == way1.id && a["visible"].nil? })
 
  86       assert_equal 1, (js["elements"].count { |a| a["id"] == way2.id && a["visible"] == false })
 
  87       assert_equal 1, (js["elements"].count { |a| a["id"] == way3.id && a["visible"].nil? })
 
  88       assert_equal 1, (js["elements"].count { |a| a["id"] == way4.id && a["visible"].nil? })
 
  90       # check error when a non-existent way is included
 
  91       get api_ways_path(:ways => "#{way1.id},#{way2.id},#{way3.id},#{way4.id},0")
 
  92       assert_response :not_found
 
  95     # -------------------------------------
 
  97     # -------------------------------------
 
  99     def test_show_not_found
 
 101       assert_response :not_found
 
 104     def test_show_deleted
 
 105       get api_way_path(create(:way, :deleted))
 
 106       assert_response :gone
 
 110       way = create(:way, :timestamp => "2021-02-03T00:00:00Z")
 
 111       node = create(:node, :timestamp => "2021-04-05T00:00:00Z")
 
 112       create(:way_node, :way => way, :node => node)
 
 114       get api_way_path(way)
 
 116       assert_response :success
 
 117       assert_not_nil @response.header["Last-Modified"]
 
 118       assert_equal "2021-02-03T00:00:00Z", Time.parse(@response.header["Last-Modified"]).utc.xmlschema
 
 122       way = create(:way_with_nodes, :nodes_count => 3)
 
 124       get api_way_path(way, :format => "json")
 
 126       assert_response :success
 
 128       js = ActiveSupport::JSON.decode(@response.body)
 
 130       assert_equal 1, js["elements"].count
 
 131       js_ways = js["elements"].filter { |e| e["type"] == "way" }
 
 132       assert_equal 1, js_ways.count
 
 133       assert_equal way.id, js_ways[0]["id"]
 
 134       assert_equal 1, js_ways[0]["version"]
 
 138     # check the "full" mode
 
 140       way = create(:way_with_nodes, :nodes_count => 3)
 
 142       get api_way_path(way, :full => true)
 
 144       assert_response :success
 
 146       # Check the way is correctly returned
 
 147       assert_select "osm way[id='#{way.id}'][version='1'][visible='true']", 1
 
 149       # check that each node in the way appears once in the output as a
 
 150       # reference and as the node element.
 
 151       way.nodes.each do |n|
 
 152         assert_select "osm way nd[ref='#{n.id}']", 1
 
 153         assert_select "osm node[id='#{n.id}'][version='1'][lat='#{format('%<lat>.7f', :lat => n.lat)}'][lon='#{format('%<lon>.7f', :lon => n.lon)}']", 1
 
 157     def test_show_full_json
 
 158       way = create(:way_with_nodes, :nodes_count => 3)
 
 160       get api_way_path(way, :full => true, :format => "json")
 
 162       assert_response :success
 
 164       # Check the way is correctly returned
 
 165       js = ActiveSupport::JSON.decode(@response.body)
 
 167       assert_equal 4, js["elements"].count
 
 168       js_ways = js["elements"].filter { |e| e["type"] == "way" }
 
 169       assert_equal 1, js_ways.count
 
 170       assert_equal way.id, js_ways[0]["id"]
 
 171       assert_equal 1, js_ways[0]["version"]
 
 173       # check that each node in the way appears once in the output as a
 
 174       # reference and as the node element.
 
 175       js_nodes = js["elements"].filter { |e| e["type"] == "node" }
 
 176       assert_equal 3, js_nodes.count
 
 178       way.nodes.each_with_index do |n, i|
 
 179         assert_equal n.id, js_ways[0]["nodes"][i]
 
 180         js_nodes_with_id = js_nodes.filter { |e| e["id"] == n.id }
 
 181         assert_equal 1, js_nodes_with_id.count
 
 182         assert_equal n.id, js_nodes_with_id[0]["id"]
 
 183         assert_equal 1, js_nodes_with_id[0]["version"]
 
 184         assert_equal n.lat, js_nodes_with_id[0]["lat"]
 
 185         assert_equal n.lon, js_nodes_with_id[0]["lon"]
 
 189     def test_show_full_deleted
 
 190       way = create(:way, :deleted)
 
 192       get api_way_path(way, :full => true)
 
 194       assert_response :gone
 
 197     # -------------------------------------
 
 198     # Test simple way creation.
 
 199     # -------------------------------------
 
 202       node1 = create(:node)
 
 203       node2 = create(:node)
 
 204       private_user = create(:user, :data_public => false)
 
 205       private_changeset = create(:changeset, :user => private_user)
 
 207       changeset = create(:changeset, :user => user)
 
 209       ## First check that it fails when creating a way using a non-public user
 
 210       auth_header = bearer_authorization_header private_user
 
 212       # use the first user's open changeset
 
 213       changeset_id = private_changeset.id
 
 215       # create a way with pre-existing nodes
 
 216       xml = "<osm><way changeset='#{changeset_id}'>" \
 
 217             "<nd ref='#{node1.id}'/><nd ref='#{node2.id}'/>" \
 
 218             "<tag k='test' v='yes' /></way></osm>"
 
 219       post api_ways_path, :params => xml, :headers => auth_header
 
 221       assert_response :forbidden,
 
 222                       "way upload did not return forbidden status"
 
 224       ## Now use a public user
 
 225       auth_header = bearer_authorization_header user
 
 227       # use the first user's open changeset
 
 228       changeset_id = changeset.id
 
 230       # create a way with pre-existing nodes
 
 231       xml = "<osm><way changeset='#{changeset_id}'>" \
 
 232             "<nd ref='#{node1.id}'/><nd ref='#{node2.id}'/>" \
 
 233             "<tag k='test' v='yes' /></way></osm>"
 
 234       post api_ways_path, :params => xml, :headers => auth_header
 
 236       assert_response :success,
 
 237                       "way upload did not return success status"
 
 238       # read id of created way and search for it
 
 239       wayid = @response.body
 
 240       checkway = Way.find(wayid)
 
 241       assert_not_nil checkway,
 
 242                      "uploaded way not found in data base after upload"
 
 244       assert_equal(2, checkway.nds.length, "saved way does not contain exactly one node")
 
 245       assert_equal checkway.nds[0], node1.id,
 
 246                    "saved way does not contain the right node on pos 0"
 
 247       assert_equal checkway.nds[1], node2.id,
 
 248                    "saved way does not contain the right node on pos 1"
 
 249       assert_equal checkway.changeset_id, changeset_id,
 
 250                    "saved way does not belong to the correct changeset"
 
 251       assert_equal user.id, checkway.changeset.user_id,
 
 252                    "saved way does not belong to user that created it"
 
 253       assert checkway.visible,
 
 254              "saved way is not visible"
 
 257     # -------------------------------------
 
 258     # Test creating some invalid ways.
 
 259     # -------------------------------------
 
 261     def test_create_invalid
 
 263       private_user = create(:user, :data_public => false)
 
 264       private_open_changeset = create(:changeset, :user => private_user)
 
 265       private_closed_changeset = create(:changeset, :closed, :user => private_user)
 
 267       open_changeset = create(:changeset, :user => user)
 
 268       closed_changeset = create(:changeset, :closed, :user => user)
 
 270       ## First test with a private user to make sure that they are not authorized
 
 271       auth_header = bearer_authorization_header private_user
 
 273       # use the first user's open changeset
 
 274       # create a way with non-existing node
 
 275       xml = "<osm><way changeset='#{private_open_changeset.id}'>" \
 
 276             "<nd ref='0'/><tag k='test' v='yes' /></way></osm>"
 
 277       post api_ways_path, :params => xml, :headers => auth_header
 
 279       assert_response :forbidden,
 
 280                       "way upload with invalid node using a private user did not return 'forbidden'"
 
 282       # create a way with no nodes
 
 283       xml = "<osm><way changeset='#{private_open_changeset.id}'>" \
 
 284             "<tag k='test' v='yes' /></way></osm>"
 
 285       post api_ways_path, :params => xml, :headers => auth_header
 
 287       assert_response :forbidden,
 
 288                       "way upload with no node using a private userdid not return 'forbidden'"
 
 290       # create a way inside a closed changeset
 
 291       xml = "<osm><way changeset='#{private_closed_changeset.id}'>" \
 
 292             "<nd ref='#{node.id}'/></way></osm>"
 
 293       post api_ways_path, :params => xml, :headers => auth_header
 
 295       assert_response :forbidden,
 
 296                       "way upload to closed changeset with a private user did not return 'forbidden'"
 
 298       ## Now test with a public user
 
 299       auth_header = bearer_authorization_header user
 
 301       # use the first user's open changeset
 
 302       # create a way with non-existing node
 
 303       xml = "<osm><way changeset='#{open_changeset.id}'>" \
 
 304             "<nd ref='0'/><tag k='test' v='yes' /></way></osm>"
 
 305       post api_ways_path, :params => xml, :headers => auth_header
 
 307       assert_response :precondition_failed,
 
 308                       "way upload with invalid node did not return 'precondition failed'"
 
 309       assert_equal "Precondition failed: Way  requires the nodes with id in (0), which either do not exist, or are not visible.", @response.body
 
 311       # create a way with no nodes
 
 312       xml = "<osm><way changeset='#{open_changeset.id}'>" \
 
 313             "<tag k='test' v='yes' /></way></osm>"
 
 314       post api_ways_path, :params => xml, :headers => auth_header
 
 316       assert_response :precondition_failed,
 
 317                       "way upload with no node did not return 'precondition failed'"
 
 318       assert_equal "Precondition failed: Cannot create way: data is invalid.", @response.body
 
 320       # create a way inside a closed changeset
 
 321       xml = "<osm><way changeset='#{closed_changeset.id}'>" \
 
 322             "<nd ref='#{node.id}'/></way></osm>"
 
 323       post api_ways_path, :params => xml, :headers => auth_header
 
 325       assert_response :conflict,
 
 326                       "way upload to closed changeset did not return 'conflict'"
 
 328       # create a way with a tag which is too long
 
 329       xml = "<osm><way changeset='#{open_changeset.id}'>" \
 
 330             "<nd ref='#{node.id}'/>" \
 
 331             "<tag k='foo' v='#{'x' * 256}'/>" \
 
 333       post api_ways_path, :params => xml, :headers => auth_header
 
 335       assert_response :bad_request,
 
 336                       "way upload to with too long tag did not return 'bad_request'"
 
 339     # -------------------------------------
 
 340     # Test deleting ways.
 
 341     # -------------------------------------
 
 344       private_user = create(:user, :data_public => false)
 
 345       private_open_changeset = create(:changeset, :user => private_user)
 
 346       private_closed_changeset = create(:changeset, :closed, :user => private_user)
 
 347       private_way = create(:way, :changeset => private_open_changeset)
 
 348       private_deleted_way = create(:way, :deleted, :changeset => private_open_changeset)
 
 349       private_used_way = create(:way, :changeset => private_open_changeset)
 
 350       create(:relation_member, :member => private_used_way)
 
 352       open_changeset = create(:changeset, :user => user)
 
 353       closed_changeset = create(:changeset, :closed, :user => user)
 
 354       way = create(:way, :changeset => open_changeset)
 
 355       deleted_way = create(:way, :deleted, :changeset => open_changeset)
 
 356       used_way = create(:way, :changeset => open_changeset)
 
 357       relation_member = create(:relation_member, :member => used_way)
 
 358       relation = relation_member.relation
 
 360       # first try to delete way without auth
 
 361       delete api_way_path(way)
 
 362       assert_response :unauthorized
 
 364       # now set auth using the private user
 
 365       auth_header = bearer_authorization_header private_user
 
 367       # this shouldn't work as with the 0.6 api we need pay load to delete
 
 368       delete api_way_path(private_way), :headers => auth_header
 
 369       assert_response :forbidden
 
 371       # Now try without having a changeset
 
 372       xml = "<osm><way id='#{private_way.id}'/></osm>"
 
 373       delete api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 374       assert_response :forbidden
 
 376       # try to delete with an invalid (closed) changeset
 
 377       xml = update_changeset(xml_for_way(private_way), private_closed_changeset.id)
 
 378       delete api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 379       assert_response :forbidden
 
 381       # try to delete with an invalid (non-existent) changeset
 
 382       xml = update_changeset(xml_for_way(private_way), 0)
 
 383       delete api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 384       assert_response :forbidden
 
 386       # Now try with a valid changeset
 
 387       xml = xml_for_way(private_way)
 
 388       delete api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 389       assert_response :forbidden
 
 391       # check the returned value - should be the new version number
 
 392       # valid delete should return the new version number, which should
 
 393       # be greater than the old version number
 
 394       # assert @response.body.to_i > current_ways(:visible_way).version,
 
 395       #   "delete request should return a new version number for way"
 
 397       # this won't work since the way is already deleted
 
 398       xml = xml_for_way(private_deleted_way)
 
 399       delete api_way_path(private_deleted_way), :params => xml.to_s, :headers => auth_header
 
 400       assert_response :forbidden
 
 402       # this shouldn't work as the way is used in a relation
 
 403       xml = xml_for_way(private_used_way)
 
 404       delete api_way_path(private_used_way), :params => xml.to_s, :headers => auth_header
 
 405       assert_response :forbidden,
 
 406                       "shouldn't be able to delete a way used in a relation (#{@response.body}), when done by a private user"
 
 408       # this won't work since the way never existed
 
 409       delete api_way_path(0), :headers => auth_header
 
 410       assert_response :forbidden
 
 412       ### Now check with a public user
 
 414       auth_header = bearer_authorization_header user
 
 416       # this shouldn't work as with the 0.6 api we need pay load to delete
 
 417       delete api_way_path(way), :headers => auth_header
 
 418       assert_response :bad_request
 
 420       # Now try without having a changeset
 
 421       xml = "<osm><way id='#{way.id}'/></osm>"
 
 422       delete api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 423       assert_response :bad_request
 
 425       # try to delete with an invalid (closed) changeset
 
 426       xml = update_changeset(xml_for_way(way), closed_changeset.id)
 
 427       delete api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 428       assert_response :conflict
 
 430       # try to delete with an invalid (non-existent) changeset
 
 431       xml = update_changeset(xml_for_way(way), 0)
 
 432       delete api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 433       assert_response :conflict
 
 435       # Now try with a valid changeset
 
 436       xml = xml_for_way(way)
 
 437       delete api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 438       assert_response :success
 
 440       # check the returned value - should be the new version number
 
 441       # valid delete should return the new version number, which should
 
 442       # be greater than the old version number
 
 443       assert_operator @response.body.to_i, :>, way.version, "delete request should return a new version number for way"
 
 445       # this won't work since the way is already deleted
 
 446       xml = xml_for_way(deleted_way)
 
 447       delete api_way_path(deleted_way), :params => xml.to_s, :headers => auth_header
 
 448       assert_response :gone
 
 450       # this shouldn't work as the way is used in a relation
 
 451       xml = xml_for_way(used_way)
 
 452       delete api_way_path(used_way), :params => xml.to_s, :headers => auth_header
 
 453       assert_response :precondition_failed,
 
 454                       "shouldn't be able to delete a way used in a relation (#{@response.body})"
 
 455       assert_equal "Precondition failed: Way #{used_way.id} is still used by relations #{relation.id}.", @response.body
 
 457       # this won't work since the way never existed
 
 458       delete api_way_path(0), :params => xml.to_s, :headers => auth_header
 
 459       assert_response :not_found
 
 463     # tests whether the API works and prevents incorrect use while trying
 
 466       private_user = create(:user, :data_public => false)
 
 467       private_way = create(:way, :changeset => create(:changeset, :user => private_user))
 
 469       way = create(:way, :changeset => create(:changeset, :user => user))
 
 471       create(:way_node, :way => private_way, :node => node)
 
 472       create(:way_node, :way => way, :node => node)
 
 474       ## First test with no user credentials
 
 475       # try and update a way without authorisation
 
 476       xml = xml_for_way(way)
 
 477       put api_way_path(way), :params => xml.to_s
 
 478       assert_response :unauthorized
 
 480       ## Second test with the private user
 
 483       auth_header = bearer_authorization_header private_user
 
 485       ## trying to break changesets
 
 487       # try and update in someone else's changeset
 
 488       xml = update_changeset(xml_for_way(private_way),
 
 489                              create(:changeset).id)
 
 490       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 491       assert_require_public_data "update with other user's changeset should be forbidden when date isn't public"
 
 493       # try and update in a closed changeset
 
 494       xml = update_changeset(xml_for_way(private_way),
 
 495                              create(:changeset, :closed, :user => private_user).id)
 
 496       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 497       assert_require_public_data "update with closed changeset should be forbidden, when data isn't public"
 
 499       # try and update in a non-existant changeset
 
 500       xml = update_changeset(xml_for_way(private_way), 0)
 
 501       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 502       assert_require_public_data("update with changeset=0 should be forbidden, when data isn't public")
 
 504       ## try and submit invalid updates
 
 505       xml = xml_replace_node(xml_for_way(private_way), node.id, 9999)
 
 506       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 507       assert_require_public_data "way with non-existent node should be forbidden, when data isn't public"
 
 509       xml = xml_replace_node(xml_for_way(private_way), node.id, create(:node, :deleted).id)
 
 510       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 511       assert_require_public_data "way with deleted node should be forbidden, when data isn't public"
 
 513       ## finally, produce a good request which will still not work
 
 514       xml = xml_for_way(private_way)
 
 515       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 516       assert_require_public_data "should have failed with a forbidden when data isn't public"
 
 518       ## Finally test with the public user
 
 521       auth_header = bearer_authorization_header user
 
 523       ## trying to break changesets
 
 525       # try and update in someone else's changeset
 
 526       xml = update_changeset(xml_for_way(way),
 
 527                              create(:changeset).id)
 
 528       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 529       assert_response :conflict, "update with other user's changeset should be rejected"
 
 531       # try and update in a closed changeset
 
 532       xml = update_changeset(xml_for_way(way),
 
 533                              create(:changeset, :closed, :user => user).id)
 
 534       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 535       assert_response :conflict, "update with closed changeset should be rejected"
 
 537       # try and update in a non-existant changeset
 
 538       xml = update_changeset(xml_for_way(way), 0)
 
 539       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 540       assert_response :conflict, "update with changeset=0 should be rejected"
 
 542       ## try and submit invalid updates
 
 543       xml = xml_replace_node(xml_for_way(way), node.id, 9999)
 
 544       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 545       assert_response :precondition_failed, "way with non-existent node should be rejected"
 
 547       xml = xml_replace_node(xml_for_way(way), node.id, create(:node, :deleted).id)
 
 548       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 549       assert_response :precondition_failed, "way with deleted node should be rejected"
 
 551       ## next, attack the versioning
 
 552       current_way_version = way.version
 
 554       # try and submit a version behind
 
 555       xml = xml_attr_rewrite(xml_for_way(way),
 
 556                              "version", current_way_version - 1)
 
 557       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 558       assert_response :conflict, "should have failed on old version number"
 
 560       # try and submit a version ahead
 
 561       xml = xml_attr_rewrite(xml_for_way(way),
 
 562                              "version", current_way_version + 1)
 
 563       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 564       assert_response :conflict, "should have failed on skipped version number"
 
 566       # try and submit total crap in the version field
 
 567       xml = xml_attr_rewrite(xml_for_way(way),
 
 568                              "version", "p1r4t3s!")
 
 569       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 570       assert_response :conflict,
 
 571                       "should not be able to put 'p1r4at3s!' in the version field"
 
 573       ## try an update with the wrong ID
 
 574       xml = xml_for_way(create(:way))
 
 575       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 576       assert_response :bad_request,
 
 577                       "should not be able to update a way with a different ID from the XML"
 
 579       ## try an update with a minimal valid XML doc which isn't a well-formed OSM doc.
 
 581       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 582       assert_response :bad_request,
 
 583                       "should not be able to update a way with non-OSM XML doc."
 
 585       ## finally, produce a good request which should work
 
 586       xml = xml_for_way(way)
 
 587       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 588       assert_response :success, "a valid update request failed"
 
 591     # ------------------------------------------------------------
 
 593     # ------------------------------------------------------------
 
 596     # Try adding a new tag to a way
 
 598       private_user = create(:user, :data_public => false)
 
 599       private_way = create(:way_with_nodes, :nodes_count => 2, :changeset => create(:changeset, :user => private_user))
 
 601       way = create(:way_with_nodes, :nodes_count => 2, :changeset => create(:changeset, :user => user))
 
 603       ## Try with the non-public user
 
 605       auth_header = bearer_authorization_header private_user
 
 607       # add an identical tag to the way
 
 608       tag_xml = XML::Node.new("tag")
 
 612       # add the tag into the existing xml
 
 613       way_xml = xml_for_way(private_way)
 
 614       way_xml.find("//osm/way").first << tag_xml
 
 617       put api_way_path(private_way), :params => way_xml.to_s, :headers => auth_header
 
 618       assert_response :forbidden,
 
 619                       "adding a duplicate tag to a way for a non-public should fail with 'forbidden'"
 
 621       ## Now try with the public user
 
 623       auth_header = bearer_authorization_header user
 
 625       # add an identical tag to the way
 
 626       tag_xml = XML::Node.new("tag")
 
 630       # add the tag into the existing xml
 
 631       way_xml = xml_for_way(way)
 
 632       way_xml.find("//osm/way").first << tag_xml
 
 635       put api_way_path(way), :params => way_xml.to_s, :headers => auth_header
 
 636       assert_response :success,
 
 637                       "adding a new tag to a way should succeed"
 
 638       assert_equal way.version + 1, @response.body.to_i
 
 642     # Try adding a duplicate of an existing tag to a way
 
 643     def test_add_duplicate_tags
 
 644       private_user = create(:user, :data_public => false)
 
 645       private_way = create(:way, :changeset => create(:changeset, :user => private_user))
 
 646       private_existing_tag = create(:way_tag, :way => private_way)
 
 648       way = create(:way, :changeset => create(:changeset, :user => user))
 
 649       existing_tag = create(:way_tag, :way => way)
 
 651       ## Try with the non-public user
 
 653       auth_header = bearer_authorization_header private_user
 
 655       # add an identical tag to the way
 
 656       tag_xml = XML::Node.new("tag")
 
 657       tag_xml["k"] = private_existing_tag.k
 
 658       tag_xml["v"] = private_existing_tag.v
 
 660       # add the tag into the existing xml
 
 661       way_xml = xml_for_way(private_way)
 
 662       way_xml.find("//osm/way").first << tag_xml
 
 665       put api_way_path(private_way), :params => way_xml.to_s, :headers => auth_header
 
 666       assert_response :forbidden,
 
 667                       "adding a duplicate tag to a way for a non-public should fail with 'forbidden'"
 
 669       ## Now try with the public user
 
 671       auth_header = bearer_authorization_header user
 
 673       # add an identical tag to the way
 
 674       tag_xml = XML::Node.new("tag")
 
 675       tag_xml["k"] = existing_tag.k
 
 676       tag_xml["v"] = existing_tag.v
 
 678       # add the tag into the existing xml
 
 679       way_xml = xml_for_way(way)
 
 680       way_xml.find("//osm/way").first << tag_xml
 
 683       put api_way_path(way), :params => way_xml.to_s, :headers => auth_header
 
 684       assert_response :bad_request,
 
 685                       "adding a duplicate tag to a way should fail with 'bad request'"
 
 686       assert_equal "Element way/#{way.id} has duplicate tags with key #{existing_tag.k}", @response.body
 
 690     # Try adding a new duplicate tags to a way
 
 691     def test_new_duplicate_tags
 
 692       private_user = create(:user, :data_public => false)
 
 693       private_way = create(:way, :changeset => create(:changeset, :user => private_user))
 
 695       way = create(:way, :changeset => create(:changeset, :user => user))
 
 697       ## First test with the non-public user so should be rejected
 
 699       auth_header = bearer_authorization_header private_user
 
 701       # create duplicate tag
 
 702       tag_xml = XML::Node.new("tag")
 
 703       tag_xml["k"] = "i_am_a_duplicate"
 
 704       tag_xml["v"] = "foobar"
 
 706       # add the tag into the existing xml
 
 707       way_xml = xml_for_way(private_way)
 
 709       # add two copies of the tag
 
 710       way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
 
 713       put api_way_path(private_way), :params => way_xml.to_s, :headers => auth_header
 
 714       assert_response :forbidden,
 
 715                       "adding new duplicate tags to a way using a non-public user should fail with 'forbidden'"
 
 717       ## Now test with the public user
 
 719       auth_header = bearer_authorization_header user
 
 721       # create duplicate tag
 
 722       tag_xml = XML::Node.new("tag")
 
 723       tag_xml["k"] = "i_am_a_duplicate"
 
 724       tag_xml["v"] = "foobar"
 
 726       # add the tag into the existing xml
 
 727       way_xml = xml_for_way(way)
 
 729       # add two copies of the tag
 
 730       way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
 
 733       put api_way_path(way), :params => way_xml.to_s, :headers => auth_header
 
 734       assert_response :bad_request,
 
 735                       "adding new duplicate tags to a way should fail with 'bad request'"
 
 736       assert_equal "Element way/#{way.id} has duplicate tags with key i_am_a_duplicate", @response.body
 
 740     # Try adding a new duplicate tags to a way.
 
 741     # But be a bit subtle - use unicode decoding ambiguities to use different
 
 742     # binary strings which have the same decoding.
 
 743     def test_invalid_duplicate_tags
 
 744       private_user = create(:user, :data_public => false)
 
 745       private_changeset = create(:changeset, :user => private_user)
 
 747       changeset = create(:changeset, :user => user)
 
 749       ## First make sure that you can't with a non-public user
 
 751       auth_header = bearer_authorization_header private_user
 
 753       # add the tag into the existing xml
 
 754       way_str = "<osm><way changeset='#{private_changeset.id}'>"
 
 755       way_str << "<tag k='addr:housenumber' v='1'/>"
 
 756       way_str << "<tag k='addr:housenumber' v='2'/>"
 
 757       way_str << "</way></osm>"
 
 760       post api_ways_path, :params => way_str, :headers => auth_header
 
 761       assert_response :forbidden,
 
 762                       "adding new duplicate tags to a way with a non-public user should fail with 'forbidden'"
 
 764       ## Now do it with a public user
 
 766       auth_header = bearer_authorization_header user
 
 768       # add the tag into the existing xml
 
 769       way_str = "<osm><way changeset='#{changeset.id}'>"
 
 770       way_str << "<tag k='addr:housenumber' v='1'/>"
 
 771       way_str << "<tag k='addr:housenumber' v='2'/>"
 
 772       way_str << "</way></osm>"
 
 775       post api_ways_path, :params => way_str, :headers => auth_header
 
 776       assert_response :bad_request,
 
 777                       "adding new duplicate tags to a way should fail with 'bad request'"
 
 778       assert_equal "Element way/ has duplicate tags with key addr:housenumber", @response.body
 
 782     # test initial rate limit
 
 783     def test_initial_rate_limit
 
 788       node1 = create(:node)
 
 789       node2 = create(:node)
 
 791       # create a changeset that puts us near the initial rate limit
 
 792       changeset = create(:changeset, :user => user,
 
 793                                      :created_at => Time.now.utc - 5.minutes,
 
 794                                      :num_changes => Settings.initial_changes_per_hour - 1)
 
 796       # create authentication header
 
 797       auth_header = bearer_authorization_header user
 
 800       xml = "<osm><way changeset='#{changeset.id}'>" \
 
 801             "<nd ref='#{node1.id}'/><nd ref='#{node2.id}'/>" \
 
 802             "<tag k='test' v='yes' /></way></osm>"
 
 803       post api_ways_path, :params => xml, :headers => auth_header
 
 804       assert_response :success, "way create did not return success status"
 
 806       # get the id of the way we created
 
 807       wayid = @response.body
 
 809       # try updating the way, which should be rate limited
 
 810       xml = "<osm><way id='#{wayid}' version='1' changeset='#{changeset.id}'>" \
 
 811             "<nd ref='#{node2.id}'/><nd ref='#{node1.id}'/>" \
 
 812             "<tag k='test' v='yes' /></way></osm>"
 
 813       put api_way_path(wayid), :params => xml, :headers => auth_header
 
 814       assert_response :too_many_requests, "way update did not hit rate limit"
 
 816       # try deleting the way, which should be rate limited
 
 817       xml = "<osm><way id='#{wayid}' version='2' changeset='#{changeset.id}'/></osm>"
 
 818       delete api_way_path(wayid), :params => xml, :headers => auth_header
 
 819       assert_response :too_many_requests, "way delete did not hit rate limit"
 
 821       # try creating a way, which should be rate limited
 
 822       xml = "<osm><way changeset='#{changeset.id}'>" \
 
 823             "<nd ref='#{node1.id}'/><nd ref='#{node2.id}'/>" \
 
 824             "<tag k='test' v='yes' /></way></osm>"
 
 825       post api_ways_path, :params => xml, :headers => auth_header
 
 826       assert_response :too_many_requests, "way create did not hit rate limit"
 
 830     # test maximum rate limit
 
 831     def test_maximum_rate_limit
 
 836       node1 = create(:node)
 
 837       node2 = create(:node)
 
 839       # create a changeset to establish our initial edit time
 
 840       changeset = create(:changeset, :user => user,
 
 841                                      :created_at => Time.now.utc - 28.days)
 
 843       # create changeset to put us near the maximum rate limit
 
 844       total_changes = Settings.max_changes_per_hour - 1
 
 845       while total_changes.positive?
 
 846         changes = [total_changes, Changeset::MAX_ELEMENTS].min
 
 847         changeset = create(:changeset, :user => user,
 
 848                                        :created_at => Time.now.utc - 5.minutes,
 
 849                                        :num_changes => changes)
 
 850         total_changes -= changes
 
 853       # create authentication header
 
 854       auth_header = bearer_authorization_header user
 
 857       xml = "<osm><way changeset='#{changeset.id}'>" \
 
 858             "<nd ref='#{node1.id}'/><nd ref='#{node2.id}'/>" \
 
 859             "<tag k='test' v='yes' /></way></osm>"
 
 860       post api_ways_path, :params => xml, :headers => auth_header
 
 861       assert_response :success, "way create did not return success status"
 
 863       # get the id of the way we created
 
 864       wayid = @response.body
 
 866       # try updating the way, which should be rate limited
 
 867       xml = "<osm><way id='#{wayid}' version='1' changeset='#{changeset.id}'>" \
 
 868             "<nd ref='#{node2.id}'/><nd ref='#{node1.id}'/>" \
 
 869             "<tag k='test' v='yes' /></way></osm>"
 
 870       put api_way_path(wayid), :params => xml, :headers => auth_header
 
 871       assert_response :too_many_requests, "way update did not hit rate limit"
 
 873       # try deleting the way, which should be rate limited
 
 874       xml = "<osm><way id='#{wayid}' version='2' changeset='#{changeset.id}'/></osm>"
 
 875       delete api_way_path(wayid), :params => xml, :headers => auth_header
 
 876       assert_response :too_many_requests, "way delete did not hit rate limit"
 
 878       # try creating a way, which should be rate limited
 
 879       xml = "<osm><way changeset='#{changeset.id}'>" \
 
 880             "<nd ref='#{node1.id}'/><nd ref='#{node2.id}'/>" \
 
 881             "<tag k='test' v='yes' /></way></osm>"
 
 882       post api_ways_path, :params => xml, :headers => auth_header
 
 883       assert_response :too_many_requests, "way create did not hit rate limit"
 
 889     # update the changeset_id of a way element
 
 890     def update_changeset(xml, changeset_id)
 
 891       xml_attr_rewrite(xml, "changeset", changeset_id)
 
 895     # update an attribute in the way element
 
 896     def xml_attr_rewrite(xml, name, value)
 
 897       xml.find("//osm/way").first[name] = value.to_s
 
 902     # replace a node in a way element
 
 903     def xml_replace_node(xml, old_node, new_node)
 
 904       xml.find("//osm/way/nd[@ref='#{old_node}']").first["ref"] = new_node.to_s