1 # frozen_string_literal: true
 
   6   class ChangesetsControllerTest < ActionDispatch::IntegrationTest
 
   8     # test all routes which lead to this controller
 
  11         { :path => "/api/0.6/changesets", :method => :get },
 
  12         { :controller => "api/changesets", :action => "index" }
 
  15         { :path => "/api/0.6/changesets.json", :method => :get },
 
  16         { :controller => "api/changesets", :action => "index", :format => "json" }
 
  19         { :path => "/api/0.6/changesets", :method => :post },
 
  20         { :controller => "api/changesets", :action => "create" }
 
  23         { :path => "/api/0.6/changeset/1", :method => :get },
 
  24         { :controller => "api/changesets", :action => "show", :id => "1" }
 
  27         { :path => "/api/0.6/changeset/1.json", :method => :get },
 
  28         { :controller => "api/changesets", :action => "show", :id => "1", :format => "json" }
 
  31         { :path => "/api/0.6/changeset/1", :method => :put },
 
  32         { :controller => "api/changesets", :action => "update", :id => "1" }
 
  36         { :controller => "api/changesets", :action => "create" },
 
  37         { :path => "/api/0.6/changeset/create", :method => :put }
 
  42     # test the query functionality of changesets
 
  44       private_user = create(:user, :data_public => false)
 
  45       private_user_changeset = create(:changeset, :user => private_user)
 
  46       private_user_closed_changeset = create(:changeset, :closed, :user => private_user)
 
  48       changeset = create(:changeset, :user => user)
 
  49       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))
 
  50       changeset2 = create(:changeset, :bbox => [5, 5, 15, 15])
 
  51       changeset3 = create(:changeset, :bbox => [4.5, 4.5, 5, 5])
 
  53       get api_changesets_path(:bbox => "-10,-10, 10, 10")
 
  54       assert_response :success, "can't get changesets in bbox"
 
  55       assert_changesets_in_order [changeset3, changeset2]
 
  57       get api_changesets_path(:bbox => "4.5,4.5,4.6,4.6")
 
  58       assert_response :success, "can't get changesets in bbox"
 
  59       assert_changesets_in_order [changeset3]
 
  61       # not found when looking for changesets of non-existing users
 
  62       get api_changesets_path(:user => User.maximum(:id) + 1)
 
  63       assert_response :not_found
 
  64       assert_equal "text/plain", @response.media_type
 
  65       get api_changesets_path(:display_name => " ")
 
  66       assert_response :not_found
 
  67       assert_equal "text/plain", @response.media_type
 
  69       # can't get changesets of user 1 without authenticating
 
  70       get api_changesets_path(:user => private_user.id)
 
  71       assert_response :not_found, "shouldn't be able to get changesets by non-public user (ID)"
 
  72       get api_changesets_path(:display_name => private_user.display_name)
 
  73       assert_response :not_found, "shouldn't be able to get changesets by non-public user (name)"
 
  75       # but this should work
 
  76       auth_header = bearer_authorization_header private_user
 
  77       get api_changesets_path(:user => private_user.id), :headers => auth_header
 
  78       assert_response :success, "can't get changesets by user ID"
 
  79       assert_changesets_in_order [private_user_changeset, private_user_closed_changeset]
 
  81       get api_changesets_path(:display_name => private_user.display_name), :headers => auth_header
 
  82       assert_response :success, "can't get changesets by user name"
 
  83       assert_changesets_in_order [private_user_changeset, private_user_closed_changeset]
 
  86       get api_changesets_path(:display_name => private_user.display_name), :headers => auth_header, :params => { :format => "json" }
 
  87       assert_response :success, "can't get changesets by user name"
 
  89       js = ActiveSupport::JSON.decode(@response.body)
 
  92       assert_equal Settings.api_version, js["version"]
 
  93       assert_equal Settings.generator, js["generator"]
 
  94       assert_equal 2, js["changesets"].count
 
  96       # check that the correct error is given when we provide both UID and name
 
  97       get api_changesets_path(:user => private_user.id,
 
  98                               :display_name => private_user.display_name), :headers => auth_header
 
  99       assert_response :bad_request, "should be a bad request to have both ID and name specified"
 
 101       get api_changesets_path(:user => private_user.id, :open => true), :headers => auth_header
 
 102       assert_response :success, "can't get changesets by user and open"
 
 103       assert_changesets_in_order [private_user_changeset]
 
 105       get api_changesets_path(:time => "2007-12-31"), :headers => auth_header
 
 106       assert_response :success, "can't get changesets by time-since"
 
 107       assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset, private_user_closed_changeset, closed_changeset]
 
 109       get api_changesets_path(:time => "2008-01-01T12:34Z"), :headers => auth_header
 
 110       assert_response :success, "can't get changesets by time-since with hour"
 
 111       assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset, private_user_closed_changeset, closed_changeset]
 
 113       get api_changesets_path(:time => "2007-12-31T23:59Z,2008-01-02T00:01Z"), :headers => auth_header
 
 114       assert_response :success, "can't get changesets by time-range"
 
 115       assert_changesets_in_order [closed_changeset]
 
 117       get api_changesets_path(:open => "true"), :headers => auth_header
 
 118       assert_response :success, "can't get changesets by open-ness"
 
 119       assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset]
 
 121       get api_changesets_path(:closed => "true"), :headers => auth_header
 
 122       assert_response :success, "can't get changesets by closed-ness"
 
 123       assert_changesets_in_order [private_user_closed_changeset, closed_changeset]
 
 125       get api_changesets_path(:closed => "true", :user => private_user.id), :headers => auth_header
 
 126       assert_response :success, "can't get changesets by closed-ness and user"
 
 127       assert_changesets_in_order [private_user_closed_changeset]
 
 129       get api_changesets_path(:closed => "true", :user => user.id), :headers => auth_header
 
 130       assert_response :success, "can't get changesets by closed-ness and user"
 
 131       assert_changesets_in_order [closed_changeset]
 
 133       get api_changesets_path(:changesets => "#{private_user_changeset.id},#{changeset.id},#{closed_changeset.id}"), :headers => auth_header
 
 134       assert_response :success, "can't get changesets by id (as comma-separated string)"
 
 135       assert_changesets_in_order [changeset, private_user_changeset, closed_changeset]
 
 137       get api_changesets_path(:changesets => ""), :headers => auth_header
 
 138       assert_response :bad_request, "should be a bad request since changesets is empty"
 
 142     # test the query functionality of changesets with the limit parameter
 
 145       changeset1 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 1, 1, 0, 0, 0), :closed_at => Time.utc(2008, 1, 2, 0, 0, 0))
 
 146       changeset2 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 2, 1, 0, 0, 0), :closed_at => Time.utc(2008, 2, 2, 0, 0, 0))
 
 147       changeset3 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 3, 1, 0, 0, 0), :closed_at => Time.utc(2008, 3, 2, 0, 0, 0))
 
 148       changeset4 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 4, 1, 0, 0, 0), :closed_at => Time.utc(2008, 4, 2, 0, 0, 0))
 
 149       changeset5 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 5, 1, 0, 0, 0), :closed_at => Time.utc(2008, 5, 2, 0, 0, 0))
 
 151       get api_changesets_path
 
 152       assert_response :success
 
 153       assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
 
 155       get api_changesets_path(:limit => "3")
 
 156       assert_response :success
 
 157       assert_changesets_in_order [changeset5, changeset4, changeset3]
 
 159       get api_changesets_path(:limit => "0")
 
 160       assert_response :bad_request
 
 162       get api_changesets_path(:limit => Settings.max_changeset_query_limit)
 
 163       assert_response :success
 
 164       assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
 
 166       get api_changesets_path(:limit => Settings.max_changeset_query_limit + 1)
 
 167       assert_response :bad_request
 
 171     # test the query functionality of sequential changesets with order and time parameters
 
 174       changeset1 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 1, 1, 0, 0, 0), :closed_at => Time.utc(2008, 1, 2, 0, 0, 0))
 
 175       changeset2 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 2, 1, 0, 0, 0), :closed_at => Time.utc(2008, 2, 2, 0, 0, 0))
 
 176       changeset3 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 3, 1, 0, 0, 0), :closed_at => Time.utc(2008, 3, 2, 0, 0, 0))
 
 177       changeset4 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 4, 1, 0, 0, 0), :closed_at => Time.utc(2008, 4, 2, 0, 0, 0))
 
 178       changeset5 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 5, 1, 0, 0, 0), :closed_at => Time.utc(2008, 5, 2, 0, 0, 0))
 
 179       changeset6 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 6, 1, 0, 0, 0), :closed_at => Time.utc(2008, 6, 2, 0, 0, 0))
 
 181       get api_changesets_path
 
 182       assert_response :success
 
 183       assert_changesets_in_order [changeset6, changeset5, changeset4, changeset3, changeset2, changeset1]
 
 185       get api_changesets_path(:order => "oldest")
 
 186       assert_response :success
 
 187       assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4, changeset5, changeset6]
 
 190         # lower time bound at the opening time of a changeset
 
 191         ["2008-02-01T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3, changeset2]],
 
 192         # lower time bound in the middle of a changeset
 
 193         ["2008-02-01T12:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
 
 194         # lower time bound at the closing time of a changeset
 
 195         ["2008-02-02T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
 
 196         # lower time bound after the closing time of a changeset
 
 197         ["2008-02-02T00:00:01Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3], [changeset5, changeset4, changeset3]],
 
 198         # upper time bound in the middle of a changeset
 
 199         ["2007-09-09T12:00:00Z", "2008-04-01T12:00:00Z", [changeset4, changeset3, changeset2, changeset1], [changeset4, changeset3, changeset2, changeset1]],
 
 201         ["2009-02-02T00:00:01Z", "2018-05-15T00:00:00Z", [], []]
 
 202       ].each do |from, to, interval_changesets, point_changesets|
 
 203         get api_changesets_path(:time => "#{from},#{to}")
 
 204         assert_response :success
 
 205         assert_changesets_in_order interval_changesets
 
 207         get api_changesets_path(:from => from, :to => to)
 
 208         assert_response :success
 
 209         assert_changesets_in_order point_changesets
 
 211         get api_changesets_path(:from => from, :to => to, :order => "oldest")
 
 212         assert_response :success
 
 213         assert_changesets_in_order point_changesets.reverse
 
 218     # test the query functionality of overlapping changesets with order and time parameters
 
 219     def test_index_order_overlapping
 
 221       changeset1 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 4, 17, 0, 0), :closed_at => Time.utc(2015, 6, 4, 17, 0, 0))
 
 222       changeset2 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 4, 16, 0, 0), :closed_at => Time.utc(2015, 6, 4, 18, 0, 0))
 
 223       changeset3 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 4, 14, 0, 0), :closed_at => Time.utc(2015, 6, 4, 20, 0, 0))
 
 224       changeset4 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 3, 23, 0, 0), :closed_at => Time.utc(2015, 6, 4, 23, 0, 0))
 
 225       create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 2, 23, 0, 0), :closed_at => Time.utc(2015, 6, 3, 23, 0, 0))
 
 227       get api_changesets_path(:time => "2015-06-04T00:00:00Z")
 
 228       assert_response :success
 
 229       assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
 
 231       get api_changesets_path(:from => "2015-06-04T00:00:00Z")
 
 232       assert_response :success
 
 233       assert_changesets_in_order [changeset1, changeset2, changeset3]
 
 235       get api_changesets_path(:from => "2015-06-04T00:00:00Z", :order => "oldest")
 
 236       assert_response :success
 
 237       assert_changesets_in_order [changeset3, changeset2, changeset1]
 
 239       get api_changesets_path(:time => "2015-06-04T16:00:00Z,2015-06-04T17:30:00Z")
 
 240       assert_response :success
 
 241       assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
 
 243       get api_changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z")
 
 244       assert_response :success
 
 245       assert_changesets_in_order [changeset1, changeset2]
 
 247       get api_changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z", :order => "oldest")
 
 248       assert_response :success
 
 249       assert_changesets_in_order [changeset2, changeset1]
 
 253     # check that errors are returned if garbage is inserted
 
 255     def test_index_invalid
 
 258        ";drop table users;"].each do |bbox|
 
 259         get api_changesets_path(:bbox => bbox)
 
 260         assert_response :bad_request, "'#{bbox}' isn't a bbox"
 
 265        ";drop table users;",
 
 267        "-,-"].each do |time|
 
 268         get api_changesets_path(:time => time)
 
 269         assert_response :bad_request, "'#{time}' isn't a valid time range"
 
 276         get api_changesets_path(:user => uid)
 
 277         assert_response :bad_request, "'#{uid}' isn't a valid user ID"
 
 280       get api_changesets_path(:order => "oldest", :time => "2008-01-01T00:00Z,2018-01-01T00:00Z")
 
 281       assert_response :bad_request, "cannot use order=oldest with time"
 
 284     # -----------------------
 
 285     # Test simple changeset creation
 
 286     # -----------------------
 
 290       auth_header = bearer_authorization_header user
 
 291       # Create the first user's changeset
 
 292       xml = "<osm><changeset>" \
 
 293             "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
 296       assert_difference "Changeset.count", 1 do
 
 297         post api_changesets_path, :params => xml, :headers => auth_header
 
 298         assert_response :success, "Creation of changeset did not return success status"
 
 300       newid = @response.body.to_i
 
 302       # check end time, should be an hour ahead of creation time
 
 303       changeset = Changeset.find(newid)
 
 304       duration = changeset.closed_at - changeset.created_at
 
 305       # the difference can either be a rational, or a floating point number
 
 306       # of seconds, depending on the code path taken :-(
 
 307       if duration.instance_of?(Rational)
 
 308         assert_equal Rational(1, 24), duration, "initial idle timeout should be an hour (#{changeset.created_at} -> #{changeset.closed_at})"
 
 310         # must be number of seconds...
 
 311         assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{changeset.created_at} -> #{changeset.closed_at})"
 
 314       assert_equal [user], changeset.subscribers
 
 315       assert_predicate changeset, :num_type_changes_in_sync?
 
 318     def test_create_invalid
 
 319       auth_header = bearer_authorization_header create(:user, :data_public => false)
 
 320       xml = "<osm><changeset></osm>"
 
 321       post api_changesets_path, :params => xml, :headers => auth_header
 
 322       assert_require_public_data
 
 324       ## Try the public user
 
 325       auth_header = bearer_authorization_header
 
 326       xml = "<osm><changeset></osm>"
 
 327       post api_changesets_path, :params => xml, :headers => auth_header
 
 328       assert_response :bad_request, "creating a invalid changeset should fail"
 
 331     def test_create_invalid_no_content
 
 332       ## First check with no auth
 
 333       post api_changesets_path
 
 334       assert_response :unauthorized, "shouldn't be able to create a changeset with no auth"
 
 336       ## Now try to with a non-public user
 
 337       auth_header = bearer_authorization_header create(:user, :data_public => false)
 
 338       post api_changesets_path, :headers => auth_header
 
 339       assert_require_public_data
 
 341       ## Try an inactive user
 
 342       auth_header = bearer_authorization_header create(:user, :pending)
 
 343       post api_changesets_path, :headers => auth_header
 
 346       ## Now try to use a normal user
 
 347       auth_header = bearer_authorization_header
 
 348       post api_changesets_path, :headers => auth_header
 
 349       assert_response :bad_request, "creating a changeset with no content should fail"
 
 352     def test_create_wrong_method
 
 353       auth_header = bearer_authorization_header
 
 355       put api_changesets_path, :headers => auth_header
 
 356       assert_response :not_found
 
 357       assert_template "rescues/routing_error"
 
 360     def test_create_legacy_path
 
 361       auth_header = bearer_authorization_header
 
 362       xml = "<osm><changeset></changeset></osm>"
 
 364       assert_difference "Changeset.count", 1 do
 
 365         put "/api/0.6/changeset/create", :params => xml, :headers => auth_header
 
 368       assert_response :success, "Creation of changeset did not return success status"
 
 369       assert_equal Changeset.last.id, @response.body.to_i
 
 373     # check that the changeset can be shown and returns the correct
 
 374     # document structure.
 
 376       changeset = create(:changeset)
 
 378       get api_changeset_path(changeset)
 
 379       assert_response :success, "cannot get first changeset"
 
 381       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 382       assert_single_changeset changeset do
 
 383         assert_dom "> discussion", 0
 
 386       get api_changeset_path(changeset, :include_discussion => true)
 
 387       assert_response :success, "cannot get first changeset with comments"
 
 389       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 390       assert_single_changeset changeset do
 
 391         assert_dom "> discussion", 1
 
 392         assert_dom "> discussion > comment", 0
 
 396     def test_show_comments
 
 397       # all comments visible
 
 398       changeset = create(:changeset, :closed)
 
 399       comment1, comment2, comment3 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
 
 401       get api_changeset_path(changeset, :include_discussion => true)
 
 402       assert_response :success, "cannot get closed changeset with comments"
 
 404       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
 
 405         assert_single_changeset changeset do
 
 406           assert_dom "> discussion", 1 do
 
 407             assert_dom "> comment", 3 do |dom_comments|
 
 408               assert_dom dom_comments[0], "> @id", comment1.id.to_s
 
 409               assert_dom dom_comments[0], "> @visible", "true"
 
 410               assert_dom dom_comments[1], "> @id", comment2.id.to_s
 
 411               assert_dom dom_comments[1], "> @visible", "true"
 
 412               assert_dom dom_comments[2], "> @id", comment3.id.to_s
 
 413               assert_dom dom_comments[2], "> @visible", "true"
 
 419       # one hidden comment not included because not asked for
 
 420       comment2.update(:visible => false)
 
 423       get api_changeset_path(changeset, :include_discussion => true)
 
 424       assert_response :success, "cannot get closed changeset with comments"
 
 426       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 427       assert_single_changeset changeset do
 
 428         assert_dom "> discussion", 1 do
 
 429           assert_dom "> comment", 2 do |dom_comments|
 
 430             assert_dom dom_comments[0], "> @id", comment1.id.to_s
 
 431             assert_dom dom_comments[0], "> @visible", "true"
 
 432             assert_dom dom_comments[1], "> @id", comment3.id.to_s
 
 433             assert_dom dom_comments[1], "> @visible", "true"
 
 438       # one hidden comment not included because no permissions
 
 439       get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true)
 
 440       assert_response :success, "cannot get closed changeset with comments"
 
 442       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 443       assert_single_changeset changeset do
 
 444         assert_dom "> discussion", 1 do
 
 445           assert_dom "> comment", 2 do |dom_comments|
 
 446             assert_dom dom_comments[0], "> @id", comment1.id.to_s
 
 447             assert_dom dom_comments[0], "> @visible", "true"
 
 448             # maybe will show an empty comment element with visible=false in the future
 
 449             assert_dom dom_comments[1], "> @id", comment3.id.to_s
 
 450             assert_dom dom_comments[1], "> @visible", "true"
 
 455       # one hidden comment shown to moderators
 
 456       moderator_user = create(:moderator_user)
 
 457       auth_header = bearer_authorization_header moderator_user
 
 458       get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
 
 459       assert_response :success, "cannot get closed changeset with comments"
 
 461       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 462       assert_single_changeset changeset do
 
 463         assert_dom "> discussion", 1 do
 
 464           assert_dom "> comment", 3 do |dom_comments|
 
 465             assert_dom dom_comments[0], "> @id", comment1.id.to_s
 
 466             assert_dom dom_comments[0], "> @visible", "true"
 
 467             assert_dom dom_comments[1], "> @id", comment2.id.to_s
 
 468             assert_dom dom_comments[1], "> @visible", "false"
 
 469             assert_dom dom_comments[2], "> @id", comment3.id.to_s
 
 470             assert_dom dom_comments[2], "> @visible", "true"
 
 477       changeset = create(:changeset, :closed)
 
 478       create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
 
 479       create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
 
 481       get api_changeset_path(changeset)
 
 483       assert_response :success
 
 484       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
 
 485       assert_single_changeset changeset do
 
 486         assert_dom "> tag", 2
 
 487         assert_dom "> tag[k='created_by'][v='JOSM/1.5 (18364)']", 1
 
 488         assert_dom "> tag[k='comment'][v='changeset comment']", 1
 
 493       changeset = create(:changeset)
 
 495       get api_changeset_path(changeset, :format => "json")
 
 496       assert_response :success, "cannot get first changeset"
 
 498       js = ActiveSupport::JSON.decode(@response.body)
 
 501       assert_equal Settings.api_version, js["version"]
 
 502       assert_equal Settings.generator, js["generator"]
 
 503       assert_single_changeset_json changeset, js
 
 504       assert_nil js["changeset"]["tags"]
 
 505       assert_nil js["changeset"]["comments"]
 
 506       assert_equal changeset.user.id, js["changeset"]["uid"]
 
 507       assert_equal changeset.user.display_name, js["changeset"]["user"]
 
 509       get api_changeset_path(changeset, :format => "json", :include_discussion => true)
 
 510       assert_response :success, "cannot get first changeset with comments"
 
 512       js = ActiveSupport::JSON.decode(@response.body)
 
 514       assert_equal Settings.api_version, js["version"]
 
 515       assert_equal Settings.generator, js["generator"]
 
 516       assert_single_changeset_json changeset, js
 
 517       assert_nil js["changeset"]["tags"]
 
 518       assert_nil js["changeset"]["min_lat"]
 
 519       assert_nil js["changeset"]["min_lon"]
 
 520       assert_nil js["changeset"]["max_lat"]
 
 521       assert_nil js["changeset"]["max_lon"]
 
 522       assert_equal 0, js["changeset"]["comments"].count
 
 525     def test_show_comments_json
 
 526       # all comments visible
 
 527       changeset = create(:changeset, :closed)
 
 528       comment0, comment1, comment2 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
 
 530       get api_changeset_path(changeset, :format => "json", :include_discussion => true)
 
 531       assert_response :success, "cannot get closed changeset with comments"
 
 533       js = ActiveSupport::JSON.decode(@response.body)
 
 535       assert_equal Settings.api_version, js["version"]
 
 536       assert_equal Settings.generator, js["generator"]
 
 537       assert_single_changeset_json changeset, js
 
 538       assert_equal 3, js["changeset"]["comments"].count
 
 539       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
 
 540       assert js["changeset"]["comments"][0]["visible"]
 
 541       assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
 
 542       assert js["changeset"]["comments"][1]["visible"]
 
 543       assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
 
 544       assert js["changeset"]["comments"][2]["visible"]
 
 546       # one hidden comment not included because not asked for
 
 547       comment1.update(:visible => false)
 
 550       get api_changeset_path(changeset, :format => "json", :include_discussion => true)
 
 551       assert_response :success, "cannot get closed changeset with comments"
 
 553       js = ActiveSupport::JSON.decode(@response.body)
 
 555       assert_equal Settings.api_version, js["version"]
 
 556       assert_equal Settings.generator, js["generator"]
 
 557       assert_single_changeset_json changeset, js
 
 558       assert_equal 2, js["changeset"]["comments"].count
 
 559       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
 
 560       assert js["changeset"]["comments"][0]["visible"]
 
 561       assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
 
 562       assert js["changeset"]["comments"][1]["visible"]
 
 564       # one hidden comment not included because no permissions
 
 565       get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true)
 
 566       assert_response :success, "cannot get closed changeset with comments"
 
 568       js = ActiveSupport::JSON.decode(@response.body)
 
 570       assert_equal Settings.api_version, js["version"]
 
 571       assert_equal Settings.generator, js["generator"]
 
 572       assert_single_changeset_json changeset, js
 
 573       assert_equal 2, js["changeset"]["comments"].count
 
 574       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
 
 575       assert js["changeset"]["comments"][0]["visible"]
 
 576       # maybe will show an empty comment element with visible=false in the future
 
 577       assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
 
 578       assert js["changeset"]["comments"][1]["visible"]
 
 580       # one hidden comment shown to moderators
 
 581       moderator_user = create(:moderator_user)
 
 582       auth_header = bearer_authorization_header moderator_user
 
 583       get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
 
 584       assert_response :success, "cannot get closed changeset with comments"
 
 586       js = ActiveSupport::JSON.decode(@response.body)
 
 588       assert_equal Settings.api_version, js["version"]
 
 589       assert_equal Settings.generator, js["generator"]
 
 590       assert_single_changeset_json changeset, js
 
 591       assert_equal 3, js["changeset"]["comments"].count
 
 592       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
 
 593       assert js["changeset"]["comments"][0]["visible"]
 
 594       assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
 
 595       assert_not js["changeset"]["comments"][1]["visible"]
 
 596       assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
 
 597       assert js["changeset"]["comments"][2]["visible"]
 
 600     def test_show_tags_json
 
 601       changeset = create(:changeset, :closed)
 
 602       create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
 
 603       create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
 
 605       get api_changeset_path(changeset, :format => "json")
 
 607       assert_response :success
 
 608       js = ActiveSupport::JSON.decode(@response.body)
 
 610       assert_equal Settings.api_version, js["version"]
 
 611       assert_equal Settings.generator, js["generator"]
 
 612       assert_single_changeset_json changeset, js
 
 613       assert_equal 2, js["changeset"]["tags"].count
 
 614       assert_equal "JOSM/1.5 (18364)", js["changeset"]["tags"]["created_by"]
 
 615       assert_equal "changeset comment", js["changeset"]["tags"]["comment"]
 
 618     def test_show_bbox_json
 
 619       changeset = create(:changeset, :bbox => [5, -5, 12, 15])
 
 621       get api_changeset_path(changeset, :format => "json")
 
 622       assert_response :success, "cannot get first changeset"
 
 624       js = ActiveSupport::JSON.decode(@response.body)
 
 626       assert_equal(-5, js["changeset"]["min_lat"])
 
 627       assert_equal 5, js["changeset"]["min_lon"]
 
 628       assert_equal 15, js["changeset"]["max_lat"]
 
 629       assert_equal 12, js["changeset"]["max_lon"]
 
 633     # check that a changeset that doesn't exist returns an appropriate message
 
 634     def test_show_not_found
 
 635       [0, -32, 233455644, "afg", "213"].each do |id|
 
 636         get api_changeset_path(id)
 
 637         assert_response :not_found, "should get a not found"
 
 638       rescue ActionController::UrlGenerationError => e
 
 639         assert_match(/No route matches/, e.to_s)
 
 643     def test_repeated_changeset_create
 
 645         auth_header = bearer_authorization_header
 
 647         # create a temporary changeset
 
 648         xml = "<osm><changeset>" \
 
 649               "<tag k='created_by' v='osm test suite checking changesets'/>" \
 
 651         assert_difference "Changeset.count", 1 do
 
 652           post api_changesets_path, :params => xml, :headers => auth_header
 
 654         assert_response :success
 
 659     # check updating tags on a changeset
 
 660     def test_changeset_update
 
 661       private_user = create(:user, :data_public => false)
 
 662       private_changeset = create(:changeset, :user => private_user)
 
 664       changeset = create(:changeset, :user => user)
 
 666       ## First try with a non-public user
 
 667       new_changeset = create_changeset_xml(:user => private_user)
 
 668       new_tag = XML::Node.new "tag"
 
 669       new_tag["k"] = "tagtesting"
 
 670       new_tag["v"] = "valuetesting"
 
 671       new_changeset.find("//osm/changeset").first << new_tag
 
 673       # try without any authorization
 
 674       put api_changeset_path(private_changeset), :params => new_changeset.to_s
 
 675       assert_response :unauthorized
 
 677       # try with the wrong authorization
 
 678       auth_header = bearer_authorization_header
 
 679       put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
 
 680       assert_response :conflict
 
 682       # now this should get an unauthorized
 
 683       auth_header = bearer_authorization_header private_user
 
 684       put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
 
 685       assert_require_public_data "user with their data non-public, shouldn't be able to edit their changeset"
 
 687       ## Now try with the public user
 
 688       new_changeset = create_changeset_xml(:id => 1)
 
 689       new_tag = XML::Node.new "tag"
 
 690       new_tag["k"] = "tagtesting"
 
 691       new_tag["v"] = "valuetesting"
 
 692       new_changeset.find("//osm/changeset").first << new_tag
 
 694       # try without any authorization
 
 695       put api_changeset_path(changeset), :params => new_changeset.to_s
 
 696       assert_response :unauthorized
 
 698       # try with the wrong authorization
 
 699       auth_header = bearer_authorization_header
 
 700       put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
 
 701       assert_response :conflict
 
 703       # now this should work...
 
 704       auth_header = bearer_authorization_header user
 
 705       put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
 
 706       assert_response :success
 
 708       assert_select "osm>changeset[id='#{changeset.id}']", 1
 
 709       assert_select "osm>changeset>tag", 1
 
 710       assert_select "osm>changeset>tag[k='tagtesting'][v='valuetesting']", 1
 
 714     # check that a user different from the one who opened the changeset
 
 716     def test_changeset_update_invalid
 
 717       auth_header = bearer_authorization_header
 
 719       changeset = create(:changeset)
 
 720       new_changeset = create_changeset_xml(:user => changeset.user, :id => changeset.id)
 
 721       new_tag = XML::Node.new "tag"
 
 722       new_tag["k"] = "testing"
 
 723       new_tag["v"] = "testing"
 
 724       new_changeset.find("//osm/changeset").first << new_tag
 
 726       put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
 
 727       assert_response :conflict
 
 731     # check that a changeset can contain a certain max number of changes.
 
 732     ## FIXME should be changed to an integration test due to the with_controller
 
 733     def test_changeset_limits
 
 735       auth_header = bearer_authorization_header user
 
 737       # create an old changeset to ensure we have the maximum rate limit
 
 738       create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
 
 740       # open a new changeset
 
 741       xml = "<osm><changeset/></osm>"
 
 742       post api_changesets_path, :params => xml, :headers => auth_header
 
 743       assert_response :success, "can't create a new changeset"
 
 744       changeset_id = @response.body.to_i
 
 746       # start the counter just short of where the changeset should finish.
 
 748       # alter the database to set the counter on the changeset directly,
 
 749       # otherwise it takes about 6 minutes to fill all of them.
 
 750       changeset = Changeset.find(changeset_id)
 
 751       changeset.num_changes = Changeset::MAX_ELEMENTS - offset
 
 754       with_controller(NodesController.new) do
 
 756         xml = "<osm><node changeset='#{changeset_id}' lat='0.0' lon='0.0'/></osm>"
 
 757         post api_nodes_path, :params => xml, :headers => auth_header
 
 758         assert_response :success, "can't create a new node"
 
 759         node_id = @response.body.to_i
 
 761         get api_node_path(node_id)
 
 762         assert_response :success, "can't read back new node"
 
 763         node_doc = XML::Parser.string(@response.body).parse
 
 764         node_xml = node_doc.find("//osm/node").first
 
 766         # loop until we fill the changeset with nodes
 
 768           node_xml["lat"] = rand.to_s
 
 769           node_xml["lon"] = rand.to_s
 
 770           node_xml["version"] = (i + 1).to_s
 
 772           put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
 
 773           assert_response :success, "attempt #{i} should have succeeded"
 
 776         # trying again should fail
 
 777         node_xml["lat"] = rand.to_s
 
 778         node_xml["lon"] = rand.to_s
 
 779         node_xml["version"] = offset.to_s
 
 781         put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
 
 782         assert_response :conflict, "final attempt should have failed"
 
 785       changeset = Changeset.find(changeset_id)
 
 786       assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
 
 788       # check that the changeset is now closed as well
 
 789       assert_not(changeset.open?,
 
 790                  "changeset should have been auto-closed by exceeding " \
 
 797     # check that the output consists of one specific changeset
 
 798     def assert_single_changeset(changeset, &)
 
 799       assert_dom "> changeset", 1 do
 
 800         assert_dom "> @id", changeset.id.to_s
 
 801         assert_dom "> @created_at", changeset.created_at.xmlschema
 
 803           assert_dom "> @open", "true"
 
 804           assert_dom "> @closed_at", 0
 
 806           assert_dom "> @open", "false"
 
 807           assert_dom "> @closed_at", changeset.closed_at.xmlschema
 
 809         assert_dom "> @comments_count", changeset.comments.length.to_s
 
 810         assert_dom "> @changes_count", changeset.num_changes.to_s
 
 811         yield if block_given?
 
 815     def assert_single_changeset_json(changeset, js)
 
 816       assert_equal changeset.id, js["changeset"]["id"]
 
 817       assert_equal changeset.created_at.xmlschema, js["changeset"]["created_at"]
 
 819         assert js["changeset"]["open"]
 
 820         assert_nil js["changeset"]["closed_at"]
 
 822         assert_not js["changeset"]["open"]
 
 823         assert_equal changeset.closed_at.xmlschema, js["changeset"]["closed_at"]
 
 825       assert_equal changeset.comments.length, js["changeset"]["comments_count"]
 
 826       assert_equal changeset.num_changes, js["changeset"]["changes_count"]
 
 830     # check that certain changesets exist in the output in the specified order
 
 831     def assert_changesets_in_order(changesets)
 
 832       assert_select "osm>changeset", changesets.size
 
 833       changesets.each_with_index do |changeset, index|
 
 834         assert_select "osm>changeset:nth-child(#{index + 1})[id='#{changeset.id}']", 1
 
 839     # build XML for changesets
 
 840     def create_changeset_xml(user: nil, id: nil)
 
 841       root = XML::Document.new
 
 842       root.root = XML::Node.new "osm"
 
 843       changeset = XML::Node.new "changeset"
 
 845         changeset["user"] = user.display_name
 
 846         changeset["uid"] = user.id.to_s
 
 848       changeset["id"] = id.to_s if id
 
 849       root.root << changeset