1 # frozen_string_literal: true
 
   7     class UploadsControllerTest < ActionDispatch::IntegrationTest
 
   9       # test all routes which lead to this controller
 
  12           { :path => "/api/0.6/changeset/1/upload", :method => :post },
 
  13           { :controller => "api/changesets/uploads", :action => "create", :changeset_id => "1" }
 
  17       def test_upload_when_unauthorized
 
  18         changeset = create(:changeset)
 
  19         node = create(:node, :latitude => 0, :longitude => 0)
 
  24               <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='1'/>
 
  29         post api_changeset_upload_path(changeset), :params => diff
 
  31         assert_response :unauthorized
 
  33         assert_no_changes_in changeset
 
  36         assert_equal 1, node.version
 
  37         assert_equal 0, node.latitude
 
  38         assert_equal 0, node.longitude
 
  41       def test_upload_by_private_user
 
  42         user = create(:user, :data_public => false)
 
  43         changeset = create(:changeset, :user => user)
 
  44         node = create(:node, :latitude => 0, :longitude => 0)
 
  49               <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='1'/>
 
  54         auth_header = bearer_authorization_header user
 
  56         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
  58         assert_response :forbidden
 
  60         assert_no_changes_in changeset
 
  63         assert_equal 1, node.version
 
  64         assert_equal 0, node.latitude
 
  65         assert_equal 0, node.longitude
 
  68       def test_upload_without_required_scope
 
  70         changeset = create(:changeset, :user => user)
 
  71         node = create(:node, :latitude => 0, :longitude => 0)
 
  76               <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='1'/>
 
  81         auth_header = bearer_authorization_header user, :scopes => %w[read_prefs]
 
  83         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
  85         assert_response :forbidden
 
  87         assert_no_changes_in changeset
 
  90         assert_equal 1, node.version
 
  91         assert_equal 0, node.latitude
 
  92         assert_equal 0, node.longitude
 
  95       def test_upload_with_required_scope
 
  97         changeset = create(:changeset, :user => user)
 
  98         node = create(:node, :latitude => 0, :longitude => 0)
 
 103               <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='1'/>
 
 108         auth_header = bearer_authorization_header user, :scopes => %w[write_api]
 
 110         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 112         assert_response :success
 
 114         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 115           assert_dom "> node", 1 do
 
 116             assert_dom "> @old_id", node.id.to_s
 
 117             assert_dom "> @new_id", node.id.to_s
 
 118             assert_dom "> @new_version", "2"
 
 123         assert_equal 1, changeset.num_changes
 
 124         assert_predicate changeset, :num_type_changes_in_sync?
 
 125         assert_equal 1, changeset.num_modified_nodes
 
 128         assert_equal 2, node.version
 
 129         assert_equal 2 * GeoRecord::SCALE, node.latitude
 
 130         assert_equal 1 * GeoRecord::SCALE, node.longitude
 
 134       # try to upload with commands other than create, modify, or delete
 
 135       def test_upload_unknown_action
 
 136         changeset = create(:changeset)
 
 141               <node id='1' lon='1' lat='1' changeset='#{changeset.id}' />
 
 146         auth_header = bearer_authorization_header changeset.user
 
 148         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 150         assert_response :bad_request
 
 151         assert_equal "Unknown action ping, choices are create, modify, delete", @response.body
 
 153         assert_no_changes_in changeset
 
 157       # test for issues in https://github.com/openstreetmap/trac-tickets/issues/1568
 
 158       def test_upload_empty_changeset
 
 159         changeset = create(:changeset)
 
 161         auth_header = bearer_authorization_header changeset.user
 
 164          "<osmChange></osmChange>",
 
 165          "<osmChange><modify/></osmChange>",
 
 166          "<osmChange><modify></modify></osmChange>"].each do |diff|
 
 167           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 169           assert_response :success
 
 172         assert_no_changes_in changeset
 
 176       # test that the X-Error-Format header works to request XML errors
 
 177       def test_upload_xml_errors
 
 178         changeset = create(:changeset)
 
 180         create(:relation_member, :member => node)
 
 182         # try and delete a node that is in use
 
 183         diff = XML::Document.new
 
 184         diff.root = XML::Node.new "osmChange"
 
 185         delete = XML::Node.new "delete"
 
 187         delete << xml_node_for_node(node)
 
 189         auth_header = bearer_authorization_header changeset.user
 
 190         error_header = error_format_header "xml"
 
 192         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header.merge(error_header)
 
 194         assert_response :success
 
 196         assert_dom "osmError[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 197         assert_dom "osmError>status", 1
 
 198         assert_dom "osmError>message", 1
 
 201       def test_upload_race_condition
 
 203         changeset = create(:changeset, :user => user)
 
 208               <node id='-1' lon='1' lat='2' changeset='#{changeset.id}'/>
 
 213         auth_header = bearer_authorization_header user, :scopes => %w[write_api]
 
 214         path = api_changeset_upload_path(changeset)
 
 215         concurrency_level = 16
 
 217         threads = Array.new(concurrency_level) do
 
 219             post path, :params => diff, :headers => auth_header
 
 225         assert_equal concurrency_level, changeset.num_changes
 
 226         assert_predicate changeset, :num_type_changes_in_sync?
 
 227         assert_equal concurrency_level, changeset.num_created_nodes
 
 230       # -------------------------------------
 
 231       # Test creating elements.
 
 232       # -------------------------------------
 
 234       def test_upload_create_node
 
 236         changeset = create(:changeset, :user => user)
 
 241               <node id='-1' lon='30' lat='60' changeset='#{changeset.id}'>
 
 242                 <tag k='amenity' v='bar'/>
 
 243                 <tag k='name' v='Foo'/>
 
 249         auth_header = bearer_authorization_header user
 
 251         assert_difference "Node.count" => 1,
 
 252                           "OldNode.count" => 1,
 
 253                           "NodeTag.count" => 2,
 
 254                           "OldNodeTag.count" => 2 do
 
 255           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 257           assert_response :success
 
 261         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 262           assert_dom "> node", 1 do |(node_el)|
 
 263             node = Node.find(node_el["new_id"].to_i)
 
 264             assert_dom "> @old_id", "-1"
 
 265             assert_dom "> @new_version", "1"
 
 270         assert_equal 1, changeset.num_changes
 
 271         assert_predicate changeset, :num_type_changes_in_sync?
 
 272         assert_equal 1, changeset.num_created_nodes
 
 274         assert_equal 1, node.version
 
 275         assert_equal changeset, node.changeset
 
 276         assert_predicate node, :visible?
 
 277         assert_equal({ "name" => "Foo", "amenity" => "bar" }, node.tags)
 
 278         assert_equal 60, node.lat
 
 279         assert_equal 30, node.lon
 
 282       def test_upload_create_way
 
 283         node1 = create(:node)
 
 284         node2 = create(:node)
 
 286         changeset = create(:changeset, :user => user)
 
 291               <way id='-1' changeset='#{changeset.id}'>
 
 292                 <tag k='highway' v='primary'/>
 
 293                 <tag k='name' v='Foo'/>
 
 294                 <nd ref='#{node1.id}'/>
 
 295                 <nd ref='#{node2.id}'/>
 
 301         auth_header = bearer_authorization_header user
 
 303         assert_difference "Way.count" => 1,
 
 306                           "OldWayTag.count" => 2,
 
 307                           "WayNode.count" => 2,
 
 308                           "OldWayNode.count" => 2 do
 
 309           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 311           assert_response :success
 
 315         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 316           assert_dom "> way", 1 do |(way_el)|
 
 317             way = Way.find(way_el["new_id"].to_i)
 
 318             assert_dom "> @old_id", "-1"
 
 319             assert_dom "> @new_version", "1"
 
 324         assert_equal 1, changeset.num_changes
 
 325         assert_predicate changeset, :num_type_changes_in_sync?
 
 326         assert_equal 1, changeset.num_created_ways
 
 328         assert_equal 1, way.version
 
 329         assert_equal changeset, way.changeset
 
 330         assert_predicate way, :visible?
 
 331         assert_equal({ "name" => "Foo", "highway" => "primary" }, way.tags)
 
 332         assert_equal [node1, node2], way.nodes
 
 335       def test_upload_create_relation
 
 336         node1 = create(:node)
 
 337         way1 = create(:way_with_nodes)
 
 338         relation1 = create(:relation)
 
 340         changeset = create(:changeset, :user => user)
 
 345               <relation id='-1' changeset='#{changeset.id}'>
 
 346                 <member type='node' role='n_role' ref='#{node1.id}'/>
 
 347                 <member type='way' role='w_role' ref='#{way1.id}'/>
 
 348                 <member type='relation' role='r_role' ref='#{relation1.id}'/>
 
 349                 <tag k='type' v='collection'/>
 
 355         auth_header = bearer_authorization_header user
 
 357         assert_difference "Relation.count" => 1,
 
 358                           "OldRelation.count" => 1,
 
 359                           "RelationTag.count" => 1,
 
 360                           "OldRelationTag.count" => 1,
 
 361                           "RelationMember.count" => 3,
 
 362                           "OldRelationMember.count" => 3 do
 
 363           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 365           assert_response :success
 
 369         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 370           assert_dom "> relation", 1 do |(relation_el)|
 
 371             relation = Relation.find(relation_el["new_id"].to_i)
 
 372             assert_dom "> @old_id", "-1"
 
 373             assert_dom "> @new_version", "1"
 
 378         assert_equal 1, changeset.num_changes
 
 379         assert_predicate changeset, :num_type_changes_in_sync?
 
 380         assert_equal 1, changeset.num_created_relations
 
 382         assert_equal 1, relation.version
 
 383         assert_equal changeset, relation.changeset
 
 384         assert_predicate relation, :visible?
 
 385         assert_equal({ "type" => "collection" }, relation.tags)
 
 386         assert_equal [["Node", node1.id, "n_role"],
 
 387                       ["Way", way1.id, "w_role"],
 
 388                       ["Relation", relation1.id, "r_role"]], relation.members
 
 391       def test_upload_create_elements
 
 393         changeset = create(:changeset, :user => user)
 
 395         way = create(:way_with_nodes, :nodes_count => 2)
 
 396         relation = create(:relation)
 
 401               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 402                 <tag k='foo' v='bar'/>
 
 403                 <tag k='baz' v='bat'/>
 
 405               <way id='-1' changeset='#{changeset.id}'>
 
 406                 <nd ref='#{node.id}'/>
 
 410               <relation id='-1' changeset='#{changeset.id}'>
 
 411                 <member type='way' role='some' ref='#{way.id}'/>
 
 412                 <member type='node' role='some' ref='#{node.id}'/>
 
 413                 <member type='relation' role='some' ref='#{relation.id}'/>
 
 419         auth_header = bearer_authorization_header user
 
 421         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 423         assert_response :success
 
 425         new_node_id, new_way_id, new_rel_id = nil
 
 426         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 427           # inspect the response to find out what the new element IDs are
 
 428           # check the old IDs are all present and negative one
 
 429           # check the versions are present and equal one
 
 430           assert_dom "> node", 1 do |(node_el)|
 
 431             new_node_id = node_el["new_id"].to_i
 
 432             assert_dom "> @old_id", "-1"
 
 433             assert_dom "> @new_version", "1"
 
 435           assert_dom "> way", 1 do |(way_el)|
 
 436             new_way_id = way_el["new_id"].to_i
 
 437             assert_dom "> @old_id", "-1"
 
 438             assert_dom "> @new_version", "1"
 
 440           assert_dom "> relation", 1 do |(rel_el)|
 
 441             new_rel_id = rel_el["new_id"].to_i
 
 442             assert_dom "> @old_id", "-1"
 
 443             assert_dom "> @new_version", "1"
 
 448         assert_equal 3, changeset.num_changes
 
 449         assert_predicate changeset, :num_type_changes_in_sync?
 
 450         assert_equal 1, changeset.num_created_nodes
 
 451         assert_equal 1, changeset.num_created_ways
 
 452         assert_equal 1, changeset.num_created_relations
 
 454         assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
 455         assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
 
 456         assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
 
 460       # upload an element with a really long tag value
 
 461       def test_upload_create_node_with_tag_too_long
 
 462         changeset = create(:changeset)
 
 467               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 468                 <tag k='foo' v='#{'x' * 256}'/>
 
 474         auth_header = bearer_authorization_header changeset.user
 
 476         assert_no_difference "Node.count" do
 
 477           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 479           assert_response :bad_request
 
 482         assert_no_changes_in changeset
 
 485       def test_upload_create_nodes_with_invalid_placeholder_reuse_in_one_action_block
 
 486         changeset = create(:changeset)
 
 491               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
 492               <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
 497         auth_header = bearer_authorization_header changeset.user
 
 499         assert_no_difference "Node.count" do
 
 500           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 502           assert_response :bad_request
 
 505         assert_no_changes_in changeset
 
 508       def test_upload_create_nodes_with_invalid_placeholder_reuse_in_two_action_blocks
 
 509         changeset = create(:changeset)
 
 514               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
 517               <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
 522         auth_header = bearer_authorization_header changeset.user
 
 524         assert_no_difference "Node.count" do
 
 525           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 527           assert_response :bad_request
 
 530         assert_no_changes_in changeset
 
 533       def test_upload_create_way_referring_node_placeholder_defined_later
 
 534         changeset = create(:changeset)
 
 539               <way id="-1" changeset="#{changeset.id}">
 
 542               <node id="-1" lat="1" lon="2" changeset="#{changeset.id}"/>
 
 547         auth_header = bearer_authorization_header changeset.user
 
 549         assert_no_difference "Node.count" do
 
 550           assert_no_difference "Way.count" do
 
 551             post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 553             assert_response :bad_request
 
 556         assert_equal "Placeholder node not found for reference -1 in way -1", @response.body
 
 558         assert_no_changes_in changeset
 
 561       def test_upload_create_way_referring_undefined_node_placeholder
 
 562         changeset = create(:changeset)
 
 567               <way id="-1" changeset="#{changeset.id}">
 
 574         auth_header = bearer_authorization_header changeset.user
 
 576         assert_no_difference "Way.count" do
 
 577           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 579           assert_response :bad_request
 
 581         assert_equal "Placeholder node not found for reference -1 in way -1", @response.body
 
 583         assert_no_changes_in changeset
 
 586       def test_upload_create_existing_way_referring_undefined_node_placeholder
 
 587         changeset = create(:changeset)
 
 593               <way id="#{way.id}" changeset="#{changeset.id}" version="1">
 
 600         auth_header = bearer_authorization_header changeset.user
 
 602         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 604         assert_response :bad_request
 
 605         assert_equal "Placeholder node not found for reference -1 in way #{way.id}", @response.body
 
 607         assert_no_changes_in changeset
 
 610         assert_equal 1, way.version
 
 613       def test_upload_create_relation_referring_undefined_node_placeholder
 
 614         changeset = create(:changeset)
 
 619               <relation id="-1" changeset="#{changeset.id}" version="1">
 
 620                 <member type="node" role="foo" ref="-1"/>
 
 626         auth_header = bearer_authorization_header changeset.user
 
 628         assert_no_difference "Relation.count" do
 
 629           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 631           assert_response :bad_request
 
 633         assert_equal "Placeholder Node not found for reference -1 in relation -1.", @response.body
 
 635         assert_no_changes_in changeset
 
 638       def test_upload_create_existing_relation_referring_undefined_way_placeholder
 
 639         changeset = create(:changeset)
 
 640         relation = create(:relation)
 
 645               <relation id="#{relation.id}" changeset="#{changeset.id}" version="1">
 
 646                 <member type="way" role="bar" ref="-1"/>
 
 652         auth_header = bearer_authorization_header changeset.user
 
 654         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 656         assert_response :bad_request
 
 657         assert_equal "Placeholder Way not found for reference -1 in relation #{relation.id}.", @response.body
 
 659         assert_no_changes_in changeset
 
 662         assert_equal 1, relation.version
 
 665       def test_upload_create_relations_with_circular_references
 
 666         changeset = create(:changeset)
 
 669           <osmChange version='0.6'>
 
 671               <relation id='-2' version='0' changeset='#{changeset.id}'>
 
 672                 <member type='relation' role='' ref='-4' />
 
 673                 <tag k='type' v='route' />
 
 674                 <tag k='name' v='AtoB' />
 
 676               <relation id='-3' version='0' changeset='#{changeset.id}'>
 
 677                 <tag k='type' v='route' />
 
 678                 <tag k='name' v='BtoA' />
 
 680               <relation id='-4' version='0' changeset='#{changeset.id}'>
 
 681                 <member type='relation' role='' ref='-2' />
 
 682                 <member type='relation' role='' ref='-3' />
 
 683                 <tag k='type' v='route_master' />
 
 684                 <tag k='name' v='master' />
 
 690         auth_header = bearer_authorization_header changeset.user
 
 692         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
 694         assert_response :bad_request
 
 695         assert_equal "Placeholder Relation not found for reference -4 in relation -2.", @response.body
 
 697         assert_no_changes_in changeset
 
 700       # -------------------------------------
 
 701       # Test modifying elements.
 
 702       # -------------------------------------
 
 704       def test_upload_modify_node
 
 706         changeset = create(:changeset, :user => user)
 
 707         node = create(:node, :latitude => 0, :longitude => 0)
 
 708         create(:node_tag, :node => node)
 
 713               <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='1'/>
 
 718         auth_header = bearer_authorization_header user
 
 720         assert_difference "Node.count" => 0,
 
 721                           "OldNode.count" => 1,
 
 722                           "NodeTag.count" => -1,
 
 723                           "OldNodeTag.count" => 0 do
 
 724           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 726           assert_response :success
 
 729         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 730           assert_dom "> node", 1 do
 
 731             assert_dom "> @old_id", node.id.to_s
 
 732             assert_dom "> @new_id", node.id.to_s
 
 733             assert_dom "> @new_version", "2"
 
 738         assert_equal 1, changeset.num_changes
 
 739         assert_predicate changeset, :num_type_changes_in_sync?
 
 740         assert_equal 1, changeset.num_modified_nodes
 
 743         assert_equal 2, node.version
 
 744         assert_equal 2 * GeoRecord::SCALE, node.latitude
 
 745         assert_equal 1 * GeoRecord::SCALE, node.longitude
 
 746         assert_equal 0, node.tags.size, "node #{node.id} should now have no tags"
 
 749       def test_upload_modify_way
 
 751         changeset = create(:changeset, :user => user)
 
 753         way = create(:way_with_nodes, :nodes_count => 3)
 
 754         create(:way_tag, :way => way)
 
 759               <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
 760                 <nd ref='#{node.id}'/>
 
 766         auth_header = bearer_authorization_header user
 
 768         assert_difference "Way.count" => 0,
 
 770                           "WayTag.count" => -1,
 
 771                           "OldWayTag.count" => 0,
 
 772                           "WayNode.count" => -2,
 
 773                           "OldWayNode.count" => 1 do
 
 774           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 776           assert_response :success
 
 779         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 780           assert_dom "> way", 1 do
 
 781             assert_dom "> @old_id", way.id.to_s
 
 782             assert_dom "> @new_id", way.id.to_s
 
 783             assert_dom "> @new_version", "2"
 
 788         assert_equal 1, changeset.num_changes
 
 789         assert_predicate changeset, :num_type_changes_in_sync?
 
 790         assert_equal 1, changeset.num_modified_ways
 
 793         assert_equal 2, way.version
 
 794         assert_equal 0, way.tags.size, "way #{way.id} should now have no tags"
 
 795         assert_equal [node], way.nodes
 
 798       def test_upload_modify_relation
 
 800         changeset = create(:changeset, :user => user)
 
 802         way = create(:way_with_nodes)
 
 803         relation = create(:relation)
 
 804         other_relation = create(:relation)
 
 805         create(:relation_tag, :relation => relation)
 
 810               <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
 811                 <member type='way' role='some' ref='#{way.id}'/>
 
 812                 <member type='node' role='some' ref='#{node.id}'/>
 
 813                 <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 819         auth_header = bearer_authorization_header user
 
 821         assert_difference "Relation.count" => 0,
 
 822                           "OldRelation.count" => 1,
 
 823                           "RelationTag.count" => -1,
 
 824                           "OldRelationTag.count" => 0,
 
 825                           "RelationMember.count" => 3,
 
 826                           "OldRelationMember.count" => 3 do
 
 827           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 829           assert_response :success
 
 832         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 833           assert_dom "> relation", 1 do
 
 834             assert_dom "> @old_id", relation.id.to_s
 
 835             assert_dom "> @new_id", relation.id.to_s
 
 836             assert_dom "> @new_version", "2"
 
 841         assert_equal 1, changeset.num_changes
 
 842         assert_predicate changeset, :num_type_changes_in_sync?
 
 843         assert_equal 1, changeset.num_modified_relations
 
 846         assert_equal 2, relation.version
 
 847         assert_equal 0, relation.tags.size, "relation #{relation.id} should now have no tags"
 
 848         assert_equal [["Way", way.id, "some"], ["Node", node.id, "some"], ["Relation", other_relation.id, "some"]], relation.members
 
 851       def test_upload_modify_elements
 
 853         changeset = create(:changeset, :user => user)
 
 854         node = create(:node, :latitude => 0, :longitude => 0)
 
 856         relation = create(:relation)
 
 857         other_relation = create(:relation)
 
 859         # create some tags, since we test that they are removed later
 
 860         create(:node_tag, :node => node)
 
 861         create(:way_tag, :way => way)
 
 862         create(:relation_tag, :relation => relation)
 
 864         # simple diff to change a node, way and relation by removing their tags
 
 868               <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='1'/>
 
 869               <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
 870                 <nd ref='#{node.id}'/>
 
 874               <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
 875                 <member type='way' role='some' ref='#{way.id}'/>
 
 876                 <member type='node' role='some' ref='#{node.id}'/>
 
 877                 <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 883         auth_header = bearer_authorization_header user
 
 885         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 887         assert_response :success
 
 889         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 890           assert_dom "> node", 1 do
 
 891             assert_dom "> @old_id", node.id.to_s
 
 892             assert_dom "> @new_id", node.id.to_s
 
 893             assert_dom "> @new_version", "2"
 
 895           assert_dom "> way", 1 do
 
 896             assert_dom "> @old_id", way.id.to_s
 
 897             assert_dom "> @new_id", way.id.to_s
 
 898             assert_dom "> @new_version", "2"
 
 900           assert_dom "> relation", 1 do
 
 901             assert_dom "> @old_id", relation.id.to_s
 
 902             assert_dom "> @new_id", relation.id.to_s
 
 903             assert_dom "> @new_version", "2"
 
 908         assert_equal 3, changeset.num_changes
 
 909         assert_predicate changeset, :num_type_changes_in_sync?
 
 910         assert_equal 1, changeset.num_modified_nodes
 
 911         assert_equal 1, changeset.num_modified_ways
 
 912         assert_equal 1, changeset.num_modified_relations
 
 915         assert_equal 2, node.version
 
 916         assert_equal 2 * GeoRecord::SCALE, node.latitude
 
 917         assert_equal 1 * GeoRecord::SCALE, node.longitude
 
 918         assert_equal 0, node.tags.size, "node #{node.id} should now have no tags"
 
 920         assert_equal 2, way.version
 
 921         assert_equal 0, way.tags.size, "way #{way.id} should now have no tags"
 
 922         assert_equal [node], way.nodes
 
 924         assert_equal 2, relation.version
 
 925         assert_equal 0, relation.tags.size, "relation #{relation.id} should now have no tags"
 
 926         assert_equal [["Way", way.id, "some"], ["Node", node.id, "some"], ["Relation", other_relation.id, "some"]], relation.members
 
 930       # upload multiple versions of the same element in the same diff.
 
 931       def test_upload_modify_multiple_node_versions
 
 933         changeset = create(:changeset)
 
 935         # change the location of a node multiple times, each time referencing
 
 936         # the last version. doesn't this depend on version numbers being
 
 941               <node id='#{node.id}' lon='0.0' lat='0.0' changeset='#{changeset.id}' version='1'/>
 
 942               <node id='#{node.id}' lon='0.1' lat='0.0' changeset='#{changeset.id}' version='2'/>
 
 943               <node id='#{node.id}' lon='0.1' lat='0.1' changeset='#{changeset.id}' version='3'/>
 
 944               <node id='#{node.id}' lon='0.1' lat='0.2' changeset='#{changeset.id}' version='4'/>
 
 945               <node id='#{node.id}' lon='0.2' lat='0.2' changeset='#{changeset.id}' version='5'/>
 
 946               <node id='#{node.id}' lon='0.3' lat='0.2' changeset='#{changeset.id}' version='6'/>
 
 947               <node id='#{node.id}' lon='0.3' lat='0.3' changeset='#{changeset.id}' version='7'/>
 
 948               <node id='#{node.id}' lon='0.9' lat='0.9' changeset='#{changeset.id}' version='8'/>
 
 953         auth_header = bearer_authorization_header changeset.user
 
 955         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 957         assert_response :success
 
 959         assert_dom "diffResult>node", 8
 
 962         assert_equal 8, changeset.num_changes
 
 963         assert_predicate changeset, :num_type_changes_in_sync?
 
 964         assert_equal 8, changeset.num_modified_nodes
 
 967         assert_equal 9, node.version
 
 968         assert_equal 0.9 * GeoRecord::SCALE, node.latitude
 
 969         assert_equal 0.9 * GeoRecord::SCALE, node.longitude
 
 973       # upload multiple versions of the same element in the same diff, but
 
 974       # keep the version numbers the same.
 
 975       def test_upload_modify_duplicate_node_versions
 
 976         node = create(:node, :latitude => 0, :longitude => 0)
 
 977         changeset = create(:changeset)
 
 982               <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
 983               <node id='#{node.id}' lon='2' lat='2' changeset='#{changeset.id}' version='1'/>
 
 988         auth_header = bearer_authorization_header changeset.user
 
 990         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 992         assert_response :conflict
 
 994         assert_no_changes_in changeset
 
 997         assert_equal 1, node.version
 
 998         assert_equal 0, node.latitude
 
 999         assert_equal 0, node.longitude
 
1003       # try to upload some elements without specifying the version
 
1004       def test_upload_modify_missing_node_version
 
1005         node = create(:node, :latitude => 0, :longitude => 0)
 
1006         changeset = create(:changeset)
 
1011               <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}'/>
 
1016         auth_header = bearer_authorization_header changeset.user
 
1018         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1020         assert_response :bad_request
 
1022         assert_no_changes_in changeset
 
1025         assert_equal 1, node.version
 
1026         assert_equal 0, node.latitude
 
1027         assert_equal 0, node.longitude
 
1031       # create a diff which references several changesets, which should cause
 
1032       # a rollback and none of the diff gets committed
 
1033       def test_upload_modify_with_references_to_different_changesets
 
1034         changeset1 = create(:changeset)
 
1035         changeset2 = create(:changeset, :user => changeset1.user)
 
1036         node1 = create(:node)
 
1037         node2 = create(:node)
 
1039         # simple diff to create a node way and relation using placeholders
 
1043               <node id='#{node1.id}' lon='0' lat='0' changeset='#{changeset1.id}' version='1'/>
 
1046               <node id='#{node2.id}' lon='0' lat='0' changeset='#{changeset2.id}' version='1'/>
 
1051         auth_header = bearer_authorization_header changeset1.user
 
1053         post api_changeset_upload_path(changeset1), :params => diff, :headers => auth_header
 
1055         assert_response :conflict
 
1057         assert_no_changes_in changeset1
 
1058         assert_no_changes_in changeset2
 
1060         assert_nodes_are_equal(node1, Node.find(node1.id))
 
1061         assert_nodes_are_equal(node2, Node.find(node2.id))
 
1065       # upload a valid changeset which has a mixture of whitespace
 
1066       # to check a bug https://github.com/openstreetmap/trac-tickets/issues/1565
 
1067       def test_upload_modify_with_mixed_whitespace
 
1068         changeset = create(:changeset)
 
1069         node = create(:node)
 
1070         way = create(:way_with_nodes, :nodes_count => 2)
 
1071         relation = create(:relation)
 
1072         other_relation = create(:relation)
 
1073         create(:relation_tag, :relation => relation)
 
1077           <modify><node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}'
 
1079             <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='2'><tag k='k' v='v'/></node></modify>
 
1081           <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'><member
 
1082             type='way' role='some' ref='#{way.id}'/><member
 
1083               type='node' role='some' ref='#{node.id}'/>
 
1084             <member type='relation' role='some' ref='#{other_relation.id}'/>
 
1086           </modify></osmChange>
 
1089         auth_header = bearer_authorization_header changeset.user
 
1091         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1093         assert_response :success
 
1095         assert_dom "diffResult>node", 2
 
1096         assert_dom "diffResult>relation", 1
 
1099         assert_equal 3, changeset.num_changes
 
1100         assert_predicate changeset, :num_type_changes_in_sync?
 
1101         assert_equal 2, changeset.num_modified_nodes
 
1102         assert_equal 1, changeset.num_modified_relations
 
1104         assert_equal 1, Node.find(node.id).tags.size, "node #{node.id} should now have one tag"
 
1105         assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
 
1108       def test_upload_modify_unknown_node_placeholder
 
1109         check_upload_results_in_not_found do |changeset|
 
1110           "<modify><node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/></modify>"
 
1114       def test_upload_modify_unknown_way_placeholder
 
1115         check_upload_results_in_not_found do |changeset|
 
1116           "<modify><way id='-1' changeset='#{changeset.id}' version='1'/></modify>"
 
1120       def test_upload_modify_unknown_relation_placeholder
 
1121         check_upload_results_in_not_found do |changeset|
 
1122           "<modify><relation id='-1' changeset='#{changeset.id}' version='1'/></modify>"
 
1126       # -------------------------------------
 
1127       # Test deleting elements.
 
1128       # -------------------------------------
 
1130       def test_upload_delete_node
 
1131         changeset = create(:changeset)
 
1132         node = create(:node, :lat => 0, :lon => 0)
 
1133         create(:node_tag, :node => node)
 
1138               <node id='#{node.id}' changeset='#{changeset.id}' version='1' lat='0' lon='0'/>
 
1143         auth_header = bearer_authorization_header changeset.user
 
1145         assert_difference "Node.count" => 0,
 
1146                           "OldNode.count" => 1,
 
1147                           "NodeTag.count" => -1,
 
1148                           "OldNodeTag.count" => 0 do
 
1149           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1151           assert_response :success
 
1154         assert_dom "diffResult", 1 do
 
1155           assert_dom "> node", 1 do
 
1156             assert_dom "> @old_id", node.id.to_s
 
1161         assert_equal 1, changeset.num_changes
 
1162         assert_predicate changeset, :num_type_changes_in_sync?
 
1163         assert_equal 1, changeset.num_deleted_nodes
 
1166         assert_not_predicate node, :visible?
 
1169       def test_upload_delete_way
 
1170         changeset = create(:changeset)
 
1171         way = create(:way_with_nodes, :nodes_count => 3)
 
1172         create(:way_tag, :way => way)
 
1177               <way id='#{way.id}' changeset='#{changeset.id}' version='1'/>
 
1182         auth_header = bearer_authorization_header changeset.user
 
1184         assert_difference "Way.count" => 0,
 
1185                           "OldWay.count" => 1,
 
1186                           "WayTag.count" => -1,
 
1187                           "OldWayTag.count" => 0,
 
1188                           "WayNode.count" => -3,
 
1189                           "OldWayNode.count" => 0 do
 
1190           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1192           assert_response :success
 
1195         assert_dom "diffResult", 1 do
 
1196           assert_dom "> way", 1 do
 
1197             assert_dom "> @old_id", way.id.to_s
 
1202         assert_equal 1, changeset.num_changes
 
1203         assert_predicate changeset, :num_type_changes_in_sync?
 
1204         assert_equal 1, changeset.num_deleted_ways
 
1207         assert_not_predicate way, :visible?
 
1210       def test_upload_delete_relation
 
1211         changeset = create(:changeset)
 
1212         relation = create(:relation)
 
1213         create(:relation_member, :relation => relation, :member => create(:node))
 
1214         create(:relation_tag, :relation => relation)
 
1219               <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'/>
 
1224         auth_header = bearer_authorization_header changeset.user
 
1226         assert_difference "Relation.count" => 0,
 
1227                           "OldRelation.count" => 1,
 
1228                           "RelationTag.count" => -1,
 
1229                           "OldRelationTag.count" => 0,
 
1230                           "RelationMember.count" => -1,
 
1231                           "OldRelationMember.count" => 0 do
 
1232           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1234           assert_response :success
 
1237         assert_dom "diffResult", 1 do
 
1238           assert_dom "> relation", 1 do
 
1239             assert_dom "> @old_id", relation.id.to_s
 
1244         assert_equal 1, changeset.num_changes
 
1245         assert_predicate changeset, :num_type_changes_in_sync?
 
1246         assert_equal 1, changeset.num_deleted_relations
 
1249         assert_not_predicate relation, :visible?
 
1253       # test a complex delete where we delete elements which rely on each other
 
1254       # in the same transaction.
 
1255       def test_upload_delete_elements
 
1256         changeset = create(:changeset)
 
1257         super_relation = create(:relation)
 
1258         used_relation = create(:relation)
 
1259         used_way = create(:way)
 
1260         used_node = create(:node)
 
1261         create(:relation_member, :relation => super_relation, :member => used_relation)
 
1262         create(:relation_member, :relation => super_relation, :member => used_way)
 
1263         create(:relation_member, :relation => super_relation, :member => used_node)
 
1265         diff = XML::Document.new
 
1266         diff.root = XML::Node.new "osmChange"
 
1267         delete = XML::Node.new "delete"
 
1269         delete << xml_node_for_relation(super_relation)
 
1270         delete << xml_node_for_relation(used_relation)
 
1271         delete << xml_node_for_way(used_way)
 
1272         delete << xml_node_for_node(used_node)
 
1273         %w[node way relation].each do |type|
 
1274           delete.find("//osmChange/delete/#{type}").each do |n|
 
1275             n["changeset"] = changeset.id.to_s
 
1279         auth_header = bearer_authorization_header changeset.user
 
1281         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1283         assert_response :success
 
1285         assert_dom "diffResult", 1 do
 
1286           assert_dom "> node", 1
 
1287           assert_dom "> way", 1
 
1288           assert_dom "> relation", 2
 
1292         assert_equal 4, changeset.num_changes
 
1293         assert_predicate changeset, :num_type_changes_in_sync?
 
1294         assert_equal 1, changeset.num_deleted_nodes
 
1295         assert_equal 1, changeset.num_deleted_ways
 
1296         assert_equal 2, changeset.num_deleted_relations
 
1298         assert_not Node.find(used_node.id).visible
 
1299         assert_not Way.find(used_way.id).visible
 
1300         assert_not Relation.find(super_relation.id).visible
 
1301         assert_not Relation.find(used_relation.id).visible
 
1305       # test uploading a delete with no lat/lon, as they are optional in the osmChange spec.
 
1306       def test_upload_delete_node_without_latlon
 
1307         node = create(:node)
 
1308         changeset = create(:changeset)
 
1310         diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{changeset.id}'/></delete></osmChange>"
 
1312         auth_header = bearer_authorization_header changeset.user
 
1314         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1316         assert_response :success
 
1318         assert_dom "diffResult", 1 do
 
1319           assert_dom "> node", 1 do
 
1320             assert_dom "> @old_id", node.id.to_s
 
1321             assert_dom "> @new_id", 0
 
1322             assert_dom "> @new_version", 0
 
1327         assert_equal 1, changeset.num_changes
 
1328         assert_predicate changeset, :num_type_changes_in_sync?
 
1329         assert_equal 1, changeset.num_deleted_nodes
 
1332         assert_not node.visible
 
1336       # test that deleting stuff in a transaction doesn't bypass the checks
 
1337       # to ensure that used elements are not deleted.
 
1338       def test_upload_delete_referenced_elements
 
1339         changeset = create(:changeset)
 
1340         relation = create(:relation)
 
1341         other_relation = create(:relation)
 
1342         used_way = create(:way)
 
1343         used_node = create(:node)
 
1344         create(:relation_member, :relation => relation, :member => used_way)
 
1345         create(:relation_member, :relation => relation, :member => used_node)
 
1347         diff = XML::Document.new
 
1348         diff.root = XML::Node.new "osmChange"
 
1349         delete = XML::Node.new "delete"
 
1351         delete << xml_node_for_relation(other_relation)
 
1352         delete << xml_node_for_way(used_way)
 
1353         delete << xml_node_for_node(used_node)
 
1354         %w[node way relation].each do |type|
 
1355           delete.find("//osmChange/delete/#{type}").each do |n|
 
1356             n["changeset"] = changeset.id.to_s
 
1360         auth_header = bearer_authorization_header changeset.user
 
1362         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1364         assert_response :precondition_failed
 
1365         assert_equal "Precondition failed: Way #{used_way.id} is still used by relations #{relation.id}.", @response.body
 
1367         assert_no_changes_in changeset
 
1369         assert Node.find(used_node.id).visible
 
1370         assert Way.find(used_way.id).visible
 
1371         assert Relation.find(relation.id).visible
 
1372         assert Relation.find(other_relation.id).visible
 
1376       # test that a conditional delete of an in use object works.
 
1377       def test_upload_delete_if_unused
 
1378         changeset = create(:changeset)
 
1379         super_relation = create(:relation)
 
1380         used_relation = create(:relation)
 
1381         used_way = create(:way)
 
1382         used_node = create(:node)
 
1383         create(:relation_member, :relation => super_relation, :member => used_relation)
 
1384         create(:relation_member, :relation => super_relation, :member => used_way)
 
1385         create(:relation_member, :relation => super_relation, :member => used_node)
 
1387         diff = XML::Document.new
 
1388         diff.root = XML::Node.new "osmChange"
 
1389         delete = XML::Node.new "delete"
 
1391         delete["if-unused"] = ""
 
1392         delete << xml_node_for_relation(used_relation)
 
1393         delete << xml_node_for_way(used_way)
 
1394         delete << xml_node_for_node(used_node)
 
1395         %w[node way relation].each do |type|
 
1396           delete.find("//osmChange/delete/#{type}").each do |n|
 
1397             n["changeset"] = changeset.id.to_s
 
1401         auth_header = bearer_authorization_header changeset.user
 
1403         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1405         assert_response :success
 
1407         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
1408           assert_dom "> node", 1 do
 
1409             assert_dom "> @old_id", used_node.id.to_s
 
1410             assert_dom "> @new_id", used_node.id.to_s
 
1411             assert_dom "> @new_version", used_node.version.to_s
 
1413           assert_dom "> way", 1 do
 
1414             assert_dom "> @old_id", used_way.id.to_s
 
1415             assert_dom "> @new_id", used_way.id.to_s
 
1416             assert_dom "> @new_version", used_way.version.to_s
 
1418           assert_dom "> relation", 1 do
 
1419             assert_dom "> @old_id", used_relation.id.to_s
 
1420             assert_dom "> @new_id", used_relation.id.to_s
 
1421             assert_dom "> @new_version", used_relation.version.to_s
 
1425         assert_no_changes_in changeset
 
1427         assert Node.find(used_node.id).visible
 
1428         assert Way.find(used_way.id).visible
 
1429         assert Relation.find(used_relation.id).visible
 
1432       def test_upload_delete_with_multiple_blocks_and_if_unused
 
1433         changeset = create(:changeset)
 
1434         node = create(:node)
 
1436         create(:way_node, :way => way, :node => node)
 
1437         alone_node = create(:node)
 
1440           <osmChange version='0.6'>
 
1441             <delete version="0.6">
 
1442               <node id="#{node.id}" version="#{node.version}" changeset="#{changeset.id}"/>
 
1444             <delete version="0.6" if-unused="true">
 
1445               <node id="#{alone_node.id}" version="#{alone_node.version}" changeset="#{changeset.id}"/>
 
1450         auth_header = bearer_authorization_header changeset.user
 
1452         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1454         assert_response :precondition_failed
 
1455         assert_equal "Precondition failed: Node #{node.id} is still used by ways #{way.id}.", @response.body
 
1457         assert_no_changes_in changeset
 
1460       def test_upload_delete_unknown_node_placeholder
 
1461         check_upload_results_in_not_found do |changeset|
 
1462           "<delete><node id='-1' changeset='#{changeset.id}' version='1'/></delete>"
 
1466       def test_upload_delete_unknown_way_placeholder
 
1467         check_upload_results_in_not_found do |changeset|
 
1468           "<delete><way id='-1' changeset='#{changeset.id}' version='1'/></delete>"
 
1472       def test_upload_delete_unknown_relation_placeholder
 
1473         check_upload_results_in_not_found do |changeset|
 
1474           "<delete><relation id='-1' changeset='#{changeset.id}' version='1'/></delete>"
 
1478       # -------------------------------------
 
1479       # Test combined element changes.
 
1480       # -------------------------------------
 
1483       # upload something which creates new objects and inserts them into
 
1484       # existing containers using placeholders.
 
1485       def test_upload_create_and_insert_elements
 
1487         node = create(:node)
 
1488         relation = create(:relation)
 
1489         create(:way_node, :way => way, :node => node)
 
1490         changeset = create(:changeset)
 
1495               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1496                 <tag k='foo' v='bar'/>
 
1497                 <tag k='baz' v='bat'/>
 
1501               <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
1503                 <nd ref='#{node.id}'/>
 
1505               <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
1506                 <member type='way' role='some' ref='#{way.id}'/>
 
1507                 <member type='node' role='some' ref='-1'/>
 
1508                 <member type='relation' role='some' ref='#{relation.id}'/>
 
1514         auth_header = bearer_authorization_header changeset.user
 
1516         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1518         assert_response :success
 
1521         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
1522           assert_dom "> node", 1 do |(node_el)|
 
1523             new_node_id = node_el["new_id"].to_i
 
1525           assert_dom "> way", 1
 
1526           assert_dom "> relation", 1
 
1530         assert_equal 3, changeset.num_changes
 
1531         assert_predicate changeset, :num_type_changes_in_sync?
 
1532         assert_equal 1, changeset.num_created_nodes
 
1533         assert_equal 1, changeset.num_modified_ways
 
1534         assert_equal 1, changeset.num_modified_relations
 
1536         assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
1537         assert_equal [new_node_id, node.id], Way.find(way.id).nds, "way nodes should match"
 
1538         Relation.find(relation.id).members.each do |type, id, _role|
 
1539           assert_equal new_node_id, id, "relation should contain new node" if type == "node"
 
1544       # test that a placeholder can be reused within the same upload.
 
1545       def test_upload_create_modify_delete_node_reusing_placeholder
 
1546         changeset = create(:changeset)
 
1551               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1552                 <tag k="foo" v="bar"/>
 
1556               <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
1559               <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
 
1564         auth_header = bearer_authorization_header changeset.user
 
1566         assert_difference "Node.count", 1 do
 
1567           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1569           assert_response :success
 
1572         assert_dom "diffResult>node", 3
 
1573         assert_dom "diffResult>node[old_id='-1']", 3
 
1576         assert_equal 3, changeset.num_changes
 
1577         assert_predicate changeset, :num_type_changes_in_sync?
 
1578         assert_equal 1, changeset.num_created_nodes
 
1579         assert_equal 1, changeset.num_modified_nodes
 
1580         assert_equal 1, changeset.num_deleted_nodes
 
1583         assert_equal 3, node.version
 
1584         assert_not node.visible
 
1587       def test_upload_create_and_duplicate_delete
 
1588         changeset = create(:changeset)
 
1593               <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
 
1596               <node id="-1" version="1" changeset="#{changeset.id}" />
 
1597               <node id="-1" version="1" changeset="#{changeset.id}" />
 
1602         auth_header = bearer_authorization_header changeset.user
 
1604         assert_no_difference "Node.count" do
 
1605           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1607           assert_response :gone
 
1610         assert_no_changes_in changeset
 
1613       def test_upload_create_and_duplicate_delete_if_unused
 
1614         changeset = create(:changeset)
 
1619               <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
 
1621             <delete if-unused="true">
 
1622               <node id="-1" version="1" changeset="#{changeset.id}" />
 
1623               <node id="-1" version="1" changeset="#{changeset.id}" />
 
1628         auth_header = bearer_authorization_header changeset.user
 
1630         assert_difference "Node.count", 1 do
 
1631           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1633           assert_response :success
 
1636         assert_dom "diffResult>node", 3
 
1637         assert_dom "diffResult>node[old_id='-1']", 3
 
1638         assert_dom "diffResult>node[new_version='1']", 1
 
1639         assert_dom "diffResult>node[new_version='2']", 1
 
1642         assert_equal 2, changeset.num_changes
 
1643         assert_predicate changeset, :num_type_changes_in_sync?
 
1644         assert_equal 1, changeset.num_created_nodes
 
1645         assert_equal 1, changeset.num_deleted_nodes
 
1648         assert_equal 2, node.version
 
1649         assert_not node.visible
 
1652       # -------------------------------------
 
1653       # Test bounding boxes.
 
1654       # -------------------------------------
 
1656       def test_upload_bbox_of_widely_spaced_nodes
 
1657         user = create(:user)
 
1659         # create an old changeset to ensure we have the maximum rate limit
 
1660         create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
 
1662         changeset = create(:changeset, :user => user)
 
1664         # upload some widely-spaced nodes, spiralling positive and negative
 
1668               <node id='-1' lon='-20' lat='-10' changeset='#{changeset.id}'/>
 
1669               <node id='-10' lon='20'  lat='10' changeset='#{changeset.id}'/>
 
1670               <node id='-2' lon='-40' lat='-20' changeset='#{changeset.id}'/>
 
1671               <node id='-11' lon='40'  lat='20' changeset='#{changeset.id}'/>
 
1672               <node id='-3' lon='-60' lat='-30' changeset='#{changeset.id}'/>
 
1673               <node id='-12' lon='60'  lat='30' changeset='#{changeset.id}'/>
 
1674               <node id='-4' lon='-80' lat='-40' changeset='#{changeset.id}'/>
 
1675               <node id='-13' lon='80'  lat='40' changeset='#{changeset.id}'/>
 
1676               <node id='-5' lon='-100' lat='-50' changeset='#{changeset.id}'/>
 
1677               <node id='-14' lon='100'  lat='50' changeset='#{changeset.id}'/>
 
1678               <node id='-6' lon='-120' lat='-60' changeset='#{changeset.id}'/>
 
1679               <node id='-15' lon='120'  lat='60' changeset='#{changeset.id}'/>
 
1680               <node id='-7' lon='-140' lat='-70' changeset='#{changeset.id}'/>
 
1681               <node id='-16' lon='140'  lat='70' changeset='#{changeset.id}'/>
 
1682               <node id='-8' lon='-160' lat='-80' changeset='#{changeset.id}'/>
 
1683               <node id='-17' lon='160'  lat='80' changeset='#{changeset.id}'/>
 
1684               <node id='-9' lon='-179.9' lat='-89.9' changeset='#{changeset.id}'/>
 
1685               <node id='-18' lon='179.9'  lat='89.9' changeset='#{changeset.id}'/>
 
1690         auth_header = bearer_authorization_header user
 
1692         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1694         assert_response :success
 
1697         assert_equal 18, changeset.num_changes
 
1698         assert_predicate changeset, :num_type_changes_in_sync?
 
1699         assert_equal 18, changeset.num_created_nodes
 
1701         # check that the changeset bbox is within bounds
 
1702         assert_operator changeset.min_lon, :>=, -180 * GeoRecord::SCALE, "Minimum longitude (#{changeset.min_lon / GeoRecord::SCALE}) should be >= -180 to be valid."
 
1703         assert_operator changeset.max_lon, :<=, 180 * GeoRecord::SCALE, "Maximum longitude (#{changeset.max_lon / GeoRecord::SCALE}) should be <= 180 to be valid."
 
1704         assert_operator changeset.min_lat, :>=, -90 * GeoRecord::SCALE, "Minimum latitude (#{changeset.min_lat / GeoRecord::SCALE}) should be >= -90 to be valid."
 
1705         assert_operator changeset.max_lat, :<=, 90 * GeoRecord::SCALE, "Maximum latitude (#{changeset.max_lat / GeoRecord::SCALE}) should be <= 90 to be valid."
 
1708       def test_upload_bbox_of_moved_node
 
1709         changeset = create(:changeset)
 
1710         node = create(:node, :lat => 1.0, :lon => 2.0)
 
1715               <node id='#{node.id}' lat='1.1' lon='2.1' changeset='#{changeset.id}' version='1'/>
 
1720         auth_header = bearer_authorization_header changeset.user
 
1722         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1724         assert_response :success
 
1727         assert_equal 1, changeset.num_changes
 
1728         assert_predicate changeset, :num_type_changes_in_sync?
 
1729         assert_equal 1, changeset.num_modified_nodes
 
1732         assert_equal 1.0 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1.0 degrees"
 
1733         assert_equal 2.0 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 2.0 degrees"
 
1734         assert_equal 1.1 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 1.1 degrees"
 
1735         assert_equal 2.1 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 2.1 degrees"
 
1738       def test_upload_bbox_of_extended_way
 
1740         initial_node = create(:node, :lat => 1.1, :lon => 2.1)
 
1741         create(:way_node, :way => way, :node => initial_node)
 
1742         added_node = create(:node, :lat => 1.3, :lon => 2.3)
 
1743         changeset = create(:changeset)
 
1748               <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
1749                 <nd ref='#{initial_node.id}'/>
 
1750                 <nd ref='#{added_node.id}'/>
 
1756         auth_header = bearer_authorization_header changeset.user
 
1758         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1760         assert_response :success
 
1763         assert_equal 1, changeset.num_changes
 
1764         assert_predicate changeset, :num_type_changes_in_sync?
 
1765         assert_equal 1, changeset.num_modified_ways
 
1768         assert_equal 1.1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1.1 degrees"
 
1769         assert_equal 2.1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 2.1 degrees"
 
1770         assert_equal 1.3 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 1.3 degrees"
 
1771         assert_equal 2.3 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 2.3 degrees"
 
1774       # -------------------------------------
 
1775       # Test upload rate/size limits.
 
1776       # -------------------------------------
 
1778       def test_upload_initial_rate_limit
 
1779         user = create(:user)
 
1780         node = create(:node)
 
1781         way = create(:way_with_nodes, :nodes_count => 2)
 
1782         relation = create(:relation)
 
1784         # create a changeset that puts us near the initial rate limit
 
1785         num_changes = Settings.initial_changes_per_hour - 2
 
1786         changeset = create(:changeset, :user => user,
 
1787                                        :created_at => Time.now.utc - 5.minutes,
 
1788                                        :num_changes => num_changes,
 
1789                                        :num_created_nodes => num_changes)
 
1794               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1795                 <tag k='foo' v='bar'/>
 
1796                 <tag k='baz' v='bat'/>
 
1798               <way id='-1' changeset='#{changeset.id}'>
 
1799                 <nd ref='#{node.id}'/>
 
1803               <relation id='-1' changeset='#{changeset.id}'>
 
1804                 <member type='way' role='some' ref='#{way.id}'/>
 
1805                 <member type='node' role='some' ref='#{node.id}'/>
 
1806                 <member type='relation' role='some' ref='#{relation.id}'/>
 
1812         auth_header = bearer_authorization_header user
 
1814         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1816         assert_response :too_many_requests, "upload did not hit rate limit"
 
1819         assert_equal num_changes, changeset.num_changes
 
1820         assert_predicate changeset, :num_type_changes_in_sync?
 
1823       def test_upload_maximum_rate_limit
 
1824         user = create(:user)
 
1825         node = create(:node)
 
1826         way = create(:way_with_nodes, :nodes_count => 2)
 
1827         relation = create(:relation)
 
1829         # create a changeset to establish our initial edit time
 
1830         changeset = create(:changeset, :user => user,
 
1831                                        :created_at => Time.now.utc - 28.days)
 
1833         # create changeset to put us near the maximum rate limit
 
1834         remaining_num_changes = Settings.max_changes_per_hour - 2
 
1836         while remaining_num_changes.positive?
 
1837           num_changes = [remaining_num_changes, Changeset::MAX_ELEMENTS].min
 
1838           changeset = create(:changeset, :user => user,
 
1839                                          :created_at => Time.now.utc - 5.minutes,
 
1840                                          :num_changes => num_changes,
 
1841                                          :num_created_nodes => num_changes)
 
1842           remaining_num_changes -= num_changes
 
1848               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1849                 <tag k='foo' v='bar'/>
 
1850                 <tag k='baz' v='bat'/>
 
1852               <way id='-1' changeset='#{changeset.id}'>
 
1853                 <nd ref='#{node.id}'/>
 
1857               <relation id='-1' changeset='#{changeset.id}'>
 
1858                 <member type='way' role='some' ref='#{way.id}'/>
 
1859                 <member type='node' role='some' ref='#{node.id}'/>
 
1860                 <member type='relation' role='some' ref='#{relation.id}'/>
 
1866         auth_header = bearer_authorization_header user
 
1868         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1870         assert_response :too_many_requests, "upload did not hit rate limit"
 
1873         assert_equal num_changes, changeset.num_changes
 
1874         assert_predicate changeset, :num_type_changes_in_sync?
 
1877       def test_upload_initial_size_limit
 
1878         user = create(:user)
 
1880         # create a changeset that puts us near the initial size limit
 
1881         changeset = create(:changeset, :user => user,
 
1882                                        :min_lat => (-0.5 * GeoRecord::SCALE).round, :min_lon => (0.5 * GeoRecord::SCALE).round,
 
1883                                        :max_lat => (0.5 * GeoRecord::SCALE).round, :max_lon => (2.5 * GeoRecord::SCALE).round)
 
1888               <node id='-1' lon='0.9' lat='2.9' changeset='#{changeset.id}'>
 
1889                 <tag k='foo' v='bar'/>
 
1890                 <tag k='baz' v='bat'/>
 
1896         auth_header = bearer_authorization_header user
 
1898         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1900         assert_response :content_too_large, "upload did not hit size limit"
 
1902         assert_no_changes_in changeset
 
1905       def test_upload_size_limit_after_one_week
 
1906         user = create(:user)
 
1908         # create a changeset to establish our initial edit time
 
1909         create(:changeset, :user => user, :created_at => Time.now.utc - 7.days)
 
1911         # create a changeset that puts us near the initial size limit
 
1912         changeset = create(:changeset, :user => user, :bbox => [0.5, -0.5, 2.5, 0.5])
 
1917               <node id='-1' lon='35' lat='35' changeset='#{changeset.id}'>
 
1918                 <tag k='foo' v='bar'/>
 
1919                 <tag k='baz' v='bat'/>
 
1925         auth_header = bearer_authorization_header user
 
1927         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1929         assert_response :content_too_large, "upload did not hit size limit"
 
1931         assert_no_changes_in changeset
 
1936       def check_upload_results_in_not_found(&)
 
1937         changeset = create(:changeset)
 
1938         diff = "<osmChange>#{yield changeset}</osmChange>"
 
1939         auth_header = bearer_authorization_header changeset.user
 
1941         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1943         assert_response :not_found
 
1945         assert_no_changes_in changeset
 
1948       def assert_no_changes_in(changeset)
 
1950         assert_equal 0, changeset.num_changes
 
1951         assert_predicate changeset, :num_type_changes_in_sync?