3 class ChangesetsControllerTest < ActionController::TestCase
 
   5   # test all routes which lead to this controller
 
   8       { :path => "/api/0.6/changeset/create", :method => :put },
 
   9       { :controller => "changesets", :action => "create" }
 
  12       { :path => "/api/0.6/changeset/1/upload", :method => :post },
 
  13       { :controller => "changesets", :action => "upload", :id => "1" }
 
  16       { :path => "/api/0.6/changeset/1/download", :method => :get },
 
  17       { :controller => "changesets", :action => "download", :id => "1" }
 
  20       { :path => "/api/0.6/changeset/1/expand_bbox", :method => :post },
 
  21       { :controller => "changesets", :action => "expand_bbox", :id => "1" }
 
  24       { :path => "/api/0.6/changeset/1", :method => :get },
 
  25       { :controller => "changesets", :action => "read", :id => "1" }
 
  28       { :path => "/api/0.6/changeset/1/subscribe", :method => :post },
 
  29       { :controller => "changesets", :action => "subscribe", :id => "1" }
 
  32       { :path => "/api/0.6/changeset/1/unsubscribe", :method => :post },
 
  33       { :controller => "changesets", :action => "unsubscribe", :id => "1" }
 
  36       { :path => "/api/0.6/changeset/1", :method => :put },
 
  37       { :controller => "changesets", :action => "update", :id => "1" }
 
  40       { :path => "/api/0.6/changeset/1/close", :method => :put },
 
  41       { :controller => "changesets", :action => "close", :id => "1" }
 
  44       { :path => "/api/0.6/changesets", :method => :get },
 
  45       { :controller => "changesets", :action => "query" }
 
  48       { :path => "/user/name/history", :method => :get },
 
  49       { :controller => "changesets", :action => "index", :display_name => "name" }
 
  52       { :path => "/user/name/history/feed", :method => :get },
 
  53       { :controller => "changesets", :action => "feed", :display_name => "name", :format => :atom }
 
  56       { :path => "/history/friends", :method => :get },
 
  57       { :controller => "changesets", :action => "index", :friends => true, :format => :html }
 
  60       { :path => "/history/nearby", :method => :get },
 
  61       { :controller => "changesets", :action => "index", :nearby => true, :format => :html }
 
  64       { :path => "/history", :method => :get },
 
  65       { :controller => "changesets", :action => "index" }
 
  68       { :path => "/history/feed", :method => :get },
 
  69       { :controller => "changesets", :action => "feed", :format => :atom }
 
  73   # -----------------------
 
  74   # Test simple changeset creation
 
  75   # -----------------------
 
  78     basic_authorization create(:user, :data_public => false).email, "test"
 
  79     # Create the first user's changeset
 
  80     content "<osm><changeset>" \
 
  81             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
  84     assert_require_public_data
 
  86     basic_authorization create(:user).email, "test"
 
  87     # Create the first user's changeset
 
  88     content "<osm><changeset>" \
 
  89             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
  93     assert_response :success, "Creation of changeset did not return sucess status"
 
  94     newid = @response.body.to_i
 
  96     # check end time, should be an hour ahead of creation time
 
  97     cs = Changeset.find(newid)
 
  98     duration = cs.closed_at - cs.created_at
 
  99     # the difference can either be a rational, or a floating point number
 
 100     # of seconds, depending on the code path taken :-(
 
 101     if duration.class == Rational
 
 102       assert_equal Rational(1, 24), duration, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
 
 104       # must be number of seconds...
 
 105       assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
 
 108     # checks if uploader was subscribed
 
 109     assert_equal 1, cs.subscribers.length
 
 112   def test_create_invalid
 
 113     basic_authorization create(:user, :data_public => false).email, "test"
 
 114     content "<osm><changeset></osm>"
 
 116     assert_require_public_data
 
 118     ## Try the public user
 
 119     basic_authorization create(:user).email, "test"
 
 120     content "<osm><changeset></osm>"
 
 122     assert_response :bad_request, "creating a invalid changeset should fail"
 
 125   def test_create_invalid_no_content
 
 126     ## First check with no auth
 
 128     assert_response :unauthorized, "shouldn't be able to create a changeset with no auth"
 
 130     ## Now try to with a non-public user
 
 131     basic_authorization create(:user, :data_public => false).email, "test"
 
 133     assert_require_public_data
 
 135     ## Try an inactive user
 
 136     basic_authorization create(:user, :pending).email, "test"
 
 140     ## Now try to use a normal user
 
 141     basic_authorization create(:user).email, "test"
 
 143     assert_response :bad_request, "creating a changeset with no content should fail"
 
 146   def test_create_wrong_method
 
 147     basic_authorization create(:user).email, "test"
 
 149     assert_response :method_not_allowed
 
 151     assert_response :method_not_allowed
 
 155   # check that the changeset can be read and returns the correct
 
 156   # document structure.
 
 158     changeset_id = create(:changeset).id
 
 160     get :read, :params => { :id => changeset_id }
 
 161     assert_response :success, "cannot get first changeset"
 
 163     assert_select "osm[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
 
 164     assert_select "osm>changeset[id='#{changeset_id}']", 1
 
 165     assert_select "osm>changeset>discussion", 0
 
 167     get :read, :params => { :id => changeset_id, :include_discussion => true }
 
 168     assert_response :success, "cannot get first changeset with comments"
 
 170     assert_select "osm[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
 
 171     assert_select "osm>changeset[id='#{changeset_id}']", 1
 
 172     assert_select "osm>changeset>discussion", 1
 
 173     assert_select "osm>changeset>discussion>comment", 0
 
 175     changeset_id = create(:changeset, :closed).id
 
 176     create_list(:changeset_comment, 3, :changeset_id => changeset_id)
 
 178     get :read, :params => { :id => changeset_id, :include_discussion => true }
 
 179     assert_response :success, "cannot get closed changeset with comments"
 
 181     assert_select "osm[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
 
 182     assert_select "osm>changeset[id='#{changeset_id}']", 1
 
 183     assert_select "osm>changeset>discussion", 1
 
 184     assert_select "osm>changeset>discussion>comment", 3
 
 188   # check that a changeset that doesn't exist returns an appropriate message
 
 189   def test_read_not_found
 
 190     [0, -32, 233455644, "afg", "213"].each do |id|
 
 192         get :read, :params => { :id => id }
 
 193         assert_response :not_found, "should get a not found"
 
 194       rescue ActionController::UrlGenerationError => ex
 
 195         assert_match(/No route matches/, ex.to_s)
 
 201   # test that the user who opened a change can close it
 
 203     private_user = create(:user, :data_public => false)
 
 204     private_changeset = create(:changeset, :user => private_user)
 
 206     changeset = create(:changeset, :user => user)
 
 208     ## Try without authentication
 
 209     put :close, :params => { :id => changeset.id }
 
 210     assert_response :unauthorized
 
 212     ## Try using the non-public user
 
 213     basic_authorization private_user.email, "test"
 
 214     put :close, :params => { :id => private_changeset.id }
 
 215     assert_require_public_data
 
 217     ## The try with the public user
 
 218     basic_authorization user.email, "test"
 
 221     put :close, :params => { :id => cs_id }
 
 222     assert_response :success
 
 224     # test that it really is closed now
 
 225     cs = Changeset.find(cs_id)
 
 226     assert_not(cs.is_open?,
 
 227                "changeset should be closed now (#{cs.closed_at} > #{Time.now.getutc}.")
 
 231   # test that a different user can't close another user's changeset
 
 232   def test_close_invalid
 
 234     changeset = create(:changeset)
 
 236     basic_authorization user.email, "test"
 
 238     put :close, :params => { :id => changeset.id }
 
 239     assert_response :conflict
 
 240     assert_equal "The user doesn't own that changeset", @response.body
 
 244   # test that you can't close using another method
 
 245   def test_close_method_invalid
 
 247     changeset = create(:changeset, :user => user)
 
 249     basic_authorization user.email, "test"
 
 251     get :close, :params => { :id => changeset.id }
 
 252     assert_response :method_not_allowed
 
 254     post :close, :params => { :id => changeset.id }
 
 255     assert_response :method_not_allowed
 
 259   # check that you can't close a changeset that isn't found
 
 260   def test_close_not_found
 
 261     cs_ids = [0, -132, "123"]
 
 263     # First try to do it with no auth
 
 266         put :close, :params => { :id => id }
 
 267         assert_response :unauthorized, "Shouldn't be able close the non-existant changeset #{id}, when not authorized"
 
 268       rescue ActionController::UrlGenerationError => ex
 
 269         assert_match(/No route matches/, ex.to_s)
 
 274     basic_authorization create(:user).email, "test"
 
 277         put :close, :params => { :id => id }
 
 278         assert_response :not_found, "The changeset #{id} doesn't exist, so can't be closed"
 
 279       rescue ActionController::UrlGenerationError => ex
 
 280         assert_match(/No route matches/, ex.to_s)
 
 286   # upload something simple, but valid and check that it can
 
 288   # Also try without auth and another user.
 
 289   def test_upload_simple_valid
 
 290     private_user = create(:user, :data_public => false)
 
 291     private_changeset = create(:changeset, :user => private_user)
 
 293     changeset = create(:changeset, :user => user)
 
 297     relation = create(:relation)
 
 298     other_relation = create(:relation)
 
 299     # create some tags, since we test that they are removed later
 
 300     create(:node_tag, :node => node)
 
 301     create(:way_tag, :way => way)
 
 302     create(:relation_tag, :relation => relation)
 
 305     changeset_id = changeset.id
 
 307     # simple diff to change a node, way and relation by removing
 
 309     diff = <<CHANGESET.strip_heredoc
 
 312         <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
 313         <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
 
 314          <nd ref='#{node.id}'/>
 
 318         <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
 
 319          <member type='way' role='some' ref='#{way.id}'/>
 
 320          <member type='node' role='some' ref='#{node.id}'/>
 
 321          <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 329     post :upload, :params => { :id => changeset_id }
 
 330     assert_response :unauthorized,
 
 331                     "shouldn't be able to upload a simple valid diff to changeset: #{@response.body}"
 
 333     ## Now try with a private user
 
 334     basic_authorization private_user.email, "test"
 
 335     changeset_id = private_changeset.id
 
 337     # simple diff to change a node, way and relation by removing
 
 339     diff = <<CHANGESET.strip_heredoc
 
 342         <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
 343         <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
 
 344          <nd ref='#{node.id}'/>
 
 348         <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
 
 349          <member type='way' role='some' ref='#{way.id}'/>
 
 350          <member type='node' role='some' ref='#{node.id}'/>
 
 351          <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 359     post :upload, :params => { :id => changeset_id }
 
 360     assert_response :forbidden,
 
 361                     "can't upload a simple valid diff to changeset: #{@response.body}"
 
 363     ## Now try with the public user
 
 364     basic_authorization user.email, "test"
 
 365     changeset_id = changeset.id
 
 367     # simple diff to change a node, way and relation by removing
 
 369     diff = <<CHANGESET.strip_heredoc
 
 372         <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
 373         <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
 
 374          <nd ref='#{node.id}'/>
 
 378         <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
 
 379          <member type='way' role='some' ref='#{way.id}'/>
 
 380          <member type='node' role='some' ref='#{node.id}'/>
 
 381          <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 389     post :upload, :params => { :id => changeset_id }
 
 390     assert_response :success,
 
 391                     "can't upload a simple valid diff to changeset: #{@response.body}"
 
 393     # check that the changes made it into the database
 
 394     assert_equal 0, Node.find(node.id).tags.size, "node #{node.id} should now have no tags"
 
 395     assert_equal 0, Way.find(way.id).tags.size, "way #{way.id} should now have no tags"
 
 396     assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
 
 400   # upload something which creates new objects using placeholders
 
 401   def test_upload_create_valid
 
 403     changeset = create(:changeset, :user => user)
 
 405     way = create(:way_with_nodes, :nodes_count => 2)
 
 406     relation = create(:relation)
 
 408     basic_authorization user.email, "test"
 
 410     # simple diff to create a node way and relation using placeholders
 
 411     diff = <<CHANGESET.strip_heredoc
 
 414         <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 415          <tag k='foo' v='bar'/>
 
 416          <tag k='baz' v='bat'/>
 
 418         <way id='-1' changeset='#{changeset.id}'>
 
 419          <nd ref='#{node.id}'/>
 
 423         <relation id='-1' changeset='#{changeset.id}'>
 
 424          <member type='way' role='some' ref='#{way.id}'/>
 
 425          <member type='node' role='some' ref='#{node.id}'/>
 
 426          <member type='relation' role='some' ref='#{relation.id}'/>
 
 434     post :upload, :params => { :id => changeset.id }
 
 435     assert_response :success,
 
 436                     "can't upload a simple valid creation to changeset: #{@response.body}"
 
 438     # check the returned payload
 
 439     assert_select "diffResult[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
 
 440     assert_select "diffResult>node", 1
 
 441     assert_select "diffResult>way", 1
 
 442     assert_select "diffResult>relation", 1
 
 444     # inspect the response to find out what the new element IDs are
 
 445     doc = XML::Parser.string(@response.body).parse
 
 446     new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
 
 447     new_way_id = doc.find("//diffResult/way").first["new_id"].to_i
 
 448     new_rel_id = doc.find("//diffResult/relation").first["new_id"].to_i
 
 450     # check the old IDs are all present and negative one
 
 451     assert_equal(-1, doc.find("//diffResult/node").first["old_id"].to_i)
 
 452     assert_equal(-1, doc.find("//diffResult/way").first["old_id"].to_i)
 
 453     assert_equal(-1, doc.find("//diffResult/relation").first["old_id"].to_i)
 
 455     # check the versions are present and equal one
 
 456     assert_equal 1, doc.find("//diffResult/node").first["new_version"].to_i
 
 457     assert_equal 1, doc.find("//diffResult/way").first["new_version"].to_i
 
 458     assert_equal 1, doc.find("//diffResult/relation").first["new_version"].to_i
 
 460     # check that the changes made it into the database
 
 461     assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
 462     assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
 
 463     assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
 
 467   # test a complex delete where we delete elements which rely on eachother
 
 468   # in the same transaction.
 
 469   def test_upload_delete
 
 470     changeset = create(:changeset)
 
 471     super_relation = create(:relation)
 
 472     used_relation = create(:relation)
 
 473     used_way = create(:way)
 
 474     used_node = create(:node)
 
 475     create(:relation_member, :relation => super_relation, :member => used_relation)
 
 476     create(:relation_member, :relation => super_relation, :member => used_way)
 
 477     create(:relation_member, :relation => super_relation, :member => used_node)
 
 479     basic_authorization changeset.user.display_name, "test"
 
 481     diff = XML::Document.new
 
 482     diff.root = XML::Node.new "osmChange"
 
 483     delete = XML::Node.new "delete"
 
 485     delete << super_relation.to_xml_node
 
 486     delete << used_relation.to_xml_node
 
 487     delete << used_way.to_xml_node
 
 488     delete << used_node.to_xml_node
 
 490     # update the changeset to one that this user owns
 
 491     %w[node way relation].each do |type|
 
 492       delete.find("//osmChange/delete/#{type}").each do |n|
 
 493         n["changeset"] = changeset.id.to_s
 
 499     post :upload, :params => { :id => changeset.id }
 
 500     assert_response :success,
 
 501                     "can't upload a deletion diff to changeset: #{@response.body}"
 
 503     # check the response is well-formed
 
 504     assert_select "diffResult>node", 1
 
 505     assert_select "diffResult>way", 1
 
 506     assert_select "diffResult>relation", 2
 
 508     # check that everything was deleted
 
 509     assert_equal false, Node.find(used_node.id).visible
 
 510     assert_equal false, Way.find(used_way.id).visible
 
 511     assert_equal false, Relation.find(super_relation.id).visible
 
 512     assert_equal false, Relation.find(used_relation.id).visible
 
 516   # test uploading a delete with no lat/lon, as they are optional in
 
 517   # the osmChange spec.
 
 518   def test_upload_nolatlon_delete
 
 520     changeset = create(:changeset)
 
 522     basic_authorization changeset.user.display_name, "test"
 
 523     diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{changeset.id}'/></delete></osmChange>"
 
 527     post :upload, :params => { :id => changeset.id }
 
 528     assert_response :success,
 
 529                     "can't upload a deletion diff to changeset: #{@response.body}"
 
 531     # check the response is well-formed
 
 532     assert_select "diffResult>node", 1
 
 534     # check that everything was deleted
 
 535     assert_equal false, Node.find(node.id).visible
 
 538   def test_repeated_changeset_create
 
 540       basic_authorization create(:user).email, "test"
 
 542       # create a temporary changeset
 
 543       content "<osm><changeset>" \
 
 544               "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
 546       assert_difference "Changeset.count", 1 do
 
 549       assert_response :success
 
 553   def test_upload_large_changeset
 
 554     basic_authorization create(:user).email, "test"
 
 557     content "<osm><changeset/></osm>"
 
 559     assert_response :success, "Should be able to create a changeset: #{@response.body}"
 
 560     changeset_id = @response.body.to_i
 
 562     # upload some widely-spaced nodes, spiralling positive and negative
 
 563     diff = <<CHANGESET.strip_heredoc
 
 566         <node id='-1' lon='-20' lat='-10' changeset='#{changeset_id}'/>
 
 567         <node id='-10' lon='20'  lat='10' changeset='#{changeset_id}'/>
 
 568         <node id='-2' lon='-40' lat='-20' changeset='#{changeset_id}'/>
 
 569         <node id='-11' lon='40'  lat='20' changeset='#{changeset_id}'/>
 
 570         <node id='-3' lon='-60' lat='-30' changeset='#{changeset_id}'/>
 
 571         <node id='-12' lon='60'  lat='30' changeset='#{changeset_id}'/>
 
 572         <node id='-4' lon='-80' lat='-40' changeset='#{changeset_id}'/>
 
 573         <node id='-13' lon='80'  lat='40' changeset='#{changeset_id}'/>
 
 574         <node id='-5' lon='-100' lat='-50' changeset='#{changeset_id}'/>
 
 575         <node id='-14' lon='100'  lat='50' changeset='#{changeset_id}'/>
 
 576         <node id='-6' lon='-120' lat='-60' changeset='#{changeset_id}'/>
 
 577         <node id='-15' lon='120'  lat='60' changeset='#{changeset_id}'/>
 
 578         <node id='-7' lon='-140' lat='-70' changeset='#{changeset_id}'/>
 
 579         <node id='-16' lon='140'  lat='70' changeset='#{changeset_id}'/>
 
 580         <node id='-8' lon='-160' lat='-80' changeset='#{changeset_id}'/>
 
 581         <node id='-17' lon='160'  lat='80' changeset='#{changeset_id}'/>
 
 582         <node id='-9' lon='-179.9' lat='-89.9' changeset='#{changeset_id}'/>
 
 583         <node id='-18' lon='179.9'  lat='89.9' changeset='#{changeset_id}'/>
 
 588     # upload it, which used to cause an error like "PGError: ERROR:
 
 589     # integer out of range" (bug #2152). but shouldn't any more.
 
 591     post :upload, :params => { :id => changeset_id }
 
 592     assert_response :success,
 
 593                     "can't upload a spatially-large diff to changeset: #{@response.body}"
 
 595     # check that the changeset bbox is within bounds
 
 596     cs = Changeset.find(changeset_id)
 
 597     assert cs.min_lon >= -180 * GeoRecord::SCALE, "Minimum longitude (#{cs.min_lon / GeoRecord::SCALE}) should be >= -180 to be valid."
 
 598     assert cs.max_lon <= 180 * GeoRecord::SCALE, "Maximum longitude (#{cs.max_lon / GeoRecord::SCALE}) should be <= 180 to be valid."
 
 599     assert cs.min_lat >= -90 * GeoRecord::SCALE, "Minimum latitude (#{cs.min_lat / GeoRecord::SCALE}) should be >= -90 to be valid."
 
 600     assert cs.max_lat <= 90 * GeoRecord::SCALE, "Maximum latitude (#{cs.max_lat / GeoRecord::SCALE}) should be <= 90 to be valid."
 
 604   # test that deleting stuff in a transaction doesn't bypass the checks
 
 605   # to ensure that used elements are not deleted.
 
 606   def test_upload_delete_invalid
 
 607     changeset = create(:changeset)
 
 608     relation = create(:relation)
 
 609     other_relation = create(:relation)
 
 610     used_way = create(:way)
 
 611     used_node = create(:node)
 
 612     create(:relation_member, :relation => relation, :member => used_way)
 
 613     create(:relation_member, :relation => relation, :member => used_node)
 
 615     basic_authorization changeset.user.email, "test"
 
 617     diff = XML::Document.new
 
 618     diff.root = XML::Node.new "osmChange"
 
 619     delete = XML::Node.new "delete"
 
 621     delete << other_relation.to_xml_node
 
 622     delete << used_way.to_xml_node
 
 623     delete << used_node.to_xml_node
 
 625     # update the changeset to one that this user owns
 
 626     %w[node way relation].each do |type|
 
 627       delete.find("//osmChange/delete/#{type}").each do |n|
 
 628         n["changeset"] = changeset.id.to_s
 
 634     post :upload, :params => { :id => changeset.id }
 
 635     assert_response :precondition_failed,
 
 636                     "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
 
 637     assert_equal "Precondition failed: Way #{used_way.id} is still used by relations #{relation.id}.", @response.body
 
 639     # check that nothing was, in fact, deleted
 
 640     assert_equal true, Node.find(used_node.id).visible
 
 641     assert_equal true, Way.find(used_way.id).visible
 
 642     assert_equal true, Relation.find(relation.id).visible
 
 643     assert_equal true, Relation.find(other_relation.id).visible
 
 647   # test that a conditional delete of an in use object works.
 
 648   def test_upload_delete_if_unused
 
 649     changeset = create(:changeset)
 
 650     super_relation = create(:relation)
 
 651     used_relation = create(:relation)
 
 652     used_way = create(:way)
 
 653     used_node = create(:node)
 
 654     create(:relation_member, :relation => super_relation, :member => used_relation)
 
 655     create(:relation_member, :relation => super_relation, :member => used_way)
 
 656     create(:relation_member, :relation => super_relation, :member => used_node)
 
 658     basic_authorization changeset.user.email, "test"
 
 660     diff = XML::Document.new
 
 661     diff.root = XML::Node.new "osmChange"
 
 662     delete = XML::Node.new "delete"
 
 664     delete["if-unused"] = ""
 
 665     delete << used_relation.to_xml_node
 
 666     delete << used_way.to_xml_node
 
 667     delete << used_node.to_xml_node
 
 669     # update the changeset to one that this user owns
 
 670     %w[node way relation].each do |type|
 
 671       delete.find("//osmChange/delete/#{type}").each do |n|
 
 672         n["changeset"] = changeset.id.to_s
 
 678     post :upload, :params => { :id => changeset.id }
 
 679     assert_response :success,
 
 680                     "can't do a conditional delete of in use objects: #{@response.body}"
 
 682     # check the returned payload
 
 683     assert_select "diffResult[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
 
 684     assert_select "diffResult>node", 1
 
 685     assert_select "diffResult>way", 1
 
 686     assert_select "diffResult>relation", 1
 
 689     doc = XML::Parser.string(@response.body).parse
 
 691     # check the old IDs are all present and what we expect
 
 692     assert_equal used_node.id, doc.find("//diffResult/node").first["old_id"].to_i
 
 693     assert_equal used_way.id, doc.find("//diffResult/way").first["old_id"].to_i
 
 694     assert_equal used_relation.id, doc.find("//diffResult/relation").first["old_id"].to_i
 
 696     # check the new IDs are all present and unchanged
 
 697     assert_equal used_node.id, doc.find("//diffResult/node").first["new_id"].to_i
 
 698     assert_equal used_way.id, doc.find("//diffResult/way").first["new_id"].to_i
 
 699     assert_equal used_relation.id, doc.find("//diffResult/relation").first["new_id"].to_i
 
 701     # check the new versions are all present and unchanged
 
 702     assert_equal used_node.version, doc.find("//diffResult/node").first["new_version"].to_i
 
 703     assert_equal used_way.version, doc.find("//diffResult/way").first["new_version"].to_i
 
 704     assert_equal used_relation.version, doc.find("//diffResult/relation").first["new_version"].to_i
 
 706     # check that nothing was, in fact, deleted
 
 707     assert_equal true, Node.find(used_node.id).visible
 
 708     assert_equal true, Way.find(used_way.id).visible
 
 709     assert_equal true, Relation.find(used_relation.id).visible
 
 713   # upload an element with a really long tag value
 
 714   def test_upload_invalid_too_long_tag
 
 715     changeset = create(:changeset)
 
 717     basic_authorization changeset.user.email, "test"
 
 719     # simple diff to create a node way and relation using placeholders
 
 720     diff = <<CHANGESET.strip_heredoc
 
 723         <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 724          <tag k='foo' v='#{'x' * 256}'/>
 
 732     post :upload, :params => { :id => changeset.id }
 
 733     assert_response :bad_request,
 
 734                     "shoudln't be able to upload too long a tag to changeset: #{@response.body}"
 
 738   # upload something which creates new objects and inserts them into
 
 739   # existing containers using placeholders.
 
 740   def test_upload_complex
 
 743     relation = create(:relation)
 
 744     create(:way_node, :way => way, :node => node)
 
 746     changeset = create(:changeset)
 
 748     basic_authorization changeset.user.email, "test"
 
 750     # simple diff to create a node way and relation using placeholders
 
 751     diff = <<CHANGESET.strip_heredoc
 
 754         <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
 755          <tag k='foo' v='bar'/>
 
 756          <tag k='baz' v='bat'/>
 
 760         <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
 762          <nd ref='#{node.id}'/>
 
 764         <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
 765          <member type='way' role='some' ref='#{way.id}'/>
 
 766          <member type='node' role='some' ref='-1'/>
 
 767          <member type='relation' role='some' ref='#{relation.id}'/>
 
 775     post :upload, :params => { :id => changeset.id }
 
 776     assert_response :success,
 
 777                     "can't upload a complex diff to changeset: #{@response.body}"
 
 779     # check the returned payload
 
 780     assert_select "diffResult[version='#{API_VERSION}'][generator='#{GENERATOR}']", 1
 
 781     assert_select "diffResult>node", 1
 
 782     assert_select "diffResult>way", 1
 
 783     assert_select "diffResult>relation", 1
 
 785     # inspect the response to find out what the new element IDs are
 
 786     doc = XML::Parser.string(@response.body).parse
 
 787     new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
 
 789     # check that the changes made it into the database
 
 790     assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
 791     assert_equal [new_node_id, node.id], Way.find(way.id).nds, "way nodes should match"
 
 792     Relation.find(relation.id).members.each do |type, id, _role|
 
 793       assert_equal new_node_id, id, "relation should contain new node" if type == "node"
 
 798   # create a diff which references several changesets, which should cause
 
 799   # a rollback and none of the diff gets committed
 
 800   def test_upload_invalid_changesets
 
 801     changeset = create(:changeset)
 
 802     other_changeset = create(:changeset, :user => changeset.user)
 
 805     relation = create(:relation)
 
 806     other_relation = create(:relation)
 
 808     basic_authorization changeset.user.email, "test"
 
 810     # simple diff to create a node way and relation using placeholders
 
 811     diff = <<CHANGESET.strip_heredoc
 
 814         <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
 815         <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
 
 816          <nd ref='#{node.id}'/>
 
 820         <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
 
 821          <member type='way' role='some' ref='#{way.id}'/>
 
 822          <member type='node' role='some' ref='#{node.id}'/>
 
 823          <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 827         <node id='-1' lon='0' lat='0' changeset='#{other_changeset.id}'>
 
 828          <tag k='foo' v='bar'/>
 
 829          <tag k='baz' v='bat'/>
 
 837     post :upload, :params => { :id => changeset.id }
 
 838     assert_response :conflict,
 
 839                     "uploading a diff with multiple changesets should have failed"
 
 841     # check that objects are unmodified
 
 842     assert_nodes_are_equal(node, Node.find(node.id))
 
 843     assert_ways_are_equal(way, Way.find(way.id))
 
 844     assert_relations_are_equal(relation, Relation.find(relation.id))
 
 848   # upload multiple versions of the same element in the same diff.
 
 849   def test_upload_multiple_valid
 
 851     changeset = create(:changeset)
 
 852     basic_authorization changeset.user.email, "test"
 
 854     # change the location of a node multiple times, each time referencing
 
 855     # the last version. doesn't this depend on version numbers being
 
 857     diff = <<CHANGESET.strip_heredoc
 
 860         <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
 861         <node id='#{node.id}' lon='1' lat='0' changeset='#{changeset.id}' version='2'/>
 
 862         <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='3'/>
 
 863         <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset.id}' version='4'/>
 
 864         <node id='#{node.id}' lon='2' lat='2' changeset='#{changeset.id}' version='5'/>
 
 865         <node id='#{node.id}' lon='3' lat='2' changeset='#{changeset.id}' version='6'/>
 
 866         <node id='#{node.id}' lon='3' lat='3' changeset='#{changeset.id}' version='7'/>
 
 867         <node id='#{node.id}' lon='9' lat='9' changeset='#{changeset.id}' version='8'/>
 
 874     post :upload, :params => { :id => changeset.id }
 
 875     assert_response :success,
 
 876                     "can't upload multiple versions of an element in a diff: #{@response.body}"
 
 878     # check the response is well-formed. its counter-intuitive, but the
 
 879     # API will return multiple elements with the same ID and different
 
 880     # version numbers for each change we made.
 
 881     assert_select "diffResult>node", 8
 
 885   # upload multiple versions of the same element in the same diff, but
 
 886   # keep the version numbers the same.
 
 887   def test_upload_multiple_duplicate
 
 889     changeset = create(:changeset)
 
 891     basic_authorization changeset.user.email, "test"
 
 893     diff = <<CHANGESET.strip_heredoc
 
 896         <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
 897         <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
 904     post :upload, :params => { :id => changeset.id }
 
 905     assert_response :conflict,
 
 906                     "shouldn't be able to upload the same element twice in a diff: #{@response.body}"
 
 910   # try to upload some elements without specifying the version
 
 911   def test_upload_missing_version
 
 912     changeset = create(:changeset)
 
 914     basic_authorization changeset.user.email, "test"
 
 916     diff = <<CHANGESET.strip_heredoc
 
 919        <node id='1' lon='1' lat='1' changeset='#{changeset.id}'/>
 
 926     post :upload, :params => { :id => changeset.id }
 
 927     assert_response :bad_request,
 
 928                     "shouldn't be able to upload an element without version: #{@response.body}"
 
 932   # try to upload with commands other than create, modify, or delete
 
 933   def test_action_upload_invalid
 
 934     changeset = create(:changeset)
 
 936     basic_authorization changeset.user.email, "test"
 
 938     diff = <<CHANGESET.strip_heredoc
 
 941          <node id='1' lon='1' lat='1' changeset='#{changeset.id}' />
 
 946     post :upload, :params => { :id => changeset.id }
 
 947     assert_response :bad_request, "Shouldn't be able to upload a diff with the action ping"
 
 948     assert_equal @response.body, "Unknown action ping, choices are create, modify, delete"
 
 952   # upload a valid changeset which has a mixture of whitespace
 
 953   # to check a bug reported by ivansanchez (#1565).
 
 954   def test_upload_whitespace_valid
 
 955     changeset = create(:changeset)
 
 957     way = create(:way_with_nodes, :nodes_count => 2)
 
 958     relation = create(:relation)
 
 959     other_relation = create(:relation)
 
 960     create(:relation_tag, :relation => relation)
 
 962     basic_authorization changeset.user.email, "test"
 
 964     diff = <<CHANGESET.strip_heredoc
 
 966        <modify><node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}'
 
 968         <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='2'><tag k='k' v='v'/></node></modify>
 
 970        <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'><member
 
 971          type='way' role='some' ref='#{way.id}'/><member
 
 972           type='node' role='some' ref='#{node.id}'/>
 
 973          <member type='relation' role='some' ref='#{other_relation.id}'/>
 
 975        </modify></osmChange>
 
 980     post :upload, :params => { :id => changeset.id }
 
 981     assert_response :success,
 
 982                     "can't upload a valid diff with whitespace variations to changeset: #{@response.body}"
 
 984     # check the response is well-formed
 
 985     assert_select "diffResult>node", 2
 
 986     assert_select "diffResult>relation", 1
 
 988     # check that the changes made it into the database
 
 989     assert_equal 1, Node.find(node.id).tags.size, "node #{node.id} should now have one tag"
 
 990     assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
 
 994   # test that a placeholder can be reused within the same upload.
 
 995   def test_upload_reuse_placeholder_valid
 
 996     changeset = create(:changeset)
 
 998     basic_authorization changeset.user.email, "test"
 
1000     diff = <<CHANGESET.strip_heredoc
 
1003         <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
 
1004          <tag k="foo" v="bar"/>
 
1008         <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
1011         <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
 
1018     post :upload, :params => { :id => changeset.id }
 
1019     assert_response :success,
 
1020                     "can't upload a valid diff with re-used placeholders to changeset: #{@response.body}"
 
1022     # check the response is well-formed
 
1023     assert_select "diffResult>node", 3
 
1024     assert_select "diffResult>node[old_id='-1']", 3
 
1028   # test what happens if a diff upload re-uses placeholder IDs in an
 
1030   def test_upload_placeholder_invalid
 
1031     changeset = create(:changeset)
 
1033     basic_authorization changeset.user.email, "test"
 
1035     diff = <<CHANGESET.strip_heredoc
 
1038         <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
 
1039         <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
 
1040         <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
 
1047     post :upload, :params => { :id => changeset.id }
 
1048     assert_response :bad_request,
 
1049                     "shouldn't be able to re-use placeholder IDs"
 
1053   # test that uploading a way referencing invalid placeholders gives a
 
1054   # proper error, not a 500.
 
1055   def test_upload_placeholder_invalid_way
 
1056     changeset = create(:changeset)
 
1059     basic_authorization changeset.user.email, "test"
 
1061     diff = <<CHANGESET.strip_heredoc
 
1064         <node id="-1" lon="0" lat="0" changeset="#{changeset.id}" version="1"/>
 
1065         <node id="-2" lon="1" lat="1" changeset="#{changeset.id}" version="1"/>
 
1066         <node id="-3" lon="2" lat="2" changeset="#{changeset.id}" version="1"/>
 
1067         <way id="-1" changeset="#{changeset.id}" version="1">
 
1079     post :upload, :params => { :id => changeset.id }
 
1080     assert_response :bad_request,
 
1081                     "shouldn't be able to use invalid placeholder IDs"
 
1082     assert_equal "Placeholder node not found for reference -4 in way -1", @response.body
 
1084     # the same again, but this time use an existing way
 
1085     diff = <<CHANGESET.strip_heredoc
 
1088         <node id="-1" lon="0" lat="0" changeset="#{changeset.id}" version="1"/>
 
1089         <node id="-2" lon="1" lat="1" changeset="#{changeset.id}" version="1"/>
 
1090         <node id="-3" lon="2" lat="2" changeset="#{changeset.id}" version="1"/>
 
1091         <way id="#{way.id}" changeset="#{changeset.id}" version="1">
 
1103     post :upload, :params => { :id => changeset.id }
 
1104     assert_response :bad_request,
 
1105                     "shouldn't be able to use invalid placeholder IDs"
 
1106     assert_equal "Placeholder node not found for reference -4 in way #{way.id}", @response.body
 
1110   # test that uploading a relation referencing invalid placeholders gives a
 
1111   # proper error, not a 500.
 
1112   def test_upload_placeholder_invalid_relation
 
1113     changeset = create(:changeset)
 
1114     relation = create(:relation)
 
1116     basic_authorization changeset.user.email, "test"
 
1118     diff = <<CHANGESET.strip_heredoc
 
1121         <node id="-1" lon="0" lat="0" changeset="#{changeset.id}" version="1"/>
 
1122         <node id="-2" lon="1" lat="1" changeset="#{changeset.id}" version="1"/>
 
1123         <node id="-3" lon="2" lat="2" changeset="#{changeset.id}" version="1"/>
 
1124         <relation id="-1" changeset="#{changeset.id}" version="1">
 
1125          <member type="node" role="foo" ref="-1"/>
 
1126          <member type="node" role="foo" ref="-2"/>
 
1127          <member type="node" role="foo" ref="-3"/>
 
1128          <member type="node" role="foo" ref="-4"/>
 
1136     post :upload, :params => { :id => changeset.id }
 
1137     assert_response :bad_request,
 
1138                     "shouldn't be able to use invalid placeholder IDs"
 
1139     assert_equal "Placeholder Node not found for reference -4 in relation -1.", @response.body
 
1141     # the same again, but this time use an existing relation
 
1142     diff = <<CHANGESET.strip_heredoc
 
1145         <node id="-1" lon="0" lat="0" changeset="#{changeset.id}" version="1"/>
 
1146         <node id="-2" lon="1" lat="1" changeset="#{changeset.id}" version="1"/>
 
1147         <node id="-3" lon="2" lat="2" changeset="#{changeset.id}" version="1"/>
 
1148         <relation id="#{relation.id}" changeset="#{changeset.id}" version="1">
 
1149          <member type="node" role="foo" ref="-1"/>
 
1150          <member type="node" role="foo" ref="-2"/>
 
1151          <member type="node" role="foo" ref="-3"/>
 
1152          <member type="way" role="bar" ref="-1"/>
 
1160     post :upload, :params => { :id => changeset.id }
 
1161     assert_response :bad_request,
 
1162                     "shouldn't be able to use invalid placeholder IDs"
 
1163     assert_equal "Placeholder Way not found for reference -1 in relation #{relation.id}.", @response.body
 
1167   # test what happens if a diff is uploaded containing only a node
 
1169   def test_upload_node_move
 
1170     basic_authorization create(:user).email, "test"
 
1172     content "<osm><changeset>" \
 
1173             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1174             "</changeset></osm>"
 
1176     assert_response :success
 
1177     changeset_id = @response.body.to_i
 
1179     old_node = create(:node, :lat => 1, :lon => 1)
 
1181     diff = XML::Document.new
 
1182     diff.root = XML::Node.new "osmChange"
 
1183     modify = XML::Node.new "modify"
 
1184     xml_old_node = old_node.to_xml_node
 
1185     xml_old_node["lat"] = 2.0.to_s
 
1186     xml_old_node["lon"] = 2.0.to_s
 
1187     xml_old_node["changeset"] = changeset_id.to_s
 
1188     modify << xml_old_node
 
1193     post :upload, :params => { :id => changeset_id }
 
1194     assert_response :success,
 
1195                     "diff should have uploaded OK"
 
1198     changeset = Changeset.find(changeset_id)
 
1199     assert_equal 1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 1 degree"
 
1200     assert_equal 2 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 2 degrees"
 
1201     assert_equal 1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1 degree"
 
1202     assert_equal 2 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 2 degrees"
 
1206   # test what happens if a diff is uploaded adding a node to a way.
 
1207   def test_upload_way_extend
 
1208     basic_authorization create(:user).email, "test"
 
1210     content "<osm><changeset>" \
 
1211             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1212             "</changeset></osm>"
 
1214     assert_response :success
 
1215     changeset_id = @response.body.to_i
 
1217     old_way = create(:way)
 
1218     create(:way_node, :way => old_way, :node => create(:node, :lat => 1, :lon => 1))
 
1220     diff = XML::Document.new
 
1221     diff.root = XML::Node.new "osmChange"
 
1222     modify = XML::Node.new "modify"
 
1223     xml_old_way = old_way.to_xml_node
 
1224     nd_ref = XML::Node.new "nd"
 
1225     nd_ref["ref"] = create(:node, :lat => 3, :lon => 3).id.to_s
 
1226     xml_old_way << nd_ref
 
1227     xml_old_way["changeset"] = changeset_id.to_s
 
1228     modify << xml_old_way
 
1233     post :upload, :params => { :id => changeset_id }
 
1234     assert_response :success,
 
1235                     "diff should have uploaded OK"
 
1238     changeset = Changeset.find(changeset_id)
 
1239     assert_equal 1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 1 degree"
 
1240     assert_equal 3 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 3 degrees"
 
1241     assert_equal 1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1 degree"
 
1242     assert_equal 3 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 3 degrees"
 
1246   # test for more issues in #1568
 
1247   def test_upload_empty_invalid
 
1248     changeset = create(:changeset)
 
1250     basic_authorization changeset.user.email, "test"
 
1253      "<osmChange></osmChange>",
 
1254      "<osmChange><modify/></osmChange>",
 
1255      "<osmChange><modify></modify></osmChange>"].each do |diff|
 
1258       post :upload, :params => { :id => changeset.id }
 
1259       assert_response(:success, "should be able to upload " \
 
1260                       "empty changeset: " + diff)
 
1265   # test that the X-Error-Format header works to request XML errors
 
1266   def test_upload_xml_errors
 
1267     changeset = create(:changeset)
 
1268     node = create(:node)
 
1269     create(:relation_member, :member => node)
 
1271     basic_authorization changeset.user.email, "test"
 
1273     # try and delete a node that is in use
 
1274     diff = XML::Document.new
 
1275     diff.root = XML::Node.new "osmChange"
 
1276     delete = XML::Node.new "delete"
 
1278     delete << node.to_xml_node
 
1283     post :upload, :params => { :id => changeset.id }
 
1284     assert_response :success,
 
1285                     "failed to return error in XML format"
 
1287     # check the returned payload
 
1288     assert_select "osmError[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
 
1289     assert_select "osmError>status", 1
 
1290     assert_select "osmError>message", 1
 
1294   # when we make some simple changes we get the same changes back from the
 
1296   def test_diff_download_simple
 
1297     node = create(:node)
 
1299     ## First try with a non-public user, which should get a forbidden
 
1300     basic_authorization create(:user, :data_public => false).email, "test"
 
1302     # create a temporary changeset
 
1303     content "<osm><changeset>" \
 
1304             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1305             "</changeset></osm>"
 
1307     assert_response :forbidden
 
1309     ## Now try with a normal user
 
1310     basic_authorization create(:user).email, "test"
 
1312     # create a temporary changeset
 
1313     content "<osm><changeset>" \
 
1314             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1315             "</changeset></osm>"
 
1317     assert_response :success
 
1318     changeset_id = @response.body.to_i
 
1321     diff = <<CHANGESET.strip_heredoc
 
1324         <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
1325         <node id='#{node.id}' lon='1' lat='0' changeset='#{changeset_id}' version='2'/>
 
1326         <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset_id}' version='3'/>
 
1327         <node id='#{node.id}' lon='1' lat='2' changeset='#{changeset_id}' version='4'/>
 
1328         <node id='#{node.id}' lon='2' lat='2' changeset='#{changeset_id}' version='5'/>
 
1329         <node id='#{node.id}' lon='3' lat='2' changeset='#{changeset_id}' version='6'/>
 
1330         <node id='#{node.id}' lon='3' lat='3' changeset='#{changeset_id}' version='7'/>
 
1331         <node id='#{node.id}' lon='9' lat='9' changeset='#{changeset_id}' version='8'/>
 
1338     post :upload, :params => { :id => changeset_id }
 
1339     assert_response :success,
 
1340                     "can't upload multiple versions of an element in a diff: #{@response.body}"
 
1342     get :download, :params => { :id => changeset_id }
 
1343     assert_response :success
 
1345     assert_select "osmChange", 1
 
1346     assert_select "osmChange>modify", 8
 
1347     assert_select "osmChange>modify>node", 8
 
1351   # culled this from josm to ensure that nothing in the way that josm
 
1352   # is formatting the request is causing it to fail.
 
1354   # NOTE: the error turned out to be something else completely!
 
1355   def test_josm_upload
 
1356     basic_authorization create(:user).email, "test"
 
1358     # create a temporary changeset
 
1359     content "<osm><changeset>" \
 
1360             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1361             "</changeset></osm>"
 
1363     assert_response :success
 
1364     changeset_id = @response.body.to_i
 
1366     diff = <<OSMFILE.strip_heredoc
 
1367       <osmChange version="0.6" generator="JOSM">
 
1368       <create version="0.6" generator="JOSM">
 
1369         <node id='-1' visible='true' changeset='#{changeset_id}' lat='51.49619982187321' lon='-0.18722061869438314' />
 
1370         <node id='-2' visible='true' changeset='#{changeset_id}' lat='51.496359883909605' lon='-0.18653093576241928' />
 
1371         <node id='-3' visible='true' changeset='#{changeset_id}' lat='51.49598132358285' lon='-0.18719613290981638' />
 
1372         <node id='-4' visible='true' changeset='#{changeset_id}' lat='51.4961591711078' lon='-0.18629015888084607' />
 
1373         <node id='-5' visible='true' changeset='#{changeset_id}' lat='51.49582126021711' lon='-0.18708186591517145' />
 
1374         <node id='-6' visible='true' changeset='#{changeset_id}' lat='51.49591018437858' lon='-0.1861432441734455' />
 
1375         <node id='-7' visible='true' changeset='#{changeset_id}' lat='51.49560784152179' lon='-0.18694719410005425' />
 
1376         <node id='-8' visible='true' changeset='#{changeset_id}' lat='51.49567389979617' lon='-0.1860289771788006' />
 
1377         <node id='-9' visible='true' changeset='#{changeset_id}' lat='51.49543761398892' lon='-0.186820684213126' />
 
1378         <way id='-10' action='modiy' visible='true' changeset='#{changeset_id}'>
 
1388           <tag k='highway' v='residential' />
 
1389           <tag k='name' v='Foobar Street' />
 
1397     post :upload, :params => { :id => changeset_id }
 
1398     assert_response :success,
 
1399                     "can't upload a diff from JOSM: #{@response.body}"
 
1401     get :download, :params => { :id => changeset_id }
 
1402     assert_response :success
 
1404     assert_select "osmChange", 1
 
1405     assert_select "osmChange>create>node", 9
 
1406     assert_select "osmChange>create>way", 1
 
1407     assert_select "osmChange>create>way>nd", 9
 
1408     assert_select "osmChange>create>way>tag", 2
 
1412   # when we make some complex changes we get the same changes back from the
 
1414   def test_diff_download_complex
 
1415     node = create(:node)
 
1416     node2 = create(:node)
 
1418     basic_authorization create(:user).email, "test"
 
1420     # create a temporary changeset
 
1421     content "<osm><changeset>" \
 
1422             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
1423             "</changeset></osm>"
 
1425     assert_response :success
 
1426     changeset_id = @response.body.to_i
 
1429     diff = <<CHANGESET.strip_heredoc
 
1432         <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
1435         <node id='-1' lon='9' lat='9' changeset='#{changeset_id}' version='0'/>
 
1436         <node id='-2' lon='8' lat='9' changeset='#{changeset_id}' version='0'/>
 
1437         <node id='-3' lon='7' lat='9' changeset='#{changeset_id}' version='0'/>
 
1440         <node id='#{node2.id}' lon='20' lat='15' changeset='#{changeset_id}' version='1'/>
 
1441         <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
 
1442          <nd ref='#{node2.id}'/>
 
1453     post :upload, :params => { :id => changeset_id }
 
1454     assert_response :success,
 
1455                     "can't upload multiple versions of an element in a diff: #{@response.body}"
 
1457     get :download, :params => { :id => changeset_id }
 
1458     assert_response :success
 
1460     assert_select "osmChange", 1
 
1461     assert_select "osmChange>create", 3
 
1462     assert_select "osmChange>delete", 1
 
1463     assert_select "osmChange>modify", 2
 
1464     assert_select "osmChange>create>node", 3
 
1465     assert_select "osmChange>delete>node", 1
 
1466     assert_select "osmChange>modify>node", 1
 
1467     assert_select "osmChange>modify>way", 1
 
1470   def test_changeset_download
 
1471     changeset = create(:changeset)
 
1472     node = create(:node, :with_history, :version => 1, :changeset => changeset)
 
1473     tag = create(:old_node_tag, :old_node => node.old_nodes.find_by(:version => 1))
 
1474     node2 = create(:node, :with_history, :version => 1, :changeset => changeset)
 
1475     _node3 = create(:node, :with_history, :deleted, :version => 1, :changeset => changeset)
 
1476     _relation = create(:relation, :with_history, :version => 1, :changeset => changeset)
 
1477     _relation2 = create(:relation, :with_history, :deleted, :version => 1, :changeset => changeset)
 
1479     get :download, :params => { :id => changeset.id }
 
1481     assert_response :success
 
1483     # print @response.body
 
1484     # FIXME: needs more assert_select tests
 
1485     assert_select "osmChange[version='#{API_VERSION}'][generator='#{GENERATOR}']" do
 
1486       assert_select "create", :count => 5
 
1487       assert_select "create>node[id='#{node.id}'][visible='#{node.visible?}'][version='#{node.version}']" do
 
1488         assert_select "tag[k='#{tag.k}'][v='#{tag.v}']"
 
1490       assert_select "create>node[id='#{node2.id}']"
 
1495   # check that the bounding box of a changeset gets updated correctly
 
1496   # FIXME: This should really be moded to a integration test due to the with_controller
 
1497   def test_changeset_bbox
 
1499     create(:way_node, :way => way, :node => create(:node, :lat => 3, :lon => 3))
 
1501     basic_authorization create(:user).email, "test"
 
1503     # create a new changeset
 
1504     content "<osm><changeset/></osm>"
 
1506     assert_response :success, "Creating of changeset failed."
 
1507     changeset_id = @response.body.to_i
 
1509     # add a single node to it
 
1510     with_controller(NodesController.new) do
 
1511       content "<osm><node lon='1' lat='2' changeset='#{changeset_id}'/></osm>"
 
1513       assert_response :success, "Couldn't create node."
 
1516     # get the bounding box back from the changeset
 
1517     get :read, :params => { :id => changeset_id }
 
1518     assert_response :success, "Couldn't read back changeset."
 
1519     assert_select "osm>changeset[min_lon='1.0000000']", 1
 
1520     assert_select "osm>changeset[max_lon='1.0000000']", 1
 
1521     assert_select "osm>changeset[min_lat='2.0000000']", 1
 
1522     assert_select "osm>changeset[max_lat='2.0000000']", 1
 
1524     # add another node to it
 
1525     with_controller(NodesController.new) do
 
1526       content "<osm><node lon='2' lat='1' changeset='#{changeset_id}'/></osm>"
 
1528       assert_response :success, "Couldn't create second node."
 
1531     # get the bounding box back from the changeset
 
1532     get :read, :params => { :id => changeset_id }
 
1533     assert_response :success, "Couldn't read back changeset for the second time."
 
1534     assert_select "osm>changeset[min_lon='1.0000000']", 1
 
1535     assert_select "osm>changeset[max_lon='2.0000000']", 1
 
1536     assert_select "osm>changeset[min_lat='1.0000000']", 1
 
1537     assert_select "osm>changeset[max_lat='2.0000000']", 1
 
1539     # add (delete) a way to it, which contains a point at (3,3)
 
1540     with_controller(WaysController.new) do
 
1541       content update_changeset(way.to_xml, changeset_id)
 
1542       put :delete, :params => { :id => way.id }
 
1543       assert_response :success, "Couldn't delete a way."
 
1546     # get the bounding box back from the changeset
 
1547     get :read, :params => { :id => changeset_id }
 
1548     assert_response :success, "Couldn't read back changeset for the third time."
 
1549     assert_select "osm>changeset[min_lon='1.0000000']", 1
 
1550     assert_select "osm>changeset[max_lon='3.0000000']", 1
 
1551     assert_select "osm>changeset[min_lat='1.0000000']", 1
 
1552     assert_select "osm>changeset[max_lat='3.0000000']", 1
 
1556   # test that the changeset :include method works as it should
 
1557   def test_changeset_include
 
1558     basic_authorization create(:user).display_name, "test"
 
1560     # create a new changeset
 
1561     content "<osm><changeset/></osm>"
 
1563     assert_response :success, "Creating of changeset failed."
 
1564     changeset_id = @response.body.to_i
 
1566     # NOTE: the include method doesn't over-expand, like inserting
 
1567     # a real method does. this is because we expect the client to
 
1568     # know what it is doing!
 
1569     check_after_include(changeset_id, 1, 1, [1, 1, 1, 1])
 
1570     check_after_include(changeset_id, 3, 3, [1, 1, 3, 3])
 
1571     check_after_include(changeset_id, 4, 2, [1, 1, 4, 3])
 
1572     check_after_include(changeset_id, 2, 2, [1, 1, 4, 3])
 
1573     check_after_include(changeset_id, -1, -1, [-1, -1, 4, 3])
 
1574     check_after_include(changeset_id, -2, 5, [-2, -1, 4, 5])
 
1578   # test that a not found, wrong method with the expand bbox works as expected
 
1579   def test_changeset_expand_bbox_error
 
1580     basic_authorization create(:user).display_name, "test"
 
1582     # create a new changeset
 
1583     content "<osm><changeset/></osm>"
 
1585     assert_response :success, "Creating of changeset failed."
 
1586     changeset_id = @response.body.to_i
 
1592     content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
 
1593     put :expand_bbox, :params => { :id => changeset_id }
 
1594     assert_response :method_not_allowed, "shouldn't be able to put a bbox expand"
 
1596     # Try to get the update
 
1597     content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
 
1598     get :expand_bbox, :params => { :id => changeset_id }
 
1599     assert_response :method_not_allowed, "shouldn't be able to get a bbox expand"
 
1601     # Try to use a hopefully missing changeset
 
1602     content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
 
1603     post :expand_bbox, :params => { :id => changeset_id + 13245 }
 
1604     assert_response :not_found, "shouldn't be able to do a bbox expand on a nonexistant changeset"
 
1608   # test the query functionality of changesets
 
1610     private_user = create(:user, :data_public => false)
 
1611     private_user_changeset = create(:changeset, :user => private_user)
 
1612     private_user_closed_changeset = create(:changeset, :closed, :user => private_user)
 
1613     user = create(:user)
 
1614     changeset = create(:changeset, :user => user)
 
1615     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))
 
1616     changeset2 = create(:changeset, :min_lat => 5 * GeoRecord::SCALE, :min_lon => 5 * GeoRecord::SCALE, :max_lat => 15 * GeoRecord::SCALE, :max_lon => 15 * GeoRecord::SCALE)
 
1617     changeset3 = create(:changeset, :min_lat => 4.5 * GeoRecord::SCALE, :min_lon => 4.5 * GeoRecord::SCALE, :max_lat => 5 * GeoRecord::SCALE, :max_lon => 5 * GeoRecord::SCALE)
 
1619     get :query, :params => { :bbox => "-10,-10, 10, 10" }
 
1620     assert_response :success, "can't get changesets in bbox"
 
1621     assert_changesets [changeset2, changeset3]
 
1623     get :query, :params => { :bbox => "4.5,4.5,4.6,4.6" }
 
1624     assert_response :success, "can't get changesets in bbox"
 
1625     assert_changesets [changeset3]
 
1627     # not found when looking for changesets of non-existing users
 
1628     get :query, :params => { :user => User.maximum(:id) + 1 }
 
1629     assert_response :not_found
 
1630     get :query, :params => { :display_name => " " }
 
1631     assert_response :not_found
 
1633     # can't get changesets of user 1 without authenticating
 
1634     get :query, :params => { :user => private_user.id }
 
1635     assert_response :not_found, "shouldn't be able to get changesets by non-public user (ID)"
 
1636     get :query, :params => { :display_name => private_user.display_name }
 
1637     assert_response :not_found, "shouldn't be able to get changesets by non-public user (name)"
 
1639     # but this should work
 
1640     basic_authorization private_user.email, "test"
 
1641     get :query, :params => { :user => private_user.id }
 
1642     assert_response :success, "can't get changesets by user ID"
 
1643     assert_changesets [private_user_changeset, private_user_closed_changeset]
 
1645     get :query, :params => { :display_name => private_user.display_name }
 
1646     assert_response :success, "can't get changesets by user name"
 
1647     assert_changesets [private_user_changeset, private_user_closed_changeset]
 
1649     # check that the correct error is given when we provide both UID and name
 
1650     get :query, :params => { :user => private_user.id,
 
1651                              :display_name => private_user.display_name }
 
1652     assert_response :bad_request, "should be a bad request to have both ID and name specified"
 
1654     get :query, :params => { :user => private_user.id, :open => true }
 
1655     assert_response :success, "can't get changesets by user and open"
 
1656     assert_changesets [private_user_changeset]
 
1658     get :query, :params => { :time => "2007-12-31" }
 
1659     assert_response :success, "can't get changesets by time-since"
 
1660     assert_changesets [private_user_changeset, private_user_closed_changeset, changeset, closed_changeset, changeset2, changeset3]
 
1662     get :query, :params => { :time => "2008-01-01T12:34Z" }
 
1663     assert_response :success, "can't get changesets by time-since with hour"
 
1664     assert_changesets [private_user_changeset, private_user_closed_changeset, changeset, closed_changeset, changeset2, changeset3]
 
1666     get :query, :params => { :time => "2007-12-31T23:59Z,2008-01-02T00:01Z" }
 
1667     assert_response :success, "can't get changesets by time-range"
 
1668     assert_changesets [closed_changeset]
 
1670     get :query, :params => { :open => "true" }
 
1671     assert_response :success, "can't get changesets by open-ness"
 
1672     assert_changesets [private_user_changeset, changeset, changeset2, changeset3]
 
1674     get :query, :params => { :closed => "true" }
 
1675     assert_response :success, "can't get changesets by closed-ness"
 
1676     assert_changesets [private_user_closed_changeset, closed_changeset]
 
1678     get :query, :params => { :closed => "true", :user => private_user.id }
 
1679     assert_response :success, "can't get changesets by closed-ness and user"
 
1680     assert_changesets [private_user_closed_changeset]
 
1682     get :query, :params => { :closed => "true", :user => user.id }
 
1683     assert_response :success, "can't get changesets by closed-ness and user"
 
1684     assert_changesets [closed_changeset]
 
1686     get :query, :params => { :changesets => "#{private_user_changeset.id},#{changeset.id},#{closed_changeset.id}" }
 
1687     assert_response :success, "can't get changesets by id (as comma-separated string)"
 
1688     assert_changesets [private_user_changeset, changeset, closed_changeset]
 
1690     get :query, :params => { :changesets => "" }
 
1691     assert_response :bad_request, "should be a bad request since changesets is empty"
 
1695   # check that errors are returned if garbage is inserted
 
1696   # into query strings
 
1697   def test_query_invalid
 
1700      ";drop table users;"].each do |bbox|
 
1701       get :query, :params => { :bbox => bbox }
 
1702       assert_response :bad_request, "'#{bbox}' isn't a bbox"
 
1707      ";drop table users;",
 
1709      "-,-"].each do |time|
 
1710       get :query, :params => { :time => time }
 
1711       assert_response :bad_request, "'#{time}' isn't a valid time range"
 
1718       get :query, :params => { :user => uid }
 
1719       assert_response :bad_request, "'#{uid}' isn't a valid user ID"
 
1724   # check updating tags on a changeset
 
1725   def test_changeset_update
 
1726     private_user = create(:user, :data_public => false)
 
1727     private_changeset = create(:changeset, :user => private_user)
 
1728     user = create(:user)
 
1729     changeset = create(:changeset, :user => user)
 
1731     ## First try with a non-public user
 
1732     new_changeset = private_changeset.to_xml
 
1733     new_tag = XML::Node.new "tag"
 
1734     new_tag["k"] = "tagtesting"
 
1735     new_tag["v"] = "valuetesting"
 
1736     new_changeset.find("//osm/changeset").first << new_tag
 
1737     content new_changeset
 
1739     # try without any authorization
 
1740     put :update, :params => { :id => private_changeset.id }
 
1741     assert_response :unauthorized
 
1743     # try with the wrong authorization
 
1744     basic_authorization create(:user).email, "test"
 
1745     put :update, :params => { :id => private_changeset.id }
 
1746     assert_response :conflict
 
1748     # now this should get an unauthorized
 
1749     basic_authorization private_user.email, "test"
 
1750     put :update, :params => { :id => private_changeset.id }
 
1751     assert_require_public_data "user with their data non-public, shouldn't be able to edit their changeset"
 
1753     ## Now try with the public user
 
1754     create(:changeset_tag, :changeset => changeset)
 
1755     new_changeset = changeset.to_xml
 
1756     new_tag = XML::Node.new "tag"
 
1757     new_tag["k"] = "tagtesting"
 
1758     new_tag["v"] = "valuetesting"
 
1759     new_changeset.find("//osm/changeset").first << new_tag
 
1760     content new_changeset
 
1762     # try without any authorization
 
1763     @request.env["HTTP_AUTHORIZATION"] = nil
 
1764     put :update, :params => { :id => changeset.id }
 
1765     assert_response :unauthorized
 
1767     # try with the wrong authorization
 
1768     basic_authorization create(:user).email, "test"
 
1769     put :update, :params => { :id => changeset.id }
 
1770     assert_response :conflict
 
1772     # now this should work...
 
1773     basic_authorization user.email, "test"
 
1774     put :update, :params => { :id => changeset.id }
 
1775     assert_response :success
 
1777     assert_select "osm>changeset[id='#{changeset.id}']", 1
 
1778     assert_select "osm>changeset>tag", 2
 
1779     assert_select "osm>changeset>tag[k='tagtesting'][v='valuetesting']", 1
 
1783   # check that a user different from the one who opened the changeset
 
1785   def test_changeset_update_invalid
 
1786     basic_authorization create(:user).email, "test"
 
1788     changeset = create(:changeset)
 
1789     new_changeset = changeset.to_xml
 
1790     new_tag = XML::Node.new "tag"
 
1791     new_tag["k"] = "testing"
 
1792     new_tag["v"] = "testing"
 
1793     new_changeset.find("//osm/changeset").first << new_tag
 
1795     content new_changeset
 
1796     put :update, :params => { :id => changeset.id }
 
1797     assert_response :conflict
 
1801   # check that a changeset can contain a certain max number of changes.
 
1802   ## FIXME should be changed to an integration test due to the with_controller
 
1803   def test_changeset_limits
 
1804     basic_authorization create(:user).email, "test"
 
1806     # open a new changeset
 
1807     content "<osm><changeset/></osm>"
 
1809     assert_response :success, "can't create a new changeset"
 
1810     cs_id = @response.body.to_i
 
1812     # start the counter just short of where the changeset should finish.
 
1814     # alter the database to set the counter on the changeset directly,
 
1815     # otherwise it takes about 6 minutes to fill all of them.
 
1816     changeset = Changeset.find(cs_id)
 
1817     changeset.num_changes = Changeset::MAX_ELEMENTS - offset
 
1820     with_controller(NodesController.new) do
 
1822       content "<osm><node changeset='#{cs_id}' lat='0.0' lon='0.0'/></osm>"
 
1824       assert_response :success, "can't create a new node"
 
1825       node_id = @response.body.to_i
 
1827       get :read, :params => { :id => node_id }
 
1828       assert_response :success, "can't read back new node"
 
1829       node_doc = XML::Parser.string(@response.body).parse
 
1830       node_xml = node_doc.find("//osm/node").first
 
1832       # loop until we fill the changeset with nodes
 
1834         node_xml["lat"] = rand.to_s
 
1835         node_xml["lon"] = rand.to_s
 
1836         node_xml["version"] = (i + 1).to_s
 
1839         put :update, :params => { :id => node_id }
 
1840         assert_response :success, "attempt #{i} should have succeeded"
 
1843       # trying again should fail
 
1844       node_xml["lat"] = rand.to_s
 
1845       node_xml["lon"] = rand.to_s
 
1846       node_xml["version"] = offset.to_s
 
1849       put :update, :params => { :id => node_id }
 
1850       assert_response :conflict, "final attempt should have failed"
 
1853     changeset = Changeset.find(cs_id)
 
1854     assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
 
1856     # check that the changeset is now closed as well
 
1857     assert_not(changeset.is_open?,
 
1858                "changeset should have been auto-closed by exceeding " \
 
1863   # This should display the last 20 changesets closed
 
1865     get :index, :params => { :format => "html" }
 
1866     assert_response :success
 
1867     assert_template "history"
 
1868     assert_template :layout => "map"
 
1869     assert_select "h2", :text => "Changesets", :count => 1
 
1871     get :index, :params => { :format => "html", :list => "1" }, :xhr => true
 
1872     assert_response :success
 
1873     assert_template "index"
 
1875     check_index_result(Changeset.all)
 
1879   # This should display the last 20 changesets closed
 
1881     get :index, :params => { :format => "html" }, :xhr => true
 
1882     assert_response :success
 
1883     assert_template "history"
 
1884     assert_template :layout => "xhr"
 
1885     assert_select "h2", :text => "Changesets", :count => 1
 
1887     get :index, :params => { :format => "html", :list => "1" }, :xhr => true
 
1888     assert_response :success
 
1889     assert_template "index"
 
1891     check_index_result(Changeset.all)
 
1895   # This should display the last 20 changesets closed in a specific area
 
1897     get :index, :params => { :format => "html", :bbox => "4.5,4.5,5.5,5.5" }
 
1898     assert_response :success
 
1899     assert_template "history"
 
1900     assert_template :layout => "map"
 
1901     assert_select "h2", :text => "Changesets", :count => 1
 
1903     get :index, :params => { :format => "html", :bbox => "4.5,4.5,5.5,5.5", :list => "1" }, :xhr => true
 
1904     assert_response :success
 
1905     assert_template "index"
 
1907     check_index_result(Changeset.where("min_lon < 55000000 and max_lon > 45000000 and min_lat < 55000000 and max_lat > 45000000"))
 
1911   # Checks the display of the user changesets listing
 
1913     user = create(:user)
 
1914     create(:changeset, :user => user)
 
1915     create(:changeset, :closed, :user => user)
 
1917     get :index, :params => { :format => "html", :display_name => user.display_name }
 
1918     assert_response :success
 
1919     assert_template "history"
 
1921     get :index, :params => { :format => "html", :display_name => user.display_name, :list => "1" }, :xhr => true
 
1922     assert_response :success
 
1923     assert_template "index"
 
1925     check_index_result(user.changesets)
 
1929   # Checks the display of the user changesets listing for a private user
 
1930   def test_index_private_user
 
1931     private_user = create(:user, :data_public => false)
 
1932     create(:changeset, :user => private_user)
 
1933     create(:changeset, :closed, :user => private_user)
 
1935     get :index, :params => { :format => "html", :display_name => private_user.display_name }
 
1936     assert_response :success
 
1937     assert_template "history"
 
1939     get :index, :params => { :format => "html", :display_name => private_user.display_name, :list => "1" }, :xhr => true
 
1940     assert_response :success
 
1941     assert_template "index"
 
1943     check_index_result(Changeset.none)
 
1947   # Check the not found of the index user changesets
 
1948   def test_index_user_not_found
 
1949     get :index, :params => { :format => "html", :display_name => "Some random user" }
 
1950     assert_response :not_found
 
1951     assert_template "users/no_such_user"
 
1953     get :index, :params => { :format => "html", :display_name => "Some random user", :list => "1" }, :xhr => true
 
1954     assert_response :not_found
 
1955     assert_template "users/no_such_user"
 
1959   # Checks the display of the friends changesets listing
 
1960   def test_index_friends
 
1961     private_user = create(:user, :data_public => true)
 
1962     friend = create(:friend, :befriender => private_user)
 
1963     create(:changeset, :user => friend.befriendee)
 
1965     get :index, :params => { :friends => true }
 
1966     assert_response :redirect
 
1967     assert_redirected_to :controller => :users, :action => :login, :referer => friend_changesets_path
 
1969     session[:user] = private_user.id
 
1971     get :index, :params => { :friends => true }
 
1972     assert_response :success
 
1973     assert_template "history"
 
1975     get :index, :params => { :friends => true, :list => "1" }, :xhr => true
 
1976     assert_response :success
 
1977     assert_template "index"
 
1979     check_index_result(Changeset.where(:user => private_user.friend_users.identifiable))
 
1983   # Checks the display of the nearby user changesets listing
 
1984   def test_index_nearby
 
1985     private_user = create(:user, :data_public => false, :home_lat => 51.1, :home_lon => 1.0)
 
1986     user = create(:user, :home_lat => 51.0, :home_lon => 1.0)
 
1987     create(:changeset, :user => user)
 
1989     get :index, :params => { :nearby => true }
 
1990     assert_response :redirect
 
1991     assert_redirected_to :controller => :users, :action => :login, :referer => nearby_changesets_path
 
1993     session[:user] = private_user.id
 
1995     get :index, :params => { :nearby => true }
 
1996     assert_response :success
 
1997     assert_template "history"
 
1999     get :index, :params => { :nearby => true, :list => "1" }, :xhr => true
 
2000     assert_response :success
 
2001     assert_template "index"
 
2003     check_index_result(Changeset.where(:user => user.nearby))
 
2007   # Check that we can't request later pages of the changesets index
 
2008   def test_index_max_id
 
2009     get :index, :params => { :format => "html", :max_id => 4 }, :xhr => true
 
2010     assert_response :success
 
2011     assert_template "history"
 
2012     assert_template :layout => "xhr"
 
2013     assert_select "h2", :text => "Changesets", :count => 1
 
2015     get :index, :params => { :format => "html", :list => "1", :max_id => 4 }, :xhr => true
 
2016     assert_response :success
 
2017     assert_template "index"
 
2019     check_index_result(Changeset.where("id <= 4"))
 
2023   # Check that a list with a next page link works
 
2025     create_list(:changeset, 50)
 
2027     get :index, :params => { :format => "html" }
 
2028     assert_response :success
 
2030     get :index, :params => { :format => "html" }, :xhr => true
 
2031     assert_response :success
 
2035   # This should display the last 20 non-empty changesets
 
2037     changeset = create(:changeset, :num_changes => 1)
 
2038     create(:changeset_tag, :changeset => changeset)
 
2039     create(:changeset_tag, :changeset => changeset, :k => "website", :v => "http://example.com/")
 
2040     closed_changeset = create(:changeset, :closed, :num_changes => 1)
 
2041     _empty_changeset = create(:changeset, :num_changes => 0)
 
2043     get :feed, :params => { :format => :atom }
 
2044     assert_response :success
 
2045     assert_template "index"
 
2046     assert_equal "application/atom+xml", response.content_type
 
2048     check_feed_result([changeset, closed_changeset])
 
2052   # This should display the last 20 changesets closed in a specific area
 
2054     changeset = create(:changeset, :num_changes => 1, :min_lat => 5 * GeoRecord::SCALE, :min_lon => 5 * GeoRecord::SCALE, :max_lat => 5 * GeoRecord::SCALE, :max_lon => 5 * GeoRecord::SCALE)
 
2055     create(:changeset_tag, :changeset => changeset)
 
2056     create(:changeset_tag, :changeset => changeset, :k => "website", :v => "http://example.com/")
 
2057     closed_changeset = create(:changeset, :closed, :num_changes => 1, :min_lat => 5 * GeoRecord::SCALE, :min_lon => 5 * GeoRecord::SCALE, :max_lat => 5 * GeoRecord::SCALE, :max_lon => 5 * GeoRecord::SCALE)
 
2058     _elsewhere_changeset = create(:changeset, :num_changes => 1, :min_lat => -5 * GeoRecord::SCALE, :min_lon => -5 * GeoRecord::SCALE, :max_lat => -5 * GeoRecord::SCALE, :max_lon => -5 * GeoRecord::SCALE)
 
2059     _empty_changeset = create(:changeset, :num_changes => 0, :min_lat => -5 * GeoRecord::SCALE, :min_lon => -5 * GeoRecord::SCALE, :max_lat => -5 * GeoRecord::SCALE, :max_lon => -5 * GeoRecord::SCALE)
 
2061     get :feed, :params => { :format => :atom, :bbox => "4.5,4.5,5.5,5.5" }
 
2062     assert_response :success
 
2063     assert_template "index"
 
2064     assert_equal "application/atom+xml", response.content_type
 
2066     check_feed_result([changeset, closed_changeset])
 
2070   # Checks the display of the user changesets feed
 
2072     user = create(:user)
 
2073     changesets = create_list(:changeset, 3, :user => user, :num_changes => 4)
 
2074     create(:changeset_tag, :changeset => changesets[1])
 
2075     create(:changeset_tag, :changeset => changesets[1], :k => "website", :v => "http://example.com/")
 
2076     _other_changeset = create(:changeset)
 
2078     get :feed, :params => { :format => :atom, :display_name => user.display_name }
 
2080     assert_response :success
 
2081     assert_template "index"
 
2082     assert_equal "application/atom+xml", response.content_type
 
2084     check_feed_result(changesets)
 
2088   # Check the not found of the user changesets feed
 
2089   def test_feed_user_not_found
 
2090     get :feed, :params => { :format => "atom", :display_name => "Some random user" }
 
2091     assert_response :not_found
 
2095   # Check that we can't request later pages of the changesets feed
 
2096   def test_feed_max_id
 
2097     get :feed, :params => { :format => "atom", :max_id => 100 }
 
2098     assert_response :redirect
 
2099     assert_redirected_to :action => :feed
 
2103   # check that the changeset download for a changeset with a redacted
 
2104   # element in it doesn't contain that element.
 
2105   def test_diff_download_redacted
 
2106     changeset = create(:changeset)
 
2107     node = create(:node, :with_history, :version => 2, :changeset => changeset)
 
2108     node_v1 = node.old_nodes.find_by(:version => 1)
 
2109     node_v1.redact!(create(:redaction))
 
2111     get :download, :params => { :id => changeset.id }
 
2112     assert_response :success
 
2114     assert_select "osmChange", 1
 
2115     # this changeset contains the node in versions 1 & 2, but 1 should
 
2117     assert_select "osmChange node[id='#{node.id}']", 1
 
2118     assert_select "osmChange node[id='#{node.id}'][version='1']", 0
 
2122   # test subscribe success
 
2123   def test_subscribe_success
 
2124     basic_authorization create(:user).email, "test"
 
2125     changeset = create(:changeset, :closed)
 
2127     assert_difference "changeset.subscribers.count", 1 do
 
2128       post :subscribe, :params => { :id => changeset.id }
 
2130     assert_response :success
 
2132     # not closed changeset
 
2133     changeset = create(:changeset)
 
2134     assert_difference "changeset.subscribers.count", 1 do
 
2135       post :subscribe, :params => { :id => changeset.id }
 
2137     assert_response :success
 
2141   # test subscribe fail
 
2142   def test_subscribe_fail
 
2143     user = create(:user)
 
2146     changeset = create(:changeset, :closed)
 
2147     assert_no_difference "changeset.subscribers.count" do
 
2148       post :subscribe, :params => { :id => changeset.id }
 
2150     assert_response :unauthorized
 
2152     basic_authorization user.email, "test"
 
2155     assert_no_difference "changeset.subscribers.count" do
 
2156       post :subscribe, :params => { :id => 999111 }
 
2158     assert_response :not_found
 
2160     # trying to subscribe when already subscribed
 
2161     changeset = create(:changeset, :closed)
 
2162     changeset.subscribers.push(user)
 
2163     assert_no_difference "changeset.subscribers.count" do
 
2164       post :subscribe, :params => { :id => changeset.id }
 
2166     assert_response :conflict
 
2170   # test unsubscribe success
 
2171   def test_unsubscribe_success
 
2172     user = create(:user)
 
2173     basic_authorization user.email, "test"
 
2174     changeset = create(:changeset, :closed)
 
2175     changeset.subscribers.push(user)
 
2177     assert_difference "changeset.subscribers.count", -1 do
 
2178       post :unsubscribe, :params => { :id => changeset.id }
 
2180     assert_response :success
 
2182     # not closed changeset
 
2183     changeset = create(:changeset)
 
2184     changeset.subscribers.push(user)
 
2186     assert_difference "changeset.subscribers.count", -1 do
 
2187       post :unsubscribe, :params => { :id => changeset.id }
 
2189     assert_response :success
 
2193   # test unsubscribe fail
 
2194   def test_unsubscribe_fail
 
2196     changeset = create(:changeset, :closed)
 
2197     assert_no_difference "changeset.subscribers.count" do
 
2198       post :unsubscribe, :params => { :id => changeset.id }
 
2200     assert_response :unauthorized
 
2202     basic_authorization create(:user).email, "test"
 
2205     assert_no_difference "changeset.subscribers.count" do
 
2206       post :unsubscribe, :params => { :id => 999111 }
 
2208     assert_response :not_found
 
2210     # trying to unsubscribe when not subscribed
 
2211     changeset = create(:changeset, :closed)
 
2212     assert_no_difference "changeset.subscribers.count" do
 
2213       post :unsubscribe, :params => { :id => changeset.id }
 
2215     assert_response :not_found
 
2221   # boilerplate for checking that certain changesets exist in the
 
2223   def assert_changesets(changesets)
 
2224     assert_select "osm>changeset", changesets.size
 
2225     changesets.each do |changeset|
 
2226       assert_select "osm>changeset[id='#{changeset.id}']", 1
 
2231   # call the include method and assert properties of the bbox
 
2232   def check_after_include(changeset_id, lon, lat, bbox)
 
2233     content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
 
2234     post :expand_bbox, :params => { :id => changeset_id }
 
2235     assert_response :success, "Setting include of changeset failed: #{@response.body}"
 
2237     # check exactly one changeset
 
2238     assert_select "osm>changeset", 1
 
2239     assert_select "osm>changeset[id='#{changeset_id}']", 1
 
2242     doc = XML::Parser.string(@response.body).parse
 
2243     changeset = doc.find("//osm/changeset").first
 
2244     assert_equal bbox[0], changeset["min_lon"].to_f, "min lon"
 
2245     assert_equal bbox[1], changeset["min_lat"].to_f, "min lat"
 
2246     assert_equal bbox[2], changeset["max_lon"].to_f, "max lon"
 
2247     assert_equal bbox[3], changeset["max_lat"].to_f, "max lat"
 
2251   # update the changeset_id of a way element
 
2252   def update_changeset(xml, changeset_id)
 
2253     xml_attr_rewrite(xml, "changeset", changeset_id)
 
2257   # update an attribute in a way element
 
2258   def xml_attr_rewrite(xml, name, value)
 
2259     xml.find("//osm/way").first[name] = value.to_s
 
2264   # check the result of a index
 
2265   def check_index_result(changesets)
 
2266     changesets = changesets.where("num_changes > 0")
 
2267                            .order(:created_at => :desc)
 
2269     assert changesets.size <= 20
 
2271     assert_select "ol.changesets", :count => [changesets.size, 1].min do
 
2272       assert_select "li", :count => changesets.size
 
2274       changesets.each do |changeset|
 
2275         assert_select "li#changeset_#{changeset.id}", :count => 1
 
2281   # check the result of a feed
 
2282   def check_feed_result(changesets)
 
2283     assert changesets.size <= 20
 
2285     assert_select "feed", :count => [changesets.size, 1].min do
 
2286       assert_select "> title", :count => 1, :text => /^Changesets/
 
2287       assert_select "> entry", :count => changesets.size
 
2289       changesets.each do |changeset|
 
2290         assert_select "> entry > id", changeset_url(:id => changeset.id)