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       # -------------------------------------
 
 202       # Test creating elements.
 
 203       # -------------------------------------
 
 205       def test_upload_create_node
 
 207         changeset = create(:changeset, :user => user)
 
 212               <node id='-1' lon='30' lat='60' changeset='#{changeset.id}'>
 
 213                 <tag k='amenity' v='bar'/>
 
 214                 <tag k='name' v='Foo'/>
 
 220         auth_header = bearer_authorization_header user
 
 222         assert_difference "Node.count" => 1,
 
 223                           "OldNode.count" => 1,
 
 224                           "NodeTag.count" => 2,
 
 225                           "OldNodeTag.count" => 2 do
 
 226           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 228           assert_response :success
 
 232         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 233           assert_dom "> node", 1 do |(node_el)|
 
 234             node = Node.find(node_el["new_id"].to_i)
 
 235             assert_dom "> @old_id", "-1"
 
 236             assert_dom "> @new_version", "1"
 
 241         assert_equal 1, changeset.num_changes
 
 242         assert_predicate changeset, :num_type_changes_in_sync?
 
 243         assert_equal 1, changeset.num_created_nodes
 
 245         assert_equal 1, node.version
 
 246         assert_equal changeset, node.changeset
 
 247         assert_predicate node, :visible?
 
 248         assert_equal({ "name" => "Foo", "amenity" => "bar" }, node.tags)
 
 249         assert_equal 60, node.lat
 
 250         assert_equal 30, node.lon
 
 253       def test_upload_create_way
 
 254         node1 = create(:node)
 
 255         node2 = create(:node)
 
 257         changeset = create(:changeset, :user => user)
 
 262               <way id='-1' changeset='#{changeset.id}'>
 
 263                 <tag k='highway' v='primary'/>
 
 264                 <tag k='name' v='Foo'/>
 
 265                 <nd ref='#{node1.id}'/>
 
 266                 <nd ref='#{node2.id}'/>
 
 272         auth_header = bearer_authorization_header user
 
 274         assert_difference "Way.count" => 1,
 
 277                           "OldWayTag.count" => 2,
 
 278                           "WayNode.count" => 2,
 
 279                           "OldWayNode.count" => 2 do
 
 280           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 282           assert_response :success
 
 286         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 287           assert_dom "> way", 1 do |(way_el)|
 
 288             way = Way.find(way_el["new_id"].to_i)
 
 289             assert_dom "> @old_id", "-1"
 
 290             assert_dom "> @new_version", "1"
 
 295         assert_equal 1, changeset.num_changes
 
 296         assert_predicate changeset, :num_type_changes_in_sync?
 
 297         assert_equal 1, changeset.num_created_ways
 
 299         assert_equal 1, way.version
 
 300         assert_equal changeset, way.changeset
 
 301         assert_predicate way, :visible?
 
 302         assert_equal({ "name" => "Foo", "highway" => "primary" }, way.tags)
 
 303         assert_equal [node1, node2], way.nodes
 
 306       def test_upload_create_relation
 
 307         node1 = create(:node)
 
 308         way1 = create(:way_with_nodes)
 
 309         relation1 = create(:relation)
 
 311         changeset = create(:changeset, :user => user)
 
 316               <relation id='-1' changeset='#{changeset.id}'>
 
 317                 <member type='node' role='n_role' ref='#{node1.id}'/>
 
 318                 <member type='way' role='w_role' ref='#{way1.id}'/>
 
 319                 <member type='relation' role='r_role' ref='#{relation1.id}'/>
 
 320                 <tag k='type' v='collection'/>
 
 326         auth_header = bearer_authorization_header user
 
 328         assert_difference "Relation.count" => 1,
 
 329                           "OldRelation.count" => 1,
 
 330                           "RelationTag.count" => 1,
 
 331                           "OldRelationTag.count" => 1,
 
 332                           "RelationMember.count" => 3,
 
 333                           "OldRelationMember.count" => 3 do
 
 334           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 336           assert_response :success
 
 340         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 341           assert_dom "> relation", 1 do |(relation_el)|
 
 342             relation = Relation.find(relation_el["new_id"].to_i)
 
 343             assert_dom "> @old_id", "-1"
 
 344             assert_dom "> @new_version", "1"
 
 349         assert_equal 1, changeset.num_changes
 
 350         assert_predicate changeset, :num_type_changes_in_sync?
 
 351         assert_equal 1, changeset.num_created_relations
 
 353         assert_equal 1, relation.version
 
 354         assert_equal changeset, relation.changeset
 
 355         assert_predicate relation, :visible?
 
 356         assert_equal({ "type" => "collection" }, relation.tags)
 
 357         assert_equal [["Node", node1.id, "n_role"],
 
 358                       ["Way", way1.id, "w_role"],
 
 359                       ["Relation", relation1.id, "r_role"]], relation.members
 
 362       def test_upload_create_elements
 
 364         changeset = create(:changeset, :user => user)
 
 366         way = create(:way_with_nodes, :nodes_count => 2)
 
 367         relation = create(:relation)
 
 372               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 373                 <tag k='foo' v='bar'/>
 
 374                 <tag k='baz' v='bat'/>
 
 376               <way id='-1' changeset='#{changeset.id}'>
 
 377                 <nd ref='#{node.id}'/>
 
 381               <relation id='-1' changeset='#{changeset.id}'>
 
 382                 <member type='way' role='some' ref='#{way.id}'/>
 
 383                 <member type='node' role='some' ref='#{node.id}'/>
 
 384                 <member type='relation' role='some' ref='#{relation.id}'/>
 
 390         auth_header = bearer_authorization_header user
 
 392         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 394         assert_response :success
 
 396         new_node_id, new_way_id, new_rel_id = nil
 
 397         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 398           # inspect the response to find out what the new element IDs are
 
 399           # check the old IDs are all present and negative one
 
 400           # check the versions are present and equal one
 
 401           assert_dom "> node", 1 do |(node_el)|
 
 402             new_node_id = node_el["new_id"].to_i
 
 403             assert_dom "> @old_id", "-1"
 
 404             assert_dom "> @new_version", "1"
 
 406           assert_dom "> way", 1 do |(way_el)|
 
 407             new_way_id = way_el["new_id"].to_i
 
 408             assert_dom "> @old_id", "-1"
 
 409             assert_dom "> @new_version", "1"
 
 411           assert_dom "> relation", 1 do |(rel_el)|
 
 412             new_rel_id = rel_el["new_id"].to_i
 
 413             assert_dom "> @old_id", "-1"
 
 414             assert_dom "> @new_version", "1"
 
 419         assert_equal 3, changeset.num_changes
 
 420         assert_predicate changeset, :num_type_changes_in_sync?
 
 421         assert_equal 1, changeset.num_created_nodes
 
 422         assert_equal 1, changeset.num_created_ways
 
 423         assert_equal 1, changeset.num_created_relations
 
 425         assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
 426         assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
 
 427         assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
 
 431       # upload an element with a really long tag value
 
 432       def test_upload_create_node_with_tag_too_long
 
 433         changeset = create(:changeset)
 
 438               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 439                 <tag k='foo' v='#{'x' * 256}'/>
 
 445         auth_header = bearer_authorization_header changeset.user
 
 447         assert_no_difference "Node.count" do
 
 448           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 450           assert_response :bad_request
 
 453         assert_no_changes_in changeset
 
 456       def test_upload_create_nodes_with_invalid_placeholder_reuse_in_one_action_block
 
 457         changeset = create(:changeset)
 
 462               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
 463               <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
 468         auth_header = bearer_authorization_header changeset.user
 
 470         assert_no_difference "Node.count" do
 
 471           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 473           assert_response :bad_request
 
 476         assert_no_changes_in changeset
 
 479       def test_upload_create_nodes_with_invalid_placeholder_reuse_in_two_action_blocks
 
 480         changeset = create(:changeset)
 
 485               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
 488               <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
 493         auth_header = bearer_authorization_header changeset.user
 
 495         assert_no_difference "Node.count" do
 
 496           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 498           assert_response :bad_request
 
 501         assert_no_changes_in changeset
 
 504       def test_upload_create_way_referring_node_placeholder_defined_later
 
 505         changeset = create(:changeset)
 
 510               <way id="-1" changeset="#{changeset.id}">
 
 513               <node id="-1" lat="1" lon="2" changeset="#{changeset.id}"/>
 
 518         auth_header = bearer_authorization_header changeset.user
 
 520         assert_no_difference "Node.count" do
 
 521           assert_no_difference "Way.count" do
 
 522             post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 524             assert_response :bad_request
 
 527         assert_equal "Placeholder node not found for reference -1 in way -1", @response.body
 
 529         assert_no_changes_in changeset
 
 532       def test_upload_create_way_referring_undefined_node_placeholder
 
 533         changeset = create(:changeset)
 
 538               <way id="-1" changeset="#{changeset.id}">
 
 545         auth_header = bearer_authorization_header changeset.user
 
 547         assert_no_difference "Way.count" do
 
 548           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 550           assert_response :bad_request
 
 552         assert_equal "Placeholder node not found for reference -1 in way -1", @response.body
 
 554         assert_no_changes_in changeset
 
 557       def test_upload_create_existing_way_referring_undefined_node_placeholder
 
 558         changeset = create(:changeset)
 
 564               <way id="#{way.id}" changeset="#{changeset.id}" version="1">
 
 571         auth_header = bearer_authorization_header changeset.user
 
 573         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 575         assert_response :bad_request
 
 576         assert_equal "Placeholder node not found for reference -1 in way #{way.id}", @response.body
 
 578         assert_no_changes_in changeset
 
 581         assert_equal 1, way.version
 
 584       def test_upload_create_relation_referring_undefined_node_placeholder
 
 585         changeset = create(:changeset)
 
 590               <relation id="-1" changeset="#{changeset.id}" version="1">
 
 591                 <member type="node" role="foo" ref="-1"/>
 
 597         auth_header = bearer_authorization_header changeset.user
 
 599         assert_no_difference "Relation.count" do
 
 600           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 602           assert_response :bad_request
 
 604         assert_equal "Placeholder Node not found for reference -1 in relation -1.", @response.body
 
 606         assert_no_changes_in changeset
 
 609       def test_upload_create_existing_relation_referring_undefined_way_placeholder
 
 610         changeset = create(:changeset)
 
 611         relation = create(:relation)
 
 616               <relation id="#{relation.id}" changeset="#{changeset.id}" version="1">
 
 617                 <member type="way" role="bar" ref="-1"/>
 
 623         auth_header = bearer_authorization_header changeset.user
 
 625         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 627         assert_response :bad_request
 
 628         assert_equal "Placeholder Way not found for reference -1 in relation #{relation.id}.", @response.body
 
 630         assert_no_changes_in changeset
 
 633         assert_equal 1, relation.version
 
 636       def test_upload_create_relations_with_circular_references
 
 637         changeset = create(:changeset)
 
 640           <osmChange version='0.6'>
 
 642               <relation id='-2' version='0' changeset='#{changeset.id}'>
 
 643                 <member type='relation' role='' ref='-4' />
 
 644                 <tag k='type' v='route' />
 
 645                 <tag k='name' v='AtoB' />
 
 647               <relation id='-3' version='0' changeset='#{changeset.id}'>
 
 648                 <tag k='type' v='route' />
 
 649                 <tag k='name' v='BtoA' />
 
 651               <relation id='-4' version='0' changeset='#{changeset.id}'>
 
 652                 <member type='relation' role='' ref='-2' />
 
 653                 <member type='relation' role='' ref='-3' />
 
 654                 <tag k='type' v='route_master' />
 
 655                 <tag k='name' v='master' />
 
 661         auth_header = bearer_authorization_header changeset.user
 
 663         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
 665         assert_response :bad_request
 
 666         assert_equal "Placeholder Relation not found for reference -4 in relation -2.", @response.body
 
 668         assert_no_changes_in changeset
 
 671       # -------------------------------------
 
 672       # Test modifying elements.
 
 673       # -------------------------------------
 
 675       def test_upload_modify_node
 
 677         changeset = create(:changeset, :user => user)
 
 678         node = create(:node, :latitude => 0, :longitude => 0)
 
 679         create(:node_tag, :node => node)
 
 684               <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='1'/>
 
 689         auth_header = bearer_authorization_header user
 
 691         assert_difference "Node.count" => 0,
 
 692                           "OldNode.count" => 1,
 
 693                           "NodeTag.count" => -1,
 
 694                           "OldNodeTag.count" => 0 do
 
 695           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 697           assert_response :success
 
 700         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 701           assert_dom "> node", 1 do
 
 702             assert_dom "> @old_id", node.id.to_s
 
 703             assert_dom "> @new_id", node.id.to_s
 
 704             assert_dom "> @new_version", "2"
 
 709         assert_equal 1, changeset.num_changes
 
 710         assert_predicate changeset, :num_type_changes_in_sync?
 
 711         assert_equal 1, changeset.num_modified_nodes
 
 714         assert_equal 2, node.version
 
 715         assert_equal 2 * GeoRecord::SCALE, node.latitude
 
 716         assert_equal 1 * GeoRecord::SCALE, node.longitude
 
 717         assert_equal 0, node.tags.size, "node #{node.id} should now have no tags"
 
 720       def test_upload_modify_way
 
 722         changeset = create(:changeset, :user => user)
 
 724         way = create(:way_with_nodes, :nodes_count => 3)
 
 725         create(:way_tag, :way => way)
 
 730               <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
 731                 <nd ref='#{node.id}'/>
 
 737         auth_header = bearer_authorization_header user
 
 739         assert_difference "Way.count" => 0,
 
 741                           "WayTag.count" => -1,
 
 742                           "OldWayTag.count" => 0,
 
 743                           "WayNode.count" => -2,
 
 744                           "OldWayNode.count" => 1 do
 
 745           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 747           assert_response :success
 
 750         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 751           assert_dom "> way", 1 do
 
 752             assert_dom "> @old_id", way.id.to_s
 
 753             assert_dom "> @new_id", way.id.to_s
 
 754             assert_dom "> @new_version", "2"
 
 759         assert_equal 1, changeset.num_changes
 
 760         assert_predicate changeset, :num_type_changes_in_sync?
 
 761         assert_equal 1, changeset.num_modified_ways
 
 764         assert_equal 2, way.version
 
 765         assert_equal 0, way.tags.size, "way #{way.id} should now have no tags"
 
 766         assert_equal [node], way.nodes
 
 769       def test_upload_modify_relation
 
 771         changeset = create(:changeset, :user => user)
 
 773         way = create(:way_with_nodes)
 
 774         relation = create(:relation)
 
 775         other_relation = create(:relation)
 
 776         create(:relation_tag, :relation => relation)
 
 781               <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
 782                 <member type='way' role='some' ref='#{way.id}'/>
 
 783                 <member type='node' role='some' ref='#{node.id}'/>
 
 784                 <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 790         auth_header = bearer_authorization_header user
 
 792         assert_difference "Relation.count" => 0,
 
 793                           "OldRelation.count" => 1,
 
 794                           "RelationTag.count" => -1,
 
 795                           "OldRelationTag.count" => 0,
 
 796                           "RelationMember.count" => 3,
 
 797                           "OldRelationMember.count" => 3 do
 
 798           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 800           assert_response :success
 
 803         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 804           assert_dom "> relation", 1 do
 
 805             assert_dom "> @old_id", relation.id.to_s
 
 806             assert_dom "> @new_id", relation.id.to_s
 
 807             assert_dom "> @new_version", "2"
 
 812         assert_equal 1, changeset.num_changes
 
 813         assert_predicate changeset, :num_type_changes_in_sync?
 
 814         assert_equal 1, changeset.num_modified_relations
 
 817         assert_equal 2, relation.version
 
 818         assert_equal 0, relation.tags.size, "relation #{relation.id} should now have no tags"
 
 819         assert_equal [["Way", way.id, "some"], ["Node", node.id, "some"], ["Relation", other_relation.id, "some"]], relation.members
 
 822       def test_upload_modify_elements
 
 824         changeset = create(:changeset, :user => user)
 
 825         node = create(:node, :latitude => 0, :longitude => 0)
 
 827         relation = create(:relation)
 
 828         other_relation = create(:relation)
 
 830         # create some tags, since we test that they are removed later
 
 831         create(:node_tag, :node => node)
 
 832         create(:way_tag, :way => way)
 
 833         create(:relation_tag, :relation => relation)
 
 835         # simple diff to change a node, way and relation by removing their tags
 
 839               <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='1'/>
 
 840               <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
 841                 <nd ref='#{node.id}'/>
 
 845               <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
 846                 <member type='way' role='some' ref='#{way.id}'/>
 
 847                 <member type='node' role='some' ref='#{node.id}'/>
 
 848                 <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 854         auth_header = bearer_authorization_header user
 
 856         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 858         assert_response :success
 
 860         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 861           assert_dom "> node", 1 do
 
 862             assert_dom "> @old_id", node.id.to_s
 
 863             assert_dom "> @new_id", node.id.to_s
 
 864             assert_dom "> @new_version", "2"
 
 866           assert_dom "> way", 1 do
 
 867             assert_dom "> @old_id", way.id.to_s
 
 868             assert_dom "> @new_id", way.id.to_s
 
 869             assert_dom "> @new_version", "2"
 
 871           assert_dom "> relation", 1 do
 
 872             assert_dom "> @old_id", relation.id.to_s
 
 873             assert_dom "> @new_id", relation.id.to_s
 
 874             assert_dom "> @new_version", "2"
 
 879         assert_equal 3, changeset.num_changes
 
 880         assert_predicate changeset, :num_type_changes_in_sync?
 
 881         assert_equal 1, changeset.num_modified_nodes
 
 882         assert_equal 1, changeset.num_modified_ways
 
 883         assert_equal 1, changeset.num_modified_relations
 
 886         assert_equal 2, node.version
 
 887         assert_equal 2 * GeoRecord::SCALE, node.latitude
 
 888         assert_equal 1 * GeoRecord::SCALE, node.longitude
 
 889         assert_equal 0, node.tags.size, "node #{node.id} should now have no tags"
 
 891         assert_equal 2, way.version
 
 892         assert_equal 0, way.tags.size, "way #{way.id} should now have no tags"
 
 893         assert_equal [node], way.nodes
 
 895         assert_equal 2, relation.version
 
 896         assert_equal 0, relation.tags.size, "relation #{relation.id} should now have no tags"
 
 897         assert_equal [["Way", way.id, "some"], ["Node", node.id, "some"], ["Relation", other_relation.id, "some"]], relation.members
 
 901       # upload multiple versions of the same element in the same diff.
 
 902       def test_upload_modify_multiple_node_versions
 
 904         changeset = create(:changeset)
 
 906         # change the location of a node multiple times, each time referencing
 
 907         # the last version. doesn't this depend on version numbers being
 
 912               <node id='#{node.id}' lon='0.0' lat='0.0' changeset='#{changeset.id}' version='1'/>
 
 913               <node id='#{node.id}' lon='0.1' lat='0.0' changeset='#{changeset.id}' version='2'/>
 
 914               <node id='#{node.id}' lon='0.1' lat='0.1' changeset='#{changeset.id}' version='3'/>
 
 915               <node id='#{node.id}' lon='0.1' lat='0.2' changeset='#{changeset.id}' version='4'/>
 
 916               <node id='#{node.id}' lon='0.2' lat='0.2' changeset='#{changeset.id}' version='5'/>
 
 917               <node id='#{node.id}' lon='0.3' lat='0.2' changeset='#{changeset.id}' version='6'/>
 
 918               <node id='#{node.id}' lon='0.3' lat='0.3' changeset='#{changeset.id}' version='7'/>
 
 919               <node id='#{node.id}' lon='0.9' lat='0.9' changeset='#{changeset.id}' version='8'/>
 
 924         auth_header = bearer_authorization_header changeset.user
 
 926         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 928         assert_response :success
 
 930         assert_dom "diffResult>node", 8
 
 933         assert_equal 8, changeset.num_changes
 
 934         assert_predicate changeset, :num_type_changes_in_sync?
 
 935         assert_equal 8, changeset.num_modified_nodes
 
 938         assert_equal 9, node.version
 
 939         assert_equal 0.9 * GeoRecord::SCALE, node.latitude
 
 940         assert_equal 0.9 * GeoRecord::SCALE, node.longitude
 
 944       # upload multiple versions of the same element in the same diff, but
 
 945       # keep the version numbers the same.
 
 946       def test_upload_modify_duplicate_node_versions
 
 947         node = create(:node, :latitude => 0, :longitude => 0)
 
 948         changeset = create(:changeset)
 
 953               <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
 954               <node id='#{node.id}' lon='2' lat='2' changeset='#{changeset.id}' version='1'/>
 
 959         auth_header = bearer_authorization_header changeset.user
 
 961         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 963         assert_response :conflict
 
 965         assert_no_changes_in changeset
 
 968         assert_equal 1, node.version
 
 969         assert_equal 0, node.latitude
 
 970         assert_equal 0, node.longitude
 
 974       # try to upload some elements without specifying the version
 
 975       def test_upload_modify_missing_node_version
 
 976         node = create(:node, :latitude => 0, :longitude => 0)
 
 977         changeset = create(:changeset)
 
 982               <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}'/>
 
 987         auth_header = bearer_authorization_header changeset.user
 
 989         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 991         assert_response :bad_request
 
 993         assert_no_changes_in changeset
 
 996         assert_equal 1, node.version
 
 997         assert_equal 0, node.latitude
 
 998         assert_equal 0, node.longitude
 
1002       # create a diff which references several changesets, which should cause
 
1003       # a rollback and none of the diff gets committed
 
1004       def test_upload_modify_with_references_to_different_changesets
 
1005         changeset1 = create(:changeset)
 
1006         changeset2 = create(:changeset, :user => changeset1.user)
 
1007         node1 = create(:node)
 
1008         node2 = create(:node)
 
1010         # simple diff to create a node way and relation using placeholders
 
1014               <node id='#{node1.id}' lon='0' lat='0' changeset='#{changeset1.id}' version='1'/>
 
1017               <node id='#{node2.id}' lon='0' lat='0' changeset='#{changeset2.id}' version='1'/>
 
1022         auth_header = bearer_authorization_header changeset1.user
 
1024         post api_changeset_upload_path(changeset1), :params => diff, :headers => auth_header
 
1026         assert_response :conflict
 
1028         assert_no_changes_in changeset1
 
1029         assert_no_changes_in changeset2
 
1031         assert_nodes_are_equal(node1, Node.find(node1.id))
 
1032         assert_nodes_are_equal(node2, Node.find(node2.id))
 
1036       # upload a valid changeset which has a mixture of whitespace
 
1037       # to check a bug https://github.com/openstreetmap/trac-tickets/issues/1565
 
1038       def test_upload_modify_with_mixed_whitespace
 
1039         changeset = create(:changeset)
 
1040         node = create(:node)
 
1041         way = create(:way_with_nodes, :nodes_count => 2)
 
1042         relation = create(:relation)
 
1043         other_relation = create(:relation)
 
1044         create(:relation_tag, :relation => relation)
 
1048           <modify><node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}'
 
1050             <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='2'><tag k='k' v='v'/></node></modify>
 
1052           <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'><member
 
1053             type='way' role='some' ref='#{way.id}'/><member
 
1054               type='node' role='some' ref='#{node.id}'/>
 
1055             <member type='relation' role='some' ref='#{other_relation.id}'/>
 
1057           </modify></osmChange>
 
1060         auth_header = bearer_authorization_header changeset.user
 
1062         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1064         assert_response :success
 
1066         assert_dom "diffResult>node", 2
 
1067         assert_dom "diffResult>relation", 1
 
1070         assert_equal 3, changeset.num_changes
 
1071         assert_predicate changeset, :num_type_changes_in_sync?
 
1072         assert_equal 2, changeset.num_modified_nodes
 
1073         assert_equal 1, changeset.num_modified_relations
 
1075         assert_equal 1, Node.find(node.id).tags.size, "node #{node.id} should now have one tag"
 
1076         assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
 
1079       def test_upload_modify_unknown_node_placeholder
 
1080         check_upload_results_in_not_found do |changeset|
 
1081           "<modify><node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/></modify>"
 
1085       def test_upload_modify_unknown_way_placeholder
 
1086         check_upload_results_in_not_found do |changeset|
 
1087           "<modify><way id='-1' changeset='#{changeset.id}' version='1'/></modify>"
 
1091       def test_upload_modify_unknown_relation_placeholder
 
1092         check_upload_results_in_not_found do |changeset|
 
1093           "<modify><relation id='-1' changeset='#{changeset.id}' version='1'/></modify>"
 
1097       # -------------------------------------
 
1098       # Test deleting elements.
 
1099       # -------------------------------------
 
1101       def test_upload_delete_node
 
1102         changeset = create(:changeset)
 
1103         node = create(:node, :lat => 0, :lon => 0)
 
1104         create(:node_tag, :node => node)
 
1109               <node id='#{node.id}' changeset='#{changeset.id}' version='1' lat='0' lon='0'/>
 
1114         auth_header = bearer_authorization_header changeset.user
 
1116         assert_difference "Node.count" => 0,
 
1117                           "OldNode.count" => 1,
 
1118                           "NodeTag.count" => -1,
 
1119                           "OldNodeTag.count" => 0 do
 
1120           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1122           assert_response :success
 
1125         assert_dom "diffResult", 1 do
 
1126           assert_dom "> node", 1 do
 
1127             assert_dom "> @old_id", node.id.to_s
 
1132         assert_equal 1, changeset.num_changes
 
1133         assert_predicate changeset, :num_type_changes_in_sync?
 
1134         assert_equal 1, changeset.num_deleted_nodes
 
1137         assert_not_predicate node, :visible?
 
1140       def test_upload_delete_way
 
1141         changeset = create(:changeset)
 
1142         way = create(:way_with_nodes, :nodes_count => 3)
 
1143         create(:way_tag, :way => way)
 
1148               <way id='#{way.id}' changeset='#{changeset.id}' version='1'/>
 
1153         auth_header = bearer_authorization_header changeset.user
 
1155         assert_difference "Way.count" => 0,
 
1156                           "OldWay.count" => 1,
 
1157                           "WayTag.count" => -1,
 
1158                           "OldWayTag.count" => 0,
 
1159                           "WayNode.count" => -3,
 
1160                           "OldWayNode.count" => 0 do
 
1161           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1163           assert_response :success
 
1166         assert_dom "diffResult", 1 do
 
1167           assert_dom "> way", 1 do
 
1168             assert_dom "> @old_id", way.id.to_s
 
1173         assert_equal 1, changeset.num_changes
 
1174         assert_predicate changeset, :num_type_changes_in_sync?
 
1175         assert_equal 1, changeset.num_deleted_ways
 
1178         assert_not_predicate way, :visible?
 
1181       def test_upload_delete_relation
 
1182         changeset = create(:changeset)
 
1183         relation = create(:relation)
 
1184         create(:relation_member, :relation => relation, :member => create(:node))
 
1185         create(:relation_tag, :relation => relation)
 
1190               <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'/>
 
1195         auth_header = bearer_authorization_header changeset.user
 
1197         assert_difference "Relation.count" => 0,
 
1198                           "OldRelation.count" => 1,
 
1199                           "RelationTag.count" => -1,
 
1200                           "OldRelationTag.count" => 0,
 
1201                           "RelationMember.count" => -1,
 
1202                           "OldRelationMember.count" => 0 do
 
1203           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1205           assert_response :success
 
1208         assert_dom "diffResult", 1 do
 
1209           assert_dom "> relation", 1 do
 
1210             assert_dom "> @old_id", relation.id.to_s
 
1215         assert_equal 1, changeset.num_changes
 
1216         assert_predicate changeset, :num_type_changes_in_sync?
 
1217         assert_equal 1, changeset.num_deleted_relations
 
1220         assert_not_predicate relation, :visible?
 
1224       # test a complex delete where we delete elements which rely on each other
 
1225       # in the same transaction.
 
1226       def test_upload_delete_elements
 
1227         changeset = create(:changeset)
 
1228         super_relation = create(:relation)
 
1229         used_relation = create(:relation)
 
1230         used_way = create(:way)
 
1231         used_node = create(:node)
 
1232         create(:relation_member, :relation => super_relation, :member => used_relation)
 
1233         create(:relation_member, :relation => super_relation, :member => used_way)
 
1234         create(:relation_member, :relation => super_relation, :member => used_node)
 
1236         diff = XML::Document.new
 
1237         diff.root = XML::Node.new "osmChange"
 
1238         delete = XML::Node.new "delete"
 
1240         delete << xml_node_for_relation(super_relation)
 
1241         delete << xml_node_for_relation(used_relation)
 
1242         delete << xml_node_for_way(used_way)
 
1243         delete << xml_node_for_node(used_node)
 
1244         %w[node way relation].each do |type|
 
1245           delete.find("//osmChange/delete/#{type}").each do |n|
 
1246             n["changeset"] = changeset.id.to_s
 
1250         auth_header = bearer_authorization_header changeset.user
 
1252         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1254         assert_response :success
 
1256         assert_dom "diffResult", 1 do
 
1257           assert_dom "> node", 1
 
1258           assert_dom "> way", 1
 
1259           assert_dom "> relation", 2
 
1263         assert_equal 4, changeset.num_changes
 
1264         assert_predicate changeset, :num_type_changes_in_sync?
 
1265         assert_equal 1, changeset.num_deleted_nodes
 
1266         assert_equal 1, changeset.num_deleted_ways
 
1267         assert_equal 2, changeset.num_deleted_relations
 
1269         assert_not Node.find(used_node.id).visible
 
1270         assert_not Way.find(used_way.id).visible
 
1271         assert_not Relation.find(super_relation.id).visible
 
1272         assert_not Relation.find(used_relation.id).visible
 
1276       # test uploading a delete with no lat/lon, as they are optional in the osmChange spec.
 
1277       def test_upload_delete_node_without_latlon
 
1278         node = create(:node)
 
1279         changeset = create(:changeset)
 
1281         diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{changeset.id}'/></delete></osmChange>"
 
1283         auth_header = bearer_authorization_header changeset.user
 
1285         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1287         assert_response :success
 
1289         assert_dom "diffResult", 1 do
 
1290           assert_dom "> node", 1 do
 
1291             assert_dom "> @old_id", node.id.to_s
 
1292             assert_dom "> @new_id", 0
 
1293             assert_dom "> @new_version", 0
 
1298         assert_equal 1, changeset.num_changes
 
1299         assert_predicate changeset, :num_type_changes_in_sync?
 
1300         assert_equal 1, changeset.num_deleted_nodes
 
1303         assert_not node.visible
 
1307       # test that deleting stuff in a transaction doesn't bypass the checks
 
1308       # to ensure that used elements are not deleted.
 
1309       def test_upload_delete_referenced_elements
 
1310         changeset = create(:changeset)
 
1311         relation = create(:relation)
 
1312         other_relation = create(:relation)
 
1313         used_way = create(:way)
 
1314         used_node = create(:node)
 
1315         create(:relation_member, :relation => relation, :member => used_way)
 
1316         create(:relation_member, :relation => relation, :member => used_node)
 
1318         diff = XML::Document.new
 
1319         diff.root = XML::Node.new "osmChange"
 
1320         delete = XML::Node.new "delete"
 
1322         delete << xml_node_for_relation(other_relation)
 
1323         delete << xml_node_for_way(used_way)
 
1324         delete << xml_node_for_node(used_node)
 
1325         %w[node way relation].each do |type|
 
1326           delete.find("//osmChange/delete/#{type}").each do |n|
 
1327             n["changeset"] = changeset.id.to_s
 
1331         auth_header = bearer_authorization_header changeset.user
 
1333         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1335         assert_response :precondition_failed
 
1336         assert_equal "Precondition failed: Way #{used_way.id} is still used by relations #{relation.id}.", @response.body
 
1338         assert_no_changes_in changeset
 
1340         assert Node.find(used_node.id).visible
 
1341         assert Way.find(used_way.id).visible
 
1342         assert Relation.find(relation.id).visible
 
1343         assert Relation.find(other_relation.id).visible
 
1347       # test that a conditional delete of an in use object works.
 
1348       def test_upload_delete_if_unused
 
1349         changeset = create(:changeset)
 
1350         super_relation = create(:relation)
 
1351         used_relation = create(:relation)
 
1352         used_way = create(:way)
 
1353         used_node = create(:node)
 
1354         create(:relation_member, :relation => super_relation, :member => used_relation)
 
1355         create(:relation_member, :relation => super_relation, :member => used_way)
 
1356         create(:relation_member, :relation => super_relation, :member => used_node)
 
1358         diff = XML::Document.new
 
1359         diff.root = XML::Node.new "osmChange"
 
1360         delete = XML::Node.new "delete"
 
1362         delete["if-unused"] = ""
 
1363         delete << xml_node_for_relation(used_relation)
 
1364         delete << xml_node_for_way(used_way)
 
1365         delete << xml_node_for_node(used_node)
 
1366         %w[node way relation].each do |type|
 
1367           delete.find("//osmChange/delete/#{type}").each do |n|
 
1368             n["changeset"] = changeset.id.to_s
 
1372         auth_header = bearer_authorization_header changeset.user
 
1374         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1376         assert_response :success
 
1378         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
1379           assert_dom "> node", 1 do
 
1380             assert_dom "> @old_id", used_node.id.to_s
 
1381             assert_dom "> @new_id", used_node.id.to_s
 
1382             assert_dom "> @new_version", used_node.version.to_s
 
1384           assert_dom "> way", 1 do
 
1385             assert_dom "> @old_id", used_way.id.to_s
 
1386             assert_dom "> @new_id", used_way.id.to_s
 
1387             assert_dom "> @new_version", used_way.version.to_s
 
1389           assert_dom "> relation", 1 do
 
1390             assert_dom "> @old_id", used_relation.id.to_s
 
1391             assert_dom "> @new_id", used_relation.id.to_s
 
1392             assert_dom "> @new_version", used_relation.version.to_s
 
1396         assert_no_changes_in changeset
 
1398         assert Node.find(used_node.id).visible
 
1399         assert Way.find(used_way.id).visible
 
1400         assert Relation.find(used_relation.id).visible
 
1403       def test_upload_delete_with_multiple_blocks_and_if_unused
 
1404         changeset = create(:changeset)
 
1405         node = create(:node)
 
1407         create(:way_node, :way => way, :node => node)
 
1408         alone_node = create(:node)
 
1411           <osmChange version='0.6'>
 
1412             <delete version="0.6">
 
1413               <node id="#{node.id}" version="#{node.version}" changeset="#{changeset.id}"/>
 
1415             <delete version="0.6" if-unused="true">
 
1416               <node id="#{alone_node.id}" version="#{alone_node.version}" changeset="#{changeset.id}"/>
 
1421         auth_header = bearer_authorization_header changeset.user
 
1423         post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1425         assert_response :precondition_failed
 
1426         assert_equal "Precondition failed: Node #{node.id} is still used by ways #{way.id}.", @response.body
 
1428         assert_no_changes_in changeset
 
1431       def test_upload_delete_unknown_node_placeholder
 
1432         check_upload_results_in_not_found do |changeset|
 
1433           "<delete><node id='-1' changeset='#{changeset.id}' version='1'/></delete>"
 
1437       def test_upload_delete_unknown_way_placeholder
 
1438         check_upload_results_in_not_found do |changeset|
 
1439           "<delete><way id='-1' changeset='#{changeset.id}' version='1'/></delete>"
 
1443       def test_upload_delete_unknown_relation_placeholder
 
1444         check_upload_results_in_not_found do |changeset|
 
1445           "<delete><relation id='-1' changeset='#{changeset.id}' version='1'/></delete>"
 
1449       # -------------------------------------
 
1450       # Test combined element changes.
 
1451       # -------------------------------------
 
1454       # upload something which creates new objects and inserts them into
 
1455       # existing containers using placeholders.
 
1456       def test_upload_create_and_insert_elements
 
1458         node = create(:node)
 
1459         relation = create(:relation)
 
1460         create(:way_node, :way => way, :node => node)
 
1461         changeset = create(:changeset)
 
1466               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1467                 <tag k='foo' v='bar'/>
 
1468                 <tag k='baz' v='bat'/>
 
1472               <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
1474                 <nd ref='#{node.id}'/>
 
1476               <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
1477                 <member type='way' role='some' ref='#{way.id}'/>
 
1478                 <member type='node' role='some' ref='-1'/>
 
1479                 <member type='relation' role='some' ref='#{relation.id}'/>
 
1485         auth_header = bearer_authorization_header changeset.user
 
1487         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1489         assert_response :success
 
1492         assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
1493           assert_dom "> node", 1 do |(node_el)|
 
1494             new_node_id = node_el["new_id"].to_i
 
1496           assert_dom "> way", 1
 
1497           assert_dom "> relation", 1
 
1501         assert_equal 3, changeset.num_changes
 
1502         assert_predicate changeset, :num_type_changes_in_sync?
 
1503         assert_equal 1, changeset.num_created_nodes
 
1504         assert_equal 1, changeset.num_modified_ways
 
1505         assert_equal 1, changeset.num_modified_relations
 
1507         assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
1508         assert_equal [new_node_id, node.id], Way.find(way.id).nds, "way nodes should match"
 
1509         Relation.find(relation.id).members.each do |type, id, _role|
 
1510           assert_equal new_node_id, id, "relation should contain new node" if type == "node"
 
1515       # test that a placeholder can be reused within the same upload.
 
1516       def test_upload_create_modify_delete_node_reusing_placeholder
 
1517         changeset = create(:changeset)
 
1522               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1523                 <tag k="foo" v="bar"/>
 
1527               <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
1530               <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
 
1535         auth_header = bearer_authorization_header changeset.user
 
1537         assert_difference "Node.count", 1 do
 
1538           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1540           assert_response :success
 
1543         assert_dom "diffResult>node", 3
 
1544         assert_dom "diffResult>node[old_id='-1']", 3
 
1547         assert_equal 3, changeset.num_changes
 
1548         assert_predicate changeset, :num_type_changes_in_sync?
 
1549         assert_equal 1, changeset.num_created_nodes
 
1550         assert_equal 1, changeset.num_modified_nodes
 
1551         assert_equal 1, changeset.num_deleted_nodes
 
1554         assert_equal 3, node.version
 
1555         assert_not node.visible
 
1558       def test_upload_create_and_duplicate_delete
 
1559         changeset = create(:changeset)
 
1564               <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
 
1567               <node id="-1" version="1" changeset="#{changeset.id}" />
 
1568               <node id="-1" version="1" changeset="#{changeset.id}" />
 
1573         auth_header = bearer_authorization_header changeset.user
 
1575         assert_no_difference "Node.count" do
 
1576           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1578           assert_response :gone
 
1581         assert_no_changes_in changeset
 
1584       def test_upload_create_and_duplicate_delete_if_unused
 
1585         changeset = create(:changeset)
 
1590               <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
 
1592             <delete if-unused="true">
 
1593               <node id="-1" version="1" changeset="#{changeset.id}" />
 
1594               <node id="-1" version="1" changeset="#{changeset.id}" />
 
1599         auth_header = bearer_authorization_header changeset.user
 
1601         assert_difference "Node.count", 1 do
 
1602           post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1604           assert_response :success
 
1607         assert_dom "diffResult>node", 3
 
1608         assert_dom "diffResult>node[old_id='-1']", 3
 
1609         assert_dom "diffResult>node[new_version='1']", 1
 
1610         assert_dom "diffResult>node[new_version='2']", 1
 
1613         assert_equal 2, changeset.num_changes
 
1614         assert_predicate changeset, :num_type_changes_in_sync?
 
1615         assert_equal 1, changeset.num_created_nodes
 
1616         assert_equal 1, changeset.num_deleted_nodes
 
1619         assert_equal 2, node.version
 
1620         assert_not node.visible
 
1623       # -------------------------------------
 
1624       # Test bounding boxes.
 
1625       # -------------------------------------
 
1627       def test_upload_bbox_of_widely_spaced_nodes
 
1628         user = create(:user)
 
1630         # create an old changeset to ensure we have the maximum rate limit
 
1631         create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
 
1633         changeset = create(:changeset, :user => user)
 
1635         # upload some widely-spaced nodes, spiralling positive and negative
 
1639               <node id='-1' lon='-20' lat='-10' changeset='#{changeset.id}'/>
 
1640               <node id='-10' lon='20'  lat='10' changeset='#{changeset.id}'/>
 
1641               <node id='-2' lon='-40' lat='-20' changeset='#{changeset.id}'/>
 
1642               <node id='-11' lon='40'  lat='20' changeset='#{changeset.id}'/>
 
1643               <node id='-3' lon='-60' lat='-30' changeset='#{changeset.id}'/>
 
1644               <node id='-12' lon='60'  lat='30' changeset='#{changeset.id}'/>
 
1645               <node id='-4' lon='-80' lat='-40' changeset='#{changeset.id}'/>
 
1646               <node id='-13' lon='80'  lat='40' changeset='#{changeset.id}'/>
 
1647               <node id='-5' lon='-100' lat='-50' changeset='#{changeset.id}'/>
 
1648               <node id='-14' lon='100'  lat='50' changeset='#{changeset.id}'/>
 
1649               <node id='-6' lon='-120' lat='-60' changeset='#{changeset.id}'/>
 
1650               <node id='-15' lon='120'  lat='60' changeset='#{changeset.id}'/>
 
1651               <node id='-7' lon='-140' lat='-70' changeset='#{changeset.id}'/>
 
1652               <node id='-16' lon='140'  lat='70' changeset='#{changeset.id}'/>
 
1653               <node id='-8' lon='-160' lat='-80' changeset='#{changeset.id}'/>
 
1654               <node id='-17' lon='160'  lat='80' changeset='#{changeset.id}'/>
 
1655               <node id='-9' lon='-179.9' lat='-89.9' changeset='#{changeset.id}'/>
 
1656               <node id='-18' lon='179.9'  lat='89.9' changeset='#{changeset.id}'/>
 
1661         auth_header = bearer_authorization_header user
 
1663         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1665         assert_response :success
 
1668         assert_equal 18, changeset.num_changes
 
1669         assert_predicate changeset, :num_type_changes_in_sync?
 
1670         assert_equal 18, changeset.num_created_nodes
 
1672         # check that the changeset bbox is within bounds
 
1673         assert_operator changeset.min_lon, :>=, -180 * GeoRecord::SCALE, "Minimum longitude (#{changeset.min_lon / GeoRecord::SCALE}) should be >= -180 to be valid."
 
1674         assert_operator changeset.max_lon, :<=, 180 * GeoRecord::SCALE, "Maximum longitude (#{changeset.max_lon / GeoRecord::SCALE}) should be <= 180 to be valid."
 
1675         assert_operator changeset.min_lat, :>=, -90 * GeoRecord::SCALE, "Minimum latitude (#{changeset.min_lat / GeoRecord::SCALE}) should be >= -90 to be valid."
 
1676         assert_operator changeset.max_lat, :<=, 90 * GeoRecord::SCALE, "Maximum latitude (#{changeset.max_lat / GeoRecord::SCALE}) should be <= 90 to be valid."
 
1679       def test_upload_bbox_of_moved_node
 
1680         changeset = create(:changeset)
 
1681         node = create(:node, :lat => 1.0, :lon => 2.0)
 
1686               <node id='#{node.id}' lat='1.1' lon='2.1' changeset='#{changeset.id}' version='1'/>
 
1691         auth_header = bearer_authorization_header changeset.user
 
1693         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1695         assert_response :success
 
1698         assert_equal 1, changeset.num_changes
 
1699         assert_predicate changeset, :num_type_changes_in_sync?
 
1700         assert_equal 1, changeset.num_modified_nodes
 
1703         assert_equal 1.0 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1.0 degrees"
 
1704         assert_equal 2.0 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 2.0 degrees"
 
1705         assert_equal 1.1 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 1.1 degrees"
 
1706         assert_equal 2.1 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 2.1 degrees"
 
1709       def test_upload_bbox_of_extended_way
 
1711         initial_node = create(:node, :lat => 1.1, :lon => 2.1)
 
1712         create(:way_node, :way => way, :node => initial_node)
 
1713         added_node = create(:node, :lat => 1.3, :lon => 2.3)
 
1714         changeset = create(:changeset)
 
1719               <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
1720                 <nd ref='#{initial_node.id}'/>
 
1721                 <nd ref='#{added_node.id}'/>
 
1727         auth_header = bearer_authorization_header changeset.user
 
1729         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1731         assert_response :success
 
1734         assert_equal 1, changeset.num_changes
 
1735         assert_predicate changeset, :num_type_changes_in_sync?
 
1736         assert_equal 1, changeset.num_modified_ways
 
1739         assert_equal 1.1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1.1 degrees"
 
1740         assert_equal 2.1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 2.1 degrees"
 
1741         assert_equal 1.3 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 1.3 degrees"
 
1742         assert_equal 2.3 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 2.3 degrees"
 
1745       # -------------------------------------
 
1746       # Test upload rate/size limits.
 
1747       # -------------------------------------
 
1749       def test_upload_initial_rate_limit
 
1750         user = create(:user)
 
1751         node = create(:node)
 
1752         way = create(:way_with_nodes, :nodes_count => 2)
 
1753         relation = create(:relation)
 
1755         # create a changeset that puts us near the initial rate limit
 
1756         num_changes = Settings.initial_changes_per_hour - 2
 
1757         changeset = create(:changeset, :user => user,
 
1758                                        :created_at => Time.now.utc - 5.minutes,
 
1759                                        :num_changes => num_changes,
 
1760                                        :num_created_nodes => num_changes)
 
1765               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1766                 <tag k='foo' v='bar'/>
 
1767                 <tag k='baz' v='bat'/>
 
1769               <way id='-1' changeset='#{changeset.id}'>
 
1770                 <nd ref='#{node.id}'/>
 
1774               <relation id='-1' changeset='#{changeset.id}'>
 
1775                 <member type='way' role='some' ref='#{way.id}'/>
 
1776                 <member type='node' role='some' ref='#{node.id}'/>
 
1777                 <member type='relation' role='some' ref='#{relation.id}'/>
 
1783         auth_header = bearer_authorization_header user
 
1785         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1787         assert_response :too_many_requests, "upload did not hit rate limit"
 
1790         assert_equal num_changes, changeset.num_changes
 
1791         assert_predicate changeset, :num_type_changes_in_sync?
 
1794       def test_upload_maximum_rate_limit
 
1795         user = create(:user)
 
1796         node = create(:node)
 
1797         way = create(:way_with_nodes, :nodes_count => 2)
 
1798         relation = create(:relation)
 
1800         # create a changeset to establish our initial edit time
 
1801         changeset = create(:changeset, :user => user,
 
1802                                        :created_at => Time.now.utc - 28.days)
 
1804         # create changeset to put us near the maximum rate limit
 
1805         remaining_num_changes = Settings.max_changes_per_hour - 2
 
1807         while remaining_num_changes.positive?
 
1808           num_changes = [remaining_num_changes, Changeset::MAX_ELEMENTS].min
 
1809           changeset = create(:changeset, :user => user,
 
1810                                          :created_at => Time.now.utc - 5.minutes,
 
1811                                          :num_changes => num_changes,
 
1812                                          :num_created_nodes => num_changes)
 
1813           remaining_num_changes -= num_changes
 
1819               <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1820                 <tag k='foo' v='bar'/>
 
1821                 <tag k='baz' v='bat'/>
 
1823               <way id='-1' changeset='#{changeset.id}'>
 
1824                 <nd ref='#{node.id}'/>
 
1828               <relation id='-1' changeset='#{changeset.id}'>
 
1829                 <member type='way' role='some' ref='#{way.id}'/>
 
1830                 <member type='node' role='some' ref='#{node.id}'/>
 
1831                 <member type='relation' role='some' ref='#{relation.id}'/>
 
1837         auth_header = bearer_authorization_header user
 
1839         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1841         assert_response :too_many_requests, "upload did not hit rate limit"
 
1844         assert_equal num_changes, changeset.num_changes
 
1845         assert_predicate changeset, :num_type_changes_in_sync?
 
1848       def test_upload_initial_size_limit
 
1849         user = create(:user)
 
1851         # create a changeset that puts us near the initial size limit
 
1852         changeset = create(:changeset, :user => user,
 
1853                                        :min_lat => (-0.5 * GeoRecord::SCALE).round, :min_lon => (0.5 * GeoRecord::SCALE).round,
 
1854                                        :max_lat => (0.5 * GeoRecord::SCALE).round, :max_lon => (2.5 * GeoRecord::SCALE).round)
 
1859               <node id='-1' lon='0.9' lat='2.9' changeset='#{changeset.id}'>
 
1860                 <tag k='foo' v='bar'/>
 
1861                 <tag k='baz' v='bat'/>
 
1867         auth_header = bearer_authorization_header user
 
1869         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1871         assert_response :content_too_large, "upload did not hit size limit"
 
1873         assert_no_changes_in changeset
 
1876       def test_upload_size_limit_after_one_week
 
1877         user = create(:user)
 
1879         # create a changeset to establish our initial edit time
 
1880         create(:changeset, :user => user, :created_at => Time.now.utc - 7.days)
 
1882         # create a changeset that puts us near the initial size limit
 
1883         changeset = create(:changeset, :user => user, :bbox => [0.5, -0.5, 2.5, 0.5])
 
1888               <node id='-1' lon='35' lat='35' 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
 
1907       def check_upload_results_in_not_found(&)
 
1908         changeset = create(:changeset)
 
1909         diff = "<osmChange>#{yield changeset}</osmChange>"
 
1910         auth_header = bearer_authorization_header changeset.user
 
1912         post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1914         assert_response :not_found
 
1916         assert_no_changes_in changeset
 
1919       def assert_no_changes_in(changeset)
 
1921         assert_equal 0, changeset.num_changes
 
1922         assert_predicate changeset, :num_type_changes_in_sync?