1 require File.dirname(__FILE__) + '/../test_helper'
 
   2 require 'changeset_controller'
 
   4 class ChangesetControllerTest < ActionController::TestCase
 
   7   # -----------------------
 
   8   # Test simple changeset creation
 
   9   # -----------------------
 
  12     basic_authorization "test@openstreetmap.org", "test"
 
  14     # Create the first user's changeset
 
  15     content "<osm><changeset>" +
 
  16       "<tag k='created_by' v='osm test suite checking changesets'/>" + 
 
  20     assert_response :success, "Creation of changeset did not return sucess status"
 
  21     newid = @response.body.to_i
 
  23     # check end time, should be an hour ahead of creation time
 
  24     cs = Changeset.find(newid)
 
  25     duration = cs.closed_at - cs.created_at
 
  26     # the difference can either be a rational, or a floating point number
 
  27     # of seconds, depending on the code path taken :-(
 
  28     if duration.class == Rational
 
  29       assert_equal Rational(1,24), duration , "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
 
  31       # must be number of seconds...
 
  32       assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
 
  36   def test_create_invalid
 
  37     basic_authorization "test@openstreetmap.org", "test"
 
  38     content "<osm><changeset></osm>"
 
  40     assert_response :bad_request, "creating a invalid changeset should fail"
 
  43   def test_create_invalid_no_content
 
  44     basic_authorization "test@openstreetmap.org", "test"
 
  46     assert_response :bad_request, "creating a changeset with no content should fail"
 
  49   def test_create_wrong_method
 
  50     basic_authorization "test@openstreetmap.org", "test"
 
  52     assert_response :method_not_allowed
 
  56   # check that the changeset can be read and returns the correct
 
  59     changeset_id = changesets(:normal_user_first_change).id
 
  60     get :read, :id => changeset_id
 
  61     assert_response :success, "cannot get first changeset"
 
  63     assert_select "osm[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
 
  64     assert_select "osm>changeset[id=#{changeset_id}]", 1
 
  68   # test that the user who opened a change can close it
 
  70     basic_authorization "test@openstreetmap.org", "test"
 
  72     cs_id = changesets(:normal_user_first_change).id
 
  73     put :close, :id => cs_id
 
  74     assert_response :success
 
  76     # test that it really is closed now
 
  77     cs = Changeset.find(cs_id)
 
  79            "changeset should be closed now (#{cs.closed_at} > #{Time.now}.")
 
  83   # test that a different user can't close another user's changeset
 
  84   def test_close_invalid
 
  85     basic_authorization "test@example.com", "test"
 
  87     put :close, :id => changesets(:normal_user_first_change).id
 
  88     assert_response :conflict
 
  89     assert_equal "The user doesn't own that changeset", @response.body
 
  93   # upload something simple, but valid and check that it can 
 
  95   def test_upload_simple_valid
 
  96     basic_authorization "test@openstreetmap.org", "test"
 
  98     # simple diff to change a node, way and relation by removing 
 
 103   <node id='1' lon='0' lat='0' changeset='1' version='1'/>
 
 104   <way id='1' changeset='1' version='1'>
 
 109   <relation id='1' changeset='1' version='1'>
 
 110    <member type='way' role='some' ref='3'/>
 
 111    <member type='node' role='some' ref='5'/>
 
 112    <member type='relation' role='some' ref='3'/>
 
 120     post :upload, :id => 1
 
 121     assert_response :success, 
 
 122       "can't upload a simple valid diff to changeset: #{@response.body}"
 
 124     # check that the changes made it into the database
 
 125     assert_equal 0, Node.find(1).tags.size, "node 1 should now have no tags"
 
 126     assert_equal 0, Way.find(1).tags.size, "way 1 should now have no tags"
 
 127     assert_equal 0, Relation.find(1).tags.size, "relation 1 should now have no tags"
 
 131   # upload something which creates new objects using placeholders
 
 132   def test_upload_create_valid
 
 133     basic_authorization "test@openstreetmap.org", "test"
 
 135     # simple diff to create a node way and relation using placeholders
 
 139   <node id='-1' lon='0' lat='0' changeset='1'>
 
 140    <tag k='foo' v='bar'/>
 
 141    <tag k='baz' v='bat'/>
 
 143   <way id='-1' changeset='1'>
 
 148   <relation id='-1' changeset='1'>
 
 149    <member type='way' role='some' ref='3'/>
 
 150    <member type='node' role='some' ref='5'/>
 
 151    <member type='relation' role='some' ref='3'/>
 
 159     post :upload, :id => 1
 
 160     assert_response :success, 
 
 161       "can't upload a simple valid creation to changeset: #{@response.body}"
 
 163     # check the returned payload
 
 164     assert_select "diffResult[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
 
 165     assert_select "diffResult>node", 1
 
 166     assert_select "diffresult>way", 1
 
 167     assert_select "diffResult>relation", 1
 
 169     # inspect the response to find out what the new element IDs are
 
 170     doc = XML::Parser.string(@response.body).parse
 
 171     new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
 
 172     new_way_id = doc.find("//diffResult/way").first["new_id"].to_i
 
 173     new_rel_id = doc.find("//diffResult/relation").first["new_id"].to_i
 
 175     # check the old IDs are all present and negative one
 
 176     assert_equal -1, doc.find("//diffResult/node").first["old_id"].to_i
 
 177     assert_equal -1, doc.find("//diffResult/way").first["old_id"].to_i
 
 178     assert_equal -1, doc.find("//diffResult/relation").first["old_id"].to_i
 
 180     # check the versions are present and equal one
 
 181     assert_equal 1, doc.find("//diffResult/node").first["new_version"].to_i
 
 182     assert_equal 1, doc.find("//diffResult/way").first["new_version"].to_i
 
 183     assert_equal 1, doc.find("//diffResult/relation").first["new_version"].to_i
 
 185     # check that the changes made it into the database
 
 186     assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
 187     assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
 
 188     assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
 
 192   # test a complex delete where we delete elements which rely on eachother
 
 193   # in the same transaction.
 
 194   def test_upload_delete
 
 195     basic_authorization "test@openstreetmap.org", "test"
 
 197     diff = XML::Document.new
 
 198     diff.root = XML::Node.new "osmChange"
 
 199     delete = XML::Node.new "delete"
 
 201     delete << current_relations(:visible_relation).to_xml_node
 
 202     delete << current_relations(:used_relation).to_xml_node
 
 203     delete << current_ways(:used_way).to_xml_node
 
 204     delete << current_nodes(:node_used_by_relationship).to_xml_node
 
 208     post :upload, :id => 1
 
 209     assert_response :success, 
 
 210       "can't upload a deletion diff to changeset: #{@response.body}"
 
 212     # check the response is well-formed
 
 213     assert_select "diffResult>node", 1
 
 214     assert_select "diffResult>way", 1
 
 215     assert_select "diffResult>relation", 2
 
 217     # check that everything was deleted
 
 218     assert_equal false, Node.find(current_nodes(:node_used_by_relationship).id).visible
 
 219     assert_equal false, Way.find(current_ways(:used_way).id).visible
 
 220     assert_equal false, Relation.find(current_relations(:visible_relation).id).visible
 
 221     assert_equal false, Relation.find(current_relations(:used_relation).id).visible
 
 225   # test uploading a delete with no lat/lon, as they are optional in
 
 226   # the osmChange spec.
 
 227   def test_upload_nolatlon_delete
 
 228     basic_authorization "test@openstreetmap.org", "test"
 
 230     node = current_nodes(:visible_node)
 
 231     cs = changesets(:normal_user_first_change)
 
 232     diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{cs.id}'/></delete></osmChange>"
 
 236     post :upload, :id => cs.id
 
 237     assert_response :success, 
 
 238       "can't upload a deletion diff to changeset: #{@response.body}"
 
 240     # check the response is well-formed
 
 241     assert_select "diffResult>node", 1
 
 243     # check that everything was deleted
 
 244     assert_equal false, Node.find(node.id).visible
 
 247   def test_repeated_changeset_create
 
 249       basic_authorization "test@openstreetmap.org", "test"
 
 251       # create a temporary changeset
 
 252       content "<osm><changeset>" +
 
 253         "<tag k='created_by' v='osm test suite checking changesets'/>" + 
 
 255       assert_difference('Changeset.count', 1) do
 
 258       assert_response :success
 
 259       changeset_id = @response.body.to_i
 
 264   # test that deleting stuff in a transaction doesn't bypass the checks
 
 265   # to ensure that used elements are not deleted.
 
 266   def test_upload_delete_invalid
 
 267     basic_authorization "test@openstreetmap.org", "test"
 
 269     diff = XML::Document.new
 
 270     diff.root = XML::Node.new "osmChange"
 
 271     delete = XML::Node.new "delete"
 
 273     delete << current_relations(:visible_relation).to_xml_node
 
 274     delete << current_ways(:used_way).to_xml_node
 
 275     delete << current_nodes(:node_used_by_relationship).to_xml_node
 
 279     post :upload, :id => 1
 
 280     assert_response :precondition_failed, 
 
 281       "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
 
 283     # check that nothing was, in fact, deleted
 
 284     assert_equal true, Node.find(current_nodes(:node_used_by_relationship).id).visible
 
 285     assert_equal true, Way.find(current_ways(:used_way).id).visible
 
 286     assert_equal true, Relation.find(current_relations(:visible_relation).id).visible
 
 290   # upload something which creates new objects and inserts them into
 
 291   # existing containers using placeholders.
 
 292   def test_upload_complex
 
 293     basic_authorization "test@openstreetmap.org", "test"
 
 295     # simple diff to create a node way and relation using placeholders
 
 299   <node id='-1' lon='0' lat='0' changeset='1'>
 
 300    <tag k='foo' v='bar'/>
 
 301    <tag k='baz' v='bat'/>
 
 305   <way id='1' changeset='1' version='1'>
 
 309   <relation id='1' changeset='1' version='1'>
 
 310    <member type='way' role='some' ref='3'/>
 
 311    <member type='node' role='some' ref='-1'/>
 
 312    <member type='relation' role='some' ref='3'/>
 
 320     post :upload, :id => 1
 
 321     assert_response :success, 
 
 322       "can't upload a complex diff to changeset: #{@response.body}"
 
 324     # check the returned payload
 
 325     assert_select "diffResult[version=#{API_VERSION}][generator=\"#{GENERATOR}\"]", 1
 
 326     assert_select "diffResult>node", 1
 
 327     assert_select "diffResult>way", 1
 
 328     assert_select "diffResult>relation", 1
 
 330     # inspect the response to find out what the new element IDs are
 
 331     doc = XML::Parser.string(@response.body).parse
 
 332     new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
 
 334     # check that the changes made it into the database
 
 335     assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
 
 336     assert_equal [new_node_id, 3], Way.find(1).nds, "way nodes should match"
 
 337     Relation.find(1).members.each do |type,id,role|
 
 339         assert_equal new_node_id, id, "relation should contain new node"
 
 345   # create a diff which references several changesets, which should cause
 
 346   # a rollback and none of the diff gets committed
 
 347   def test_upload_invalid_changesets
 
 348     basic_authorization "test@openstreetmap.org", "test"
 
 350     # simple diff to create a node way and relation using placeholders
 
 354   <node id='1' lon='0' lat='0' changeset='1' version='1'/>
 
 355   <way id='1' changeset='1' version='1'>
 
 360   <relation id='1' changeset='1' version='1'>
 
 361    <member type='way' role='some' ref='3'/>
 
 362    <member type='node' role='some' ref='5'/>
 
 363    <member type='relation' role='some' ref='3'/>
 
 367   <node id='-1' lon='0' lat='0' changeset='4'>
 
 368    <tag k='foo' v='bar'/>
 
 369    <tag k='baz' v='bat'/>
 
 374     # cache the objects before uploading them
 
 375     node = current_nodes(:visible_node)
 
 376     way = current_ways(:visible_way)
 
 377     rel = current_relations(:visible_relation)
 
 381     post :upload, :id => 1
 
 382     assert_response :conflict, 
 
 383       "uploading a diff with multiple changsets should have failed"
 
 385     # check that objects are unmodified
 
 386     assert_nodes_are_equal(node, Node.find(1))
 
 387     assert_ways_are_equal(way, Way.find(1))
 
 391   # upload multiple versions of the same element in the same diff.
 
 392   def test_upload_multiple_valid
 
 393     basic_authorization "test@openstreetmap.org", "test"
 
 395     # change the location of a node multiple times, each time referencing
 
 396     # the last version. doesn't this depend on version numbers being
 
 401   <node id='1' lon='0' lat='0' changeset='1' version='1'/>
 
 402   <node id='1' lon='1' lat='0' changeset='1' version='2'/>
 
 403   <node id='1' lon='1' lat='1' changeset='1' version='3'/>
 
 404   <node id='1' lon='1' lat='2' changeset='1' version='4'/>
 
 405   <node id='1' lon='2' lat='2' changeset='1' version='5'/>
 
 406   <node id='1' lon='3' lat='2' changeset='1' version='6'/>
 
 407   <node id='1' lon='3' lat='3' changeset='1' version='7'/>
 
 408   <node id='1' lon='9' lat='9' changeset='1' version='8'/>
 
 415     post :upload, :id => 1
 
 416     assert_response :success, 
 
 417       "can't upload multiple versions of an element in a diff: #{@response.body}"
 
 419     # check the response is well-formed. its counter-intuitive, but the
 
 420     # API will return multiple elements with the same ID and different
 
 421     # version numbers for each change we made.
 
 422     assert_select "diffResult>node", 8
 
 426   # upload multiple versions of the same element in the same diff, but
 
 427   # keep the version numbers the same.
 
 428   def test_upload_multiple_duplicate
 
 429     basic_authorization "test@openstreetmap.org", "test"
 
 434   <node id='1' lon='0' lat='0' changeset='1' version='1'/>
 
 435   <node id='1' lon='1' lat='1' changeset='1' version='1'/>
 
 442     post :upload, :id => 1
 
 443     assert_response :conflict, 
 
 444       "shouldn't be able to upload the same element twice in a diff: #{@response.body}"
 
 448   # try to upload some elements without specifying the version
 
 449   def test_upload_missing_version
 
 450     basic_authorization "test@openstreetmap.org", "test"
 
 455   <node id='1' lon='1' lat='1' changeset='1'/>
 
 462     post :upload, :id => 1
 
 463     assert_response :bad_request, 
 
 464       "shouldn't be able to upload an element without version: #{@response.body}"
 
 468   # try to upload with commands other than create, modify, or delete
 
 469   def test_action_upload_invalid
 
 470     basic_authorization "test@openstreetmap.org", "test"
 
 475     <node id='1' lon='1' lat='1' changeset='1' />
 
 480   post :upload, :id => 1
 
 481   assert_response :bad_request, "Shouldn't be able to upload a diff with the action ping"
 
 482   assert_equal @response.body, "Unknown action ping, choices are create, modify, delete."
 
 486   # upload a valid changeset which has a mixture of whitespace
 
 487   # to check a bug reported by ivansanchez (#1565).
 
 488   def test_upload_whitespace_valid
 
 489     basic_authorization "test@openstreetmap.org", "test"
 
 493  <modify><node id='1' lon='0' lat='0' changeset='1' 
 
 495   <node id='1' lon='1' lat='1' changeset='1' version='2'><tag k='k' v='v'/></node></modify>
 
 497   <relation id='1' changeset='1' version='1'><member 
 
 498    type='way' role='some' ref='3'/><member 
 
 499     type='node' role='some' ref='5'/>
 
 500    <member type='relation' role='some' ref='3'/>
 
 502  </modify></osmChange>
 
 507     post :upload, :id => 1
 
 508     assert_response :success, 
 
 509       "can't upload a valid diff with whitespace variations to changeset: #{@response.body}"
 
 511     # check the response is well-formed
 
 512     assert_select "diffResult>node", 2
 
 513     assert_select "diffResult>relation", 1
 
 515     # check that the changes made it into the database
 
 516     assert_equal 1, Node.find(1).tags.size, "node 1 should now have one tag"
 
 517     assert_equal 0, Relation.find(1).tags.size, "relation 1 should now have no tags"
 
 521   # upload a valid changeset which has a mixture of whitespace
 
 522   # to check a bug reported by ivansanchez.
 
 523   def test_upload_reuse_placeholder_valid
 
 524     basic_authorization "test@openstreetmap.org", "test"
 
 529   <node id='-1' lon='0' lat='0' changeset='1'>
 
 530    <tag k="foo" v="bar"/>
 
 534   <node id='-1' lon='1' lat='1' changeset='1' version='1'/>
 
 537   <node id='-1' lon='2' lat='2' changeset='1' version='2'/>
 
 544     post :upload, :id => 1
 
 545     assert_response :success, 
 
 546       "can't upload a valid diff with re-used placeholders to changeset: #{@response.body}"
 
 548     # check the response is well-formed
 
 549     assert_select "diffResult>node", 3
 
 550     assert_select "diffResult>node[old_id=-1]", 3
 
 554   # test what happens if a diff upload re-uses placeholder IDs in an
 
 556   def test_upload_placeholder_invalid
 
 557     basic_authorization "test@openstreetmap.org", "test"
 
 562   <node id='-1' lon='0' lat='0' changeset='1' version='1'/>
 
 563   <node id='-1' lon='1' lat='1' changeset='1' version='1'/>
 
 564   <node id='-1' lon='2' lat='2' changeset='1' version='2'/>
 
 571     post :upload, :id => 1
 
 572     assert_response :bad_request, 
 
 573       "shouldn't be able to re-use placeholder IDs"
 
 577   # test what happens if a diff is uploaded containing only a node
 
 579   def test_upload_node_move
 
 580     basic_authorization "test@openstreetmap.org", "test"
 
 582     content "<osm><changeset>" +
 
 583       "<tag k='created_by' v='osm test suite checking changesets'/>" + 
 
 586     assert_response :success
 
 587     changeset_id = @response.body.to_i
 
 589     old_node = current_nodes(:visible_node)
 
 591     diff = XML::Document.new
 
 592     diff.root = XML::Node.new "osmChange"
 
 593     modify = XML::Node.new "modify"
 
 594     xml_old_node = old_node.to_xml_node
 
 595     xml_old_node["lat"] = (2.0).to_s
 
 596     xml_old_node["lon"] = (2.0).to_s
 
 597     xml_old_node["changeset"] = changeset_id.to_s
 
 598     modify << xml_old_node
 
 603     post :upload, :id => changeset_id
 
 604     assert_response :success, 
 
 605       "diff should have uploaded OK"
 
 608     changeset = Changeset.find(changeset_id)
 
 609     assert_equal 1*SCALE, changeset.min_lon, "min_lon should be 1 degree"
 
 610     assert_equal 2*SCALE, changeset.max_lon, "max_lon should be 2 degrees"
 
 611     assert_equal 1*SCALE, changeset.min_lat, "min_lat should be 1 degree"
 
 612     assert_equal 2*SCALE, changeset.max_lat, "max_lat should be 2 degrees"
 
 616   # test what happens if a diff is uploaded adding a node to a way.
 
 617   def test_upload_way_extend
 
 618     basic_authorization "test@openstreetmap.org", "test"
 
 620     content "<osm><changeset>" +
 
 621       "<tag k='created_by' v='osm test suite checking changesets'/>" + 
 
 624     assert_response :success
 
 625     changeset_id = @response.body.to_i
 
 627     old_way = current_ways(:visible_way)
 
 629     diff = XML::Document.new
 
 630     diff.root = XML::Node.new "osmChange"
 
 631     modify = XML::Node.new "modify"
 
 632     xml_old_way = old_way.to_xml_node
 
 633     nd_ref = XML::Node.new "nd"
 
 634     nd_ref["ref"] = current_nodes(:visible_node).id.to_s
 
 635     xml_old_way << nd_ref
 
 636     xml_old_way["changeset"] = changeset_id.to_s
 
 637     modify << xml_old_way
 
 642     post :upload, :id => changeset_id
 
 643     assert_response :success, 
 
 644       "diff should have uploaded OK"
 
 647     changeset = Changeset.find(changeset_id)
 
 648     assert_equal 1*SCALE, changeset.min_lon, "min_lon should be 1 degree"
 
 649     assert_equal 3*SCALE, changeset.max_lon, "max_lon should be 3 degrees"
 
 650     assert_equal 1*SCALE, changeset.min_lat, "min_lat should be 1 degree"
 
 651     assert_equal 3*SCALE, changeset.max_lat, "max_lat should be 3 degrees"
 
 655   # test for more issues in #1568
 
 656   def test_upload_empty_invalid
 
 657     basic_authorization "test@openstreetmap.org", "test"
 
 660       "<osmChange></osmChange>",
 
 661       "<osmChange><modify/></osmChange>",
 
 662       "<osmChange><modify></modify></osmChange>"
 
 666       post :upload, :id => 1
 
 667       assert_response(:success, "should be able to upload " +
 
 668                       "empty changeset: " + diff)
 
 673   # when we make some simple changes we get the same changes back from the 
 
 675   def test_diff_download_simple
 
 676     basic_authorization(users(:normal_user).email, "test")
 
 678     # create a temporary changeset
 
 679     content "<osm><changeset>" +
 
 680       "<tag k='created_by' v='osm test suite checking changesets'/>" + 
 
 683     assert_response :success
 
 684     changeset_id = @response.body.to_i
 
 690   <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
 691   <node id='1' lon='1' lat='0' changeset='#{changeset_id}' version='2'/>
 
 692   <node id='1' lon='1' lat='1' changeset='#{changeset_id}' version='3'/>
 
 693   <node id='1' lon='1' lat='2' changeset='#{changeset_id}' version='4'/>
 
 694   <node id='1' lon='2' lat='2' changeset='#{changeset_id}' version='5'/>
 
 695   <node id='1' lon='3' lat='2' changeset='#{changeset_id}' version='6'/>
 
 696   <node id='1' lon='3' lat='3' changeset='#{changeset_id}' version='7'/>
 
 697   <node id='1' lon='9' lat='9' changeset='#{changeset_id}' version='8'/>
 
 704     post :upload, :id => changeset_id
 
 705     assert_response :success, 
 
 706       "can't upload multiple versions of an element in a diff: #{@response.body}"
 
 708     get :download, :id => changeset_id
 
 709     assert_response :success
 
 711     assert_select "osmChange", 1
 
 712     assert_select "osmChange>modify", 8
 
 713     assert_select "osmChange>modify>node", 8
 
 717   # culled this from josm to ensure that nothing in the way that josm
 
 718   # is formatting the request is causing it to fail.
 
 720   # NOTE: the error turned out to be something else completely!
 
 722     basic_authorization(users(:normal_user).email, "test")
 
 724     # create a temporary changeset
 
 725     content "<osm><changeset>" +
 
 726       "<tag k='created_by' v='osm test suite checking changesets'/>" + 
 
 729     assert_response :success
 
 730     changeset_id = @response.body.to_i
 
 733 <osmChange version="0.6" generator="JOSM">
 
 734 <create version="0.6" generator="JOSM">
 
 735   <node id='-1' visible='true' changeset='#{changeset_id}' lat='51.49619982187321' lon='-0.18722061869438314' />
 
 736   <node id='-2' visible='true' changeset='#{changeset_id}' lat='51.496359883909605' lon='-0.18653093576241928' />
 
 737   <node id='-3' visible='true' changeset='#{changeset_id}' lat='51.49598132358285' lon='-0.18719613290981638' />
 
 738   <node id='-4' visible='true' changeset='#{changeset_id}' lat='51.4961591711078' lon='-0.18629015888084607' />
 
 739   <node id='-5' visible='true' changeset='#{changeset_id}' lat='51.49582126021711' lon='-0.18708186591517145' />
 
 740   <node id='-6' visible='true' changeset='#{changeset_id}' lat='51.49591018437858' lon='-0.1861432441734455' />
 
 741   <node id='-7' visible='true' changeset='#{changeset_id}' lat='51.49560784152179' lon='-0.18694719410005425' />
 
 742   <node id='-8' visible='true' changeset='#{changeset_id}' lat='51.49567389979617' lon='-0.1860289771788006' />
 
 743   <node id='-9' visible='true' changeset='#{changeset_id}' lat='51.49543761398892' lon='-0.186820684213126' />
 
 744   <way id='-10' action='modiy' visible='true' changeset='#{changeset_id}'>
 
 754     <tag k='highway' v='residential' />
 
 755     <tag k='name' v='Foobar Street' />
 
 763     post :upload, :id => changeset_id
 
 764     assert_response :success, 
 
 765       "can't upload a diff from JOSM: #{@response.body}"
 
 767     get :download, :id => changeset_id
 
 768     assert_response :success
 
 770     assert_select "osmChange", 1
 
 771     assert_select "osmChange>create>node", 9
 
 772     assert_select "osmChange>create>way", 1
 
 773     assert_select "osmChange>create>way>nd", 9
 
 774     assert_select "osmChange>create>way>tag", 2
 
 778   # when we make some complex changes we get the same changes back from the 
 
 780   def test_diff_download_complex
 
 781     basic_authorization(users(:normal_user).email, "test")
 
 783     # create a temporary changeset
 
 784     content "<osm><changeset>" +
 
 785       "<tag k='created_by' v='osm test suite checking changesets'/>" + 
 
 788     assert_response :success
 
 789     changeset_id = @response.body.to_i
 
 795   <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
 
 798   <node id='-1' lon='9' lat='9' changeset='#{changeset_id}' version='0'/>
 
 799   <node id='-2' lon='8' lat='9' changeset='#{changeset_id}' version='0'/>
 
 800   <node id='-3' lon='7' lat='9' changeset='#{changeset_id}' version='0'/>
 
 803   <node id='3' lon='20' lat='15' changeset='#{changeset_id}' version='1'/>
 
 804   <way id='1' changeset='#{changeset_id}' version='1'>
 
 816     post :upload, :id => changeset_id
 
 817     assert_response :success, 
 
 818       "can't upload multiple versions of an element in a diff: #{@response.body}"
 
 820     get :download, :id => changeset_id
 
 821     assert_response :success
 
 823     assert_select "osmChange", 1
 
 824     assert_select "osmChange>create", 3
 
 825     assert_select "osmChange>delete", 1
 
 826     assert_select "osmChange>modify", 2
 
 827     assert_select "osmChange>create>node", 3
 
 828     assert_select "osmChange>delete>node", 1 
 
 829     assert_select "osmChange>modify>node", 1
 
 830     assert_select "osmChange>modify>way", 1
 
 834   # check that the bounding box of a changeset gets updated correctly
 
 835   def test_changeset_bbox
 
 836     basic_authorization "test@openstreetmap.org", "test"
 
 838     # create a new changeset
 
 839     content "<osm><changeset/></osm>"
 
 841     assert_response :success, "Creating of changeset failed."
 
 842     changeset_id = @response.body.to_i
 
 844     # add a single node to it
 
 845     with_controller(NodeController.new) do
 
 846       content "<osm><node lon='1' lat='2' changeset='#{changeset_id}'/></osm>"
 
 848       assert_response :success, "Couldn't create node."
 
 851     # get the bounding box back from the changeset
 
 852     get :read, :id => changeset_id
 
 853     assert_response :success, "Couldn't read back changeset."
 
 854     assert_select "osm>changeset[min_lon=1.0]", 1
 
 855     assert_select "osm>changeset[max_lon=1.0]", 1
 
 856     assert_select "osm>changeset[min_lat=2.0]", 1
 
 857     assert_select "osm>changeset[max_lat=2.0]", 1
 
 859     # add another node to it
 
 860     with_controller(NodeController.new) do
 
 861       content "<osm><node lon='2' lat='1' changeset='#{changeset_id}'/></osm>"
 
 863       assert_response :success, "Couldn't create second node."
 
 866     # get the bounding box back from the changeset
 
 867     get :read, :id => changeset_id
 
 868     assert_response :success, "Couldn't read back changeset for the second time."
 
 869     assert_select "osm>changeset[min_lon=1.0]", 1
 
 870     assert_select "osm>changeset[max_lon=2.0]", 1
 
 871     assert_select "osm>changeset[min_lat=1.0]", 1
 
 872     assert_select "osm>changeset[max_lat=2.0]", 1
 
 874     # add (delete) a way to it, which contains a point at (3,3)
 
 875     with_controller(WayController.new) do
 
 876       content update_changeset(current_ways(:visible_way).to_xml,
 
 878       put :delete, :id => current_ways(:visible_way).id
 
 879       assert_response :success, "Couldn't delete a way."
 
 882     # get the bounding box back from the changeset
 
 883     get :read, :id => changeset_id
 
 884     assert_response :success, "Couldn't read back changeset for the third time."
 
 885     # note that the 3.1 here is because of the bbox overexpansion
 
 886     assert_select "osm>changeset[min_lon=1.0]", 1
 
 887     assert_select "osm>changeset[max_lon=3.1]", 1
 
 888     assert_select "osm>changeset[min_lat=1.0]", 1
 
 889     assert_select "osm>changeset[max_lat=3.1]", 1    
 
 893   # test that the changeset :include method works as it should
 
 894   def test_changeset_include
 
 895     basic_authorization "test@openstreetmap.org", "test"
 
 897     # create a new changeset
 
 898     content "<osm><changeset/></osm>"
 
 900     assert_response :success, "Creating of changeset failed."
 
 901     changeset_id = @response.body.to_i
 
 903     # NOTE: the include method doesn't over-expand, like inserting
 
 904     # a real method does. this is because we expect the client to 
 
 905     # know what it is doing!
 
 906     check_after_include(changeset_id,  1,  1, [ 1,  1,  1,  1])
 
 907     check_after_include(changeset_id,  3,  3, [ 1,  1,  3,  3])
 
 908     check_after_include(changeset_id,  4,  2, [ 1,  1,  4,  3])
 
 909     check_after_include(changeset_id,  2,  2, [ 1,  1,  4,  3])
 
 910     check_after_include(changeset_id, -1, -1, [-1, -1,  4,  3])
 
 911     check_after_include(changeset_id, -2,  5, [-2, -1,  4,  5])
 
 915   # test the query functionality of changesets
 
 917     get :query, :bbox => "-10,-10, 10, 10"
 
 918     assert_response :success, "can't get changesets in bbox"
 
 919     assert_changesets [1,4,6]
 
 921     get :query, :bbox => "4.5,4.5,4.6,4.6"
 
 922     assert_response :success, "can't get changesets in bbox"
 
 923     assert_changesets [1]
 
 925     # can't get changesets of user 1 without authenticating
 
 926     get :query, :user => users(:normal_user).id
 
 927     assert_response :not_found, "shouldn't be able to get changesets by non-public user"
 
 929     # but this should work
 
 930     basic_authorization "test@openstreetmap.org", "test"
 
 931     get :query, :user => users(:normal_user).id
 
 932     assert_response :success, "can't get changesets by user"
 
 933     assert_changesets [1,3,4,6]
 
 935     get :query, :user => users(:normal_user).id, :open => true
 
 936     assert_response :success, "can't get changesets by user and open"
 
 937     assert_changesets [1,4]
 
 939     get :query, :time => '2007-12-31'
 
 940     assert_response :success, "can't get changesets by time-since"
 
 941     assert_changesets [1,2,4,5,6]
 
 943     get :query, :time => '2008-01-01T12:34Z'
 
 944     assert_response :success, "can't get changesets by time-since with hour"
 
 945     assert_changesets [1,2,4,5,6]
 
 947     get :query, :time => '2007-12-31T23:59Z,2008-01-01T00:01Z'
 
 948     assert_response :success, "can't get changesets by time-range"
 
 949     assert_changesets [1,4,5,6]
 
 951     get :query, :open => 'true'
 
 952     assert_response :success, "can't get changesets by open-ness"
 
 953     assert_changesets [1,2,4]
 
 957   # check that errors are returned if garbage is inserted 
 
 959   def test_query_invalid
 
 964       get :query, :bbox => bbox
 
 965       assert_response :bad_request, "'#{bbox}' isn't a bbox"
 
 970       ";drop table users;",
 
 974       get :query, :time => time
 
 975       assert_response :bad_request, "'#{time}' isn't a valid time range"
 
 983       get :query, :user => uid
 
 984       assert_response :bad_request, "'#{uid}' isn't a valid user ID"
 
 989   # check updating tags on a changeset
 
 990   def test_changeset_update
 
 991     changeset = changesets(:normal_user_first_change)
 
 992     new_changeset = changeset.to_xml
 
 993     new_tag = XML::Node.new "tag"
 
 994     new_tag['k'] = "tagtesting"
 
 995     new_tag['v'] = "valuetesting"
 
 996     new_changeset.find("//osm/changeset").first << new_tag
 
 997     content new_changeset
 
 999     # try without any authorization
 
1000     put :update, :id => changeset.id
 
1001     assert_response :unauthorized
 
1003     # try with the wrong authorization
 
1004     basic_authorization "test@example.com", "test"
 
1005     put :update, :id => changeset.id
 
1006     assert_response :conflict
 
1008     # now this should work...
 
1009     basic_authorization "test@openstreetmap.org", "test"
 
1010     put :update, :id => changeset.id
 
1011     assert_response :success
 
1013     assert_select "osm>changeset[id=#{changeset.id}]", 1
 
1014     assert_select "osm>changeset>tag", 2
 
1015     assert_select "osm>changeset>tag[k=tagtesting][v=valuetesting]", 1
 
1019   # check that a user different from the one who opened the changeset
 
1021   def test_changeset_update_invalid
 
1022     basic_authorization "test@example.com", "test"
 
1024     changeset = changesets(:normal_user_first_change)
 
1025     new_changeset = changeset.to_xml
 
1026     new_tag = XML::Node.new "tag"
 
1027     new_tag['k'] = "testing"
 
1028     new_tag['v'] = "testing"
 
1029     new_changeset.find("//osm/changeset").first << new_tag
 
1031     content new_changeset
 
1032     put :update, :id => changeset.id
 
1033     assert_response :conflict
 
1037   # check that a changeset can contain a certain max number of changes.
 
1038   def test_changeset_limits
 
1039     basic_authorization "test@openstreetmap.org", "test"
 
1041     # open a new changeset
 
1042     content "<osm><changeset/></osm>"
 
1044     assert_response :success, "can't create a new changeset"
 
1045     cs_id = @response.body.to_i
 
1047     # start the counter just short of where the changeset should finish.
 
1049     # alter the database to set the counter on the changeset directly, 
 
1050     # otherwise it takes about 6 minutes to fill all of them.
 
1051     changeset = Changeset.find(cs_id)
 
1052     changeset.num_changes = Changeset::MAX_ELEMENTS - offset
 
1055     with_controller(NodeController.new) do
 
1057       content "<osm><node changeset='#{cs_id}' lat='0.0' lon='0.0'/></osm>"
 
1059       assert_response :success, "can't create a new node"
 
1060       node_id = @response.body.to_i
 
1062       get :read, :id => node_id
 
1063       assert_response :success, "can't read back new node"
 
1064       node_doc = XML::Parser.string(@response.body).parse
 
1065       node_xml = node_doc.find("//osm/node").first
 
1067       # loop until we fill the changeset with nodes
 
1069         node_xml['lat'] = rand.to_s
 
1070         node_xml['lon'] = rand.to_s
 
1071         node_xml['version'] = (i+1).to_s
 
1074         put :update, :id => node_id
 
1075         assert_response :success, "attempt #{i} should have succeeded"
 
1078       # trying again should fail
 
1079       node_xml['lat'] = rand.to_s
 
1080       node_xml['lon'] = rand.to_s
 
1081       node_xml['version'] = offset.to_s
 
1084       put :update, :id => node_id
 
1085       assert_response :conflict, "final attempt should have failed"
 
1088     changeset = Changeset.find(cs_id)
 
1089     assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
 
1091     # check that the changeset is now closed as well
 
1092     assert(!changeset.is_open?, 
 
1093            "changeset should have been auto-closed by exceeding " + 
 
1097   # This should display the last 20 changesets closed.
 
1099     @changesets = Changeset.find(:all, :order => "created_at DESC", :conditions => ['min_lat IS NOT NULL'], :limit=> 20)
 
1100     assert @changesets.size <= 20
 
1102     assert_response :success
 
1103     assert_template "list"
 
1104     # Now check that all 20 (or however many were returned) changesets are in the html
 
1105     assert_select "h1", :text => "Recent Changes", :count => 1
 
1106     assert_select "table[id='keyvalue'] tr", :count => @changesets.size + 1
 
1107     @changesets.each do |changeset|
 
1108       # FIXME this test needs rewriting - test for table contents
 
1112   #------------------------------------------------------------
 
1114   #------------------------------------------------------------
 
1117   # boilerplate for checking that certain changesets exist in the
 
1119   def assert_changesets(ids)
 
1120     assert_select "osm>changeset", ids.size
 
1122       assert_select "osm>changeset[id=#{id}]", 1
 
1127   # call the include method and assert properties of the bbox
 
1128   def check_after_include(changeset_id, lon, lat, bbox)
 
1129     content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
 
1130     post :expand_bbox, :id => changeset_id
 
1131     assert_response :success, "Setting include of changeset failed: #{@response.body}"
 
1133     # check exactly one changeset
 
1134     assert_select "osm>changeset", 1
 
1135     assert_select "osm>changeset[id=#{changeset_id}]", 1
 
1138     doc = XML::Parser.string(@response.body).parse
 
1139     changeset = doc.find("//osm/changeset").first
 
1140     assert_equal bbox[0], changeset['min_lon'].to_f, "min lon"
 
1141     assert_equal bbox[1], changeset['min_lat'].to_f, "min lat"
 
1142     assert_equal bbox[2], changeset['max_lon'].to_f, "max lon"
 
1143     assert_equal bbox[3], changeset['max_lat'].to_f, "max lat"
 
1147   # update the changeset_id of a way element
 
1148   def update_changeset(xml, changeset_id)
 
1149     xml_attr_rewrite(xml, 'changeset', changeset_id)
 
1153   # update an attribute in a way element
 
1154   def xml_attr_rewrite(xml, name, value)
 
1155     xml.find("//osm/way").first[name] = value.to_s