4   class ChangesetsControllerTest < ActionDispatch::IntegrationTest
 
   6     # test all routes which lead to this controller
 
   9         { :path => "/api/0.6/changeset/create", :method => :put },
 
  10         { :controller => "api/changesets", :action => "create" }
 
  13         { :path => "/api/0.6/changeset/1/upload", :method => :post },
 
  14         { :controller => "api/changesets", :action => "upload", :id => "1" }
 
  17         { :path => "/api/0.6/changeset/1/download", :method => :get },
 
  18         { :controller => "api/changesets", :action => "download", :id => "1" }
 
  21         { :path => "/api/0.6/changeset/1", :method => :get },
 
  22         { :controller => "api/changesets", :action => "show", :id => "1" }
 
  25         { :path => "/api/0.6/changeset/1.json", :method => :get },
 
  26         { :controller => "api/changesets", :action => "show", :id => "1", :format => "json" }
 
  29         { :path => "/api/0.6/changeset/1/subscribe", :method => :post },
 
  30         { :controller => "api/changesets", :action => "subscribe", :id => "1" }
 
  33         { :path => "/api/0.6/changeset/1/subscribe.json", :method => :post },
 
  34         { :controller => "api/changesets", :action => "subscribe", :id => "1", :format => "json" }
 
  37         { :path => "/api/0.6/changeset/1/unsubscribe", :method => :post },
 
  38         { :controller => "api/changesets", :action => "unsubscribe", :id => "1" }
 
  41         { :path => "/api/0.6/changeset/1/unsubscribe.json", :method => :post },
 
  42         { :controller => "api/changesets", :action => "unsubscribe", :id => "1", :format => "json" }
 
  45         { :path => "/api/0.6/changeset/1", :method => :put },
 
  46         { :controller => "api/changesets", :action => "update", :id => "1" }
 
  49         { :path => "/api/0.6/changeset/1/close", :method => :put },
 
  50         { :controller => "api/changesets", :action => "close", :id => "1" }
 
  53         { :path => "/api/0.6/changesets", :method => :get },
 
  54         { :controller => "api/changesets", :action => "index" }
 
  57         { :path => "/api/0.6/changesets.json", :method => :get },
 
  58         { :controller => "api/changesets", :action => "index", :format => "json" }
 
  62     # -----------------------
 
  63     # Test simple changeset creation
 
  64     # -----------------------
 
  67       auth_header = basic_authorization_header create(:user, :data_public => false).email, "test"
 
  68       # Create the first user's changeset
 
  69       xml = "<osm><changeset>" \
 
  70             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
  72       put changeset_create_path, :params => xml, :headers => auth_header
 
  73       assert_require_public_data
 
  75       auth_header = basic_authorization_header create(:user).email, "test"
 
  76       # Create the first user's changeset
 
  77       xml = "<osm><changeset>" \
 
  78             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
  80       put changeset_create_path, :params => xml, :headers => auth_header
 
  82       assert_response :success, "Creation of changeset did not return success status"
 
  83       newid = @response.body.to_i
 
  85       # check end time, should be an hour ahead of creation time
 
  86       cs = Changeset.find(newid)
 
  87       duration = cs.closed_at - cs.created_at
 
  88       # the difference can either be a rational, or a floating point number
 
  89       # of seconds, depending on the code path taken :-(
 
  90       if duration.instance_of?(Rational)
 
  91         assert_equal Rational(1, 24), duration, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
 
  93         # must be number of seconds...
 
  94         assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
 
  97       # checks if uploader was subscribed
 
  98       assert_equal 1, cs.subscribers.length
 
 101     def test_create_invalid
 
 102       auth_header = basic_authorization_header create(:user, :data_public => false).email, "test"
 
 103       xml = "<osm><changeset></osm>"
 
 104       put changeset_create_path, :params => xml, :headers => auth_header
 
 105       assert_require_public_data
 
 107       ## Try the public user
 
 108       auth_header = basic_authorization_header create(:user).email, "test"
 
 109       xml = "<osm><changeset></osm>"
 
 110       put changeset_create_path, :params => xml, :headers => auth_header
 
 111       assert_response :bad_request, "creating a invalid changeset should fail"
 
 114     def test_create_invalid_no_content
 
 115       ## First check with no auth
 
 116       put changeset_create_path
 
 117       assert_response :unauthorized, "shouldn't be able to create a changeset with no auth"
 
 119       ## Now try to with a non-public user
 
 120       auth_header = basic_authorization_header create(:user, :data_public => false).email, "test"
 
 121       put changeset_create_path, :headers => auth_header
 
 122       assert_require_public_data
 
 124       ## Try an inactive user
 
 125       auth_header = basic_authorization_header create(:user, :pending).email, "test"
 
 126       put changeset_create_path, :headers => auth_header
 
 129       ## Now try to use a normal user
 
 130       auth_header = basic_authorization_header create(:user).email, "test"
 
 131       put changeset_create_path, :headers => auth_header
 
 132       assert_response :bad_request, "creating a changeset with no content should fail"
 
 135     def test_create_wrong_method
 
 136       auth_header = basic_authorization_header create(:user).email, "test"
 
 138       get changeset_create_path, :headers => auth_header
 
 139       assert_response :not_found
 
 140       assert_template "rescues/routing_error"
 
 142       post changeset_create_path, :headers => auth_header
 
 143       assert_response :not_found
 
 144       assert_template "rescues/routing_error"
 
 148     # check that the changeset can be shown and returns the correct
 
 149     # document structure.
 
 151       changeset = create(:changeset)
 
 153       get changeset_show_path(changeset)
 
 154       assert_response :success, "cannot get first changeset"
 
 156       assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 157       assert_single_changeset changeset
 
 158       assert_select "osm>changeset>discussion", 0
 
 160       get changeset_show_path(changeset), :params => { :include_discussion => true }
 
 161       assert_response :success, "cannot get first changeset with comments"
 
 163       assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 164       assert_single_changeset changeset
 
 165       assert_select "osm>changeset>discussion", 1
 
 166       assert_select "osm>changeset>discussion>comment", 0
 
 169     def test_show_comments
 
 170       # all comments visible
 
 171       changeset = create(:changeset, :closed)
 
 172       comment1, comment2, comment3 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
 
 174       get changeset_show_path(changeset), :params => { :include_discussion => true }
 
 175       assert_response :success, "cannot get closed changeset with comments"
 
 177       assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 178       assert_single_changeset changeset
 
 179       assert_select "osm>changeset>discussion", 1
 
 180       assert_select "osm>changeset>discussion>comment", 3
 
 181       assert_select "osm>changeset>discussion>comment:nth-child(1)>@id", comment1.id.to_s
 
 182       assert_select "osm>changeset>discussion>comment:nth-child(1)>@visible", "true"
 
 183       assert_select "osm>changeset>discussion>comment:nth-child(2)>@id", comment2.id.to_s
 
 184       assert_select "osm>changeset>discussion>comment:nth-child(2)>@visible", "true"
 
 185       assert_select "osm>changeset>discussion>comment:nth-child(3)>@id", comment3.id.to_s
 
 186       assert_select "osm>changeset>discussion>comment:nth-child(3)>@visible", "true"
 
 188       # one hidden comment not included because not asked for
 
 189       comment2.update(:visible => false)
 
 191       get changeset_show_path(changeset), :params => { :include_discussion => true }
 
 192       assert_response :success, "cannot get closed changeset with comments"
 
 194       assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 195       assert_single_changeset changeset
 
 196       assert_select "osm>changeset>discussion", 1
 
 197       assert_select "osm>changeset>discussion>comment", 2
 
 198       assert_select "osm>changeset>discussion>comment:nth-child(1)>@id", comment1.id.to_s
 
 199       assert_select "osm>changeset>discussion>comment:nth-child(1)>@visible", "true"
 
 200       assert_select "osm>changeset>discussion>comment:nth-child(2)>@id", comment3.id.to_s
 
 201       assert_select "osm>changeset>discussion>comment:nth-child(2)>@visible", "true"
 
 203       # one hidden comment not included because no permissions
 
 204       get changeset_show_path(changeset), :params => { :include_discussion => true, :show_hidden_comments => true }
 
 205       assert_response :success, "cannot get closed changeset with comments"
 
 207       assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 208       assert_single_changeset changeset
 
 209       assert_select "osm>changeset>discussion", 1
 
 210       assert_select "osm>changeset>discussion>comment", 2
 
 211       assert_select "osm>changeset>discussion>comment:nth-child(1)>@id", comment1.id.to_s
 
 212       assert_select "osm>changeset>discussion>comment:nth-child(1)>@visible", "true"
 
 213       # maybe will show an empty comment element with visible=false in the future
 
 214       assert_select "osm>changeset>discussion>comment:nth-child(2)>@id", comment3.id.to_s
 
 215       assert_select "osm>changeset>discussion>comment:nth-child(2)>@visible", "true"
 
 217       # one hidden comment shown to moderators
 
 218       moderator_user = create(:moderator_user)
 
 219       auth_header = basic_authorization_header moderator_user.email, "test"
 
 220       get changeset_show_path(changeset), :params => { :include_discussion => true, :show_hidden_comments => true },
 
 221                                           :headers => auth_header
 
 222       assert_response :success, "cannot get closed changeset with comments"
 
 224       assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 225       assert_single_changeset changeset
 
 226       assert_select "osm>changeset>discussion", 1
 
 227       assert_select "osm>changeset>discussion>comment", 3
 
 228       assert_select "osm>changeset>discussion>comment:nth-child(1)>@id", comment1.id.to_s
 
 229       assert_select "osm>changeset>discussion>comment:nth-child(1)>@visible", "true"
 
 230       assert_select "osm>changeset>discussion>comment:nth-child(2)>@id", comment2.id.to_s
 
 231       assert_select "osm>changeset>discussion>comment:nth-child(2)>@visible", "false"
 
 232       assert_select "osm>changeset>discussion>comment:nth-child(3)>@id", comment3.id.to_s
 
 233       assert_select "osm>changeset>discussion>comment:nth-child(3)>@visible", "true"
 
 237       changeset = create(:changeset)
 
 239       get changeset_show_path(changeset), :params => { :format => "json" }
 
 240       assert_response :success, "cannot get first changeset"
 
 242       js = ActiveSupport::JSON.decode(@response.body)
 
 245       assert_equal Settings.api_version, js["version"]
 
 246       assert_equal Settings.generator, js["generator"]
 
 247       assert_single_changeset_json changeset, js
 
 248       assert_nil js["changeset"]["tags"]
 
 249       assert_nil js["changeset"]["comments"]
 
 250       assert_equal changeset.user.id, js["changeset"]["uid"]
 
 251       assert_equal changeset.user.display_name, js["changeset"]["user"]
 
 253       get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true }
 
 254       assert_response :success, "cannot get first changeset with comments"
 
 256       js = ActiveSupport::JSON.decode(@response.body)
 
 258       assert_equal Settings.api_version, js["version"]
 
 259       assert_equal Settings.generator, js["generator"]
 
 260       assert_single_changeset_json changeset, js
 
 261       assert_nil js["changeset"]["tags"]
 
 262       assert_nil js["changeset"]["min_lat"]
 
 263       assert_nil js["changeset"]["min_lon"]
 
 264       assert_nil js["changeset"]["max_lat"]
 
 265       assert_nil js["changeset"]["max_lon"]
 
 266       assert_equal 0, js["changeset"]["comments"].count
 
 269     def test_show_comments_json
 
 270       # all comments visible
 
 271       changeset = create(:changeset, :closed)
 
 272       comment0, comment1, comment2 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
 
 274       get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true }
 
 275       assert_response :success, "cannot get closed changeset with comments"
 
 277       js = ActiveSupport::JSON.decode(@response.body)
 
 279       assert_equal Settings.api_version, js["version"]
 
 280       assert_equal Settings.generator, js["generator"]
 
 281       assert_single_changeset_json changeset, js
 
 282       assert_equal 3, js["changeset"]["comments"].count
 
 283       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
 
 284       assert js["changeset"]["comments"][0]["visible"]
 
 285       assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
 
 286       assert js["changeset"]["comments"][1]["visible"]
 
 287       assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
 
 288       assert js["changeset"]["comments"][2]["visible"]
 
 290       # one hidden comment not included because not asked for
 
 291       comment1.update(:visible => false)
 
 293       get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true }
 
 294       assert_response :success, "cannot get closed changeset with comments"
 
 296       js = ActiveSupport::JSON.decode(@response.body)
 
 298       assert_equal Settings.api_version, js["version"]
 
 299       assert_equal Settings.generator, js["generator"]
 
 300       assert_single_changeset_json changeset, js
 
 301       assert_equal 2, js["changeset"]["comments"].count
 
 302       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
 
 303       assert js["changeset"]["comments"][0]["visible"]
 
 304       assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
 
 305       assert js["changeset"]["comments"][1]["visible"]
 
 307       # one hidden comment not included because no permissions
 
 308       get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true, :show_hidden_comments => true }
 
 309       assert_response :success, "cannot get closed changeset with comments"
 
 311       js = ActiveSupport::JSON.decode(@response.body)
 
 313       assert_equal Settings.api_version, js["version"]
 
 314       assert_equal Settings.generator, js["generator"]
 
 315       assert_single_changeset_json changeset, js
 
 316       assert_equal 2, js["changeset"]["comments"].count
 
 317       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
 
 318       assert js["changeset"]["comments"][0]["visible"]
 
 319       # maybe will show an empty comment element with visible=false in the future
 
 320       assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
 
 321       assert js["changeset"]["comments"][1]["visible"]
 
 323       # one hidden comment shown to moderators
 
 324       moderator_user = create(:moderator_user)
 
 325       auth_header = basic_authorization_header moderator_user.email, "test"
 
 326       get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true, :show_hidden_comments => true },
 
 327                                           :headers => auth_header
 
 328       assert_response :success, "cannot get closed changeset with comments"
 
 330       js = ActiveSupport::JSON.decode(@response.body)
 
 332       assert_equal Settings.api_version, js["version"]
 
 333       assert_equal Settings.generator, js["generator"]
 
 334       assert_single_changeset_json changeset, js
 
 335       assert_equal 3, js["changeset"]["comments"].count
 
 336       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
 
 337       assert js["changeset"]["comments"][0]["visible"]
 
 338       assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
 
 339       assert_not js["changeset"]["comments"][1]["visible"]
 
 340       assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
 
 341       assert js["changeset"]["comments"][2]["visible"]
 
 344     def test_show_tag_and_discussion_json
 
 345       changeset = create(:changeset, :closed)
 
 347       tag1 = ChangesetTag.new
 
 348       tag1.changeset_id = changeset.id
 
 349       tag1.k = "created_by"
 
 350       tag1.v = "JOSM/1.5 (18364)"
 
 352       tag2 = ChangesetTag.new
 
 353       tag2.changeset_id = changeset.id
 
 355       tag2.v = "changeset comment"
 
 357       changeset.changeset_tags = [tag1, tag2]
 
 359       create_list(:changeset_comment, 3, :changeset_id => changeset.id)
 
 361       get changeset_show_path(changeset), :params => { :format => "json", :include_discussion => true }
 
 362       assert_response :success, "cannot get closed changeset with comments"
 
 364       js = ActiveSupport::JSON.decode(@response.body)
 
 367       assert_equal Settings.api_version, js["version"]
 
 368       assert_equal Settings.generator, js["generator"]
 
 369       assert_single_changeset_json changeset, js
 
 370       assert_equal 2, js["changeset"]["tags"].count
 
 371       assert_equal 3, js["changeset"]["comments"].count
 
 372       assert_equal 3, js["changeset"]["comments_count"]
 
 373       assert_equal 0, js["changeset"]["changes_count"]
 
 374       assert_not_nil js["changeset"]["comments"][0]["uid"]
 
 375       assert_not_nil js["changeset"]["comments"][0]["user"]
 
 376       assert_not_nil js["changeset"]["comments"][0]["text"]
 
 379     def test_show_bbox_json
 
 380       # test bbox attribute
 
 381       changeset = create(:changeset, :min_lat => (-5 * GeoRecord::SCALE).round, :min_lon => (5 * GeoRecord::SCALE).round,
 
 382                                      :max_lat => (15 * GeoRecord::SCALE).round, :max_lon => (12 * GeoRecord::SCALE).round)
 
 384       get changeset_show_path(changeset), :params => { :format => "json" }
 
 385       assert_response :success, "cannot get first changeset"
 
 387       js = ActiveSupport::JSON.decode(@response.body)
 
 389       assert_equal(-5, js["changeset"]["min_lat"])
 
 390       assert_equal 5, js["changeset"]["min_lon"]
 
 391       assert_equal 15, js["changeset"]["max_lat"]
 
 392       assert_equal 12, js["changeset"]["max_lon"]
 
 396     # check that a changeset that doesn't exist returns an appropriate message
 
 397     def test_show_not_found
 
 398       [0, -32, 233455644, "afg", "213"].each do |id|
 
 399         get changeset_show_path(:id => id)
 
 400         assert_response :not_found, "should get a not found"
 
 401       rescue ActionController::UrlGenerationError => e
 
 402         assert_match(/No route matches/, e.to_s)
 
 407     # test that the user who opened a change can close it
 
 409       private_user = create(:user, :data_public => false)
 
 410       private_changeset = create(:changeset, :user => private_user)
 
 412       changeset = create(:changeset, :user => user)
 
 414       ## Try without authentication
 
 415       put changeset_close_path(changeset)
 
 416       assert_response :unauthorized
 
 418       ## Try using the non-public user
 
 419       auth_header = basic_authorization_header private_user.email, "test"
 
 420       put changeset_close_path(private_changeset), :headers => auth_header
 
 421       assert_require_public_data
 
 423       ## The try with the public user
 
 424       auth_header = basic_authorization_header user.email, "test"
 
 427       put changeset_close_path(:id => cs_id), :headers => auth_header
 
 428       assert_response :success
 
 430       # test that it really is closed now
 
 431       cs = Changeset.find(changeset.id)
 
 433                  "changeset should be closed now (#{cs.closed_at} > #{Time.now.utc}.")
 
 437     # test that a different user can't close another user's changeset
 
 438     def test_close_invalid
 
 440       changeset = create(:changeset)
 
 442       auth_header = basic_authorization_header user.email, "test"
 
 444       put changeset_close_path(changeset), :headers => auth_header
 
 445       assert_response :conflict
 
 446       assert_equal "The user doesn't own that changeset", @response.body
 
 450     # test that you can't close using another method
 
 451     def test_close_method_invalid
 
 453       changeset = create(:changeset, :user => user)
 
 455       auth_header = basic_authorization_header user.email, "test"
 
 457       get changeset_close_path(changeset), :headers => auth_header
 
 458       assert_response :not_found
 
 459       assert_template "rescues/routing_error"
 
 461       post changeset_close_path(changeset), :headers => auth_header
 
 462       assert_response :not_found
 
 463       assert_template "rescues/routing_error"
 
 467     # check that you can't close a changeset that isn't found
 
 468     def test_close_not_found
 
 469       cs_ids = [0, -132, "123"]
 
 471       # First try to do it with no auth
 
 473         put changeset_close_path(:id => id)
 
 474         assert_response :unauthorized, "Shouldn't be able close the non-existant changeset #{id}, when not authorized"
 
 475       rescue ActionController::UrlGenerationError => e
 
 476         assert_match(/No route matches/, e.to_s)
 
 480       auth_header = basic_authorization_header create(:user).email, "test"
 
 482         put changeset_close_path(:id => id), :headers => auth_header
 
 483         assert_response :not_found, "The changeset #{id} doesn't exist, so can't be closed"
 
 484       rescue ActionController::UrlGenerationError => e
 
 485         assert_match(/No route matches/, e.to_s)
 
 490     # upload something simple, but valid and check that it can
 
 492     # Also try without auth and another user.
 
 493     def test_upload_simple_valid
 
 494       private_user = create(:user, :data_public => false)
 
 495       private_changeset = create(:changeset, :user => private_user)
 
 497       changeset = create(:changeset, :user => user)
 
 501       relation = create(:relation)
 
 502       other_relation = create(:relation)
 
 503       # create some tags, since we test that they are removed later
 
 504       create(:node_tag, :node => node)
 
 505       create(:way_tag, :way => way)
 
 506       create(:relation_tag, :relation => relation)
 
 509       changeset_id = changeset.id
 
 511       # simple diff to change a node, way and relation by removing
 
 516           <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
 517           <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
 
 518            <nd ref='#{node.id}'/>
 
 522           <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
 
 523            <member type='way' role='some' ref='#{way.id}'/>
 
 524            <member type='node' role='some' ref='#{node.id}'/>
 
 525            <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 532       post changeset_upload_path(changeset), :params => diff
 
 533       assert_response :unauthorized,
 
 534                       "shouldn't be able to upload a simple valid diff to changeset: #{@response.body}"
 
 536       ## Now try with a private user
 
 537       auth_header = basic_authorization_header private_user.email, "test"
 
 538       changeset_id = private_changeset.id
 
 540       # simple diff to change a node, way and relation by removing
 
 545           <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
 546           <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
 
 547            <nd ref='#{node.id}'/>
 
 551           <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
 
 552            <member type='way' role='some' ref='#{way.id}'/>
 
 553            <member type='node' role='some' ref='#{node.id}'/>
 
 554            <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 561       post changeset_upload_path(private_changeset), :params => diff, :headers => auth_header
 
 562       assert_response :forbidden,
 
 563                       "can't upload a simple valid diff to changeset: #{@response.body}"
 
 565       ## Now try with the public user
 
 566       auth_header = basic_authorization_header user.email, "test"
 
 567       changeset_id = changeset.id
 
 569       # simple diff to change a node, way and relation by removing
 
 574           <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
 575           <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
 
 576            <nd ref='#{node.id}'/>
 
 580           <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
 
 581            <member type='way' role='some' ref='#{way.id}'/>
 
 582            <member type='node' role='some' ref='#{node.id}'/>
 
 583            <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 590       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 591       assert_response :success,
 
 592                       "can't upload a simple valid diff to changeset: #{@response.body}"
 
 594       # check that the changes made it into the database
 
 595       assert_equal 0, Node.find(node.id).tags.size, "node #{node.id} should now have no tags"
 
 596       assert_equal 0, Way.find(way.id).tags.size, "way #{way.id} should now have no tags"
 
 597       assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
 
 601     # upload something which creates new objects using placeholders
 
 602     def test_upload_create_valid
 
 604       changeset = create(:changeset, :user => user)
 
 606       way = create(:way_with_nodes, :nodes_count => 2)
 
 607       relation = create(:relation)
 
 609       auth_header = basic_authorization_header user.email, "test"
 
 611       # simple diff to create a node way and relation using placeholders
 
 615           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 616            <tag k='foo' v='bar'/>
 
 617            <tag k='baz' v='bat'/>
 
 619           <way id='-1' changeset='#{changeset.id}'>
 
 620            <nd ref='#{node.id}'/>
 
 624           <relation id='-1' changeset='#{changeset.id}'>
 
 625            <member type='way' role='some' ref='#{way.id}'/>
 
 626            <member type='node' role='some' ref='#{node.id}'/>
 
 627            <member type='relation' role='some' ref='#{relation.id}'/>
 
 634       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 635       assert_response :success,
 
 636                       "can't upload a simple valid creation to changeset: #{@response.body}"
 
 638       # check the returned payload
 
 639       assert_select "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 640       assert_select "diffResult>node", 1
 
 641       assert_select "diffResult>way", 1
 
 642       assert_select "diffResult>relation", 1
 
 644       # inspect the response to find out what the new element IDs are
 
 645       doc = XML::Parser.string(@response.body).parse
 
 646       new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
 
 647       new_way_id = doc.find("//diffResult/way").first["new_id"].to_i
 
 648       new_rel_id = doc.find("//diffResult/relation").first["new_id"].to_i
 
 650       # check the old IDs are all present and negative one
 
 651       assert_equal(-1, doc.find("//diffResult/node").first["old_id"].to_i)
 
 652       assert_equal(-1, doc.find("//diffResult/way").first["old_id"].to_i)
 
 653       assert_equal(-1, doc.find("//diffResult/relation").first["old_id"].to_i)
 
 655       # check the versions are present and equal one
 
 656       assert_equal 1, doc.find("//diffResult/node").first["new_version"].to_i
 
 657       assert_equal 1, doc.find("//diffResult/way").first["new_version"].to_i
 
 658       assert_equal 1, doc.find("//diffResult/relation").first["new_version"].to_i
 
 660       # check that the changes made it into the database
 
 661       assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
 662       assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
 
 663       assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
 
 667     # test a complex delete where we delete elements which rely on eachother
 
 668     # in the same transaction.
 
 669     def test_upload_delete
 
 670       changeset = create(:changeset)
 
 671       super_relation = create(:relation)
 
 672       used_relation = create(:relation)
 
 673       used_way = create(:way)
 
 674       used_node = create(:node)
 
 675       create(:relation_member, :relation => super_relation, :member => used_relation)
 
 676       create(:relation_member, :relation => super_relation, :member => used_way)
 
 677       create(:relation_member, :relation => super_relation, :member => used_node)
 
 679       auth_header = basic_authorization_header changeset.user.display_name, "test"
 
 681       diff = XML::Document.new
 
 682       diff.root = XML::Node.new "osmChange"
 
 683       delete = XML::Node.new "delete"
 
 685       delete << xml_node_for_relation(super_relation)
 
 686       delete << xml_node_for_relation(used_relation)
 
 687       delete << xml_node_for_way(used_way)
 
 688       delete << xml_node_for_node(used_node)
 
 690       # update the changeset to one that this user owns
 
 691       %w[node way relation].each do |type|
 
 692         delete.find("//osmChange/delete/#{type}").each do |n|
 
 693           n["changeset"] = changeset.id.to_s
 
 698       post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
 699       assert_response :success,
 
 700                       "can't upload a deletion diff to changeset: #{@response.body}"
 
 702       # check the response is well-formed
 
 703       assert_select "diffResult>node", 1
 
 704       assert_select "diffResult>way", 1
 
 705       assert_select "diffResult>relation", 2
 
 707       # check that everything was deleted
 
 708       assert_not Node.find(used_node.id).visible
 
 709       assert_not Way.find(used_way.id).visible
 
 710       assert_not Relation.find(super_relation.id).visible
 
 711       assert_not Relation.find(used_relation.id).visible
 
 715     # test uploading a delete with no lat/lon, as they are optional in
 
 716     # the osmChange spec.
 
 717     def test_upload_nolatlon_delete
 
 719       changeset = create(:changeset)
 
 721       auth_header = basic_authorization_header changeset.user.display_name, "test"
 
 722       diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{changeset.id}'/></delete></osmChange>"
 
 725       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 726       assert_response :success,
 
 727                       "can't upload a deletion diff to changeset: #{@response.body}"
 
 729       # check the response is well-formed
 
 730       assert_select "diffResult>node", 1
 
 732       # check that everything was deleted
 
 733       assert_not Node.find(node.id).visible
 
 736     def test_repeated_changeset_create
 
 738         auth_header = basic_authorization_header create(:user).email, "test"
 
 740         # create a temporary changeset
 
 741         xml = "<osm><changeset>" \
 
 742               "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
 744         assert_difference "Changeset.count", 1 do
 
 745           put changeset_create_path, :params => xml, :headers => auth_header
 
 747         assert_response :success
 
 751     def test_upload_large_changeset
 
 752       auth_header = basic_authorization_header create(:user).email, "test"
 
 755       put changeset_create_path, :params => "<osm><changeset/></osm>", :headers => auth_header
 
 756       assert_response :success, "Should be able to create a changeset: #{@response.body}"
 
 757       changeset_id = @response.body.to_i
 
 759       # upload some widely-spaced nodes, spiralling positive and negative
 
 763           <node id='-1' lon='-20' lat='-10' changeset='#{changeset_id}'/>
 
 764           <node id='-10' lon='20'  lat='10' changeset='#{changeset_id}'/>
 
 765           <node id='-2' lon='-40' lat='-20' changeset='#{changeset_id}'/>
 
 766           <node id='-11' lon='40'  lat='20' changeset='#{changeset_id}'/>
 
 767           <node id='-3' lon='-60' lat='-30' changeset='#{changeset_id}'/>
 
 768           <node id='-12' lon='60'  lat='30' changeset='#{changeset_id}'/>
 
 769           <node id='-4' lon='-80' lat='-40' changeset='#{changeset_id}'/>
 
 770           <node id='-13' lon='80'  lat='40' changeset='#{changeset_id}'/>
 
 771           <node id='-5' lon='-100' lat='-50' changeset='#{changeset_id}'/>
 
 772           <node id='-14' lon='100'  lat='50' changeset='#{changeset_id}'/>
 
 773           <node id='-6' lon='-120' lat='-60' changeset='#{changeset_id}'/>
 
 774           <node id='-15' lon='120'  lat='60' changeset='#{changeset_id}'/>
 
 775           <node id='-7' lon='-140' lat='-70' changeset='#{changeset_id}'/>
 
 776           <node id='-16' lon='140'  lat='70' changeset='#{changeset_id}'/>
 
 777           <node id='-8' lon='-160' lat='-80' changeset='#{changeset_id}'/>
 
 778           <node id='-17' lon='160'  lat='80' changeset='#{changeset_id}'/>
 
 779           <node id='-9' lon='-179.9' lat='-89.9' changeset='#{changeset_id}'/>
 
 780           <node id='-18' lon='179.9'  lat='89.9' changeset='#{changeset_id}'/>
 
 785       # upload it, which used to cause an error like "PGError: ERROR:
 
 786       # integer out of range" (bug #2152). but shouldn't any more.
 
 787       post changeset_upload_path(:id => changeset_id), :params => diff, :headers => auth_header
 
 788       assert_response :success,
 
 789                       "can't upload a spatially-large diff to changeset: #{@response.body}"
 
 791       # check that the changeset bbox is within bounds
 
 792       cs = Changeset.find(changeset_id)
 
 793       assert_operator cs.min_lon, :>=, -180 * GeoRecord::SCALE, "Minimum longitude (#{cs.min_lon / GeoRecord::SCALE}) should be >= -180 to be valid."
 
 794       assert_operator cs.max_lon, :<=, 180 * GeoRecord::SCALE, "Maximum longitude (#{cs.max_lon / GeoRecord::SCALE}) should be <= 180 to be valid."
 
 795       assert_operator cs.min_lat, :>=, -90 * GeoRecord::SCALE, "Minimum latitude (#{cs.min_lat / GeoRecord::SCALE}) should be >= -90 to be valid."
 
 796       assert_operator cs.max_lat, :<=, 90 * GeoRecord::SCALE, "Maximum latitude (#{cs.max_lat / GeoRecord::SCALE}) should be <= 90 to be valid."
 
 800     # test that deleting stuff in a transaction doesn't bypass the checks
 
 801     # to ensure that used elements are not deleted.
 
 802     def test_upload_delete_invalid
 
 803       changeset = create(:changeset)
 
 804       relation = create(:relation)
 
 805       other_relation = create(:relation)
 
 806       used_way = create(:way)
 
 807       used_node = create(:node)
 
 808       create(:relation_member, :relation => relation, :member => used_way)
 
 809       create(:relation_member, :relation => relation, :member => used_node)
 
 811       auth_header = basic_authorization_header changeset.user.email, "test"
 
 813       diff = XML::Document.new
 
 814       diff.root = XML::Node.new "osmChange"
 
 815       delete = XML::Node.new "delete"
 
 817       delete << xml_node_for_relation(other_relation)
 
 818       delete << xml_node_for_way(used_way)
 
 819       delete << xml_node_for_node(used_node)
 
 821       # update the changeset to one that this user owns
 
 822       %w[node way relation].each do |type|
 
 823         delete.find("//osmChange/delete/#{type}").each do |n|
 
 824           n["changeset"] = changeset.id.to_s
 
 829       post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
 830       assert_response :precondition_failed,
 
 831                       "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
 
 832       assert_equal "Precondition failed: Way #{used_way.id} is still used by relations #{relation.id}.", @response.body
 
 834       # check that nothing was, in fact, deleted
 
 835       assert Node.find(used_node.id).visible
 
 836       assert Way.find(used_way.id).visible
 
 837       assert Relation.find(relation.id).visible
 
 838       assert Relation.find(other_relation.id).visible
 
 842     # test that a conditional delete of an in use object works.
 
 843     def test_upload_delete_if_unused
 
 844       changeset = create(:changeset)
 
 845       super_relation = create(:relation)
 
 846       used_relation = create(:relation)
 
 847       used_way = create(:way)
 
 848       used_node = create(:node)
 
 849       create(:relation_member, :relation => super_relation, :member => used_relation)
 
 850       create(:relation_member, :relation => super_relation, :member => used_way)
 
 851       create(:relation_member, :relation => super_relation, :member => used_node)
 
 853       auth_header = basic_authorization_header changeset.user.email, "test"
 
 855       diff = XML::Document.new
 
 856       diff.root = XML::Node.new "osmChange"
 
 857       delete = XML::Node.new "delete"
 
 859       delete["if-unused"] = ""
 
 860       delete << xml_node_for_relation(used_relation)
 
 861       delete << xml_node_for_way(used_way)
 
 862       delete << xml_node_for_node(used_node)
 
 864       # update the changeset to one that this user owns
 
 865       %w[node way relation].each do |type|
 
 866         delete.find("//osmChange/delete/#{type}").each do |n|
 
 867           n["changeset"] = changeset.id.to_s
 
 872       post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
 873       assert_response :success,
 
 874                       "can't do a conditional delete of in use objects: #{@response.body}"
 
 876       # check the returned payload
 
 877       assert_select "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 878       assert_select "diffResult>node", 1
 
 879       assert_select "diffResult>way", 1
 
 880       assert_select "diffResult>relation", 1
 
 883       doc = XML::Parser.string(@response.body).parse
 
 885       # check the old IDs are all present and what we expect
 
 886       assert_equal used_node.id, doc.find("//diffResult/node").first["old_id"].to_i
 
 887       assert_equal used_way.id, doc.find("//diffResult/way").first["old_id"].to_i
 
 888       assert_equal used_relation.id, doc.find("//diffResult/relation").first["old_id"].to_i
 
 890       # check the new IDs are all present and unchanged
 
 891       assert_equal used_node.id, doc.find("//diffResult/node").first["new_id"].to_i
 
 892       assert_equal used_way.id, doc.find("//diffResult/way").first["new_id"].to_i
 
 893       assert_equal used_relation.id, doc.find("//diffResult/relation").first["new_id"].to_i
 
 895       # check the new versions are all present and unchanged
 
 896       assert_equal used_node.version, doc.find("//diffResult/node").first["new_version"].to_i
 
 897       assert_equal used_way.version, doc.find("//diffResult/way").first["new_version"].to_i
 
 898       assert_equal used_relation.version, doc.find("//diffResult/relation").first["new_version"].to_i
 
 900       # check that nothing was, in fact, deleted
 
 901       assert Node.find(used_node.id).visible
 
 902       assert Way.find(used_way.id).visible
 
 903       assert Relation.find(used_relation.id).visible
 
 907     # upload an element with a really long tag value
 
 908     def test_upload_invalid_too_long_tag
 
 909       changeset = create(:changeset)
 
 911       auth_header = basic_authorization_header changeset.user.email, "test"
 
 913       # simple diff to create a node way and relation using placeholders
 
 917           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 918            <tag k='foo' v='#{'x' * 256}'/>
 
 925       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 926       assert_response :bad_request,
 
 927                       "shouldn't be able to upload too long a tag to changeset: #{@response.body}"
 
 931     # upload something which creates new objects and inserts them into
 
 932     # existing containers using placeholders.
 
 933     def test_upload_complex
 
 936       relation = create(:relation)
 
 937       create(:way_node, :way => way, :node => node)
 
 939       changeset = create(:changeset)
 
 941       auth_header = basic_authorization_header changeset.user.email, "test"
 
 943       # simple diff to create a node way and relation using placeholders
 
 947           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 948            <tag k='foo' v='bar'/>
 
 949            <tag k='baz' v='bat'/>
 
 953           <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
 955            <nd ref='#{node.id}'/>
 
 957           <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
 958            <member type='way' role='some' ref='#{way.id}'/>
 
 959            <member type='node' role='some' ref='-1'/>
 
 960            <member type='relation' role='some' ref='#{relation.id}'/>
 
 967       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
 968       assert_response :success,
 
 969                       "can't upload a complex diff to changeset: #{@response.body}"
 
 971       # check the returned payload
 
 972       assert_select "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 973       assert_select "diffResult>node", 1
 
 974       assert_select "diffResult>way", 1
 
 975       assert_select "diffResult>relation", 1
 
 977       # inspect the response to find out what the new element IDs are
 
 978       doc = XML::Parser.string(@response.body).parse
 
 979       new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
 
 981       # check that the changes made it into the database
 
 982       assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
 983       assert_equal [new_node_id, node.id], Way.find(way.id).nds, "way nodes should match"
 
 984       Relation.find(relation.id).members.each do |type, id, _role|
 
 985         assert_equal new_node_id, id, "relation should contain new node" if type == "node"
 
 990     # create a diff which references several changesets, which should cause
 
 991     # a rollback and none of the diff gets committed
 
 992     def test_upload_invalid_changesets
 
 993       changeset = create(:changeset)
 
 994       other_changeset = create(:changeset, :user => changeset.user)
 
 997       relation = create(:relation)
 
 998       other_relation = create(:relation)
 
1000       auth_header = basic_authorization_header changeset.user.email, "test"
 
1002       # simple diff to create a node way and relation using placeholders
 
1006           <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1007           <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
1008            <nd ref='#{node.id}'/>
 
1012           <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
1013            <member type='way' role='some' ref='#{way.id}'/>
 
1014            <member type='node' role='some' ref='#{node.id}'/>
 
1015            <member type='relation' role='some' ref='#{other_relation.id}'/>
 
1019           <node id='-1' lon='0' lat='0' changeset='#{other_changeset.id}'>
 
1020            <tag k='foo' v='bar'/>
 
1021            <tag k='baz' v='bat'/>
 
1028       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1029       assert_response :conflict,
 
1030                       "uploading a diff with multiple changesets should have failed"
 
1032       # check that objects are unmodified
 
1033       assert_nodes_are_equal(node, Node.find(node.id))
 
1034       assert_ways_are_equal(way, Way.find(way.id))
 
1035       assert_relations_are_equal(relation, Relation.find(relation.id))
 
1039     # upload multiple versions of the same element in the same diff.
 
1040     def test_upload_multiple_valid
 
1041       node = create(:node)
 
1042       changeset = create(:changeset)
 
1043       auth_header = basic_authorization_header changeset.user.email, "test"
 
1045       # change the location of a node multiple times, each time referencing
 
1046       # the last version. doesn't this depend on version numbers being
 
1051           <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1052           <node id='#{node.id}' lon='1' lat='0' changeset='#{changeset.id}' version='2'/>
 
1053           <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='3'/>
 
1054           <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='4'/>
 
1055           <node id='#{node.id}' lon='2' lat='2' changeset='#{changeset.id}' version='5'/>
 
1056           <node id='#{node.id}' lon='3' lat='2' changeset='#{changeset.id}' version='6'/>
 
1057           <node id='#{node.id}' lon='3' lat='3' changeset='#{changeset.id}' version='7'/>
 
1058           <node id='#{node.id}' lon='9' lat='9' changeset='#{changeset.id}' version='8'/>
 
1064       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1065       assert_response :success,
 
1066                       "can't upload multiple versions of an element in a diff: #{@response.body}"
 
1068       # check the response is well-formed. its counter-intuitive, but the
 
1069       # API will return multiple elements with the same ID and different
 
1070       # version numbers for each change we made.
 
1071       assert_select "diffResult>node", 8
 
1075     # upload multiple versions of the same element in the same diff, but
 
1076     # keep the version numbers the same.
 
1077     def test_upload_multiple_duplicate
 
1078       node = create(:node)
 
1079       changeset = create(:changeset)
 
1081       auth_header = basic_authorization_header changeset.user.email, "test"
 
1086           <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1087           <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
1093       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1094       assert_response :conflict,
 
1095                       "shouldn't be able to upload the same element twice in a diff: #{@response.body}"
 
1099     # try to upload some elements without specifying the version
 
1100     def test_upload_missing_version
 
1101       changeset = create(:changeset)
 
1103       auth_header = basic_authorization_header changeset.user.email, "test"
 
1108          <node id='1' lon='1' lat='1' changeset='#{changeset.id}'/>
 
1114       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1115       assert_response :bad_request,
 
1116                       "shouldn't be able to upload an element without version: #{@response.body}"
 
1120     # try to upload with commands other than create, modify, or delete
 
1121     def test_action_upload_invalid
 
1122       changeset = create(:changeset)
 
1124       auth_header = basic_authorization_header changeset.user.email, "test"
 
1129            <node id='1' lon='1' lat='1' changeset='#{changeset.id}' />
 
1133       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1134       assert_response :bad_request, "Shouldn't be able to upload a diff with the action ping"
 
1135       assert_equal("Unknown action ping, choices are create, modify, delete", @response.body)
 
1139     # upload a valid changeset which has a mixture of whitespace
 
1140     # to check a bug reported by ivansanchez (#1565).
 
1141     def test_upload_whitespace_valid
 
1142       changeset = create(:changeset)
 
1143       node = create(:node)
 
1144       way = create(:way_with_nodes, :nodes_count => 2)
 
1145       relation = create(:relation)
 
1146       other_relation = create(:relation)
 
1147       create(:relation_tag, :relation => relation)
 
1149       auth_header = basic_authorization_header changeset.user.email, "test"
 
1153          <modify><node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}'
 
1155           <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='2'><tag k='k' v='v'/></node></modify>
 
1157          <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'><member
 
1158            type='way' role='some' ref='#{way.id}'/><member
 
1159             type='node' role='some' ref='#{node.id}'/>
 
1160            <member type='relation' role='some' ref='#{other_relation.id}'/>
 
1162          </modify></osmChange>
 
1166       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1167       assert_response :success,
 
1168                       "can't upload a valid diff with whitespace variations to changeset: #{@response.body}"
 
1170       # check the response is well-formed
 
1171       assert_select "diffResult>node", 2
 
1172       assert_select "diffResult>relation", 1
 
1174       # check that the changes made it into the database
 
1175       assert_equal 1, Node.find(node.id).tags.size, "node #{node.id} should now have one tag"
 
1176       assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
 
1180     # test that a placeholder can be reused within the same upload.
 
1181     def test_upload_reuse_placeholder_valid
 
1182       changeset = create(:changeset)
 
1184       auth_header = basic_authorization_header changeset.user.email, "test"
 
1189           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1190            <tag k="foo" v="bar"/>
 
1194           <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
1197           <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
 
1203       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1204       assert_response :success,
 
1205                       "can't upload a valid diff with re-used placeholders to changeset: #{@response.body}"
 
1207       # check the response is well-formed
 
1208       assert_select "diffResult>node", 3
 
1209       assert_select "diffResult>node[old_id='-1']", 3
 
1213     # test what happens if a diff upload re-uses placeholder IDs in an
 
1215     def test_upload_placeholder_invalid
 
1216       changeset = create(:changeset)
 
1218       auth_header = basic_authorization_header changeset.user.email, "test"
 
1223           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1224           <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
1225           <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
 
1231       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1232       assert_response :bad_request,
 
1233                       "shouldn't be able to re-use placeholder IDs"
 
1235       # placeholder_ids must be unique across all action blocks
 
1239           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1242           <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
1248       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1249       assert_response :bad_request,
 
1250                       "shouldn't be able to re-use placeholder IDs"
 
1253     def test_upload_process_order
 
1254       changeset = create(:changeset)
 
1256       auth_header = basic_authorization_header changeset.user.email, "test"
 
1261           <node id="-1" lat="1" lon="2" changeset="#{changeset.id}"/>
 
1262           <way id="-1" changeset="#{changeset.id}">
 
1266           <node id="-2" lat="1" lon="2" changeset="#{changeset.id}"/>
 
1272       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1273       assert_response :bad_request,
 
1274                       "shouldn't refer elements behind it"
 
1277     def test_upload_duplicate_delete
 
1278       changeset = create(:changeset)
 
1280       auth_header = basic_authorization_header changeset.user.email, "test"
 
1285             <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
 
1288             <node id="-1" version="1" changeset="#{changeset.id}" />
 
1289             <node id="-1" version="1" changeset="#{changeset.id}" />
 
1295       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1296       assert_response :gone,
 
1297                       "transaction should be cancelled by second deletion"
 
1302             <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
 
1304           <delete if-unused="true">
 
1305             <node id="-1" version="1" changeset="#{changeset.id}" />
 
1306             <node id="-1" version="1" changeset="#{changeset.id}" />
 
1312       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1314       assert_select "diffResult>node", 3
 
1315       assert_select "diffResult>node[old_id='-1']", 3
 
1316       assert_select "diffResult>node[new_version='1']", 1
 
1317       assert_select "diffResult>node[new_version='2']", 1
 
1321     # test that uploading a way referencing invalid placeholders gives a
 
1322     # proper error, not a 500.
 
1323     def test_upload_placeholder_invalid_way
 
1324       changeset = create(:changeset)
 
1327       auth_header = basic_authorization_header changeset.user.email, "test"
 
1332           <node id="-1" lon="0" lat="0" changeset="#{changeset.id}" version="1"/>
 
1333           <node id="-2" lon="1" lat="1" changeset="#{changeset.id}" version="1"/>
 
1334           <node id="-3" lon="2" lat="2" changeset="#{changeset.id}" version="1"/>
 
1335           <way id="-1" changeset="#{changeset.id}" version="1">
 
1346       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1347       assert_response :bad_request,
 
1348                       "shouldn't be able to use invalid placeholder IDs"
 
1349       assert_equal "Placeholder node not found for reference -4 in way -1", @response.body
 
1351       # the same again, but this time use an existing way
 
1355           <node id="-1" lon="0" lat="0" changeset="#{changeset.id}" version="1"/>
 
1356           <node id="-2" lon="1" lat="1" changeset="#{changeset.id}" version="1"/>
 
1357           <node id="-3" lon="2" lat="2" changeset="#{changeset.id}" version="1"/>
 
1358           <way id="#{way.id}" changeset="#{changeset.id}" version="1">
 
1369       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1370       assert_response :bad_request,
 
1371                       "shouldn't be able to use invalid placeholder IDs"
 
1372       assert_equal "Placeholder node not found for reference -4 in way #{way.id}", @response.body
 
1376     # test that uploading a relation referencing invalid placeholders gives a
 
1377     # proper error, not a 500.
 
1378     def test_upload_placeholder_invalid_relation
 
1379       changeset = create(:changeset)
 
1380       relation = create(:relation)
 
1382       auth_header = basic_authorization_header changeset.user.email, "test"
 
1387           <node id="-1" lon="0" lat="0" changeset="#{changeset.id}" version="1"/>
 
1388           <node id="-2" lon="1" lat="1" changeset="#{changeset.id}" version="1"/>
 
1389           <node id="-3" lon="2" lat="2" changeset="#{changeset.id}" version="1"/>
 
1390           <relation id="-1" changeset="#{changeset.id}" version="1">
 
1391            <member type="node" role="foo" ref="-1"/>
 
1392            <member type="node" role="foo" ref="-2"/>
 
1393            <member type="node" role="foo" ref="-3"/>
 
1394            <member type="node" role="foo" ref="-4"/>
 
1401       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1402       assert_response :bad_request,
 
1403                       "shouldn't be able to use invalid placeholder IDs"
 
1404       assert_equal "Placeholder Node not found for reference -4 in relation -1.", @response.body
 
1406       # the same again, but this time use an existing relation
 
1410           <node id="-1" lon="0" lat="0" changeset="#{changeset.id}" version="1"/>
 
1411           <node id="-2" lon="1" lat="1" changeset="#{changeset.id}" version="1"/>
 
1412           <node id="-3" lon="2" lat="2" changeset="#{changeset.id}" version="1"/>
 
1413           <relation id="#{relation.id}" changeset="#{changeset.id}" version="1">
 
1414            <member type="node" role="foo" ref="-1"/>
 
1415            <member type="node" role="foo" ref="-2"/>
 
1416            <member type="node" role="foo" ref="-3"/>
 
1417            <member type="way" role="bar" ref="-1"/>
 
1424       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1425       assert_response :bad_request,
 
1426                       "shouldn't be able to use invalid placeholder IDs"
 
1427       assert_equal "Placeholder Way not found for reference -1 in relation #{relation.id}.", @response.body
 
1431     # test what happens if a diff is uploaded containing only a node
 
1433     def test_upload_node_move
 
1434       auth_header = basic_authorization_header create(:user).email, "test"
 
1436       xml = "<osm><changeset>" \
 
1437             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1438             "</changeset></osm>"
 
1439       put changeset_create_path, :params => xml, :headers => auth_header
 
1440       assert_response :success
 
1441       changeset_id = @response.body.to_i
 
1443       old_node = create(:node, :lat => 1, :lon => 1)
 
1445       diff = XML::Document.new
 
1446       diff.root = XML::Node.new "osmChange"
 
1447       modify = XML::Node.new "modify"
 
1448       xml_old_node = xml_node_for_node(old_node)
 
1449       xml_old_node["lat"] = 2.0.to_s
 
1450       xml_old_node["lon"] = 2.0.to_s
 
1451       xml_old_node["changeset"] = changeset_id.to_s
 
1452       modify << xml_old_node
 
1456       post changeset_upload_path(:id => changeset_id), :params => diff.to_s, :headers => auth_header
 
1457       assert_response :success,
 
1458                       "diff should have uploaded OK"
 
1461       changeset = Changeset.find(changeset_id)
 
1462       assert_equal 1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 1 degree"
 
1463       assert_equal 2 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 2 degrees"
 
1464       assert_equal 1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1 degree"
 
1465       assert_equal 2 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 2 degrees"
 
1469     # test what happens if a diff is uploaded adding a node to a way.
 
1470     def test_upload_way_extend
 
1471       auth_header = basic_authorization_header create(:user).email, "test"
 
1473       xml = "<osm><changeset>" \
 
1474             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1475             "</changeset></osm>"
 
1476       put changeset_create_path, :params => xml, :headers => auth_header
 
1477       assert_response :success
 
1478       changeset_id = @response.body.to_i
 
1480       old_way = create(:way)
 
1481       create(:way_node, :way => old_way, :node => create(:node, :lat => 1, :lon => 1))
 
1483       diff = XML::Document.new
 
1484       diff.root = XML::Node.new "osmChange"
 
1485       modify = XML::Node.new "modify"
 
1486       xml_old_way = xml_node_for_way(old_way)
 
1487       nd_ref = XML::Node.new "nd"
 
1488       nd_ref["ref"] = create(:node, :lat => 3, :lon => 3).id.to_s
 
1489       xml_old_way << nd_ref
 
1490       xml_old_way["changeset"] = changeset_id.to_s
 
1491       modify << xml_old_way
 
1495       post changeset_upload_path(:id => changeset_id), :params => diff.to_s, :headers => auth_header
 
1496       assert_response :success,
 
1497                       "diff should have uploaded OK"
 
1500       changeset = Changeset.find(changeset_id)
 
1501       assert_equal 1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 1 degree"
 
1502       assert_equal 3 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 3 degrees"
 
1503       assert_equal 1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1 degree"
 
1504       assert_equal 3 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 3 degrees"
 
1508     # test for more issues in #1568
 
1509     def test_upload_empty_invalid
 
1510       changeset = create(:changeset)
 
1512       auth_header = basic_authorization_header changeset.user.email, "test"
 
1515        "<osmChange></osmChange>",
 
1516        "<osmChange><modify/></osmChange>",
 
1517        "<osmChange><modify></modify></osmChange>"].each do |diff|
 
1519         post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1520         assert_response(:success, "should be able to upload " \
 
1521                                   "empty changeset: " + diff)
 
1526     # test that the X-Error-Format header works to request XML errors
 
1527     def test_upload_xml_errors
 
1528       changeset = create(:changeset)
 
1529       node = create(:node)
 
1530       create(:relation_member, :member => node)
 
1532       auth_header = basic_authorization_header changeset.user.email, "test"
 
1534       # try and delete a node that is in use
 
1535       diff = XML::Document.new
 
1536       diff.root = XML::Node.new "osmChange"
 
1537       delete = XML::Node.new "delete"
 
1539       delete << xml_node_for_node(node)
 
1542       error_header = error_format_header "xml"
 
1543       post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header.merge(error_header)
 
1544       assert_response :success,
 
1545                       "failed to return error in XML format"
 
1547       # check the returned payload
 
1548       assert_select "osmError[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
1549       assert_select "osmError>status", 1
 
1550       assert_select "osmError>message", 1
 
1553     def test_upload_not_found
 
1554       changeset = create(:changeset)
 
1556       auth_header = basic_authorization_header changeset.user.email, "test"
 
1562           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1568       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1569       assert_response :not_found, "Node should not be found"
 
1575           <way id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1581       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1582       assert_response :not_found, "Way should not be found"
 
1588           <relation id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1594       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1595       assert_response :not_found, "Relation should not be found"
 
1601           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1607       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1608       assert_response :not_found, "Node should not be deleted"
 
1614           <way id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1620       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1621       assert_response :not_found, "Way should not be deleted"
 
1627           <relation id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1633       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1634       assert_response :not_found, "Relation should not be deleted"
 
1637     def test_upload_relation_placeholder_not_fix
 
1638       changeset = create(:changeset)
 
1640       auth_header = basic_authorization_header changeset.user.email, "test"
 
1644         <osmChange version='0.6'>
 
1646             <relation id='-2' version='0' changeset='#{changeset.id}'>
 
1647               <member type='relation' role='' ref='-4' />
 
1648               <tag k='type' v='route' />
 
1649               <tag k='name' v='AtoB' />
 
1651             <relation id='-3' version='0' changeset='#{changeset.id}'>
 
1652               <tag k='type' v='route' />
 
1653               <tag k='name' v='BtoA' />
 
1655             <relation id='-4' version='0' changeset='#{changeset.id}'>
 
1656               <member type='relation' role='' ref='-2' />
 
1657               <member type='relation' role='' ref='-3' />
 
1658               <tag k='type' v='route_master' />
 
1659               <tag k='name' v='master' />
 
1666       post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1667       assert_response :bad_request, "shouldn't be able to use reference -4 in relation -2: #{@response.body}"
 
1668       assert_equal "Placeholder Relation not found for reference -4 in relation -2.", @response.body
 
1671     def test_upload_multiple_delete_block
 
1672       changeset = create(:changeset)
 
1674       auth_header = basic_authorization_header changeset.user.email, "test"
 
1676       node = create(:node)
 
1678       create(:way_node, :way => way, :node => node)
 
1679       alone_node = create(:node)
 
1683         <osmChange version='0.6'>
 
1684           <delete version="0.6">
 
1685             <node id="#{node.id}" version="#{node.version}" changeset="#{changeset.id}"/>
 
1687           <delete version="0.6" if-unused="true">
 
1688             <node id="#{alone_node.id}" version="#{alone_node.version}" changeset="#{changeset.id}"/>
 
1694       post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
 
1695       assert_response :precondition_failed,
 
1696                       "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
 
1697       assert_equal "Precondition failed: Node #{node.id} is still used by ways #{way.id}.", @response.body
 
1701     # test initial rate limit
 
1702     def test_upload_initial_rate_limit
 
1704       user = create(:user)
 
1706       # create some objects to use
 
1707       node = create(:node)
 
1708       way = create(:way_with_nodes, :nodes_count => 2)
 
1709       relation = create(:relation)
 
1711       # create a changeset that puts us near the initial rate limit
 
1712       changeset = create(:changeset, :user => user,
 
1713                                      :created_at => Time.now.utc - 5.minutes,
 
1714                                      :num_changes => Settings.initial_changes_per_hour - 2)
 
1716       # create authentication header
 
1717       auth_header = basic_authorization_header user.email, "test"
 
1719       # simple diff to create a node way and relation using placeholders
 
1723           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1724            <tag k='foo' v='bar'/>
 
1725            <tag k='baz' v='bat'/>
 
1727           <way id='-1' changeset='#{changeset.id}'>
 
1728            <nd ref='#{node.id}'/>
 
1732           <relation id='-1' changeset='#{changeset.id}'>
 
1733            <member type='way' role='some' ref='#{way.id}'/>
 
1734            <member type='node' role='some' ref='#{node.id}'/>
 
1735            <member type='relation' role='some' ref='#{relation.id}'/>
 
1742       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1743       assert_response :too_many_requests, "upload did not hit rate limit"
 
1747     # test maximum rate limit
 
1748     def test_upload_maximum_rate_limit
 
1750       user = create(:user)
 
1752       # create some objects to use
 
1753       node = create(:node)
 
1754       way = create(:way_with_nodes, :nodes_count => 2)
 
1755       relation = create(:relation)
 
1757       # create a changeset to establish our initial edit time
 
1758       changeset = create(:changeset, :user => user,
 
1759                                      :created_at => Time.now.utc - 28.days)
 
1761       # create changeset to put us near the maximum rate limit
 
1762       total_changes = Settings.max_changes_per_hour - 2
 
1763       while total_changes.positive?
 
1764         changes = [total_changes, Changeset::MAX_ELEMENTS].min
 
1765         changeset = create(:changeset, :user => user,
 
1766                                        :created_at => Time.now.utc - 5.minutes,
 
1767                                        :num_changes => changes)
 
1768         total_changes -= changes
 
1771       # create authentication header
 
1772       auth_header = basic_authorization_header user.email, "test"
 
1774       # simple diff to create a node way and relation using placeholders
 
1778           <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1779            <tag k='foo' v='bar'/>
 
1780            <tag k='baz' v='bat'/>
 
1782           <way id='-1' changeset='#{changeset.id}'>
 
1783            <nd ref='#{node.id}'/>
 
1787           <relation id='-1' changeset='#{changeset.id}'>
 
1788            <member type='way' role='some' ref='#{way.id}'/>
 
1789            <member type='node' role='some' ref='#{node.id}'/>
 
1790            <member type='relation' role='some' ref='#{relation.id}'/>
 
1797       post changeset_upload_path(changeset), :params => diff, :headers => auth_header
 
1798       assert_response :too_many_requests, "upload did not hit rate limit"
 
1802     # when we make some simple changes we get the same changes back from the
 
1804     def test_diff_download_simple
 
1805       node = create(:node)
 
1807       ## First try with a non-public user, which should get a forbidden
 
1808       auth_header = basic_authorization_header create(:user, :data_public => false).email, "test"
 
1810       # create a temporary changeset
 
1811       xml = "<osm><changeset>" \
 
1812             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1813             "</changeset></osm>"
 
1814       put changeset_create_path, :params => xml, :headers => auth_header
 
1815       assert_response :forbidden
 
1817       ## Now try with a normal user
 
1818       auth_header = basic_authorization_header create(:user).email, "test"
 
1820       # create a temporary changeset
 
1821       xml = "<osm><changeset>" \
 
1822             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1823             "</changeset></osm>"
 
1824       put changeset_create_path, :params => xml, :headers => auth_header
 
1825       assert_response :success
 
1826       changeset_id = @response.body.to_i
 
1832           <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
1833           <node id='#{node.id}' lon='1' lat='0' changeset='#{changeset_id}' version='2'/>
 
1834           <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset_id}' version='3'/>
 
1835           <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset_id}' version='4'/>
 
1836           <node id='#{node.id}' lon='2' lat='2' changeset='#{changeset_id}' version='5'/>
 
1837           <node id='#{node.id}' lon='3' lat='2' changeset='#{changeset_id}' version='6'/>
 
1838           <node id='#{node.id}' lon='3' lat='3' changeset='#{changeset_id}' version='7'/>
 
1839           <node id='#{node.id}' lon='9' lat='9' changeset='#{changeset_id}' version='8'/>
 
1845       post changeset_upload_path(:id => changeset_id), :params => diff, :headers => auth_header
 
1846       assert_response :success,
 
1847                       "can't upload multiple versions of an element in a diff: #{@response.body}"
 
1849       get changeset_download_path(:id => changeset_id)
 
1850       assert_response :success
 
1852       assert_select "osmChange", 1
 
1853       assert_select "osmChange>modify", 8
 
1854       assert_select "osmChange>modify>node", 8
 
1858     # culled this from josm to ensure that nothing in the way that josm
 
1859     # is formatting the request is causing it to fail.
 
1861     # NOTE: the error turned out to be something else completely!
 
1862     def test_josm_upload
 
1863       auth_header = basic_authorization_header create(:user).email, "test"
 
1865       # create a temporary changeset
 
1866       xml = "<osm><changeset>" \
 
1867             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1868             "</changeset></osm>"
 
1869       put changeset_create_path, :params => xml, :headers => auth_header
 
1870       assert_response :success
 
1871       changeset_id = @response.body.to_i
 
1874         <osmChange version="0.6" generator="JOSM">
 
1875         <create version="0.6" generator="JOSM">
 
1876           <node id='-1' visible='true' changeset='#{changeset_id}' lat='51.49619982187321' lon='-0.18722061869438314' />
 
1877           <node id='-2' visible='true' changeset='#{changeset_id}' lat='51.496359883909605' lon='-0.18653093576241928' />
 
1878           <node id='-3' visible='true' changeset='#{changeset_id}' lat='51.49598132358285' lon='-0.18719613290981638' />
 
1879           <node id='-4' visible='true' changeset='#{changeset_id}' lat='51.4961591711078' lon='-0.18629015888084607' />
 
1880           <node id='-5' visible='true' changeset='#{changeset_id}' lat='51.49582126021711' lon='-0.18708186591517145' />
 
1881           <node id='-6' visible='true' changeset='#{changeset_id}' lat='51.49591018437858' lon='-0.1861432441734455' />
 
1882           <node id='-7' visible='true' changeset='#{changeset_id}' lat='51.49560784152179' lon='-0.18694719410005425' />
 
1883           <node id='-8' visible='true' changeset='#{changeset_id}' lat='51.49567389979617' lon='-0.1860289771788006' />
 
1884           <node id='-9' visible='true' changeset='#{changeset_id}' lat='51.49543761398892' lon='-0.186820684213126' />
 
1885           <way id='-10' action='modify' visible='true' changeset='#{changeset_id}'>
 
1895             <tag k='highway' v='residential' />
 
1896             <tag k='name' v='Foobar Street' />
 
1903       post changeset_upload_path(:id => changeset_id), :params => diff, :headers => auth_header
 
1904       assert_response :success,
 
1905                       "can't upload a diff from JOSM: #{@response.body}"
 
1907       get changeset_download_path(:id => changeset_id)
 
1908       assert_response :success
 
1910       assert_select "osmChange", 1
 
1911       assert_select "osmChange>create>node", 9
 
1912       assert_select "osmChange>create>way", 1
 
1913       assert_select "osmChange>create>way>nd", 9
 
1914       assert_select "osmChange>create>way>tag", 2
 
1918     # when we make some complex changes we get the same changes back from the
 
1920     def test_diff_download_complex
 
1921       node = create(:node)
 
1922       node2 = create(:node)
 
1924       auth_header = basic_authorization_header create(:user).email, "test"
 
1926       # create a temporary changeset
 
1927       xml = "<osm><changeset>" \
 
1928             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1929             "</changeset></osm>"
 
1930       put changeset_create_path, :params => xml, :headers => auth_header
 
1931       assert_response :success
 
1932       changeset_id = @response.body.to_i
 
1938           <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
1941           <node id='-1' lon='9' lat='9' changeset='#{changeset_id}' version='0'/>
 
1942           <node id='-2' lon='8' lat='9' changeset='#{changeset_id}' version='0'/>
 
1943           <node id='-3' lon='7' lat='9' changeset='#{changeset_id}' version='0'/>
 
1946           <node id='#{node2.id}' lon='20' lat='15' changeset='#{changeset_id}' version='1'/>
 
1947           <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
 
1948            <nd ref='#{node2.id}'/>
 
1958       post changeset_upload_path(:id => changeset_id), :params => diff, :headers => auth_header
 
1959       assert_response :success,
 
1960                       "can't upload multiple versions of an element in a diff: #{@response.body}"
 
1962       get changeset_download_path(:id => changeset_id)
 
1963       assert_response :success
 
1965       assert_select "osmChange", 1
 
1966       assert_select "osmChange>create", 3
 
1967       assert_select "osmChange>delete", 1
 
1968       assert_select "osmChange>modify", 2
 
1969       assert_select "osmChange>create>node", 3
 
1970       assert_select "osmChange>delete>node", 1
 
1971       assert_select "osmChange>modify>node", 1
 
1972       assert_select "osmChange>modify>way", 1
 
1975     def test_changeset_download
 
1976       changeset = create(:changeset)
 
1977       node = create(:node, :with_history, :version => 1, :changeset => changeset)
 
1978       tag = create(:old_node_tag, :old_node => node.old_nodes.find_by(:version => 1))
 
1979       node2 = create(:node, :with_history, :version => 1, :changeset => changeset)
 
1980       _node3 = create(:node, :with_history, :deleted, :version => 1, :changeset => changeset)
 
1981       _relation = create(:relation, :with_history, :version => 1, :changeset => changeset)
 
1982       _relation2 = create(:relation, :with_history, :deleted, :version => 1, :changeset => changeset)
 
1984       get changeset_download_path(changeset)
 
1986       assert_response :success
 
1988       # FIXME: needs more assert_select tests
 
1989       assert_select "osmChange[version='#{Settings.api_version}'][generator='#{Settings.generator}']" do
 
1990         assert_select "create", :count => 5
 
1991         assert_select "create>node[id='#{node.id}'][visible='#{node.visible?}'][version='#{node.version}']" do
 
1992           assert_select "tag[k='#{tag.k}'][v='#{tag.v}']"
 
1994         assert_select "create>node[id='#{node2.id}']"
 
1998     test "sorts downloaded elements by timestamp" do
 
1999       changeset = create(:changeset)
 
2000       node1 = create(:old_node, :version => 2, :timestamp => "2020-02-01", :changeset => changeset)
 
2001       node0 = create(:old_node, :version => 2, :timestamp => "2020-01-01", :changeset => changeset)
 
2003       get changeset_download_path(changeset)
 
2004       assert_response :success
 
2005       assert_dom "modify", :count => 2 do |modify|
 
2006         assert_dom modify[0], ">node", :count => 1 do |node|
 
2007           assert_dom node, ">@id", node0.node_id.to_s
 
2009         assert_dom modify[1], ">node", :count => 1 do |node|
 
2010           assert_dom node, ">@id", node1.node_id.to_s
 
2015     test "sorts downloaded elements by version" do
 
2016       changeset = create(:changeset)
 
2017       node1 = create(:old_node, :version => 3, :timestamp => "2020-01-01", :changeset => changeset)
 
2018       node0 = create(:old_node, :version => 2, :timestamp => "2020-01-01", :changeset => changeset)
 
2020       get changeset_download_path(changeset)
 
2021       assert_response :success
 
2022       assert_dom "modify", :count => 2 do |modify|
 
2023         assert_dom modify[0], ">node", :count => 1 do |node|
 
2024           assert_dom node, ">@id", node0.node_id.to_s
 
2026         assert_dom modify[1], ">node", :count => 1 do |node|
 
2027           assert_dom node, ">@id", node1.node_id.to_s
 
2033     # check that the bounding box of a changeset gets updated correctly
 
2034     # FIXME: This should really be moded to a integration test due to the with_controller
 
2035     def test_changeset_bbox
 
2037       create(:way_node, :way => way, :node => create(:node, :lat => 3, :lon => 3))
 
2039       auth_header = basic_authorization_header create(:user).email, "test"
 
2041       # create a new changeset
 
2042       xml = "<osm><changeset/></osm>"
 
2043       put changeset_create_path, :params => xml, :headers => auth_header
 
2044       assert_response :success, "Creating of changeset failed."
 
2045       changeset_id = @response.body.to_i
 
2047       # add a single node to it
 
2048       with_controller(NodesController.new) do
 
2049         xml = "<osm><node lon='1' lat='2' changeset='#{changeset_id}'/></osm>"
 
2050         put node_create_path, :params => xml, :headers => auth_header
 
2051         assert_response :success, "Couldn't create node."
 
2054       # get the bounding box back from the changeset
 
2055       get changeset_show_path(:id => changeset_id)
 
2056       assert_response :success, "Couldn't read back changeset."
 
2057       assert_select "osm>changeset[min_lon='1.0000000']", 1
 
2058       assert_select "osm>changeset[max_lon='1.0000000']", 1
 
2059       assert_select "osm>changeset[min_lat='2.0000000']", 1
 
2060       assert_select "osm>changeset[max_lat='2.0000000']", 1
 
2062       # add another node to it
 
2063       with_controller(NodesController.new) do
 
2064         xml = "<osm><node lon='2' lat='1' changeset='#{changeset_id}'/></osm>"
 
2065         put node_create_path, :params => xml, :headers => auth_header
 
2066         assert_response :success, "Couldn't create second node."
 
2069       # get the bounding box back from the changeset
 
2070       get changeset_show_path(:id => changeset_id)
 
2071       assert_response :success, "Couldn't read back changeset for the second time."
 
2072       assert_select "osm>changeset[min_lon='1.0000000']", 1
 
2073       assert_select "osm>changeset[max_lon='2.0000000']", 1
 
2074       assert_select "osm>changeset[min_lat='1.0000000']", 1
 
2075       assert_select "osm>changeset[max_lat='2.0000000']", 1
 
2077       # add (delete) a way to it, which contains a point at (3,3)
 
2078       with_controller(WaysController.new) do
 
2079         xml = update_changeset(xml_for_way(way), changeset_id)
 
2080         delete api_way_path(way), :params => xml.to_s, :headers => auth_header
 
2081         assert_response :success, "Couldn't delete a way."
 
2084       # get the bounding box back from the changeset
 
2085       get changeset_show_path(:id => changeset_id)
 
2086       assert_response :success, "Couldn't read back changeset for the third time."
 
2087       assert_select "osm>changeset[min_lon='1.0000000']", 1
 
2088       assert_select "osm>changeset[max_lon='3.0000000']", 1
 
2089       assert_select "osm>changeset[min_lat='1.0000000']", 1
 
2090       assert_select "osm>changeset[max_lat='3.0000000']", 1
 
2094     # test the query functionality of changesets
 
2096       private_user = create(:user, :data_public => false)
 
2097       private_user_changeset = create(:changeset, :user => private_user)
 
2098       private_user_closed_changeset = create(:changeset, :closed, :user => private_user)
 
2099       user = create(:user)
 
2100       changeset = create(:changeset, :user => user)
 
2101       closed_changeset = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 1, 1, 0, 0, 0), :closed_at => Time.utc(2008, 1, 2, 0, 0, 0))
 
2102       changeset2 = create(:changeset, :min_lat => (5 * GeoRecord::SCALE).round, :min_lon => (5 * GeoRecord::SCALE).round, :max_lat => (15 * GeoRecord::SCALE).round, :max_lon => (15 * GeoRecord::SCALE).round)
 
2103       changeset3 = create(:changeset, :min_lat => (4.5 * GeoRecord::SCALE).round, :min_lon => (4.5 * GeoRecord::SCALE).round, :max_lat => (5 * GeoRecord::SCALE).round, :max_lon => (5 * GeoRecord::SCALE).round)
 
2105       get changesets_path(:bbox => "-10,-10, 10, 10")
 
2106       assert_response :success, "can't get changesets in bbox"
 
2107       assert_changesets [changeset2, changeset3]
 
2109       get changesets_path(:bbox => "4.5,4.5,4.6,4.6")
 
2110       assert_response :success, "can't get changesets in bbox"
 
2111       assert_changesets [changeset3]
 
2113       # not found when looking for changesets of non-existing users
 
2114       get changesets_path(:user => User.maximum(:id) + 1)
 
2115       assert_response :not_found
 
2116       assert_equal "text/plain", @response.media_type
 
2117       get changesets_path(:display_name => " ")
 
2118       assert_response :not_found
 
2119       assert_equal "text/plain", @response.media_type
 
2121       # can't get changesets of user 1 without authenticating
 
2122       get changesets_path(:user => private_user.id)
 
2123       assert_response :not_found, "shouldn't be able to get changesets by non-public user (ID)"
 
2124       get changesets_path(:display_name => private_user.display_name)
 
2125       assert_response :not_found, "shouldn't be able to get changesets by non-public user (name)"
 
2127       # but this should work
 
2128       auth_header = basic_authorization_header private_user.email, "test"
 
2129       get changesets_path(:user => private_user.id), :headers => auth_header
 
2130       assert_response :success, "can't get changesets by user ID"
 
2131       assert_changesets [private_user_changeset, private_user_closed_changeset]
 
2133       get changesets_path(:display_name => private_user.display_name), :headers => auth_header
 
2134       assert_response :success, "can't get changesets by user name"
 
2135       assert_changesets [private_user_changeset, private_user_closed_changeset]
 
2137       # test json endpoint
 
2138       get changesets_path(:display_name => private_user.display_name), :headers => auth_header, :params => { :format => "json" }
 
2139       assert_response :success, "can't get changesets by user name"
 
2141       js = ActiveSupport::JSON.decode(@response.body)
 
2144       assert_equal Settings.api_version, js["version"]
 
2145       assert_equal Settings.generator, js["generator"]
 
2146       assert_equal 2, js["changesets"].count
 
2148       # check that the correct error is given when we provide both UID and name
 
2149       get changesets_path(:user => private_user.id,
 
2150                           :display_name => private_user.display_name), :headers => auth_header
 
2151       assert_response :bad_request, "should be a bad request to have both ID and name specified"
 
2153       get changesets_path(:user => private_user.id, :open => true), :headers => auth_header
 
2154       assert_response :success, "can't get changesets by user and open"
 
2155       assert_changesets [private_user_changeset]
 
2157       get changesets_path(:time => "2007-12-31"), :headers => auth_header
 
2158       assert_response :success, "can't get changesets by time-since"
 
2159       assert_changesets [private_user_changeset, private_user_closed_changeset, changeset, closed_changeset, changeset2, changeset3]
 
2161       get changesets_path(:time => "2008-01-01T12:34Z"), :headers => auth_header
 
2162       assert_response :success, "can't get changesets by time-since with hour"
 
2163       assert_changesets [private_user_changeset, private_user_closed_changeset, changeset, closed_changeset, changeset2, changeset3]
 
2165       get changesets_path(:time => "2007-12-31T23:59Z,2008-01-02T00:01Z"), :headers => auth_header
 
2166       assert_response :success, "can't get changesets by time-range"
 
2167       assert_changesets [closed_changeset]
 
2169       get changesets_path(:open => "true"), :headers => auth_header
 
2170       assert_response :success, "can't get changesets by open-ness"
 
2171       assert_changesets [private_user_changeset, changeset, changeset2, changeset3]
 
2173       get changesets_path(:closed => "true"), :headers => auth_header
 
2174       assert_response :success, "can't get changesets by closed-ness"
 
2175       assert_changesets [private_user_closed_changeset, closed_changeset]
 
2177       get changesets_path(:closed => "true", :user => private_user.id), :headers => auth_header
 
2178       assert_response :success, "can't get changesets by closed-ness and user"
 
2179       assert_changesets [private_user_closed_changeset]
 
2181       get changesets_path(:closed => "true", :user => user.id), :headers => auth_header
 
2182       assert_response :success, "can't get changesets by closed-ness and user"
 
2183       assert_changesets [closed_changeset]
 
2185       get changesets_path(:changesets => "#{private_user_changeset.id},#{changeset.id},#{closed_changeset.id}"), :headers => auth_header
 
2186       assert_response :success, "can't get changesets by id (as comma-separated string)"
 
2187       assert_changesets [private_user_changeset, changeset, closed_changeset]
 
2189       get changesets_path(:changesets => ""), :headers => auth_header
 
2190       assert_response :bad_request, "should be a bad request since changesets is empty"
 
2194     # test the query functionality of changesets with the limit parameter
 
2195     def test_query_limit
 
2196       user = create(:user)
 
2197       changeset1 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 1, 1, 0, 0, 0), :closed_at => Time.utc(2008, 1, 2, 0, 0, 0))
 
2198       changeset2 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 2, 1, 0, 0, 0), :closed_at => Time.utc(2008, 2, 2, 0, 0, 0))
 
2199       changeset3 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 3, 1, 0, 0, 0), :closed_at => Time.utc(2008, 3, 2, 0, 0, 0))
 
2200       changeset4 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 4, 1, 0, 0, 0), :closed_at => Time.utc(2008, 4, 2, 0, 0, 0))
 
2201       changeset5 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 5, 1, 0, 0, 0), :closed_at => Time.utc(2008, 5, 2, 0, 0, 0))
 
2204       assert_response :success
 
2205       assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
 
2207       get changesets_path(:limit => "3")
 
2208       assert_response :success
 
2209       assert_changesets_in_order [changeset5, changeset4, changeset3]
 
2211       get changesets_path(:limit => "0")
 
2212       assert_response :bad_request
 
2214       get changesets_path(:limit => Settings.max_changeset_query_limit)
 
2215       assert_response :success
 
2216       assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
 
2218       get changesets_path(:limit => Settings.max_changeset_query_limit + 1)
 
2219       assert_response :bad_request
 
2223     # test the query functionality of sequential changesets with order and time parameters
 
2224     def test_query_order
 
2225       user = create(:user)
 
2226       changeset1 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 1, 1, 0, 0, 0), :closed_at => Time.utc(2008, 1, 2, 0, 0, 0))
 
2227       changeset2 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 2, 1, 0, 0, 0), :closed_at => Time.utc(2008, 2, 2, 0, 0, 0))
 
2228       changeset3 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 3, 1, 0, 0, 0), :closed_at => Time.utc(2008, 3, 2, 0, 0, 0))
 
2229       changeset4 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 4, 1, 0, 0, 0), :closed_at => Time.utc(2008, 4, 2, 0, 0, 0))
 
2230       changeset5 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 5, 1, 0, 0, 0), :closed_at => Time.utc(2008, 5, 2, 0, 0, 0))
 
2231       changeset6 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 6, 1, 0, 0, 0), :closed_at => Time.utc(2008, 6, 2, 0, 0, 0))
 
2234       assert_response :success
 
2235       assert_changesets_in_order [changeset6, changeset5, changeset4, changeset3, changeset2, changeset1]
 
2237       get changesets_path(:order => "oldest")
 
2238       assert_response :success
 
2239       assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4, changeset5, changeset6]
 
2242         # lower time bound at the opening time of a changeset
 
2243         ["2008-02-01T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3, changeset2]],
 
2244         # lower time bound in the middle of a changeset
 
2245         ["2008-02-01T12:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
 
2246         # lower time bound at the closing time of a changeset
 
2247         ["2008-02-02T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
 
2248         # lower time bound after the closing time of a changeset
 
2249         ["2008-02-02T00:00:01Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3], [changeset5, changeset4, changeset3]],
 
2250         # upper time bound in the middle of a changeset
 
2251         ["2007-09-09T12:00:00Z", "2008-04-01T12:00:00Z", [changeset4, changeset3, changeset2, changeset1], [changeset4, changeset3, changeset2, changeset1]],
 
2253         ["2009-02-02T00:00:01Z", "2018-05-15T00:00:00Z", [], []]
 
2254       ].each do |from, to, interval_changesets, point_changesets|
 
2255         get changesets_path(:time => "#{from},#{to}")
 
2256         assert_response :success
 
2257         assert_changesets_in_order interval_changesets
 
2259         get changesets_path(:from => from, :to => to)
 
2260         assert_response :success
 
2261         assert_changesets_in_order point_changesets
 
2263         get changesets_path(:from => from, :to => to, :order => "oldest")
 
2264         assert_response :success
 
2265         assert_changesets_in_order point_changesets.reverse
 
2270     # test the query functionality of overlapping changesets with order and time parameters
 
2271     def test_query_order_overlapping
 
2272       user = create(:user)
 
2273       changeset1 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 4, 17, 0, 0), :closed_at => Time.utc(2015, 6, 4, 17, 0, 0))
 
2274       changeset2 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 4, 16, 0, 0), :closed_at => Time.utc(2015, 6, 4, 18, 0, 0))
 
2275       changeset3 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 4, 14, 0, 0), :closed_at => Time.utc(2015, 6, 4, 20, 0, 0))
 
2276       changeset4 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 3, 23, 0, 0), :closed_at => Time.utc(2015, 6, 4, 23, 0, 0))
 
2277       create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 2, 23, 0, 0), :closed_at => Time.utc(2015, 6, 3, 23, 0, 0))
 
2279       get changesets_path(:time => "2015-06-04T00:00:00Z")
 
2280       assert_response :success
 
2281       assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
 
2283       get changesets_path(:from => "2015-06-04T00:00:00Z")
 
2284       assert_response :success
 
2285       assert_changesets_in_order [changeset1, changeset2, changeset3]
 
2287       get changesets_path(:from => "2015-06-04T00:00:00Z", :order => "oldest")
 
2288       assert_response :success
 
2289       assert_changesets_in_order [changeset3, changeset2, changeset1]
 
2291       get changesets_path(:time => "2015-06-04T16:00:00Z,2015-06-04T17:30:00Z")
 
2292       assert_response :success
 
2293       assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
 
2295       get changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z")
 
2296       assert_response :success
 
2297       assert_changesets_in_order [changeset1, changeset2]
 
2299       get changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z", :order => "oldest")
 
2300       assert_response :success
 
2301       assert_changesets_in_order [changeset2, changeset1]
 
2305     # check that errors are returned if garbage is inserted
 
2306     # into query strings
 
2307     def test_query_invalid
 
2310        ";drop table users;"].each do |bbox|
 
2311         get changesets_path(:bbox => bbox)
 
2312         assert_response :bad_request, "'#{bbox}' isn't a bbox"
 
2317        ";drop table users;",
 
2319        "-,-"].each do |time|
 
2320         get changesets_path(:time => time)
 
2321         assert_response :bad_request, "'#{time}' isn't a valid time range"
 
2328         get changesets_path(:user => uid)
 
2329         assert_response :bad_request, "'#{uid}' isn't a valid user ID"
 
2332       get changesets_path(:order => "oldest", :time => "2008-01-01T00:00Z,2018-01-01T00:00Z")
 
2333       assert_response :bad_request, "cannot use order=oldest with time"
 
2337     # check updating tags on a changeset
 
2338     def test_changeset_update
 
2339       private_user = create(:user, :data_public => false)
 
2340       private_changeset = create(:changeset, :user => private_user)
 
2341       user = create(:user)
 
2342       changeset = create(:changeset, :user => user)
 
2344       ## First try with a non-public user
 
2345       new_changeset = create_changeset_xml(:user => private_user)
 
2346       new_tag = XML::Node.new "tag"
 
2347       new_tag["k"] = "tagtesting"
 
2348       new_tag["v"] = "valuetesting"
 
2349       new_changeset.find("//osm/changeset").first << new_tag
 
2351       # try without any authorization
 
2352       put changeset_show_path(private_changeset), :params => new_changeset.to_s
 
2353       assert_response :unauthorized
 
2355       # try with the wrong authorization
 
2356       auth_header = basic_authorization_header create(:user).email, "test"
 
2357       put changeset_show_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
 
2358       assert_response :conflict
 
2360       # now this should get an unauthorized
 
2361       auth_header = basic_authorization_header private_user.email, "test"
 
2362       put changeset_show_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
 
2363       assert_require_public_data "user with their data non-public, shouldn't be able to edit their changeset"
 
2365       ## Now try with the public user
 
2366       new_changeset = create_changeset_xml(:id => 1)
 
2367       new_tag = XML::Node.new "tag"
 
2368       new_tag["k"] = "tagtesting"
 
2369       new_tag["v"] = "valuetesting"
 
2370       new_changeset.find("//osm/changeset").first << new_tag
 
2372       # try without any authorization
 
2373       put changeset_show_path(changeset), :params => new_changeset.to_s
 
2374       assert_response :unauthorized
 
2376       # try with the wrong authorization
 
2377       auth_header = basic_authorization_header create(:user).email, "test"
 
2378       put changeset_show_path(changeset), :params => new_changeset.to_s, :headers => auth_header
 
2379       assert_response :conflict
 
2381       # now this should work...
 
2382       auth_header = basic_authorization_header user.email, "test"
 
2383       put changeset_show_path(changeset), :params => new_changeset.to_s, :headers => auth_header
 
2384       assert_response :success
 
2386       assert_select "osm>changeset[id='#{changeset.id}']", 1
 
2387       assert_select "osm>changeset>tag", 1
 
2388       assert_select "osm>changeset>tag[k='tagtesting'][v='valuetesting']", 1
 
2392     # check that a user different from the one who opened the changeset
 
2394     def test_changeset_update_invalid
 
2395       auth_header = basic_authorization_header create(:user).email, "test"
 
2397       changeset = create(:changeset)
 
2398       new_changeset = create_changeset_xml(:user => changeset.user, :id => changeset.id)
 
2399       new_tag = XML::Node.new "tag"
 
2400       new_tag["k"] = "testing"
 
2401       new_tag["v"] = "testing"
 
2402       new_changeset.find("//osm/changeset").first << new_tag
 
2404       put changeset_show_path(changeset), :params => new_changeset.to_s, :headers => auth_header
 
2405       assert_response :conflict
 
2409     # check that a changeset can contain a certain max number of changes.
 
2410     ## FIXME should be changed to an integration test due to the with_controller
 
2411     def test_changeset_limits
 
2412       user = create(:user)
 
2413       auth_header = basic_authorization_header user.email, "test"
 
2415       # create an old changeset to ensure we have the maximum rate limit
 
2416       create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
 
2418       # open a new changeset
 
2419       xml = "<osm><changeset/></osm>"
 
2420       put changeset_create_path, :params => xml, :headers => auth_header
 
2421       assert_response :success, "can't create a new changeset"
 
2422       cs_id = @response.body.to_i
 
2424       # start the counter just short of where the changeset should finish.
 
2426       # alter the database to set the counter on the changeset directly,
 
2427       # otherwise it takes about 6 minutes to fill all of them.
 
2428       changeset = Changeset.find(cs_id)
 
2429       changeset.num_changes = Changeset::MAX_ELEMENTS - offset
 
2432       with_controller(NodesController.new) do
 
2434         xml = "<osm><node changeset='#{cs_id}' lat='0.0' lon='0.0'/></osm>"
 
2435         put node_create_path, :params => xml, :headers => auth_header
 
2436         assert_response :success, "can't create a new node"
 
2437         node_id = @response.body.to_i
 
2439         get api_node_path(node_id)
 
2440         assert_response :success, "can't read back new node"
 
2441         node_doc = XML::Parser.string(@response.body).parse
 
2442         node_xml = node_doc.find("//osm/node").first
 
2444         # loop until we fill the changeset with nodes
 
2446           node_xml["lat"] = rand.to_s
 
2447           node_xml["lon"] = rand.to_s
 
2448           node_xml["version"] = (i + 1).to_s
 
2450           put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
 
2451           assert_response :success, "attempt #{i} should have succeeded"
 
2454         # trying again should fail
 
2455         node_xml["lat"] = rand.to_s
 
2456         node_xml["lon"] = rand.to_s
 
2457         node_xml["version"] = offset.to_s
 
2459         put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
 
2460         assert_response :conflict, "final attempt should have failed"
 
2463       changeset = Changeset.find(cs_id)
 
2464       assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
 
2466       # check that the changeset is now closed as well
 
2467       assert_not(changeset.open?,
 
2468                  "changeset should have been auto-closed by exceeding " \
 
2473     # check that the changeset download for a changeset with a redacted
 
2474     # element in it doesn't contain that element.
 
2475     def test_diff_download_redacted
 
2476       changeset = create(:changeset)
 
2477       node = create(:node, :with_history, :version => 2, :changeset => changeset)
 
2478       node_v1 = node.old_nodes.find_by(:version => 1)
 
2479       node_v1.redact!(create(:redaction))
 
2481       get changeset_download_path(changeset)
 
2482       assert_response :success
 
2484       assert_select "osmChange", 1
 
2485       # this changeset contains the node in versions 1 & 2, but 1 should
 
2487       assert_select "osmChange node[id='#{node.id}']", 1
 
2488       assert_select "osmChange node[id='#{node.id}'][version='1']", 0
 
2492     # test subscribe success
 
2493     def test_subscribe_success
 
2494       auth_header = basic_authorization_header create(:user).email, "test"
 
2495       changeset = create(:changeset, :closed)
 
2497       assert_difference "changeset.subscribers.count", 1 do
 
2498         post api_changeset_subscribe_path(changeset), :headers => auth_header
 
2500       assert_response :success
 
2502       # not closed changeset
 
2503       changeset = create(:changeset)
 
2504       assert_difference "changeset.subscribers.count", 1 do
 
2505         post api_changeset_subscribe_path(changeset), :headers => auth_header
 
2507       assert_response :success
 
2511     # test subscribe fail
 
2512     def test_subscribe_fail
 
2513       user = create(:user)
 
2516       changeset = create(:changeset, :closed)
 
2517       assert_no_difference "changeset.subscribers.count" do
 
2518         post api_changeset_subscribe_path(changeset)
 
2520       assert_response :unauthorized
 
2522       auth_header = basic_authorization_header user.email, "test"
 
2525       assert_no_difference "changeset.subscribers.count" do
 
2526         post api_changeset_subscribe_path(:id => 999111), :headers => auth_header
 
2528       assert_response :not_found
 
2530       # trying to subscribe when already subscribed
 
2531       changeset = create(:changeset, :closed)
 
2532       changeset.subscribers.push(user)
 
2533       assert_no_difference "changeset.subscribers.count" do
 
2534         post api_changeset_subscribe_path(changeset), :headers => auth_header
 
2536       assert_response :conflict
 
2540     # test unsubscribe success
 
2541     def test_unsubscribe_success
 
2542       user = create(:user)
 
2543       auth_header = basic_authorization_header user.email, "test"
 
2544       changeset = create(:changeset, :closed)
 
2545       changeset.subscribers.push(user)
 
2547       assert_difference "changeset.subscribers.count", -1 do
 
2548         post api_changeset_unsubscribe_path(changeset), :headers => auth_header
 
2550       assert_response :success
 
2552       # not closed changeset
 
2553       changeset = create(:changeset)
 
2554       changeset.subscribers.push(user)
 
2556       assert_difference "changeset.subscribers.count", -1 do
 
2557         post api_changeset_unsubscribe_path(changeset), :headers => auth_header
 
2559       assert_response :success
 
2563     # test unsubscribe fail
 
2564     def test_unsubscribe_fail
 
2566       changeset = create(:changeset, :closed)
 
2567       assert_no_difference "changeset.subscribers.count" do
 
2568         post api_changeset_unsubscribe_path(changeset)
 
2570       assert_response :unauthorized
 
2572       auth_header = basic_authorization_header create(:user).email, "test"
 
2575       assert_no_difference "changeset.subscribers.count" do
 
2576         post api_changeset_unsubscribe_path(:id => 999111), :headers => auth_header
 
2578       assert_response :not_found
 
2580       # trying to unsubscribe when not subscribed
 
2581       changeset = create(:changeset, :closed)
 
2582       assert_no_difference "changeset.subscribers.count" do
 
2583         post api_changeset_unsubscribe_path(changeset), :headers => auth_header
 
2585       assert_response :not_found
 
2591     # check that the output consists of one specific changeset
 
2592     def assert_single_changeset(changeset)
 
2593       assert_select "osm>changeset", 1
 
2594       assert_select "osm>changeset>@id", changeset.id.to_s
 
2595       assert_select "osm>changeset>@created_at", changeset.created_at.xmlschema
 
2597         assert_select "osm>changeset>@open", "true"
 
2598         assert_select "osm>changeset>@closed_at", 0
 
2600         assert_select "osm>changeset>@open", "false"
 
2601         assert_select "osm>changeset>@closed_at", changeset.closed_at.xmlschema
 
2605     def assert_single_changeset_json(changeset, js)
 
2606       assert_equal changeset.id, js["changeset"]["id"]
 
2607       assert_equal changeset.created_at.xmlschema, js["changeset"]["created_at"]
 
2609         assert js["changeset"]["open"]
 
2610         assert_nil js["changeset"]["closed_at"]
 
2612         assert_not js["changeset"]["open"]
 
2613         assert_equal changeset.closed_at.xmlschema, js["changeset"]["closed_at"]
 
2618     # check that certain changesets exist in the output
 
2619     def assert_changesets(changesets)
 
2620       assert_select "osm>changeset", changesets.size
 
2621       changesets.each do |changeset|
 
2622         assert_select "osm>changeset[id='#{changeset.id}']", 1
 
2627     # check that certain changesets exist in the output in the specified order
 
2628     def assert_changesets_in_order(changesets)
 
2629       assert_select "osm>changeset", changesets.size
 
2630       changesets.each_with_index do |changeset, index|
 
2631         assert_select "osm>changeset:nth-child(#{index + 1})[id='#{changeset.id}']", 1
 
2636     # update the changeset_id of a way element
 
2637     def update_changeset(xml, changeset_id)
 
2638       xml_attr_rewrite(xml, "changeset", changeset_id)
 
2642     # update an attribute in a way element
 
2643     def xml_attr_rewrite(xml, name, value)
 
2644       xml.find("//osm/way").first[name] = value.to_s
 
2649     # build XML for changesets
 
2650     def create_changeset_xml(user: nil, id: nil)
 
2651       root = XML::Document.new
 
2652       root.root = XML::Node.new "osm"
 
2653       cs = XML::Node.new "changeset"
 
2655         cs["user"] = user.display_name
 
2656         cs["uid"] = user.id.to_s
 
2658       cs["id"] = id.to_s if id