4 class ChangesetsControllerTest < ActionDispatch::IntegrationTest
6 # test all routes which lead to this controller
9 { :path => "/api/0.6/changesets", :method => :get },
10 { :controller => "api/changesets", :action => "index" }
13 { :path => "/api/0.6/changesets.json", :method => :get },
14 { :controller => "api/changesets", :action => "index", :format => "json" }
17 { :path => "/api/0.6/changesets", :method => :post },
18 { :controller => "api/changesets", :action => "create" }
21 { :path => "/api/0.6/changeset/1", :method => :get },
22 { :controller => "api/changesets", :action => "show", :id => "1" }
25 { :path => "/api/0.6/changeset/1.json", :method => :get },
26 { :controller => "api/changesets", :action => "show", :id => "1", :format => "json" }
29 { :path => "/api/0.6/changeset/1", :method => :put },
30 { :controller => "api/changesets", :action => "update", :id => "1" }
33 { :path => "/api/0.6/changeset/1/upload", :method => :post },
34 { :controller => "api/changesets", :action => "upload", :id => "1" }
37 { :path => "/api/0.6/changeset/1/close", :method => :put },
38 { :controller => "api/changesets", :action => "close", :id => "1" }
42 { :controller => "api/changesets", :action => "create" },
43 { :path => "/api/0.6/changeset/create", :method => :put }
48 # test the query functionality of changesets
50 private_user = create(:user, :data_public => false)
51 private_user_changeset = create(:changeset, :user => private_user)
52 private_user_closed_changeset = create(:changeset, :closed, :user => private_user)
54 changeset = create(:changeset, :user => user)
55 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))
56 changeset2 = create(:changeset, :bbox => [5, 5, 15, 15])
57 changeset3 = create(:changeset, :bbox => [4.5, 4.5, 5, 5])
59 get api_changesets_path(:bbox => "-10,-10, 10, 10")
60 assert_response :success, "can't get changesets in bbox"
61 assert_changesets_in_order [changeset3, changeset2]
63 get api_changesets_path(:bbox => "4.5,4.5,4.6,4.6")
64 assert_response :success, "can't get changesets in bbox"
65 assert_changesets_in_order [changeset3]
67 # not found when looking for changesets of non-existing users
68 get api_changesets_path(:user => User.maximum(:id) + 1)
69 assert_response :not_found
70 assert_equal "text/plain", @response.media_type
71 get api_changesets_path(:display_name => " ")
72 assert_response :not_found
73 assert_equal "text/plain", @response.media_type
75 # can't get changesets of user 1 without authenticating
76 get api_changesets_path(:user => private_user.id)
77 assert_response :not_found, "shouldn't be able to get changesets by non-public user (ID)"
78 get api_changesets_path(:display_name => private_user.display_name)
79 assert_response :not_found, "shouldn't be able to get changesets by non-public user (name)"
81 # but this should work
82 auth_header = bearer_authorization_header private_user
83 get api_changesets_path(:user => private_user.id), :headers => auth_header
84 assert_response :success, "can't get changesets by user ID"
85 assert_changesets_in_order [private_user_changeset, private_user_closed_changeset]
87 get api_changesets_path(:display_name => private_user.display_name), :headers => auth_header
88 assert_response :success, "can't get changesets by user name"
89 assert_changesets_in_order [private_user_changeset, private_user_closed_changeset]
92 get api_changesets_path(:display_name => private_user.display_name), :headers => auth_header, :params => { :format => "json" }
93 assert_response :success, "can't get changesets by user name"
95 js = ActiveSupport::JSON.decode(@response.body)
98 assert_equal Settings.api_version, js["version"]
99 assert_equal Settings.generator, js["generator"]
100 assert_equal 2, js["changesets"].count
102 # check that the correct error is given when we provide both UID and name
103 get api_changesets_path(:user => private_user.id,
104 :display_name => private_user.display_name), :headers => auth_header
105 assert_response :bad_request, "should be a bad request to have both ID and name specified"
107 get api_changesets_path(:user => private_user.id, :open => true), :headers => auth_header
108 assert_response :success, "can't get changesets by user and open"
109 assert_changesets_in_order [private_user_changeset]
111 get api_changesets_path(:time => "2007-12-31"), :headers => auth_header
112 assert_response :success, "can't get changesets by time-since"
113 assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset, private_user_closed_changeset, closed_changeset]
115 get api_changesets_path(:time => "2008-01-01T12:34Z"), :headers => auth_header
116 assert_response :success, "can't get changesets by time-since with hour"
117 assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset, private_user_closed_changeset, closed_changeset]
119 get api_changesets_path(:time => "2007-12-31T23:59Z,2008-01-02T00:01Z"), :headers => auth_header
120 assert_response :success, "can't get changesets by time-range"
121 assert_changesets_in_order [closed_changeset]
123 get api_changesets_path(:open => "true"), :headers => auth_header
124 assert_response :success, "can't get changesets by open-ness"
125 assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset]
127 get api_changesets_path(:closed => "true"), :headers => auth_header
128 assert_response :success, "can't get changesets by closed-ness"
129 assert_changesets_in_order [private_user_closed_changeset, closed_changeset]
131 get api_changesets_path(:closed => "true", :user => private_user.id), :headers => auth_header
132 assert_response :success, "can't get changesets by closed-ness and user"
133 assert_changesets_in_order [private_user_closed_changeset]
135 get api_changesets_path(:closed => "true", :user => user.id), :headers => auth_header
136 assert_response :success, "can't get changesets by closed-ness and user"
137 assert_changesets_in_order [closed_changeset]
139 get api_changesets_path(:changesets => "#{private_user_changeset.id},#{changeset.id},#{closed_changeset.id}"), :headers => auth_header
140 assert_response :success, "can't get changesets by id (as comma-separated string)"
141 assert_changesets_in_order [changeset, private_user_changeset, closed_changeset]
143 get api_changesets_path(:changesets => ""), :headers => auth_header
144 assert_response :bad_request, "should be a bad request since changesets is empty"
148 # test the query functionality of changesets with the limit parameter
151 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))
152 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))
153 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))
154 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))
155 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))
157 get api_changesets_path
158 assert_response :success
159 assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
161 get api_changesets_path(:limit => "3")
162 assert_response :success
163 assert_changesets_in_order [changeset5, changeset4, changeset3]
165 get api_changesets_path(:limit => "0")
166 assert_response :bad_request
168 get api_changesets_path(:limit => Settings.max_changeset_query_limit)
169 assert_response :success
170 assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
172 get api_changesets_path(:limit => Settings.max_changeset_query_limit + 1)
173 assert_response :bad_request
177 # test the query functionality of sequential changesets with order and time parameters
180 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))
181 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))
182 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))
183 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))
184 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))
185 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))
187 get api_changesets_path
188 assert_response :success
189 assert_changesets_in_order [changeset6, changeset5, changeset4, changeset3, changeset2, changeset1]
191 get api_changesets_path(:order => "oldest")
192 assert_response :success
193 assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4, changeset5, changeset6]
196 # lower time bound at the opening time of a changeset
197 ["2008-02-01T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3, changeset2]],
198 # lower time bound in the middle of a changeset
199 ["2008-02-01T12:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
200 # lower time bound at the closing time of a changeset
201 ["2008-02-02T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
202 # lower time bound after the closing time of a changeset
203 ["2008-02-02T00:00:01Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3], [changeset5, changeset4, changeset3]],
204 # upper time bound in the middle of a changeset
205 ["2007-09-09T12:00:00Z", "2008-04-01T12:00:00Z", [changeset4, changeset3, changeset2, changeset1], [changeset4, changeset3, changeset2, changeset1]],
207 ["2009-02-02T00:00:01Z", "2018-05-15T00:00:00Z", [], []]
208 ].each do |from, to, interval_changesets, point_changesets|
209 get api_changesets_path(:time => "#{from},#{to}")
210 assert_response :success
211 assert_changesets_in_order interval_changesets
213 get api_changesets_path(:from => from, :to => to)
214 assert_response :success
215 assert_changesets_in_order point_changesets
217 get api_changesets_path(:from => from, :to => to, :order => "oldest")
218 assert_response :success
219 assert_changesets_in_order point_changesets.reverse
224 # test the query functionality of overlapping changesets with order and time parameters
225 def test_index_order_overlapping
227 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))
228 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))
229 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))
230 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))
231 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))
233 get api_changesets_path(:time => "2015-06-04T00:00:00Z")
234 assert_response :success
235 assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
237 get api_changesets_path(:from => "2015-06-04T00:00:00Z")
238 assert_response :success
239 assert_changesets_in_order [changeset1, changeset2, changeset3]
241 get api_changesets_path(:from => "2015-06-04T00:00:00Z", :order => "oldest")
242 assert_response :success
243 assert_changesets_in_order [changeset3, changeset2, changeset1]
245 get api_changesets_path(:time => "2015-06-04T16:00:00Z,2015-06-04T17:30:00Z")
246 assert_response :success
247 assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
249 get api_changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z")
250 assert_response :success
251 assert_changesets_in_order [changeset1, changeset2]
253 get api_changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z", :order => "oldest")
254 assert_response :success
255 assert_changesets_in_order [changeset2, changeset1]
259 # check that errors are returned if garbage is inserted
261 def test_index_invalid
264 ";drop table users;"].each do |bbox|
265 get api_changesets_path(:bbox => bbox)
266 assert_response :bad_request, "'#{bbox}' isn't a bbox"
271 ";drop table users;",
273 "-,-"].each do |time|
274 get api_changesets_path(:time => time)
275 assert_response :bad_request, "'#{time}' isn't a valid time range"
282 get api_changesets_path(:user => uid)
283 assert_response :bad_request, "'#{uid}' isn't a valid user ID"
286 get api_changesets_path(:order => "oldest", :time => "2008-01-01T00:00Z,2018-01-01T00:00Z")
287 assert_response :bad_request, "cannot use order=oldest with time"
290 # -----------------------
291 # Test simple changeset creation
292 # -----------------------
295 auth_header = bearer_authorization_header create(:user, :data_public => false)
296 # Create the first user's changeset
297 xml = "<osm><changeset>" \
298 "<tag k='created_by' v='osm test suite checking changesets'/>" \
300 post api_changesets_path, :params => xml, :headers => auth_header
301 assert_require_public_data
303 auth_header = bearer_authorization_header
304 # Create the first user's changeset
305 xml = "<osm><changeset>" \
306 "<tag k='created_by' v='osm test suite checking changesets'/>" \
308 post api_changesets_path, :params => xml, :headers => auth_header
310 assert_response :success, "Creation of changeset did not return success status"
311 newid = @response.body.to_i
313 # check end time, should be an hour ahead of creation time
314 cs = Changeset.find(newid)
315 duration = cs.closed_at - cs.created_at
316 # the difference can either be a rational, or a floating point number
317 # of seconds, depending on the code path taken :-(
318 if duration.instance_of?(Rational)
319 assert_equal Rational(1, 24), duration, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
321 # must be number of seconds...
322 assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
325 # checks if uploader was subscribed
326 assert_equal 1, cs.subscribers.length
329 def test_create_invalid
330 auth_header = bearer_authorization_header create(:user, :data_public => false)
331 xml = "<osm><changeset></osm>"
332 post api_changesets_path, :params => xml, :headers => auth_header
333 assert_require_public_data
335 ## Try the public user
336 auth_header = bearer_authorization_header
337 xml = "<osm><changeset></osm>"
338 post api_changesets_path, :params => xml, :headers => auth_header
339 assert_response :bad_request, "creating a invalid changeset should fail"
342 def test_create_invalid_no_content
343 ## First check with no auth
344 post api_changesets_path
345 assert_response :unauthorized, "shouldn't be able to create a changeset with no auth"
347 ## Now try to with a non-public user
348 auth_header = bearer_authorization_header create(:user, :data_public => false)
349 post api_changesets_path, :headers => auth_header
350 assert_require_public_data
352 ## Try an inactive user
353 auth_header = bearer_authorization_header create(:user, :pending)
354 post api_changesets_path, :headers => auth_header
357 ## Now try to use a normal user
358 auth_header = bearer_authorization_header
359 post api_changesets_path, :headers => auth_header
360 assert_response :bad_request, "creating a changeset with no content should fail"
363 def test_create_wrong_method
364 auth_header = bearer_authorization_header
366 put api_changesets_path, :headers => auth_header
367 assert_response :not_found
368 assert_template "rescues/routing_error"
371 def test_create_legacy_path
372 auth_header = bearer_authorization_header
373 xml = "<osm><changeset></changeset></osm>"
375 assert_difference "Changeset.count", 1 do
376 put "/api/0.6/changeset/create", :params => xml, :headers => auth_header
379 assert_response :success, "Creation of changeset did not return success status"
380 assert_equal Changeset.last.id, @response.body.to_i
384 # check that the changeset can be shown and returns the correct
385 # document structure.
387 changeset = create(:changeset)
389 get api_changeset_path(changeset)
390 assert_response :success, "cannot get first changeset"
392 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
393 assert_single_changeset changeset do
394 assert_dom "> discussion", 0
397 get api_changeset_path(changeset, :include_discussion => true)
398 assert_response :success, "cannot get first changeset with comments"
400 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
401 assert_single_changeset changeset do
402 assert_dom "> discussion", 1
403 assert_dom "> discussion > comment", 0
407 def test_show_comments
408 # all comments visible
409 changeset = create(:changeset, :closed)
410 comment1, comment2, comment3 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
412 get api_changeset_path(changeset, :include_discussion => true)
413 assert_response :success, "cannot get closed changeset with comments"
415 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
416 assert_single_changeset changeset do
417 assert_dom "> discussion", 1 do
418 assert_dom "> comment", 3 do |dom_comments|
419 assert_dom dom_comments[0], "> @id", comment1.id.to_s
420 assert_dom dom_comments[0], "> @visible", "true"
421 assert_dom dom_comments[1], "> @id", comment2.id.to_s
422 assert_dom dom_comments[1], "> @visible", "true"
423 assert_dom dom_comments[2], "> @id", comment3.id.to_s
424 assert_dom dom_comments[2], "> @visible", "true"
430 # one hidden comment not included because not asked for
431 comment2.update(:visible => false)
434 get api_changeset_path(changeset, :include_discussion => true)
435 assert_response :success, "cannot get closed changeset with comments"
437 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
438 assert_single_changeset changeset do
439 assert_dom "> discussion", 1 do
440 assert_dom "> comment", 2 do |dom_comments|
441 assert_dom dom_comments[0], "> @id", comment1.id.to_s
442 assert_dom dom_comments[0], "> @visible", "true"
443 assert_dom dom_comments[1], "> @id", comment3.id.to_s
444 assert_dom dom_comments[1], "> @visible", "true"
449 # one hidden comment not included because no permissions
450 get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true)
451 assert_response :success, "cannot get closed changeset with comments"
453 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
454 assert_single_changeset changeset do
455 assert_dom "> discussion", 1 do
456 assert_dom "> comment", 2 do |dom_comments|
457 assert_dom dom_comments[0], "> @id", comment1.id.to_s
458 assert_dom dom_comments[0], "> @visible", "true"
459 # maybe will show an empty comment element with visible=false in the future
460 assert_dom dom_comments[1], "> @id", comment3.id.to_s
461 assert_dom dom_comments[1], "> @visible", "true"
466 # one hidden comment shown to moderators
467 moderator_user = create(:moderator_user)
468 auth_header = bearer_authorization_header moderator_user
469 get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
470 assert_response :success, "cannot get closed changeset with comments"
472 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
473 assert_single_changeset changeset do
474 assert_dom "> discussion", 1 do
475 assert_dom "> comment", 3 do |dom_comments|
476 assert_dom dom_comments[0], "> @id", comment1.id.to_s
477 assert_dom dom_comments[0], "> @visible", "true"
478 assert_dom dom_comments[1], "> @id", comment2.id.to_s
479 assert_dom dom_comments[1], "> @visible", "false"
480 assert_dom dom_comments[2], "> @id", comment3.id.to_s
481 assert_dom dom_comments[2], "> @visible", "true"
488 changeset = create(:changeset, :closed)
489 create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
490 create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
492 get api_changeset_path(changeset)
494 assert_response :success
495 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
496 assert_single_changeset changeset do
497 assert_dom "> tag", 2
498 assert_dom "> tag[k='created_by'][v='JOSM/1.5 (18364)']", 1
499 assert_dom "> tag[k='comment'][v='changeset comment']", 1
504 changeset = create(:changeset)
506 get api_changeset_path(changeset, :format => "json")
507 assert_response :success, "cannot get first changeset"
509 js = ActiveSupport::JSON.decode(@response.body)
512 assert_equal Settings.api_version, js["version"]
513 assert_equal Settings.generator, js["generator"]
514 assert_single_changeset_json changeset, js
515 assert_nil js["changeset"]["tags"]
516 assert_nil js["changeset"]["comments"]
517 assert_equal changeset.user.id, js["changeset"]["uid"]
518 assert_equal changeset.user.display_name, js["changeset"]["user"]
520 get api_changeset_path(changeset, :format => "json", :include_discussion => true)
521 assert_response :success, "cannot get first changeset with comments"
523 js = ActiveSupport::JSON.decode(@response.body)
525 assert_equal Settings.api_version, js["version"]
526 assert_equal Settings.generator, js["generator"]
527 assert_single_changeset_json changeset, js
528 assert_nil js["changeset"]["tags"]
529 assert_nil js["changeset"]["min_lat"]
530 assert_nil js["changeset"]["min_lon"]
531 assert_nil js["changeset"]["max_lat"]
532 assert_nil js["changeset"]["max_lon"]
533 assert_equal 0, js["changeset"]["comments"].count
536 def test_show_comments_json
537 # all comments visible
538 changeset = create(:changeset, :closed)
539 comment0, comment1, comment2 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
541 get api_changeset_path(changeset, :format => "json", :include_discussion => true)
542 assert_response :success, "cannot get closed changeset with comments"
544 js = ActiveSupport::JSON.decode(@response.body)
546 assert_equal Settings.api_version, js["version"]
547 assert_equal Settings.generator, js["generator"]
548 assert_single_changeset_json changeset, js
549 assert_equal 3, js["changeset"]["comments"].count
550 assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
551 assert js["changeset"]["comments"][0]["visible"]
552 assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
553 assert js["changeset"]["comments"][1]["visible"]
554 assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
555 assert js["changeset"]["comments"][2]["visible"]
557 # one hidden comment not included because not asked for
558 comment1.update(:visible => false)
561 get api_changeset_path(changeset, :format => "json", :include_discussion => true)
562 assert_response :success, "cannot get closed changeset with comments"
564 js = ActiveSupport::JSON.decode(@response.body)
566 assert_equal Settings.api_version, js["version"]
567 assert_equal Settings.generator, js["generator"]
568 assert_single_changeset_json changeset, js
569 assert_equal 2, js["changeset"]["comments"].count
570 assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
571 assert js["changeset"]["comments"][0]["visible"]
572 assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
573 assert js["changeset"]["comments"][1]["visible"]
575 # one hidden comment not included because no permissions
576 get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true)
577 assert_response :success, "cannot get closed changeset with comments"
579 js = ActiveSupport::JSON.decode(@response.body)
581 assert_equal Settings.api_version, js["version"]
582 assert_equal Settings.generator, js["generator"]
583 assert_single_changeset_json changeset, js
584 assert_equal 2, js["changeset"]["comments"].count
585 assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
586 assert js["changeset"]["comments"][0]["visible"]
587 # maybe will show an empty comment element with visible=false in the future
588 assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
589 assert js["changeset"]["comments"][1]["visible"]
591 # one hidden comment shown to moderators
592 moderator_user = create(:moderator_user)
593 auth_header = bearer_authorization_header moderator_user
594 get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
595 assert_response :success, "cannot get closed changeset with comments"
597 js = ActiveSupport::JSON.decode(@response.body)
599 assert_equal Settings.api_version, js["version"]
600 assert_equal Settings.generator, js["generator"]
601 assert_single_changeset_json changeset, js
602 assert_equal 3, js["changeset"]["comments"].count
603 assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
604 assert js["changeset"]["comments"][0]["visible"]
605 assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
606 assert_not js["changeset"]["comments"][1]["visible"]
607 assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
608 assert js["changeset"]["comments"][2]["visible"]
611 def test_show_tags_json
612 changeset = create(:changeset, :closed)
613 create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
614 create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
616 get api_changeset_path(changeset, :format => "json")
618 assert_response :success
619 js = ActiveSupport::JSON.decode(@response.body)
621 assert_equal Settings.api_version, js["version"]
622 assert_equal Settings.generator, js["generator"]
623 assert_single_changeset_json changeset, js
624 assert_equal 2, js["changeset"]["tags"].count
625 assert_equal "JOSM/1.5 (18364)", js["changeset"]["tags"]["created_by"]
626 assert_equal "changeset comment", js["changeset"]["tags"]["comment"]
629 def test_show_bbox_json
630 changeset = create(:changeset, :bbox => [5, -5, 12, 15])
632 get api_changeset_path(changeset, :format => "json")
633 assert_response :success, "cannot get first changeset"
635 js = ActiveSupport::JSON.decode(@response.body)
637 assert_equal(-5, js["changeset"]["min_lat"])
638 assert_equal 5, js["changeset"]["min_lon"]
639 assert_equal 15, js["changeset"]["max_lat"]
640 assert_equal 12, js["changeset"]["max_lon"]
644 # check that a changeset that doesn't exist returns an appropriate message
645 def test_show_not_found
646 [0, -32, 233455644, "afg", "213"].each do |id|
647 get api_changeset_path(id)
648 assert_response :not_found, "should get a not found"
649 rescue ActionController::UrlGenerationError => e
650 assert_match(/No route matches/, e.to_s)
655 # test that the user who opened a change can close it
657 private_user = create(:user, :data_public => false)
658 private_changeset = create(:changeset, :user => private_user)
660 changeset = create(:changeset, :user => user)
662 ## Try without authentication
663 put changeset_close_path(changeset)
664 assert_response :unauthorized
666 ## Try using the non-public user
667 auth_header = bearer_authorization_header private_user
668 put changeset_close_path(private_changeset), :headers => auth_header
669 assert_require_public_data
671 ## The try with the public user
672 auth_header = bearer_authorization_header user
675 put changeset_close_path(cs_id), :headers => auth_header
676 assert_response :success
678 # test that it really is closed now
679 cs = Changeset.find(changeset.id)
681 "changeset should be closed now (#{cs.closed_at} > #{Time.now.utc}.")
685 # test that a different user can't close another user's changeset
686 def test_close_invalid
688 changeset = create(:changeset)
690 auth_header = bearer_authorization_header user
692 put changeset_close_path(changeset), :headers => auth_header
693 assert_response :conflict
694 assert_equal "The user doesn't own that changeset", @response.body
698 # test that you can't close using another method
699 def test_close_method_invalid
701 changeset = create(:changeset, :user => user)
703 auth_header = bearer_authorization_header user
705 get changeset_close_path(changeset), :headers => auth_header
706 assert_response :not_found
707 assert_template "rescues/routing_error"
709 post changeset_close_path(changeset), :headers => auth_header
710 assert_response :not_found
711 assert_template "rescues/routing_error"
715 # check that you can't close a changeset that isn't found
716 def test_close_not_found
717 cs_ids = [0, -132, "123"]
719 # First try to do it with no auth
721 put changeset_close_path(id)
722 assert_response :unauthorized, "Shouldn't be able close the non-existant changeset #{id}, when not authorized"
723 rescue ActionController::UrlGenerationError => e
724 assert_match(/No route matches/, e.to_s)
728 auth_header = bearer_authorization_header
730 put changeset_close_path(id), :headers => auth_header
731 assert_response :not_found, "The changeset #{id} doesn't exist, so can't be closed"
732 rescue ActionController::UrlGenerationError => e
733 assert_match(/No route matches/, e.to_s)
738 # upload something simple, but valid and check that it can
740 # Also try without auth and another user.
741 def test_upload_simple_valid
742 private_user = create(:user, :data_public => false)
743 private_changeset = create(:changeset, :user => private_user)
745 changeset = create(:changeset, :user => user)
749 relation = create(:relation)
750 other_relation = create(:relation)
751 # create some tags, since we test that they are removed later
752 create(:node_tag, :node => node)
753 create(:way_tag, :way => way)
754 create(:relation_tag, :relation => relation)
757 changeset_id = changeset.id
759 # simple diff to change a node, way and relation by removing
764 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
765 <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
766 <nd ref='#{node.id}'/>
770 <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
771 <member type='way' role='some' ref='#{way.id}'/>
772 <member type='node' role='some' ref='#{node.id}'/>
773 <member type='relation' role='some' ref='#{other_relation.id}'/>
780 post changeset_upload_path(changeset), :params => diff
781 assert_response :unauthorized,
782 "shouldn't be able to upload a simple valid diff to changeset: #{@response.body}"
784 ## Now try with a private user
785 auth_header = bearer_authorization_header private_user
786 changeset_id = private_changeset.id
788 # simple diff to change a node, way and relation by removing
793 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
794 <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
795 <nd ref='#{node.id}'/>
799 <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
800 <member type='way' role='some' ref='#{way.id}'/>
801 <member type='node' role='some' ref='#{node.id}'/>
802 <member type='relation' role='some' ref='#{other_relation.id}'/>
809 post changeset_upload_path(private_changeset), :params => diff, :headers => auth_header
810 assert_response :forbidden,
811 "can't upload a simple valid diff to changeset: #{@response.body}"
813 ## Now try with the public user
814 auth_header = bearer_authorization_header user
815 changeset_id = changeset.id
817 # simple diff to change a node, way and relation by removing
822 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
823 <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
824 <nd ref='#{node.id}'/>
828 <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
829 <member type='way' role='some' ref='#{way.id}'/>
830 <member type='node' role='some' ref='#{node.id}'/>
831 <member type='relation' role='some' ref='#{other_relation.id}'/>
838 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
839 assert_response :success,
840 "can't upload a simple valid diff to changeset: #{@response.body}"
842 # check that the changes made it into the database
843 assert_equal 0, Node.find(node.id).tags.size, "node #{node.id} should now have no tags"
844 assert_equal 0, Way.find(way.id).tags.size, "way #{way.id} should now have no tags"
845 assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
849 # upload something which creates new objects using placeholders
850 def test_upload_create_valid
852 changeset = create(:changeset, :user => user)
854 way = create(:way_with_nodes, :nodes_count => 2)
855 relation = create(:relation)
857 auth_header = bearer_authorization_header user
859 # simple diff to create a node way and relation using placeholders
863 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
864 <tag k='foo' v='bar'/>
865 <tag k='baz' v='bat'/>
867 <way id='-1' changeset='#{changeset.id}'>
868 <nd ref='#{node.id}'/>
872 <relation id='-1' changeset='#{changeset.id}'>
873 <member type='way' role='some' ref='#{way.id}'/>
874 <member type='node' role='some' ref='#{node.id}'/>
875 <member type='relation' role='some' ref='#{relation.id}'/>
882 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
883 assert_response :success,
884 "can't upload a simple valid creation to changeset: #{@response.body}"
886 # check the returned payload
887 new_node_id, new_way_id, new_rel_id = nil
888 assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
889 # inspect the response to find out what the new element IDs are
890 # check the old IDs are all present and negative one
891 # check the versions are present and equal one
892 assert_dom "> node", 1 do |(node_el)|
893 new_node_id = node_el["new_id"].to_i
894 assert_dom "> @old_id", "-1"
895 assert_dom "> @new_version", "1"
897 assert_dom "> way", 1 do |(way_el)|
898 new_way_id = way_el["new_id"].to_i
899 assert_dom "> @old_id", "-1"
900 assert_dom "> @new_version", "1"
902 assert_dom "> relation", 1 do |(rel_el)|
903 new_rel_id = rel_el["new_id"].to_i
904 assert_dom "> @old_id", "-1"
905 assert_dom "> @new_version", "1"
909 # check that the changes made it into the database
910 assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
911 assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
912 assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
916 # test a complex delete where we delete elements which rely on eachother
917 # in the same transaction.
918 def test_upload_delete
919 changeset = create(:changeset)
920 super_relation = create(:relation)
921 used_relation = create(:relation)
922 used_way = create(:way)
923 used_node = create(:node)
924 create(:relation_member, :relation => super_relation, :member => used_relation)
925 create(:relation_member, :relation => super_relation, :member => used_way)
926 create(:relation_member, :relation => super_relation, :member => used_node)
928 auth_header = bearer_authorization_header changeset.user
930 diff = XML::Document.new
931 diff.root = XML::Node.new "osmChange"
932 delete = XML::Node.new "delete"
934 delete << xml_node_for_relation(super_relation)
935 delete << xml_node_for_relation(used_relation)
936 delete << xml_node_for_way(used_way)
937 delete << xml_node_for_node(used_node)
939 # update the changeset to one that this user owns
940 %w[node way relation].each do |type|
941 delete.find("//osmChange/delete/#{type}").each do |n|
942 n["changeset"] = changeset.id.to_s
947 post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
948 assert_response :success,
949 "can't upload a deletion diff to changeset: #{@response.body}"
951 # check the response is well-formed
952 assert_select "diffResult>node", 1
953 assert_select "diffResult>way", 1
954 assert_select "diffResult>relation", 2
956 # check that everything was deleted
957 assert_not Node.find(used_node.id).visible
958 assert_not Way.find(used_way.id).visible
959 assert_not Relation.find(super_relation.id).visible
960 assert_not Relation.find(used_relation.id).visible
964 # test uploading a delete with no lat/lon, as they are optional in
965 # the osmChange spec.
966 def test_upload_nolatlon_delete
968 changeset = create(:changeset)
970 auth_header = bearer_authorization_header changeset.user
971 diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{changeset.id}'/></delete></osmChange>"
974 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
975 assert_response :success,
976 "can't upload a deletion diff to changeset: #{@response.body}"
978 # check the response is well-formed
979 assert_select "diffResult>node", 1
981 # check that everything was deleted
982 assert_not Node.find(node.id).visible
985 def test_repeated_changeset_create
987 auth_header = bearer_authorization_header
989 # create a temporary changeset
990 xml = "<osm><changeset>" \
991 "<tag k='created_by' v='osm test suite checking changesets'/>" \
993 assert_difference "Changeset.count", 1 do
994 post api_changesets_path, :params => xml, :headers => auth_header
996 assert_response :success
1000 def test_upload_large_changeset
1001 user = create(:user)
1002 auth_header = bearer_authorization_header user
1004 # create an old changeset to ensure we have the maximum rate limit
1005 create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
1007 # create a changeset
1008 post api_changesets_path, :params => "<osm><changeset/></osm>", :headers => auth_header
1009 assert_response :success, "Should be able to create a changeset: #{@response.body}"
1010 changeset_id = @response.body.to_i
1012 # upload some widely-spaced nodes, spiralling positive and negative
1016 <node id='-1' lon='-20' lat='-10' changeset='#{changeset_id}'/>
1017 <node id='-10' lon='20' lat='10' changeset='#{changeset_id}'/>
1018 <node id='-2' lon='-40' lat='-20' changeset='#{changeset_id}'/>
1019 <node id='-11' lon='40' lat='20' changeset='#{changeset_id}'/>
1020 <node id='-3' lon='-60' lat='-30' changeset='#{changeset_id}'/>
1021 <node id='-12' lon='60' lat='30' changeset='#{changeset_id}'/>
1022 <node id='-4' lon='-80' lat='-40' changeset='#{changeset_id}'/>
1023 <node id='-13' lon='80' lat='40' changeset='#{changeset_id}'/>
1024 <node id='-5' lon='-100' lat='-50' changeset='#{changeset_id}'/>
1025 <node id='-14' lon='100' lat='50' changeset='#{changeset_id}'/>
1026 <node id='-6' lon='-120' lat='-60' changeset='#{changeset_id}'/>
1027 <node id='-15' lon='120' lat='60' changeset='#{changeset_id}'/>
1028 <node id='-7' lon='-140' lat='-70' changeset='#{changeset_id}'/>
1029 <node id='-16' lon='140' lat='70' changeset='#{changeset_id}'/>
1030 <node id='-8' lon='-160' lat='-80' changeset='#{changeset_id}'/>
1031 <node id='-17' lon='160' lat='80' changeset='#{changeset_id}'/>
1032 <node id='-9' lon='-179.9' lat='-89.9' changeset='#{changeset_id}'/>
1033 <node id='-18' lon='179.9' lat='89.9' changeset='#{changeset_id}'/>
1038 # upload it, which used to cause an error like "PGError: ERROR:
1039 # integer out of range" (bug #2152). but shouldn't any more.
1040 post changeset_upload_path(changeset_id), :params => diff, :headers => auth_header
1041 assert_response :success,
1042 "can't upload a spatially-large diff to changeset: #{@response.body}"
1044 # check that the changeset bbox is within bounds
1045 cs = Changeset.find(changeset_id)
1046 assert_operator cs.min_lon, :>=, -180 * GeoRecord::SCALE, "Minimum longitude (#{cs.min_lon / GeoRecord::SCALE}) should be >= -180 to be valid."
1047 assert_operator cs.max_lon, :<=, 180 * GeoRecord::SCALE, "Maximum longitude (#{cs.max_lon / GeoRecord::SCALE}) should be <= 180 to be valid."
1048 assert_operator cs.min_lat, :>=, -90 * GeoRecord::SCALE, "Minimum latitude (#{cs.min_lat / GeoRecord::SCALE}) should be >= -90 to be valid."
1049 assert_operator cs.max_lat, :<=, 90 * GeoRecord::SCALE, "Maximum latitude (#{cs.max_lat / GeoRecord::SCALE}) should be <= 90 to be valid."
1053 # test that deleting stuff in a transaction doesn't bypass the checks
1054 # to ensure that used elements are not deleted.
1055 def test_upload_delete_invalid
1056 changeset = create(:changeset)
1057 relation = create(:relation)
1058 other_relation = create(:relation)
1059 used_way = create(:way)
1060 used_node = create(:node)
1061 create(:relation_member, :relation => relation, :member => used_way)
1062 create(:relation_member, :relation => relation, :member => used_node)
1064 auth_header = bearer_authorization_header changeset.user
1066 diff = XML::Document.new
1067 diff.root = XML::Node.new "osmChange"
1068 delete = XML::Node.new "delete"
1070 delete << xml_node_for_relation(other_relation)
1071 delete << xml_node_for_way(used_way)
1072 delete << xml_node_for_node(used_node)
1074 # update the changeset to one that this user owns
1075 %w[node way relation].each do |type|
1076 delete.find("//osmChange/delete/#{type}").each do |n|
1077 n["changeset"] = changeset.id.to_s
1082 post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
1083 assert_response :precondition_failed,
1084 "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
1085 assert_equal "Precondition failed: Way #{used_way.id} is still used by relations #{relation.id}.", @response.body
1087 # check that nothing was, in fact, deleted
1088 assert Node.find(used_node.id).visible
1089 assert Way.find(used_way.id).visible
1090 assert Relation.find(relation.id).visible
1091 assert Relation.find(other_relation.id).visible
1095 # test that a conditional delete of an in use object works.
1096 def test_upload_delete_if_unused
1097 changeset = create(:changeset)
1098 super_relation = create(:relation)
1099 used_relation = create(:relation)
1100 used_way = create(:way)
1101 used_node = create(:node)
1102 create(:relation_member, :relation => super_relation, :member => used_relation)
1103 create(:relation_member, :relation => super_relation, :member => used_way)
1104 create(:relation_member, :relation => super_relation, :member => used_node)
1106 auth_header = bearer_authorization_header changeset.user
1108 diff = XML::Document.new
1109 diff.root = XML::Node.new "osmChange"
1110 delete = XML::Node.new "delete"
1112 delete["if-unused"] = ""
1113 delete << xml_node_for_relation(used_relation)
1114 delete << xml_node_for_way(used_way)
1115 delete << xml_node_for_node(used_node)
1117 # update the changeset to one that this user owns
1118 %w[node way relation].each do |type|
1119 delete.find("//osmChange/delete/#{type}").each do |n|
1120 n["changeset"] = changeset.id.to_s
1125 post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
1126 assert_response :success,
1127 "can't do a conditional delete of in use objects: #{@response.body}"
1129 # check the returned payload
1130 assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
1131 # check the old IDs are all present and what we expect
1132 # check the new IDs are all present and unchanged
1133 # check the new versions are all present and unchanged
1134 assert_dom "> node", 1 do
1135 assert_dom "> @old_id", used_node.id.to_s
1136 assert_dom "> @new_id", used_node.id.to_s
1137 assert_dom "> @new_version", used_node.version.to_s
1139 assert_dom "> way", 1 do
1140 assert_dom "> @old_id", used_way.id.to_s
1141 assert_dom "> @new_id", used_way.id.to_s
1142 assert_dom "> @new_version", used_way.version.to_s
1144 assert_dom "> relation", 1 do
1145 assert_dom "> @old_id", used_relation.id.to_s
1146 assert_dom "> @new_id", used_relation.id.to_s
1147 assert_dom "> @new_version", used_relation.version.to_s
1151 # check that nothing was, in fact, deleted
1152 assert Node.find(used_node.id).visible
1153 assert Way.find(used_way.id).visible
1154 assert Relation.find(used_relation.id).visible
1158 # upload an element with a really long tag value
1159 def test_upload_invalid_too_long_tag
1160 changeset = create(:changeset)
1162 auth_header = bearer_authorization_header changeset.user
1164 # simple diff to create a node way and relation using placeholders
1168 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
1169 <tag k='foo' v='#{'x' * 256}'/>
1176 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1177 assert_response :bad_request,
1178 "shouldn't be able to upload too long a tag to changeset: #{@response.body}"
1182 # upload something which creates new objects and inserts them into
1183 # existing containers using placeholders.
1184 def test_upload_complex
1186 node = create(:node)
1187 relation = create(:relation)
1188 create(:way_node, :way => way, :node => node)
1190 changeset = create(:changeset)
1192 auth_header = bearer_authorization_header changeset.user
1194 # simple diff to create a node way and relation using placeholders
1198 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
1199 <tag k='foo' v='bar'/>
1200 <tag k='baz' v='bat'/>
1204 <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
1206 <nd ref='#{node.id}'/>
1208 <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
1209 <member type='way' role='some' ref='#{way.id}'/>
1210 <member type='node' role='some' ref='-1'/>
1211 <member type='relation' role='some' ref='#{relation.id}'/>
1218 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1219 assert_response :success,
1220 "can't upload a complex diff to changeset: #{@response.body}"
1222 # check the returned payload
1224 assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
1225 assert_dom "> node", 1 do |(node_el)|
1226 new_node_id = node_el["new_id"].to_i
1228 assert_dom "> way", 1
1229 assert_dom "> relation", 1
1232 # check that the changes made it into the database
1233 assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
1234 assert_equal [new_node_id, node.id], Way.find(way.id).nds, "way nodes should match"
1235 Relation.find(relation.id).members.each do |type, id, _role|
1236 assert_equal new_node_id, id, "relation should contain new node" if type == "node"
1241 # create a diff which references several changesets, which should cause
1242 # a rollback and none of the diff gets committed
1243 def test_upload_invalid_changesets
1244 changeset = create(:changeset)
1245 other_changeset = create(:changeset, :user => changeset.user)
1246 node = create(:node)
1248 relation = create(:relation)
1249 other_relation = create(:relation)
1251 auth_header = bearer_authorization_header changeset.user
1253 # simple diff to create a node way and relation using placeholders
1257 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1258 <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
1259 <nd ref='#{node.id}'/>
1263 <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
1264 <member type='way' role='some' ref='#{way.id}'/>
1265 <member type='node' role='some' ref='#{node.id}'/>
1266 <member type='relation' role='some' ref='#{other_relation.id}'/>
1270 <node id='-1' lon='0' lat='0' changeset='#{other_changeset.id}'>
1271 <tag k='foo' v='bar'/>
1272 <tag k='baz' v='bat'/>
1279 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1280 assert_response :conflict,
1281 "uploading a diff with multiple changesets should have failed"
1283 # check that objects are unmodified
1284 assert_nodes_are_equal(node, Node.find(node.id))
1285 assert_ways_are_equal(way, Way.find(way.id))
1286 assert_relations_are_equal(relation, Relation.find(relation.id))
1290 # upload multiple versions of the same element in the same diff.
1291 def test_upload_multiple_valid
1292 node = create(:node)
1293 changeset = create(:changeset)
1294 auth_header = bearer_authorization_header changeset.user
1296 # change the location of a node multiple times, each time referencing
1297 # the last version. doesn't this depend on version numbers being
1302 <node id='#{node.id}' lon='0.0' lat='0.0' changeset='#{changeset.id}' version='1'/>
1303 <node id='#{node.id}' lon='0.1' lat='0.0' changeset='#{changeset.id}' version='2'/>
1304 <node id='#{node.id}' lon='0.1' lat='0.1' changeset='#{changeset.id}' version='3'/>
1305 <node id='#{node.id}' lon='0.1' lat='0.2' changeset='#{changeset.id}' version='4'/>
1306 <node id='#{node.id}' lon='0.2' lat='0.2' changeset='#{changeset.id}' version='5'/>
1307 <node id='#{node.id}' lon='0.3' lat='0.2' changeset='#{changeset.id}' version='6'/>
1308 <node id='#{node.id}' lon='0.3' lat='0.3' changeset='#{changeset.id}' version='7'/>
1309 <node id='#{node.id}' lon='0.9' lat='0.9' changeset='#{changeset.id}' version='8'/>
1315 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1316 assert_response :success,
1317 "can't upload multiple versions of an element in a diff: #{@response.body}"
1319 # check the response is well-formed. its counter-intuitive, but the
1320 # API will return multiple elements with the same ID and different
1321 # version numbers for each change we made.
1322 assert_select "diffResult>node", 8
1326 # upload multiple versions of the same element in the same diff, but
1327 # keep the version numbers the same.
1328 def test_upload_multiple_duplicate
1329 node = create(:node)
1330 changeset = create(:changeset)
1332 auth_header = bearer_authorization_header changeset.user
1337 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1338 <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
1344 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1345 assert_response :conflict,
1346 "shouldn't be able to upload the same element twice in a diff: #{@response.body}"
1350 # try to upload some elements without specifying the version
1351 def test_upload_missing_version
1352 changeset = create(:changeset)
1354 auth_header = bearer_authorization_header changeset.user
1359 <node id='1' lon='1' lat='1' changeset='#{changeset.id}'/>
1365 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1366 assert_response :bad_request,
1367 "shouldn't be able to upload an element without version: #{@response.body}"
1371 # try to upload with commands other than create, modify, or delete
1372 def test_action_upload_invalid
1373 changeset = create(:changeset)
1375 auth_header = bearer_authorization_header changeset.user
1380 <node id='1' lon='1' lat='1' changeset='#{changeset.id}' />
1384 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1385 assert_response :bad_request, "Shouldn't be able to upload a diff with the action ping"
1386 assert_equal("Unknown action ping, choices are create, modify, delete", @response.body)
1390 # upload a valid changeset which has a mixture of whitespace
1391 # to check a bug reported by ivansanchez (#1565).
1392 def test_upload_whitespace_valid
1393 changeset = create(:changeset)
1394 node = create(:node)
1395 way = create(:way_with_nodes, :nodes_count => 2)
1396 relation = create(:relation)
1397 other_relation = create(:relation)
1398 create(:relation_tag, :relation => relation)
1400 auth_header = bearer_authorization_header changeset.user
1404 <modify><node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}'
1406 <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='2'><tag k='k' v='v'/></node></modify>
1408 <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'><member
1409 type='way' role='some' ref='#{way.id}'/><member
1410 type='node' role='some' ref='#{node.id}'/>
1411 <member type='relation' role='some' ref='#{other_relation.id}'/>
1413 </modify></osmChange>
1417 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1418 assert_response :success,
1419 "can't upload a valid diff with whitespace variations to changeset: #{@response.body}"
1421 # check the response is well-formed
1422 assert_select "diffResult>node", 2
1423 assert_select "diffResult>relation", 1
1425 # check that the changes made it into the database
1426 assert_equal 1, Node.find(node.id).tags.size, "node #{node.id} should now have one tag"
1427 assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
1431 # test that a placeholder can be reused within the same upload.
1432 def test_upload_reuse_placeholder_valid
1433 changeset = create(:changeset)
1435 auth_header = bearer_authorization_header changeset.user
1440 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
1441 <tag k="foo" v="bar"/>
1445 <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
1448 <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
1454 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1455 assert_response :success,
1456 "can't upload a valid diff with re-used placeholders to changeset: #{@response.body}"
1458 # check the response is well-formed
1459 assert_select "diffResult>node", 3
1460 assert_select "diffResult>node[old_id='-1']", 3
1464 # test what happens if a diff upload re-uses placeholder IDs in an
1466 def test_upload_placeholder_invalid
1467 changeset = create(:changeset)
1469 auth_header = bearer_authorization_header changeset.user
1474 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1475 <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
1476 <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
1482 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1483 assert_response :bad_request,
1484 "shouldn't be able to re-use placeholder IDs"
1486 # placeholder_ids must be unique across all action blocks
1490 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1493 <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
1499 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1500 assert_response :bad_request,
1501 "shouldn't be able to re-use placeholder IDs"
1504 def test_upload_process_order
1505 changeset = create(:changeset)
1507 auth_header = bearer_authorization_header changeset.user
1512 <node id="-1" lat="1" lon="2" changeset="#{changeset.id}"/>
1513 <way id="-1" changeset="#{changeset.id}">
1517 <node id="-2" lat="1" lon="2" changeset="#{changeset.id}"/>
1523 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1524 assert_response :bad_request,
1525 "shouldn't refer elements behind it"
1528 def test_upload_duplicate_delete
1529 changeset = create(:changeset)
1531 auth_header = bearer_authorization_header changeset.user
1536 <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
1539 <node id="-1" version="1" changeset="#{changeset.id}" />
1540 <node id="-1" version="1" changeset="#{changeset.id}" />
1546 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1547 assert_response :gone,
1548 "transaction should be cancelled by second deletion"
1553 <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
1555 <delete if-unused="true">
1556 <node id="-1" version="1" changeset="#{changeset.id}" />
1557 <node id="-1" version="1" changeset="#{changeset.id}" />
1563 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1565 assert_select "diffResult>node", 3
1566 assert_select "diffResult>node[old_id='-1']", 3
1567 assert_select "diffResult>node[new_version='1']", 1
1568 assert_select "diffResult>node[new_version='2']", 1
1572 # test that uploading a way referencing invalid placeholders gives a
1573 # proper error, not a 500.
1574 def test_upload_placeholder_invalid_way
1575 changeset = create(:changeset)
1578 auth_header = bearer_authorization_header changeset.user
1583 <node id="-1" lon="0.0" lat="0.0" changeset="#{changeset.id}" version="1"/>
1584 <node id="-2" lon="0.1" lat="0.1" changeset="#{changeset.id}" version="1"/>
1585 <node id="-3" lon="0.2" lat="0.2" changeset="#{changeset.id}" version="1"/>
1586 <way id="-1" changeset="#{changeset.id}" version="1">
1597 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1598 assert_response :bad_request,
1599 "shouldn't be able to use invalid placeholder IDs"
1600 assert_equal "Placeholder node not found for reference -4 in way -1", @response.body
1602 # the same again, but this time use an existing way
1606 <node id="-1" lon="0.0" lat="0.0" changeset="#{changeset.id}" version="1"/>
1607 <node id="-2" lon="0.1" lat="0.1" changeset="#{changeset.id}" version="1"/>
1608 <node id="-3" lon="0.2" lat="0.2" changeset="#{changeset.id}" version="1"/>
1609 <way id="#{way.id}" changeset="#{changeset.id}" version="1">
1620 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1621 assert_response :bad_request,
1622 "shouldn't be able to use invalid placeholder IDs"
1623 assert_equal "Placeholder node not found for reference -4 in way #{way.id}", @response.body
1627 # test that uploading a relation referencing invalid placeholders gives a
1628 # proper error, not a 500.
1629 def test_upload_placeholder_invalid_relation
1630 changeset = create(:changeset)
1631 relation = create(:relation)
1633 auth_header = bearer_authorization_header changeset.user
1638 <node id="-1" lon="0.0" lat="0.0" changeset="#{changeset.id}" version="1"/>
1639 <node id="-2" lon="0.1" lat="0.1" changeset="#{changeset.id}" version="1"/>
1640 <node id="-3" lon="0.2" lat="0.2" changeset="#{changeset.id}" version="1"/>
1641 <relation id="-1" changeset="#{changeset.id}" version="1">
1642 <member type="node" role="foo" ref="-1"/>
1643 <member type="node" role="foo" ref="-2"/>
1644 <member type="node" role="foo" ref="-3"/>
1645 <member type="node" role="foo" ref="-4"/>
1652 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1653 assert_response :bad_request,
1654 "shouldn't be able to use invalid placeholder IDs"
1655 assert_equal "Placeholder Node not found for reference -4 in relation -1.", @response.body
1657 # the same again, but this time use an existing relation
1661 <node id="-1" lon="0.0" lat="0.0" changeset="#{changeset.id}" version="1"/>
1662 <node id="-2" lon="0.1" lat="0.1" changeset="#{changeset.id}" version="1"/>
1663 <node id="-3" lon="0.2" lat="0.2" changeset="#{changeset.id}" version="1"/>
1664 <relation id="#{relation.id}" changeset="#{changeset.id}" version="1">
1665 <member type="node" role="foo" ref="-1"/>
1666 <member type="node" role="foo" ref="-2"/>
1667 <member type="node" role="foo" ref="-3"/>
1668 <member type="way" role="bar" ref="-1"/>
1675 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1676 assert_response :bad_request,
1677 "shouldn't be able to use invalid placeholder IDs"
1678 assert_equal "Placeholder Way not found for reference -1 in relation #{relation.id}.", @response.body
1682 # test what happens if a diff is uploaded containing only a node
1684 def test_upload_node_move
1685 auth_header = bearer_authorization_header
1687 xml = "<osm><changeset>" \
1688 "<tag k='created_by' v='osm test suite checking changesets'/>" \
1689 "</changeset></osm>"
1690 post api_changesets_path, :params => xml, :headers => auth_header
1691 assert_response :success
1692 changeset_id = @response.body.to_i
1694 old_node = create(:node, :lat => 1, :lon => 1)
1696 diff = XML::Document.new
1697 diff.root = XML::Node.new "osmChange"
1698 modify = XML::Node.new "modify"
1699 xml_old_node = xml_node_for_node(old_node)
1700 xml_old_node["lat"] = 2.0.to_s
1701 xml_old_node["lon"] = 2.0.to_s
1702 xml_old_node["changeset"] = changeset_id.to_s
1703 modify << xml_old_node
1707 post changeset_upload_path(changeset_id), :params => diff.to_s, :headers => auth_header
1708 assert_response :success,
1709 "diff should have uploaded OK"
1712 changeset = Changeset.find(changeset_id)
1713 assert_equal 1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 1 degree"
1714 assert_equal 2 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 2 degrees"
1715 assert_equal 1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1 degree"
1716 assert_equal 2 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 2 degrees"
1720 # test what happens if a diff is uploaded adding a node to a way.
1721 def test_upload_way_extend
1722 auth_header = bearer_authorization_header
1724 xml = "<osm><changeset>" \
1725 "<tag k='created_by' v='osm test suite checking changesets'/>" \
1726 "</changeset></osm>"
1727 post api_changesets_path, :params => xml, :headers => auth_header
1728 assert_response :success
1729 changeset_id = @response.body.to_i
1731 old_way = create(:way)
1732 create(:way_node, :way => old_way, :node => create(:node, :lat => 0.1, :lon => 0.1))
1734 diff = XML::Document.new
1735 diff.root = XML::Node.new "osmChange"
1736 modify = XML::Node.new "modify"
1737 xml_old_way = xml_node_for_way(old_way)
1738 nd_ref = XML::Node.new "nd"
1739 nd_ref["ref"] = create(:node, :lat => 0.3, :lon => 0.3).id.to_s
1740 xml_old_way << nd_ref
1741 xml_old_way["changeset"] = changeset_id.to_s
1742 modify << xml_old_way
1746 post changeset_upload_path(changeset_id), :params => diff.to_s, :headers => auth_header
1747 assert_response :success,
1748 "diff should have uploaded OK"
1751 changeset = Changeset.find(changeset_id)
1752 assert_equal 0.1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 0.1 degree"
1753 assert_equal 0.3 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 0.3 degrees"
1754 assert_equal 0.1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 0.1 degree"
1755 assert_equal 0.3 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 0.3 degrees"
1759 # test for more issues in #1568
1760 def test_upload_empty_invalid
1761 changeset = create(:changeset)
1763 auth_header = bearer_authorization_header changeset.user
1766 "<osmChange></osmChange>",
1767 "<osmChange><modify/></osmChange>",
1768 "<osmChange><modify></modify></osmChange>"].each do |diff|
1770 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1771 assert_response(:success, "should be able to upload " \
1772 "empty changeset: " + diff)
1777 # test that the X-Error-Format header works to request XML errors
1778 def test_upload_xml_errors
1779 changeset = create(:changeset)
1780 node = create(:node)
1781 create(:relation_member, :member => node)
1783 auth_header = bearer_authorization_header changeset.user
1785 # try and delete a node that is in use
1786 diff = XML::Document.new
1787 diff.root = XML::Node.new "osmChange"
1788 delete = XML::Node.new "delete"
1790 delete << xml_node_for_node(node)
1793 error_header = error_format_header "xml"
1794 post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header.merge(error_header)
1795 assert_response :success,
1796 "failed to return error in XML format"
1798 # check the returned payload
1799 assert_select "osmError[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
1800 assert_select "osmError>status", 1
1801 assert_select "osmError>message", 1
1804 def test_upload_not_found
1805 changeset = create(:changeset)
1807 auth_header = bearer_authorization_header changeset.user
1813 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1819 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1820 assert_response :not_found, "Node should not be found"
1826 <way id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1832 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1833 assert_response :not_found, "Way should not be found"
1839 <relation id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1845 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1846 assert_response :not_found, "Relation should not be found"
1852 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1858 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1859 assert_response :not_found, "Node should not be deleted"
1865 <way id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1871 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1872 assert_response :not_found, "Way should not be deleted"
1878 <relation id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1884 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1885 assert_response :not_found, "Relation should not be deleted"
1888 def test_upload_relation_placeholder_not_fix
1889 changeset = create(:changeset)
1891 auth_header = bearer_authorization_header changeset.user
1895 <osmChange version='0.6'>
1897 <relation id='-2' version='0' changeset='#{changeset.id}'>
1898 <member type='relation' role='' ref='-4' />
1899 <tag k='type' v='route' />
1900 <tag k='name' v='AtoB' />
1902 <relation id='-3' version='0' changeset='#{changeset.id}'>
1903 <tag k='type' v='route' />
1904 <tag k='name' v='BtoA' />
1906 <relation id='-4' version='0' changeset='#{changeset.id}'>
1907 <member type='relation' role='' ref='-2' />
1908 <member type='relation' role='' ref='-3' />
1909 <tag k='type' v='route_master' />
1910 <tag k='name' v='master' />
1917 post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
1918 assert_response :bad_request, "shouldn't be able to use reference -4 in relation -2: #{@response.body}"
1919 assert_equal "Placeholder Relation not found for reference -4 in relation -2.", @response.body
1922 def test_upload_multiple_delete_block
1923 changeset = create(:changeset)
1925 auth_header = bearer_authorization_header changeset.user
1927 node = create(:node)
1929 create(:way_node, :way => way, :node => node)
1930 alone_node = create(:node)
1934 <osmChange version='0.6'>
1935 <delete version="0.6">
1936 <node id="#{node.id}" version="#{node.version}" changeset="#{changeset.id}"/>
1938 <delete version="0.6" if-unused="true">
1939 <node id="#{alone_node.id}" version="#{alone_node.version}" changeset="#{changeset.id}"/>
1945 post changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
1946 assert_response :precondition_failed,
1947 "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
1948 assert_equal "Precondition failed: Node #{node.id} is still used by ways #{way.id}.", @response.body
1952 # test initial rate limit
1953 def test_upload_initial_rate_limit
1955 user = create(:user)
1957 # create some objects to use
1958 node = create(:node)
1959 way = create(:way_with_nodes, :nodes_count => 2)
1960 relation = create(:relation)
1962 # create a changeset that puts us near the initial rate limit
1963 changeset = create(:changeset, :user => user,
1964 :created_at => Time.now.utc - 5.minutes,
1965 :num_changes => Settings.initial_changes_per_hour - 2)
1967 # create authentication header
1968 auth_header = bearer_authorization_header user
1970 # simple diff to create a node way and relation using placeholders
1974 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
1975 <tag k='foo' v='bar'/>
1976 <tag k='baz' v='bat'/>
1978 <way id='-1' changeset='#{changeset.id}'>
1979 <nd ref='#{node.id}'/>
1983 <relation id='-1' changeset='#{changeset.id}'>
1984 <member type='way' role='some' ref='#{way.id}'/>
1985 <member type='node' role='some' ref='#{node.id}'/>
1986 <member type='relation' role='some' ref='#{relation.id}'/>
1993 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
1994 assert_response :too_many_requests, "upload did not hit rate limit"
1998 # test maximum rate limit
1999 def test_upload_maximum_rate_limit
2001 user = create(:user)
2003 # create some objects to use
2004 node = create(:node)
2005 way = create(:way_with_nodes, :nodes_count => 2)
2006 relation = create(:relation)
2008 # create a changeset to establish our initial edit time
2009 changeset = create(:changeset, :user => user,
2010 :created_at => Time.now.utc - 28.days)
2012 # create changeset to put us near the maximum rate limit
2013 total_changes = Settings.max_changes_per_hour - 2
2014 while total_changes.positive?
2015 changes = [total_changes, Changeset::MAX_ELEMENTS].min
2016 changeset = create(:changeset, :user => user,
2017 :created_at => Time.now.utc - 5.minutes,
2018 :num_changes => changes)
2019 total_changes -= changes
2022 # create authentication header
2023 auth_header = bearer_authorization_header user
2025 # simple diff to create a node way and relation using placeholders
2029 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
2030 <tag k='foo' v='bar'/>
2031 <tag k='baz' v='bat'/>
2033 <way id='-1' changeset='#{changeset.id}'>
2034 <nd ref='#{node.id}'/>
2038 <relation id='-1' changeset='#{changeset.id}'>
2039 <member type='way' role='some' ref='#{way.id}'/>
2040 <member type='node' role='some' ref='#{node.id}'/>
2041 <member type='relation' role='some' ref='#{relation.id}'/>
2048 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
2049 assert_response :too_many_requests, "upload did not hit rate limit"
2053 # test initial size limit
2054 def test_upload_initial_size_limit
2056 user = create(:user)
2058 # create a changeset that puts us near the initial size limit
2059 changeset = create(:changeset, :user => user,
2060 :min_lat => (-0.5 * GeoRecord::SCALE).round, :min_lon => (0.5 * GeoRecord::SCALE).round,
2061 :max_lat => (0.5 * GeoRecord::SCALE).round, :max_lon => (2.5 * GeoRecord::SCALE).round)
2063 # create authentication header
2064 auth_header = bearer_authorization_header user
2066 # simple diff to create a node
2070 <node id='-1' lon='0.9' lat='2.9' changeset='#{changeset.id}'>
2071 <tag k='foo' v='bar'/>
2072 <tag k='baz' v='bat'/>
2079 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
2080 assert_response :payload_too_large, "upload did not hit size limit"
2084 # test size limit after one week
2085 def test_upload_week_size_limit
2087 user = create(:user)
2089 # create a changeset to establish our initial edit time
2090 create(:changeset, :user => user, :created_at => Time.now.utc - 7.days)
2092 # create a changeset that puts us near the initial size limit
2093 changeset = create(:changeset, :user => user, :bbox => [0.5, -0.5, 2.5, 0.5])
2095 # create authentication header
2096 auth_header = bearer_authorization_header user
2098 # simple diff to create a node way and relation using placeholders
2102 <node id='-1' lon='35' lat='35' changeset='#{changeset.id}'>
2103 <tag k='foo' v='bar'/>
2104 <tag k='baz' v='bat'/>
2111 post changeset_upload_path(changeset), :params => diff, :headers => auth_header
2112 assert_response :payload_too_large, "upload did not hit size limit"
2116 # when we make some simple changes we get the same changes back from the
2118 def test_diff_download_simple
2119 node = create(:node)
2121 ## First try with a non-public user, which should get a forbidden
2122 auth_header = bearer_authorization_header create(:user, :data_public => false)
2124 # create a temporary changeset
2125 xml = "<osm><changeset>" \
2126 "<tag k='created_by' v='osm test suite checking changesets'/>" \
2127 "</changeset></osm>"
2128 post api_changesets_path, :params => xml, :headers => auth_header
2129 assert_response :forbidden
2131 ## Now try with a normal user
2132 auth_header = bearer_authorization_header
2134 # create a temporary changeset
2135 xml = "<osm><changeset>" \
2136 "<tag k='created_by' v='osm test suite checking changesets'/>" \
2137 "</changeset></osm>"
2138 post api_changesets_path, :params => xml, :headers => auth_header
2139 assert_response :success
2140 changeset_id = @response.body.to_i
2146 <node id='#{node.id}' lon='0.0' lat='0.0' changeset='#{changeset_id}' version='1'/>
2147 <node id='#{node.id}' lon='0.1' lat='0.0' changeset='#{changeset_id}' version='2'/>
2148 <node id='#{node.id}' lon='0.1' lat='0.1' changeset='#{changeset_id}' version='3'/>
2149 <node id='#{node.id}' lon='0.1' lat='0.2' changeset='#{changeset_id}' version='4'/>
2150 <node id='#{node.id}' lon='0.2' lat='0.2' changeset='#{changeset_id}' version='5'/>
2151 <node id='#{node.id}' lon='0.3' lat='0.2' changeset='#{changeset_id}' version='6'/>
2152 <node id='#{node.id}' lon='0.3' lat='0.3' changeset='#{changeset_id}' version='7'/>
2153 <node id='#{node.id}' lon='0.9' lat='0.9' changeset='#{changeset_id}' version='8'/>
2159 post changeset_upload_path(changeset_id), :params => diff, :headers => auth_header
2160 assert_response :success,
2161 "can't upload multiple versions of an element in a diff: #{@response.body}"
2163 get api_changeset_download_path(changeset_id)
2164 assert_response :success
2166 assert_select "osmChange", 1
2167 assert_select "osmChange>modify", 8
2168 assert_select "osmChange>modify>node", 8
2172 # culled this from josm to ensure that nothing in the way that josm
2173 # is formatting the request is causing it to fail.
2175 # NOTE: the error turned out to be something else completely!
2176 def test_josm_upload
2177 auth_header = bearer_authorization_header
2179 # create a temporary changeset
2180 xml = "<osm><changeset>" \
2181 "<tag k='created_by' v='osm test suite checking changesets'/>" \
2182 "</changeset></osm>"
2183 post api_changesets_path, :params => xml, :headers => auth_header
2184 assert_response :success
2185 changeset_id = @response.body.to_i
2188 <osmChange version="0.6" generator="JOSM">
2189 <create version="0.6" generator="JOSM">
2190 <node id='-1' visible='true' changeset='#{changeset_id}' lat='51.49619982187321' lon='-0.18722061869438314' />
2191 <node id='-2' visible='true' changeset='#{changeset_id}' lat='51.496359883909605' lon='-0.18653093576241928' />
2192 <node id='-3' visible='true' changeset='#{changeset_id}' lat='51.49598132358285' lon='-0.18719613290981638' />
2193 <node id='-4' visible='true' changeset='#{changeset_id}' lat='51.4961591711078' lon='-0.18629015888084607' />
2194 <node id='-5' visible='true' changeset='#{changeset_id}' lat='51.49582126021711' lon='-0.18708186591517145' />
2195 <node id='-6' visible='true' changeset='#{changeset_id}' lat='51.49591018437858' lon='-0.1861432441734455' />
2196 <node id='-7' visible='true' changeset='#{changeset_id}' lat='51.49560784152179' lon='-0.18694719410005425' />
2197 <node id='-8' visible='true' changeset='#{changeset_id}' lat='51.49567389979617' lon='-0.1860289771788006' />
2198 <node id='-9' visible='true' changeset='#{changeset_id}' lat='51.49543761398892' lon='-0.186820684213126' />
2199 <way id='-10' action='modify' visible='true' changeset='#{changeset_id}'>
2209 <tag k='highway' v='residential' />
2210 <tag k='name' v='Foobar Street' />
2217 post changeset_upload_path(changeset_id), :params => diff, :headers => auth_header
2218 assert_response :success,
2219 "can't upload a diff from JOSM: #{@response.body}"
2221 get api_changeset_download_path(changeset_id)
2222 assert_response :success
2224 assert_select "osmChange", 1
2225 assert_select "osmChange>create>node", 9
2226 assert_select "osmChange>create>way", 1
2227 assert_select "osmChange>create>way>nd", 9
2228 assert_select "osmChange>create>way>tag", 2
2232 # when we make some complex changes we get the same changes back from the
2234 def test_diff_download_complex
2235 node = create(:node)
2236 node2 = create(:node)
2238 auth_header = bearer_authorization_header
2240 # create a temporary changeset
2241 xml = "<osm><changeset>" \
2242 "<tag k='created_by' v='osm test suite checking changesets'/>" \
2243 "</changeset></osm>"
2244 post api_changesets_path, :params => xml, :headers => auth_header
2245 assert_response :success
2246 changeset_id = @response.body.to_i
2252 <node id='#{node.id}' lon='0.0' lat='0.0' changeset='#{changeset_id}' version='1'/>
2255 <node id='-1' lon='0.9' lat='0.9' changeset='#{changeset_id}' version='0'/>
2256 <node id='-2' lon='0.8' lat='0.9' changeset='#{changeset_id}' version='0'/>
2257 <node id='-3' lon='0.7' lat='0.9' changeset='#{changeset_id}' version='0'/>
2260 <node id='#{node2.id}' lon='2.0' lat='1.5' changeset='#{changeset_id}' version='1'/>
2261 <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
2262 <nd ref='#{node2.id}'/>
2272 post changeset_upload_path(changeset_id), :params => diff, :headers => auth_header
2273 assert_response :success,
2274 "can't upload multiple versions of an element in a diff: #{@response.body}"
2276 get api_changeset_download_path(changeset_id)
2277 assert_response :success
2279 assert_select "osmChange", 1
2280 assert_select "osmChange>create", 3
2281 assert_select "osmChange>delete", 1
2282 assert_select "osmChange>modify", 2
2283 assert_select "osmChange>create>node", 3
2284 assert_select "osmChange>delete>node", 1
2285 assert_select "osmChange>modify>node", 1
2286 assert_select "osmChange>modify>way", 1
2290 # check that the bounding box of a changeset gets updated correctly
2291 # FIXME: This should really be moded to a integration test due to the with_controller
2292 def test_changeset_bbox
2294 create(:way_node, :way => way, :node => create(:node, :lat => 0.3, :lon => 0.3))
2296 auth_header = bearer_authorization_header
2298 # create a new changeset
2299 xml = "<osm><changeset/></osm>"
2300 post api_changesets_path, :params => xml, :headers => auth_header
2301 assert_response :success, "Creating of changeset failed."
2302 changeset_id = @response.body.to_i
2304 # add a single node to it
2305 with_controller(NodesController.new) do
2306 xml = "<osm><node lon='0.1' lat='0.2' changeset='#{changeset_id}'/></osm>"
2307 post api_nodes_path, :params => xml, :headers => auth_header
2308 assert_response :success, "Couldn't create node."
2311 # get the bounding box back from the changeset
2312 get api_changeset_path(changeset_id)
2313 assert_response :success, "Couldn't read back changeset."
2314 assert_select "osm>changeset[min_lon='0.1000000']", 1
2315 assert_select "osm>changeset[max_lon='0.1000000']", 1
2316 assert_select "osm>changeset[min_lat='0.2000000']", 1
2317 assert_select "osm>changeset[max_lat='0.2000000']", 1
2319 # add another node to it
2320 with_controller(NodesController.new) do
2321 xml = "<osm><node lon='0.2' lat='0.1' changeset='#{changeset_id}'/></osm>"
2322 post api_nodes_path, :params => xml, :headers => auth_header
2323 assert_response :success, "Couldn't create second node."
2326 # get the bounding box back from the changeset
2327 get api_changeset_path(changeset_id)
2328 assert_response :success, "Couldn't read back changeset for the second time."
2329 assert_select "osm>changeset[min_lon='0.1000000']", 1
2330 assert_select "osm>changeset[max_lon='0.2000000']", 1
2331 assert_select "osm>changeset[min_lat='0.1000000']", 1
2332 assert_select "osm>changeset[max_lat='0.2000000']", 1
2334 # add (delete) a way to it, which contains a point at (3,3)
2335 with_controller(WaysController.new) do
2336 xml = update_changeset(xml_for_way(way), changeset_id)
2337 delete api_way_path(way), :params => xml.to_s, :headers => auth_header
2338 assert_response :success, "Couldn't delete a way."
2341 # get the bounding box back from the changeset
2342 get api_changeset_path(changeset_id)
2343 assert_response :success, "Couldn't read back changeset for the third time."
2344 assert_select "osm>changeset[min_lon='0.1000000']", 1
2345 assert_select "osm>changeset[max_lon='0.3000000']", 1
2346 assert_select "osm>changeset[min_lat='0.1000000']", 1
2347 assert_select "osm>changeset[max_lat='0.3000000']", 1
2351 # check updating tags on a changeset
2352 def test_changeset_update
2353 private_user = create(:user, :data_public => false)
2354 private_changeset = create(:changeset, :user => private_user)
2355 user = create(:user)
2356 changeset = create(:changeset, :user => user)
2358 ## First try with a non-public user
2359 new_changeset = create_changeset_xml(:user => private_user)
2360 new_tag = XML::Node.new "tag"
2361 new_tag["k"] = "tagtesting"
2362 new_tag["v"] = "valuetesting"
2363 new_changeset.find("//osm/changeset").first << new_tag
2365 # try without any authorization
2366 put api_changeset_path(private_changeset), :params => new_changeset.to_s
2367 assert_response :unauthorized
2369 # try with the wrong authorization
2370 auth_header = bearer_authorization_header
2371 put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
2372 assert_response :conflict
2374 # now this should get an unauthorized
2375 auth_header = bearer_authorization_header private_user
2376 put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
2377 assert_require_public_data "user with their data non-public, shouldn't be able to edit their changeset"
2379 ## Now try with the public user
2380 new_changeset = create_changeset_xml(:id => 1)
2381 new_tag = XML::Node.new "tag"
2382 new_tag["k"] = "tagtesting"
2383 new_tag["v"] = "valuetesting"
2384 new_changeset.find("//osm/changeset").first << new_tag
2386 # try without any authorization
2387 put api_changeset_path(changeset), :params => new_changeset.to_s
2388 assert_response :unauthorized
2390 # try with the wrong authorization
2391 auth_header = bearer_authorization_header
2392 put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
2393 assert_response :conflict
2395 # now this should work...
2396 auth_header = bearer_authorization_header user
2397 put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
2398 assert_response :success
2400 assert_select "osm>changeset[id='#{changeset.id}']", 1
2401 assert_select "osm>changeset>tag", 1
2402 assert_select "osm>changeset>tag[k='tagtesting'][v='valuetesting']", 1
2406 # check that a user different from the one who opened the changeset
2408 def test_changeset_update_invalid
2409 auth_header = bearer_authorization_header
2411 changeset = create(:changeset)
2412 new_changeset = create_changeset_xml(:user => changeset.user, :id => changeset.id)
2413 new_tag = XML::Node.new "tag"
2414 new_tag["k"] = "testing"
2415 new_tag["v"] = "testing"
2416 new_changeset.find("//osm/changeset").first << new_tag
2418 put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
2419 assert_response :conflict
2423 # check that a changeset can contain a certain max number of changes.
2424 ## FIXME should be changed to an integration test due to the with_controller
2425 def test_changeset_limits
2426 user = create(:user)
2427 auth_header = bearer_authorization_header user
2429 # create an old changeset to ensure we have the maximum rate limit
2430 create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
2432 # open a new changeset
2433 xml = "<osm><changeset/></osm>"
2434 post api_changesets_path, :params => xml, :headers => auth_header
2435 assert_response :success, "can't create a new changeset"
2436 cs_id = @response.body.to_i
2438 # start the counter just short of where the changeset should finish.
2440 # alter the database to set the counter on the changeset directly,
2441 # otherwise it takes about 6 minutes to fill all of them.
2442 changeset = Changeset.find(cs_id)
2443 changeset.num_changes = Changeset::MAX_ELEMENTS - offset
2446 with_controller(NodesController.new) do
2448 xml = "<osm><node changeset='#{cs_id}' lat='0.0' lon='0.0'/></osm>"
2449 post api_nodes_path, :params => xml, :headers => auth_header
2450 assert_response :success, "can't create a new node"
2451 node_id = @response.body.to_i
2453 get api_node_path(node_id)
2454 assert_response :success, "can't read back new node"
2455 node_doc = XML::Parser.string(@response.body).parse
2456 node_xml = node_doc.find("//osm/node").first
2458 # loop until we fill the changeset with nodes
2460 node_xml["lat"] = rand.to_s
2461 node_xml["lon"] = rand.to_s
2462 node_xml["version"] = (i + 1).to_s
2464 put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
2465 assert_response :success, "attempt #{i} should have succeeded"
2468 # trying again should fail
2469 node_xml["lat"] = rand.to_s
2470 node_xml["lon"] = rand.to_s
2471 node_xml["version"] = offset.to_s
2473 put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
2474 assert_response :conflict, "final attempt should have failed"
2477 changeset = Changeset.find(cs_id)
2478 assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
2480 # check that the changeset is now closed as well
2481 assert_not(changeset.open?,
2482 "changeset should have been auto-closed by exceeding " \
2489 # check that the output consists of one specific changeset
2490 def assert_single_changeset(changeset, &)
2491 assert_dom "> changeset", 1 do
2492 assert_dom "> @id", changeset.id.to_s
2493 assert_dom "> @created_at", changeset.created_at.xmlschema
2495 assert_dom "> @open", "true"
2496 assert_dom "> @closed_at", 0
2498 assert_dom "> @open", "false"
2499 assert_dom "> @closed_at", changeset.closed_at.xmlschema
2501 assert_dom "> @comments_count", changeset.comments.length.to_s
2502 assert_dom "> @changes_count", changeset.num_changes.to_s
2503 yield if block_given?
2507 def assert_single_changeset_json(changeset, js)
2508 assert_equal changeset.id, js["changeset"]["id"]
2509 assert_equal changeset.created_at.xmlschema, js["changeset"]["created_at"]
2511 assert js["changeset"]["open"]
2512 assert_nil js["changeset"]["closed_at"]
2514 assert_not js["changeset"]["open"]
2515 assert_equal changeset.closed_at.xmlschema, js["changeset"]["closed_at"]
2517 assert_equal changeset.comments.length, js["changeset"]["comments_count"]
2518 assert_equal changeset.num_changes, js["changeset"]["changes_count"]
2522 # check that certain changesets exist in the output in the specified order
2523 def assert_changesets_in_order(changesets)
2524 assert_select "osm>changeset", changesets.size
2525 changesets.each_with_index do |changeset, index|
2526 assert_select "osm>changeset:nth-child(#{index + 1})[id='#{changeset.id}']", 1
2531 # update the changeset_id of a way element
2532 def update_changeset(xml, changeset_id)
2533 xml_attr_rewrite(xml, "changeset", changeset_id)
2537 # update an attribute in a way element
2538 def xml_attr_rewrite(xml, name, value)
2539 xml.find("//osm/way").first[name] = value.to_s
2544 # build XML for changesets
2545 def create_changeset_xml(user: nil, id: nil)
2546 root = XML::Document.new
2547 root.root = XML::Node.new "osm"
2548 cs = XML::Node.new "changeset"
2550 cs["user"] = user.display_name
2551 cs["uid"] = user.id.to_s
2553 cs["id"] = id.to_s if id