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/uploads", :action => "create", :changeset_id => "1" }
38 { :controller => "api/changesets", :action => "create" },
39 { :path => "/api/0.6/changeset/create", :method => :put }
44 # test the query functionality of changesets
46 private_user = create(:user, :data_public => false)
47 private_user_changeset = create(:changeset, :user => private_user)
48 private_user_closed_changeset = create(:changeset, :closed, :user => private_user)
50 changeset = create(:changeset, :user => user)
51 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))
52 changeset2 = create(:changeset, :bbox => [5, 5, 15, 15])
53 changeset3 = create(:changeset, :bbox => [4.5, 4.5, 5, 5])
55 get api_changesets_path(:bbox => "-10,-10, 10, 10")
56 assert_response :success, "can't get changesets in bbox"
57 assert_changesets_in_order [changeset3, changeset2]
59 get api_changesets_path(:bbox => "4.5,4.5,4.6,4.6")
60 assert_response :success, "can't get changesets in bbox"
61 assert_changesets_in_order [changeset3]
63 # not found when looking for changesets of non-existing users
64 get api_changesets_path(:user => User.maximum(:id) + 1)
65 assert_response :not_found
66 assert_equal "text/plain", @response.media_type
67 get api_changesets_path(:display_name => " ")
68 assert_response :not_found
69 assert_equal "text/plain", @response.media_type
71 # can't get changesets of user 1 without authenticating
72 get api_changesets_path(:user => private_user.id)
73 assert_response :not_found, "shouldn't be able to get changesets by non-public user (ID)"
74 get api_changesets_path(:display_name => private_user.display_name)
75 assert_response :not_found, "shouldn't be able to get changesets by non-public user (name)"
77 # but this should work
78 auth_header = bearer_authorization_header private_user
79 get api_changesets_path(:user => private_user.id), :headers => auth_header
80 assert_response :success, "can't get changesets by user ID"
81 assert_changesets_in_order [private_user_changeset, private_user_closed_changeset]
83 get api_changesets_path(:display_name => private_user.display_name), :headers => auth_header
84 assert_response :success, "can't get changesets by user name"
85 assert_changesets_in_order [private_user_changeset, private_user_closed_changeset]
88 get api_changesets_path(:display_name => private_user.display_name), :headers => auth_header, :params => { :format => "json" }
89 assert_response :success, "can't get changesets by user name"
91 js = ActiveSupport::JSON.decode(@response.body)
94 assert_equal Settings.api_version, js["version"]
95 assert_equal Settings.generator, js["generator"]
96 assert_equal 2, js["changesets"].count
98 # check that the correct error is given when we provide both UID and name
99 get api_changesets_path(:user => private_user.id,
100 :display_name => private_user.display_name), :headers => auth_header
101 assert_response :bad_request, "should be a bad request to have both ID and name specified"
103 get api_changesets_path(:user => private_user.id, :open => true), :headers => auth_header
104 assert_response :success, "can't get changesets by user and open"
105 assert_changesets_in_order [private_user_changeset]
107 get api_changesets_path(:time => "2007-12-31"), :headers => auth_header
108 assert_response :success, "can't get changesets by time-since"
109 assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset, private_user_closed_changeset, closed_changeset]
111 get api_changesets_path(:time => "2008-01-01T12:34Z"), :headers => auth_header
112 assert_response :success, "can't get changesets by time-since with hour"
113 assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset, private_user_closed_changeset, closed_changeset]
115 get api_changesets_path(:time => "2007-12-31T23:59Z,2008-01-02T00:01Z"), :headers => auth_header
116 assert_response :success, "can't get changesets by time-range"
117 assert_changesets_in_order [closed_changeset]
119 get api_changesets_path(:open => "true"), :headers => auth_header
120 assert_response :success, "can't get changesets by open-ness"
121 assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset]
123 get api_changesets_path(:closed => "true"), :headers => auth_header
124 assert_response :success, "can't get changesets by closed-ness"
125 assert_changesets_in_order [private_user_closed_changeset, closed_changeset]
127 get api_changesets_path(:closed => "true", :user => private_user.id), :headers => auth_header
128 assert_response :success, "can't get changesets by closed-ness and user"
129 assert_changesets_in_order [private_user_closed_changeset]
131 get api_changesets_path(:closed => "true", :user => user.id), :headers => auth_header
132 assert_response :success, "can't get changesets by closed-ness and user"
133 assert_changesets_in_order [closed_changeset]
135 get api_changesets_path(:changesets => "#{private_user_changeset.id},#{changeset.id},#{closed_changeset.id}"), :headers => auth_header
136 assert_response :success, "can't get changesets by id (as comma-separated string)"
137 assert_changesets_in_order [changeset, private_user_changeset, closed_changeset]
139 get api_changesets_path(:changesets => ""), :headers => auth_header
140 assert_response :bad_request, "should be a bad request since changesets is empty"
144 # test the query functionality of changesets with the limit parameter
147 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))
148 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))
149 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))
150 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))
151 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))
153 get api_changesets_path
154 assert_response :success
155 assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
157 get api_changesets_path(:limit => "3")
158 assert_response :success
159 assert_changesets_in_order [changeset5, changeset4, changeset3]
161 get api_changesets_path(:limit => "0")
162 assert_response :bad_request
164 get api_changesets_path(:limit => Settings.max_changeset_query_limit)
165 assert_response :success
166 assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
168 get api_changesets_path(:limit => Settings.max_changeset_query_limit + 1)
169 assert_response :bad_request
173 # test the query functionality of sequential changesets with order and time parameters
176 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))
177 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))
178 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))
179 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))
180 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))
181 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))
183 get api_changesets_path
184 assert_response :success
185 assert_changesets_in_order [changeset6, changeset5, changeset4, changeset3, changeset2, changeset1]
187 get api_changesets_path(:order => "oldest")
188 assert_response :success
189 assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4, changeset5, changeset6]
192 # lower time bound at the opening time of a changeset
193 ["2008-02-01T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3, changeset2]],
194 # lower time bound in the middle of a changeset
195 ["2008-02-01T12:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
196 # lower time bound at the closing time of a changeset
197 ["2008-02-02T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
198 # lower time bound after the closing time of a changeset
199 ["2008-02-02T00:00:01Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3], [changeset5, changeset4, changeset3]],
200 # upper time bound in the middle of a changeset
201 ["2007-09-09T12:00:00Z", "2008-04-01T12:00:00Z", [changeset4, changeset3, changeset2, changeset1], [changeset4, changeset3, changeset2, changeset1]],
203 ["2009-02-02T00:00:01Z", "2018-05-15T00:00:00Z", [], []]
204 ].each do |from, to, interval_changesets, point_changesets|
205 get api_changesets_path(:time => "#{from},#{to}")
206 assert_response :success
207 assert_changesets_in_order interval_changesets
209 get api_changesets_path(:from => from, :to => to)
210 assert_response :success
211 assert_changesets_in_order point_changesets
213 get api_changesets_path(:from => from, :to => to, :order => "oldest")
214 assert_response :success
215 assert_changesets_in_order point_changesets.reverse
220 # test the query functionality of overlapping changesets with order and time parameters
221 def test_index_order_overlapping
223 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))
224 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))
225 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))
226 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))
227 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))
229 get api_changesets_path(:time => "2015-06-04T00:00:00Z")
230 assert_response :success
231 assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
233 get api_changesets_path(:from => "2015-06-04T00:00:00Z")
234 assert_response :success
235 assert_changesets_in_order [changeset1, changeset2, changeset3]
237 get api_changesets_path(:from => "2015-06-04T00:00:00Z", :order => "oldest")
238 assert_response :success
239 assert_changesets_in_order [changeset3, changeset2, changeset1]
241 get api_changesets_path(:time => "2015-06-04T16:00:00Z,2015-06-04T17:30:00Z")
242 assert_response :success
243 assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
245 get api_changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z")
246 assert_response :success
247 assert_changesets_in_order [changeset1, changeset2]
249 get api_changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z", :order => "oldest")
250 assert_response :success
251 assert_changesets_in_order [changeset2, changeset1]
255 # check that errors are returned if garbage is inserted
257 def test_index_invalid
260 ";drop table users;"].each do |bbox|
261 get api_changesets_path(:bbox => bbox)
262 assert_response :bad_request, "'#{bbox}' isn't a bbox"
267 ";drop table users;",
269 "-,-"].each do |time|
270 get api_changesets_path(:time => time)
271 assert_response :bad_request, "'#{time}' isn't a valid time range"
278 get api_changesets_path(:user => uid)
279 assert_response :bad_request, "'#{uid}' isn't a valid user ID"
282 get api_changesets_path(:order => "oldest", :time => "2008-01-01T00:00Z,2018-01-01T00:00Z")
283 assert_response :bad_request, "cannot use order=oldest with time"
286 # -----------------------
287 # Test simple changeset creation
288 # -----------------------
291 auth_header = bearer_authorization_header create(:user, :data_public => false)
292 # Create the first user's changeset
293 xml = "<osm><changeset>" \
294 "<tag k='created_by' v='osm test suite checking changesets'/>" \
296 post api_changesets_path, :params => xml, :headers => auth_header
297 assert_require_public_data
299 auth_header = bearer_authorization_header
300 # Create the first user's changeset
301 xml = "<osm><changeset>" \
302 "<tag k='created_by' v='osm test suite checking changesets'/>" \
304 post api_changesets_path, :params => xml, :headers => auth_header
306 assert_response :success, "Creation of changeset did not return success status"
307 newid = @response.body.to_i
309 # check end time, should be an hour ahead of creation time
310 cs = Changeset.find(newid)
311 duration = cs.closed_at - cs.created_at
312 # the difference can either be a rational, or a floating point number
313 # of seconds, depending on the code path taken :-(
314 if duration.instance_of?(Rational)
315 assert_equal Rational(1, 24), duration, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
317 # must be number of seconds...
318 assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
321 # checks if uploader was subscribed
322 assert_equal 1, cs.subscribers.length
325 def test_create_invalid
326 auth_header = bearer_authorization_header create(:user, :data_public => false)
327 xml = "<osm><changeset></osm>"
328 post api_changesets_path, :params => xml, :headers => auth_header
329 assert_require_public_data
331 ## Try the public user
332 auth_header = bearer_authorization_header
333 xml = "<osm><changeset></osm>"
334 post api_changesets_path, :params => xml, :headers => auth_header
335 assert_response :bad_request, "creating a invalid changeset should fail"
338 def test_create_invalid_no_content
339 ## First check with no auth
340 post api_changesets_path
341 assert_response :unauthorized, "shouldn't be able to create a changeset with no auth"
343 ## Now try to with a non-public user
344 auth_header = bearer_authorization_header create(:user, :data_public => false)
345 post api_changesets_path, :headers => auth_header
346 assert_require_public_data
348 ## Try an inactive user
349 auth_header = bearer_authorization_header create(:user, :pending)
350 post api_changesets_path, :headers => auth_header
353 ## Now try to use a normal user
354 auth_header = bearer_authorization_header
355 post api_changesets_path, :headers => auth_header
356 assert_response :bad_request, "creating a changeset with no content should fail"
359 def test_create_wrong_method
360 auth_header = bearer_authorization_header
362 put api_changesets_path, :headers => auth_header
363 assert_response :not_found
364 assert_template "rescues/routing_error"
367 def test_create_legacy_path
368 auth_header = bearer_authorization_header
369 xml = "<osm><changeset></changeset></osm>"
371 assert_difference "Changeset.count", 1 do
372 put "/api/0.6/changeset/create", :params => xml, :headers => auth_header
375 assert_response :success, "Creation of changeset did not return success status"
376 assert_equal Changeset.last.id, @response.body.to_i
380 # check that the changeset can be shown and returns the correct
381 # document structure.
383 changeset = create(:changeset)
385 get api_changeset_path(changeset)
386 assert_response :success, "cannot get first changeset"
388 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
389 assert_single_changeset changeset do
390 assert_dom "> discussion", 0
393 get api_changeset_path(changeset, :include_discussion => true)
394 assert_response :success, "cannot get first changeset with comments"
396 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
397 assert_single_changeset changeset do
398 assert_dom "> discussion", 1
399 assert_dom "> discussion > comment", 0
403 def test_show_comments
404 # all comments visible
405 changeset = create(:changeset, :closed)
406 comment1, comment2, comment3 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
408 get api_changeset_path(changeset, :include_discussion => true)
409 assert_response :success, "cannot get closed changeset with comments"
411 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
412 assert_single_changeset changeset do
413 assert_dom "> discussion", 1 do
414 assert_dom "> comment", 3 do |dom_comments|
415 assert_dom dom_comments[0], "> @id", comment1.id.to_s
416 assert_dom dom_comments[0], "> @visible", "true"
417 assert_dom dom_comments[1], "> @id", comment2.id.to_s
418 assert_dom dom_comments[1], "> @visible", "true"
419 assert_dom dom_comments[2], "> @id", comment3.id.to_s
420 assert_dom dom_comments[2], "> @visible", "true"
426 # one hidden comment not included because not asked for
427 comment2.update(:visible => false)
430 get api_changeset_path(changeset, :include_discussion => true)
431 assert_response :success, "cannot get closed changeset with comments"
433 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
434 assert_single_changeset changeset do
435 assert_dom "> discussion", 1 do
436 assert_dom "> comment", 2 do |dom_comments|
437 assert_dom dom_comments[0], "> @id", comment1.id.to_s
438 assert_dom dom_comments[0], "> @visible", "true"
439 assert_dom dom_comments[1], "> @id", comment3.id.to_s
440 assert_dom dom_comments[1], "> @visible", "true"
445 # one hidden comment not included because no permissions
446 get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true)
447 assert_response :success, "cannot get closed changeset with comments"
449 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
450 assert_single_changeset changeset do
451 assert_dom "> discussion", 1 do
452 assert_dom "> comment", 2 do |dom_comments|
453 assert_dom dom_comments[0], "> @id", comment1.id.to_s
454 assert_dom dom_comments[0], "> @visible", "true"
455 # maybe will show an empty comment element with visible=false in the future
456 assert_dom dom_comments[1], "> @id", comment3.id.to_s
457 assert_dom dom_comments[1], "> @visible", "true"
462 # one hidden comment shown to moderators
463 moderator_user = create(:moderator_user)
464 auth_header = bearer_authorization_header moderator_user
465 get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
466 assert_response :success, "cannot get closed changeset with comments"
468 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
469 assert_single_changeset changeset do
470 assert_dom "> discussion", 1 do
471 assert_dom "> comment", 3 do |dom_comments|
472 assert_dom dom_comments[0], "> @id", comment1.id.to_s
473 assert_dom dom_comments[0], "> @visible", "true"
474 assert_dom dom_comments[1], "> @id", comment2.id.to_s
475 assert_dom dom_comments[1], "> @visible", "false"
476 assert_dom dom_comments[2], "> @id", comment3.id.to_s
477 assert_dom dom_comments[2], "> @visible", "true"
484 changeset = create(:changeset, :closed)
485 create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
486 create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
488 get api_changeset_path(changeset)
490 assert_response :success
491 assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
492 assert_single_changeset changeset do
493 assert_dom "> tag", 2
494 assert_dom "> tag[k='created_by'][v='JOSM/1.5 (18364)']", 1
495 assert_dom "> tag[k='comment'][v='changeset comment']", 1
500 changeset = create(:changeset)
502 get api_changeset_path(changeset, :format => "json")
503 assert_response :success, "cannot get first changeset"
505 js = ActiveSupport::JSON.decode(@response.body)
508 assert_equal Settings.api_version, js["version"]
509 assert_equal Settings.generator, js["generator"]
510 assert_single_changeset_json changeset, js
511 assert_nil js["changeset"]["tags"]
512 assert_nil js["changeset"]["comments"]
513 assert_equal changeset.user.id, js["changeset"]["uid"]
514 assert_equal changeset.user.display_name, js["changeset"]["user"]
516 get api_changeset_path(changeset, :format => "json", :include_discussion => true)
517 assert_response :success, "cannot get first changeset with comments"
519 js = ActiveSupport::JSON.decode(@response.body)
521 assert_equal Settings.api_version, js["version"]
522 assert_equal Settings.generator, js["generator"]
523 assert_single_changeset_json changeset, js
524 assert_nil js["changeset"]["tags"]
525 assert_nil js["changeset"]["min_lat"]
526 assert_nil js["changeset"]["min_lon"]
527 assert_nil js["changeset"]["max_lat"]
528 assert_nil js["changeset"]["max_lon"]
529 assert_equal 0, js["changeset"]["comments"].count
532 def test_show_comments_json
533 # all comments visible
534 changeset = create(:changeset, :closed)
535 comment0, comment1, comment2 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
537 get api_changeset_path(changeset, :format => "json", :include_discussion => true)
538 assert_response :success, "cannot get closed changeset with comments"
540 js = ActiveSupport::JSON.decode(@response.body)
542 assert_equal Settings.api_version, js["version"]
543 assert_equal Settings.generator, js["generator"]
544 assert_single_changeset_json changeset, js
545 assert_equal 3, js["changeset"]["comments"].count
546 assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
547 assert js["changeset"]["comments"][0]["visible"]
548 assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
549 assert js["changeset"]["comments"][1]["visible"]
550 assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
551 assert js["changeset"]["comments"][2]["visible"]
553 # one hidden comment not included because not asked for
554 comment1.update(:visible => false)
557 get api_changeset_path(changeset, :format => "json", :include_discussion => true)
558 assert_response :success, "cannot get closed changeset with comments"
560 js = ActiveSupport::JSON.decode(@response.body)
562 assert_equal Settings.api_version, js["version"]
563 assert_equal Settings.generator, js["generator"]
564 assert_single_changeset_json changeset, js
565 assert_equal 2, js["changeset"]["comments"].count
566 assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
567 assert js["changeset"]["comments"][0]["visible"]
568 assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
569 assert js["changeset"]["comments"][1]["visible"]
571 # one hidden comment not included because no permissions
572 get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true)
573 assert_response :success, "cannot get closed changeset with comments"
575 js = ActiveSupport::JSON.decode(@response.body)
577 assert_equal Settings.api_version, js["version"]
578 assert_equal Settings.generator, js["generator"]
579 assert_single_changeset_json changeset, js
580 assert_equal 2, js["changeset"]["comments"].count
581 assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
582 assert js["changeset"]["comments"][0]["visible"]
583 # maybe will show an empty comment element with visible=false in the future
584 assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
585 assert js["changeset"]["comments"][1]["visible"]
587 # one hidden comment shown to moderators
588 moderator_user = create(:moderator_user)
589 auth_header = bearer_authorization_header moderator_user
590 get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
591 assert_response :success, "cannot get closed changeset with comments"
593 js = ActiveSupport::JSON.decode(@response.body)
595 assert_equal Settings.api_version, js["version"]
596 assert_equal Settings.generator, js["generator"]
597 assert_single_changeset_json changeset, js
598 assert_equal 3, js["changeset"]["comments"].count
599 assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
600 assert js["changeset"]["comments"][0]["visible"]
601 assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
602 assert_not js["changeset"]["comments"][1]["visible"]
603 assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
604 assert js["changeset"]["comments"][2]["visible"]
607 def test_show_tags_json
608 changeset = create(:changeset, :closed)
609 create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
610 create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
612 get api_changeset_path(changeset, :format => "json")
614 assert_response :success
615 js = ActiveSupport::JSON.decode(@response.body)
617 assert_equal Settings.api_version, js["version"]
618 assert_equal Settings.generator, js["generator"]
619 assert_single_changeset_json changeset, js
620 assert_equal 2, js["changeset"]["tags"].count
621 assert_equal "JOSM/1.5 (18364)", js["changeset"]["tags"]["created_by"]
622 assert_equal "changeset comment", js["changeset"]["tags"]["comment"]
625 def test_show_bbox_json
626 changeset = create(:changeset, :bbox => [5, -5, 12, 15])
628 get api_changeset_path(changeset, :format => "json")
629 assert_response :success, "cannot get first changeset"
631 js = ActiveSupport::JSON.decode(@response.body)
633 assert_equal(-5, js["changeset"]["min_lat"])
634 assert_equal 5, js["changeset"]["min_lon"]
635 assert_equal 15, js["changeset"]["max_lat"]
636 assert_equal 12, js["changeset"]["max_lon"]
640 # check that a changeset that doesn't exist returns an appropriate message
641 def test_show_not_found
642 [0, -32, 233455644, "afg", "213"].each do |id|
643 get api_changeset_path(id)
644 assert_response :not_found, "should get a not found"
645 rescue ActionController::UrlGenerationError => e
646 assert_match(/No route matches/, e.to_s)
651 # upload something simple, but valid and check that it can
653 # Also try without auth and another user.
654 def test_upload_simple_valid
655 private_user = create(:user, :data_public => false)
656 private_changeset = create(:changeset, :user => private_user)
658 changeset = create(:changeset, :user => user)
662 relation = create(:relation)
663 other_relation = create(:relation)
664 # create some tags, since we test that they are removed later
665 create(:node_tag, :node => node)
666 create(:way_tag, :way => way)
667 create(:relation_tag, :relation => relation)
670 changeset_id = changeset.id
672 # simple diff to change a node, way and relation by removing
677 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
678 <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
679 <nd ref='#{node.id}'/>
683 <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
684 <member type='way' role='some' ref='#{way.id}'/>
685 <member type='node' role='some' ref='#{node.id}'/>
686 <member type='relation' role='some' ref='#{other_relation.id}'/>
693 post api_changeset_upload_path(changeset), :params => diff
694 assert_response :unauthorized,
695 "shouldn't be able to upload a simple valid diff to changeset: #{@response.body}"
697 ## Now try with a private user
698 auth_header = bearer_authorization_header private_user
699 changeset_id = private_changeset.id
701 # simple diff to change a node, way and relation by removing
706 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
707 <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
708 <nd ref='#{node.id}'/>
712 <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
713 <member type='way' role='some' ref='#{way.id}'/>
714 <member type='node' role='some' ref='#{node.id}'/>
715 <member type='relation' role='some' ref='#{other_relation.id}'/>
722 post api_changeset_upload_path(private_changeset), :params => diff, :headers => auth_header
723 assert_response :forbidden,
724 "can't upload a simple valid diff to changeset: #{@response.body}"
726 ## Now try with the public user
727 auth_header = bearer_authorization_header user
728 changeset_id = changeset.id
730 # simple diff to change a node, way and relation by removing
735 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
736 <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
737 <nd ref='#{node.id}'/>
741 <relation id='#{relation.id}' changeset='#{changeset_id}' version='1'>
742 <member type='way' role='some' ref='#{way.id}'/>
743 <member type='node' role='some' ref='#{node.id}'/>
744 <member type='relation' role='some' ref='#{other_relation.id}'/>
751 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
752 assert_response :success,
753 "can't upload a simple valid diff to changeset: #{@response.body}"
755 # check that the changes made it into the database
756 assert_equal 0, Node.find(node.id).tags.size, "node #{node.id} should now have no tags"
757 assert_equal 0, Way.find(way.id).tags.size, "way #{way.id} should now have no tags"
758 assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
762 # upload something which creates new objects using placeholders
763 def test_upload_create_valid
765 changeset = create(:changeset, :user => user)
767 way = create(:way_with_nodes, :nodes_count => 2)
768 relation = create(:relation)
770 auth_header = bearer_authorization_header user
772 # simple diff to create a node way and relation using placeholders
776 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
777 <tag k='foo' v='bar'/>
778 <tag k='baz' v='bat'/>
780 <way id='-1' changeset='#{changeset.id}'>
781 <nd ref='#{node.id}'/>
785 <relation id='-1' changeset='#{changeset.id}'>
786 <member type='way' role='some' ref='#{way.id}'/>
787 <member type='node' role='some' ref='#{node.id}'/>
788 <member type='relation' role='some' ref='#{relation.id}'/>
795 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
796 assert_response :success,
797 "can't upload a simple valid creation to changeset: #{@response.body}"
799 # check the returned payload
800 new_node_id, new_way_id, new_rel_id = nil
801 assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
802 # inspect the response to find out what the new element IDs are
803 # check the old IDs are all present and negative one
804 # check the versions are present and equal one
805 assert_dom "> node", 1 do |(node_el)|
806 new_node_id = node_el["new_id"].to_i
807 assert_dom "> @old_id", "-1"
808 assert_dom "> @new_version", "1"
810 assert_dom "> way", 1 do |(way_el)|
811 new_way_id = way_el["new_id"].to_i
812 assert_dom "> @old_id", "-1"
813 assert_dom "> @new_version", "1"
815 assert_dom "> relation", 1 do |(rel_el)|
816 new_rel_id = rel_el["new_id"].to_i
817 assert_dom "> @old_id", "-1"
818 assert_dom "> @new_version", "1"
822 # check that the changes made it into the database
823 assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
824 assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
825 assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
829 # test a complex delete where we delete elements which rely on eachother
830 # in the same transaction.
831 def test_upload_delete
832 changeset = create(:changeset)
833 super_relation = create(:relation)
834 used_relation = create(:relation)
835 used_way = create(:way)
836 used_node = create(:node)
837 create(:relation_member, :relation => super_relation, :member => used_relation)
838 create(:relation_member, :relation => super_relation, :member => used_way)
839 create(:relation_member, :relation => super_relation, :member => used_node)
841 auth_header = bearer_authorization_header changeset.user
843 diff = XML::Document.new
844 diff.root = XML::Node.new "osmChange"
845 delete = XML::Node.new "delete"
847 delete << xml_node_for_relation(super_relation)
848 delete << xml_node_for_relation(used_relation)
849 delete << xml_node_for_way(used_way)
850 delete << xml_node_for_node(used_node)
852 # update the changeset to one that this user owns
853 %w[node way relation].each do |type|
854 delete.find("//osmChange/delete/#{type}").each do |n|
855 n["changeset"] = changeset.id.to_s
860 post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
861 assert_response :success,
862 "can't upload a deletion diff to changeset: #{@response.body}"
864 # check the response is well-formed
865 assert_select "diffResult>node", 1
866 assert_select "diffResult>way", 1
867 assert_select "diffResult>relation", 2
869 # check that everything was deleted
870 assert_not Node.find(used_node.id).visible
871 assert_not Way.find(used_way.id).visible
872 assert_not Relation.find(super_relation.id).visible
873 assert_not Relation.find(used_relation.id).visible
877 # test uploading a delete with no lat/lon, as they are optional in
878 # the osmChange spec.
879 def test_upload_nolatlon_delete
881 changeset = create(:changeset)
883 auth_header = bearer_authorization_header changeset.user
884 diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{changeset.id}'/></delete></osmChange>"
887 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
888 assert_response :success,
889 "can't upload a deletion diff to changeset: #{@response.body}"
891 # check the response is well-formed
892 assert_select "diffResult>node", 1
894 # check that everything was deleted
895 assert_not Node.find(node.id).visible
898 def test_repeated_changeset_create
900 auth_header = bearer_authorization_header
902 # create a temporary changeset
903 xml = "<osm><changeset>" \
904 "<tag k='created_by' v='osm test suite checking changesets'/>" \
906 assert_difference "Changeset.count", 1 do
907 post api_changesets_path, :params => xml, :headers => auth_header
909 assert_response :success
913 def test_upload_large_changeset
915 auth_header = bearer_authorization_header user
917 # create an old changeset to ensure we have the maximum rate limit
918 create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
921 post api_changesets_path, :params => "<osm><changeset/></osm>", :headers => auth_header
922 assert_response :success, "Should be able to create a changeset: #{@response.body}"
923 changeset_id = @response.body.to_i
925 # upload some widely-spaced nodes, spiralling positive and negative
929 <node id='-1' lon='-20' lat='-10' changeset='#{changeset_id}'/>
930 <node id='-10' lon='20' lat='10' changeset='#{changeset_id}'/>
931 <node id='-2' lon='-40' lat='-20' changeset='#{changeset_id}'/>
932 <node id='-11' lon='40' lat='20' changeset='#{changeset_id}'/>
933 <node id='-3' lon='-60' lat='-30' changeset='#{changeset_id}'/>
934 <node id='-12' lon='60' lat='30' changeset='#{changeset_id}'/>
935 <node id='-4' lon='-80' lat='-40' changeset='#{changeset_id}'/>
936 <node id='-13' lon='80' lat='40' changeset='#{changeset_id}'/>
937 <node id='-5' lon='-100' lat='-50' changeset='#{changeset_id}'/>
938 <node id='-14' lon='100' lat='50' changeset='#{changeset_id}'/>
939 <node id='-6' lon='-120' lat='-60' changeset='#{changeset_id}'/>
940 <node id='-15' lon='120' lat='60' changeset='#{changeset_id}'/>
941 <node id='-7' lon='-140' lat='-70' changeset='#{changeset_id}'/>
942 <node id='-16' lon='140' lat='70' changeset='#{changeset_id}'/>
943 <node id='-8' lon='-160' lat='-80' changeset='#{changeset_id}'/>
944 <node id='-17' lon='160' lat='80' changeset='#{changeset_id}'/>
945 <node id='-9' lon='-179.9' lat='-89.9' changeset='#{changeset_id}'/>
946 <node id='-18' lon='179.9' lat='89.9' changeset='#{changeset_id}'/>
951 # upload it, which used to cause an error like "PGError: ERROR:
952 # integer out of range" (bug #2152). but shouldn't any more.
953 post api_changeset_upload_path(changeset_id), :params => diff, :headers => auth_header
954 assert_response :success,
955 "can't upload a spatially-large diff to changeset: #{@response.body}"
957 # check that the changeset bbox is within bounds
958 cs = Changeset.find(changeset_id)
959 assert_operator cs.min_lon, :>=, -180 * GeoRecord::SCALE, "Minimum longitude (#{cs.min_lon / GeoRecord::SCALE}) should be >= -180 to be valid."
960 assert_operator cs.max_lon, :<=, 180 * GeoRecord::SCALE, "Maximum longitude (#{cs.max_lon / GeoRecord::SCALE}) should be <= 180 to be valid."
961 assert_operator cs.min_lat, :>=, -90 * GeoRecord::SCALE, "Minimum latitude (#{cs.min_lat / GeoRecord::SCALE}) should be >= -90 to be valid."
962 assert_operator cs.max_lat, :<=, 90 * GeoRecord::SCALE, "Maximum latitude (#{cs.max_lat / GeoRecord::SCALE}) should be <= 90 to be valid."
966 # test that deleting stuff in a transaction doesn't bypass the checks
967 # to ensure that used elements are not deleted.
968 def test_upload_delete_invalid
969 changeset = create(:changeset)
970 relation = create(:relation)
971 other_relation = create(:relation)
972 used_way = create(:way)
973 used_node = create(:node)
974 create(:relation_member, :relation => relation, :member => used_way)
975 create(:relation_member, :relation => relation, :member => used_node)
977 auth_header = bearer_authorization_header changeset.user
979 diff = XML::Document.new
980 diff.root = XML::Node.new "osmChange"
981 delete = XML::Node.new "delete"
983 delete << xml_node_for_relation(other_relation)
984 delete << xml_node_for_way(used_way)
985 delete << xml_node_for_node(used_node)
987 # update the changeset to one that this user owns
988 %w[node way relation].each do |type|
989 delete.find("//osmChange/delete/#{type}").each do |n|
990 n["changeset"] = changeset.id.to_s
995 post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
996 assert_response :precondition_failed,
997 "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
998 assert_equal "Precondition failed: Way #{used_way.id} is still used by relations #{relation.id}.", @response.body
1000 # check that nothing was, in fact, deleted
1001 assert Node.find(used_node.id).visible
1002 assert Way.find(used_way.id).visible
1003 assert Relation.find(relation.id).visible
1004 assert Relation.find(other_relation.id).visible
1008 # test that a conditional delete of an in use object works.
1009 def test_upload_delete_if_unused
1010 changeset = create(:changeset)
1011 super_relation = create(:relation)
1012 used_relation = create(:relation)
1013 used_way = create(:way)
1014 used_node = create(:node)
1015 create(:relation_member, :relation => super_relation, :member => used_relation)
1016 create(:relation_member, :relation => super_relation, :member => used_way)
1017 create(:relation_member, :relation => super_relation, :member => used_node)
1019 auth_header = bearer_authorization_header changeset.user
1021 diff = XML::Document.new
1022 diff.root = XML::Node.new "osmChange"
1023 delete = XML::Node.new "delete"
1025 delete["if-unused"] = ""
1026 delete << xml_node_for_relation(used_relation)
1027 delete << xml_node_for_way(used_way)
1028 delete << xml_node_for_node(used_node)
1030 # update the changeset to one that this user owns
1031 %w[node way relation].each do |type|
1032 delete.find("//osmChange/delete/#{type}").each do |n|
1033 n["changeset"] = changeset.id.to_s
1038 post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
1039 assert_response :success,
1040 "can't do a conditional delete of in use objects: #{@response.body}"
1042 # check the returned payload
1043 assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
1044 # check the old IDs are all present and what we expect
1045 # check the new IDs are all present and unchanged
1046 # check the new versions are all present and unchanged
1047 assert_dom "> node", 1 do
1048 assert_dom "> @old_id", used_node.id.to_s
1049 assert_dom "> @new_id", used_node.id.to_s
1050 assert_dom "> @new_version", used_node.version.to_s
1052 assert_dom "> way", 1 do
1053 assert_dom "> @old_id", used_way.id.to_s
1054 assert_dom "> @new_id", used_way.id.to_s
1055 assert_dom "> @new_version", used_way.version.to_s
1057 assert_dom "> relation", 1 do
1058 assert_dom "> @old_id", used_relation.id.to_s
1059 assert_dom "> @new_id", used_relation.id.to_s
1060 assert_dom "> @new_version", used_relation.version.to_s
1064 # check that nothing was, in fact, deleted
1065 assert Node.find(used_node.id).visible
1066 assert Way.find(used_way.id).visible
1067 assert Relation.find(used_relation.id).visible
1071 # upload an element with a really long tag value
1072 def test_upload_invalid_too_long_tag
1073 changeset = create(:changeset)
1075 auth_header = bearer_authorization_header changeset.user
1077 # simple diff to create a node way and relation using placeholders
1081 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
1082 <tag k='foo' v='#{'x' * 256}'/>
1089 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1090 assert_response :bad_request,
1091 "shouldn't be able to upload too long a tag to changeset: #{@response.body}"
1095 # upload something which creates new objects and inserts them into
1096 # existing containers using placeholders.
1097 def test_upload_complex
1099 node = create(:node)
1100 relation = create(:relation)
1101 create(:way_node, :way => way, :node => node)
1103 changeset = create(:changeset)
1105 auth_header = bearer_authorization_header changeset.user
1107 # simple diff to create a node way and relation using placeholders
1111 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
1112 <tag k='foo' v='bar'/>
1113 <tag k='baz' v='bat'/>
1117 <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
1119 <nd ref='#{node.id}'/>
1121 <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
1122 <member type='way' role='some' ref='#{way.id}'/>
1123 <member type='node' role='some' ref='-1'/>
1124 <member type='relation' role='some' ref='#{relation.id}'/>
1131 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1132 assert_response :success,
1133 "can't upload a complex diff to changeset: #{@response.body}"
1135 # check the returned payload
1137 assert_dom "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
1138 assert_dom "> node", 1 do |(node_el)|
1139 new_node_id = node_el["new_id"].to_i
1141 assert_dom "> way", 1
1142 assert_dom "> relation", 1
1145 # check that the changes made it into the database
1146 assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
1147 assert_equal [new_node_id, node.id], Way.find(way.id).nds, "way nodes should match"
1148 Relation.find(relation.id).members.each do |type, id, _role|
1149 assert_equal new_node_id, id, "relation should contain new node" if type == "node"
1154 # create a diff which references several changesets, which should cause
1155 # a rollback and none of the diff gets committed
1156 def test_upload_invalid_changesets
1157 changeset = create(:changeset)
1158 other_changeset = create(:changeset, :user => changeset.user)
1159 node = create(:node)
1161 relation = create(:relation)
1162 other_relation = create(:relation)
1164 auth_header = bearer_authorization_header changeset.user
1166 # simple diff to create a node way and relation using placeholders
1170 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1171 <way id='#{way.id}' changeset='#{changeset.id}' version='1'>
1172 <nd ref='#{node.id}'/>
1176 <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'>
1177 <member type='way' role='some' ref='#{way.id}'/>
1178 <member type='node' role='some' ref='#{node.id}'/>
1179 <member type='relation' role='some' ref='#{other_relation.id}'/>
1183 <node id='-1' lon='0' lat='0' changeset='#{other_changeset.id}'>
1184 <tag k='foo' v='bar'/>
1185 <tag k='baz' v='bat'/>
1192 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1193 assert_response :conflict,
1194 "uploading a diff with multiple changesets should have failed"
1196 # check that objects are unmodified
1197 assert_nodes_are_equal(node, Node.find(node.id))
1198 assert_ways_are_equal(way, Way.find(way.id))
1199 assert_relations_are_equal(relation, Relation.find(relation.id))
1203 # upload multiple versions of the same element in the same diff.
1204 def test_upload_multiple_valid
1205 node = create(:node)
1206 changeset = create(:changeset)
1207 auth_header = bearer_authorization_header changeset.user
1209 # change the location of a node multiple times, each time referencing
1210 # the last version. doesn't this depend on version numbers being
1215 <node id='#{node.id}' lon='0.0' lat='0.0' changeset='#{changeset.id}' version='1'/>
1216 <node id='#{node.id}' lon='0.1' lat='0.0' changeset='#{changeset.id}' version='2'/>
1217 <node id='#{node.id}' lon='0.1' lat='0.1' changeset='#{changeset.id}' version='3'/>
1218 <node id='#{node.id}' lon='0.1' lat='0.2' changeset='#{changeset.id}' version='4'/>
1219 <node id='#{node.id}' lon='0.2' lat='0.2' changeset='#{changeset.id}' version='5'/>
1220 <node id='#{node.id}' lon='0.3' lat='0.2' changeset='#{changeset.id}' version='6'/>
1221 <node id='#{node.id}' lon='0.3' lat='0.3' changeset='#{changeset.id}' version='7'/>
1222 <node id='#{node.id}' lon='0.9' lat='0.9' changeset='#{changeset.id}' version='8'/>
1228 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1229 assert_response :success,
1230 "can't upload multiple versions of an element in a diff: #{@response.body}"
1232 # check the response is well-formed. its counter-intuitive, but the
1233 # API will return multiple elements with the same ID and different
1234 # version numbers for each change we made.
1235 assert_select "diffResult>node", 8
1239 # upload multiple versions of the same element in the same diff, but
1240 # keep the version numbers the same.
1241 def test_upload_multiple_duplicate
1242 node = create(:node)
1243 changeset = create(:changeset)
1245 auth_header = bearer_authorization_header changeset.user
1250 <node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1251 <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
1257 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1258 assert_response :conflict,
1259 "shouldn't be able to upload the same element twice in a diff: #{@response.body}"
1263 # try to upload some elements without specifying the version
1264 def test_upload_missing_version
1265 changeset = create(:changeset)
1267 auth_header = bearer_authorization_header changeset.user
1272 <node id='1' lon='1' lat='1' changeset='#{changeset.id}'/>
1278 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1279 assert_response :bad_request,
1280 "shouldn't be able to upload an element without version: #{@response.body}"
1284 # try to upload with commands other than create, modify, or delete
1285 def test_action_upload_invalid
1286 changeset = create(:changeset)
1288 auth_header = bearer_authorization_header changeset.user
1293 <node id='1' lon='1' lat='1' changeset='#{changeset.id}' />
1297 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1298 assert_response :bad_request, "Shouldn't be able to upload a diff with the action ping"
1299 assert_equal("Unknown action ping, choices are create, modify, delete", @response.body)
1303 # upload a valid changeset which has a mixture of whitespace
1304 # to check a bug reported by ivansanchez (#1565).
1305 def test_upload_whitespace_valid
1306 changeset = create(:changeset)
1307 node = create(:node)
1308 way = create(:way_with_nodes, :nodes_count => 2)
1309 relation = create(:relation)
1310 other_relation = create(:relation)
1311 create(:relation_tag, :relation => relation)
1313 auth_header = bearer_authorization_header changeset.user
1317 <modify><node id='#{node.id}' lon='0' lat='0' changeset='#{changeset.id}'
1319 <node id='#{node.id}' lon='1' lat='1' changeset='#{changeset.id}' version='2'><tag k='k' v='v'/></node></modify>
1321 <relation id='#{relation.id}' changeset='#{changeset.id}' version='1'><member
1322 type='way' role='some' ref='#{way.id}'/><member
1323 type='node' role='some' ref='#{node.id}'/>
1324 <member type='relation' role='some' ref='#{other_relation.id}'/>
1326 </modify></osmChange>
1330 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1331 assert_response :success,
1332 "can't upload a valid diff with whitespace variations to changeset: #{@response.body}"
1334 # check the response is well-formed
1335 assert_select "diffResult>node", 2
1336 assert_select "diffResult>relation", 1
1338 # check that the changes made it into the database
1339 assert_equal 1, Node.find(node.id).tags.size, "node #{node.id} should now have one tag"
1340 assert_equal 0, Relation.find(relation.id).tags.size, "relation #{relation.id} should now have no tags"
1344 # test that a placeholder can be reused within the same upload.
1345 def test_upload_reuse_placeholder_valid
1346 changeset = create(:changeset)
1348 auth_header = bearer_authorization_header changeset.user
1353 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
1354 <tag k="foo" v="bar"/>
1358 <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
1361 <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
1367 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1368 assert_response :success,
1369 "can't upload a valid diff with re-used placeholders to changeset: #{@response.body}"
1371 # check the response is well-formed
1372 assert_select "diffResult>node", 3
1373 assert_select "diffResult>node[old_id='-1']", 3
1377 # test what happens if a diff upload re-uses placeholder IDs in an
1379 def test_upload_placeholder_invalid
1380 changeset = create(:changeset)
1382 auth_header = bearer_authorization_header changeset.user
1387 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1388 <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
1389 <node id='-1' lon='2' lat='2' changeset='#{changeset.id}' version='2'/>
1395 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1396 assert_response :bad_request,
1397 "shouldn't be able to re-use placeholder IDs"
1399 # placeholder_ids must be unique across all action blocks
1403 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1406 <node id='-1' lon='1' lat='1' changeset='#{changeset.id}' version='1'/>
1412 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1413 assert_response :bad_request,
1414 "shouldn't be able to re-use placeholder IDs"
1417 def test_upload_process_order
1418 changeset = create(:changeset)
1420 auth_header = bearer_authorization_header changeset.user
1425 <node id="-1" lat="1" lon="2" changeset="#{changeset.id}"/>
1426 <way id="-1" changeset="#{changeset.id}">
1430 <node id="-2" lat="1" lon="2" changeset="#{changeset.id}"/>
1436 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1437 assert_response :bad_request,
1438 "shouldn't refer elements behind it"
1441 def test_upload_duplicate_delete
1442 changeset = create(:changeset)
1444 auth_header = bearer_authorization_header changeset.user
1449 <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
1452 <node id="-1" version="1" changeset="#{changeset.id}" />
1453 <node id="-1" version="1" changeset="#{changeset.id}" />
1459 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1460 assert_response :gone,
1461 "transaction should be cancelled by second deletion"
1466 <node id="-1" lat="39" lon="116" changeset="#{changeset.id}" />
1468 <delete if-unused="true">
1469 <node id="-1" version="1" changeset="#{changeset.id}" />
1470 <node id="-1" version="1" changeset="#{changeset.id}" />
1476 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1478 assert_select "diffResult>node", 3
1479 assert_select "diffResult>node[old_id='-1']", 3
1480 assert_select "diffResult>node[new_version='1']", 1
1481 assert_select "diffResult>node[new_version='2']", 1
1485 # test that uploading a way referencing invalid placeholders gives a
1486 # proper error, not a 500.
1487 def test_upload_placeholder_invalid_way
1488 changeset = create(:changeset)
1491 auth_header = bearer_authorization_header changeset.user
1496 <node id="-1" lon="0.0" lat="0.0" changeset="#{changeset.id}" version="1"/>
1497 <node id="-2" lon="0.1" lat="0.1" changeset="#{changeset.id}" version="1"/>
1498 <node id="-3" lon="0.2" lat="0.2" changeset="#{changeset.id}" version="1"/>
1499 <way id="-1" changeset="#{changeset.id}" version="1">
1510 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1511 assert_response :bad_request,
1512 "shouldn't be able to use invalid placeholder IDs"
1513 assert_equal "Placeholder node not found for reference -4 in way -1", @response.body
1515 # the same again, but this time use an existing way
1519 <node id="-1" lon="0.0" lat="0.0" changeset="#{changeset.id}" version="1"/>
1520 <node id="-2" lon="0.1" lat="0.1" changeset="#{changeset.id}" version="1"/>
1521 <node id="-3" lon="0.2" lat="0.2" changeset="#{changeset.id}" version="1"/>
1522 <way id="#{way.id}" changeset="#{changeset.id}" version="1">
1533 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1534 assert_response :bad_request,
1535 "shouldn't be able to use invalid placeholder IDs"
1536 assert_equal "Placeholder node not found for reference -4 in way #{way.id}", @response.body
1540 # test that uploading a relation referencing invalid placeholders gives a
1541 # proper error, not a 500.
1542 def test_upload_placeholder_invalid_relation
1543 changeset = create(:changeset)
1544 relation = create(:relation)
1546 auth_header = bearer_authorization_header changeset.user
1551 <node id="-1" lon="0.0" lat="0.0" changeset="#{changeset.id}" version="1"/>
1552 <node id="-2" lon="0.1" lat="0.1" changeset="#{changeset.id}" version="1"/>
1553 <node id="-3" lon="0.2" lat="0.2" changeset="#{changeset.id}" version="1"/>
1554 <relation id="-1" changeset="#{changeset.id}" version="1">
1555 <member type="node" role="foo" ref="-1"/>
1556 <member type="node" role="foo" ref="-2"/>
1557 <member type="node" role="foo" ref="-3"/>
1558 <member type="node" role="foo" ref="-4"/>
1565 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1566 assert_response :bad_request,
1567 "shouldn't be able to use invalid placeholder IDs"
1568 assert_equal "Placeholder Node not found for reference -4 in relation -1.", @response.body
1570 # the same again, but this time use an existing relation
1574 <node id="-1" lon="0.0" lat="0.0" changeset="#{changeset.id}" version="1"/>
1575 <node id="-2" lon="0.1" lat="0.1" changeset="#{changeset.id}" version="1"/>
1576 <node id="-3" lon="0.2" lat="0.2" changeset="#{changeset.id}" version="1"/>
1577 <relation id="#{relation.id}" changeset="#{changeset.id}" version="1">
1578 <member type="node" role="foo" ref="-1"/>
1579 <member type="node" role="foo" ref="-2"/>
1580 <member type="node" role="foo" ref="-3"/>
1581 <member type="way" role="bar" ref="-1"/>
1588 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1589 assert_response :bad_request,
1590 "shouldn't be able to use invalid placeholder IDs"
1591 assert_equal "Placeholder Way not found for reference -1 in relation #{relation.id}.", @response.body
1595 # test what happens if a diff is uploaded containing only a node
1597 def test_upload_node_move
1598 auth_header = bearer_authorization_header
1600 xml = "<osm><changeset>" \
1601 "<tag k='created_by' v='osm test suite checking changesets'/>" \
1602 "</changeset></osm>"
1603 post api_changesets_path, :params => xml, :headers => auth_header
1604 assert_response :success
1605 changeset_id = @response.body.to_i
1607 old_node = create(:node, :lat => 1, :lon => 1)
1609 diff = XML::Document.new
1610 diff.root = XML::Node.new "osmChange"
1611 modify = XML::Node.new "modify"
1612 xml_old_node = xml_node_for_node(old_node)
1613 xml_old_node["lat"] = 2.0.to_s
1614 xml_old_node["lon"] = 2.0.to_s
1615 xml_old_node["changeset"] = changeset_id.to_s
1616 modify << xml_old_node
1620 post api_changeset_upload_path(changeset_id), :params => diff.to_s, :headers => auth_header
1621 assert_response :success,
1622 "diff should have uploaded OK"
1625 changeset = Changeset.find(changeset_id)
1626 assert_equal 1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 1 degree"
1627 assert_equal 2 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 2 degrees"
1628 assert_equal 1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1 degree"
1629 assert_equal 2 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 2 degrees"
1633 # test what happens if a diff is uploaded adding a node to a way.
1634 def test_upload_way_extend
1635 auth_header = bearer_authorization_header
1637 xml = "<osm><changeset>" \
1638 "<tag k='created_by' v='osm test suite checking changesets'/>" \
1639 "</changeset></osm>"
1640 post api_changesets_path, :params => xml, :headers => auth_header
1641 assert_response :success
1642 changeset_id = @response.body.to_i
1644 old_way = create(:way)
1645 create(:way_node, :way => old_way, :node => create(:node, :lat => 0.1, :lon => 0.1))
1647 diff = XML::Document.new
1648 diff.root = XML::Node.new "osmChange"
1649 modify = XML::Node.new "modify"
1650 xml_old_way = xml_node_for_way(old_way)
1651 nd_ref = XML::Node.new "nd"
1652 nd_ref["ref"] = create(:node, :lat => 0.3, :lon => 0.3).id.to_s
1653 xml_old_way << nd_ref
1654 xml_old_way["changeset"] = changeset_id.to_s
1655 modify << xml_old_way
1659 post api_changeset_upload_path(changeset_id), :params => diff.to_s, :headers => auth_header
1660 assert_response :success,
1661 "diff should have uploaded OK"
1664 changeset = Changeset.find(changeset_id)
1665 assert_equal 0.1 * GeoRecord::SCALE, changeset.min_lon, "min_lon should be 0.1 degree"
1666 assert_equal 0.3 * GeoRecord::SCALE, changeset.max_lon, "max_lon should be 0.3 degrees"
1667 assert_equal 0.1 * GeoRecord::SCALE, changeset.min_lat, "min_lat should be 0.1 degree"
1668 assert_equal 0.3 * GeoRecord::SCALE, changeset.max_lat, "max_lat should be 0.3 degrees"
1672 # test for more issues in #1568
1673 def test_upload_empty_invalid
1674 changeset = create(:changeset)
1676 auth_header = bearer_authorization_header changeset.user
1679 "<osmChange></osmChange>",
1680 "<osmChange><modify/></osmChange>",
1681 "<osmChange><modify></modify></osmChange>"].each do |diff|
1683 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1684 assert_response(:success, "should be able to upload " \
1685 "empty changeset: " + diff)
1690 # test that the X-Error-Format header works to request XML errors
1691 def test_upload_xml_errors
1692 changeset = create(:changeset)
1693 node = create(:node)
1694 create(:relation_member, :member => node)
1696 auth_header = bearer_authorization_header changeset.user
1698 # try and delete a node that is in use
1699 diff = XML::Document.new
1700 diff.root = XML::Node.new "osmChange"
1701 delete = XML::Node.new "delete"
1703 delete << xml_node_for_node(node)
1706 error_header = error_format_header "xml"
1707 post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header.merge(error_header)
1708 assert_response :success,
1709 "failed to return error in XML format"
1711 # check the returned payload
1712 assert_select "osmError[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
1713 assert_select "osmError>status", 1
1714 assert_select "osmError>message", 1
1717 def test_upload_not_found
1718 changeset = create(:changeset)
1720 auth_header = bearer_authorization_header changeset.user
1726 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1732 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1733 assert_response :not_found, "Node should not be found"
1739 <way id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1745 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1746 assert_response :not_found, "Way should not be found"
1752 <relation id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1758 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1759 assert_response :not_found, "Relation should not be found"
1765 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1771 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1772 assert_response :not_found, "Node should not be deleted"
1778 <way id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1784 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1785 assert_response :not_found, "Way should not be deleted"
1791 <relation id='-1' lon='0' lat='0' changeset='#{changeset.id}' version='1'/>
1797 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1798 assert_response :not_found, "Relation should not be deleted"
1801 def test_upload_relation_placeholder_not_fix
1802 changeset = create(:changeset)
1804 auth_header = bearer_authorization_header changeset.user
1808 <osmChange version='0.6'>
1810 <relation id='-2' version='0' changeset='#{changeset.id}'>
1811 <member type='relation' role='' ref='-4' />
1812 <tag k='type' v='route' />
1813 <tag k='name' v='AtoB' />
1815 <relation id='-3' version='0' changeset='#{changeset.id}'>
1816 <tag k='type' v='route' />
1817 <tag k='name' v='BtoA' />
1819 <relation id='-4' version='0' changeset='#{changeset.id}'>
1820 <member type='relation' role='' ref='-2' />
1821 <member type='relation' role='' ref='-3' />
1822 <tag k='type' v='route_master' />
1823 <tag k='name' v='master' />
1830 post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
1831 assert_response :bad_request, "shouldn't be able to use reference -4 in relation -2: #{@response.body}"
1832 assert_equal "Placeholder Relation not found for reference -4 in relation -2.", @response.body
1835 def test_upload_multiple_delete_block
1836 changeset = create(:changeset)
1838 auth_header = bearer_authorization_header changeset.user
1840 node = create(:node)
1842 create(:way_node, :way => way, :node => node)
1843 alone_node = create(:node)
1847 <osmChange version='0.6'>
1848 <delete version="0.6">
1849 <node id="#{node.id}" version="#{node.version}" changeset="#{changeset.id}"/>
1851 <delete version="0.6" if-unused="true">
1852 <node id="#{alone_node.id}" version="#{alone_node.version}" changeset="#{changeset.id}"/>
1858 post api_changeset_upload_path(changeset), :params => diff.to_s, :headers => auth_header
1859 assert_response :precondition_failed,
1860 "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
1861 assert_equal "Precondition failed: Node #{node.id} is still used by ways #{way.id}.", @response.body
1865 # test initial rate limit
1866 def test_upload_initial_rate_limit
1868 user = create(:user)
1870 # create some objects to use
1871 node = create(:node)
1872 way = create(:way_with_nodes, :nodes_count => 2)
1873 relation = create(:relation)
1875 # create a changeset that puts us near the initial rate limit
1876 changeset = create(:changeset, :user => user,
1877 :created_at => Time.now.utc - 5.minutes,
1878 :num_changes => Settings.initial_changes_per_hour - 2)
1880 # create authentication header
1881 auth_header = bearer_authorization_header user
1883 # simple diff to create a node way and relation using placeholders
1887 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
1888 <tag k='foo' v='bar'/>
1889 <tag k='baz' v='bat'/>
1891 <way id='-1' changeset='#{changeset.id}'>
1892 <nd ref='#{node.id}'/>
1896 <relation id='-1' changeset='#{changeset.id}'>
1897 <member type='way' role='some' ref='#{way.id}'/>
1898 <member type='node' role='some' ref='#{node.id}'/>
1899 <member type='relation' role='some' ref='#{relation.id}'/>
1906 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1907 assert_response :too_many_requests, "upload did not hit rate limit"
1911 # test maximum rate limit
1912 def test_upload_maximum_rate_limit
1914 user = create(:user)
1916 # create some objects to use
1917 node = create(:node)
1918 way = create(:way_with_nodes, :nodes_count => 2)
1919 relation = create(:relation)
1921 # create a changeset to establish our initial edit time
1922 changeset = create(:changeset, :user => user,
1923 :created_at => Time.now.utc - 28.days)
1925 # create changeset to put us near the maximum rate limit
1926 total_changes = Settings.max_changes_per_hour - 2
1927 while total_changes.positive?
1928 changes = [total_changes, Changeset::MAX_ELEMENTS].min
1929 changeset = create(:changeset, :user => user,
1930 :created_at => Time.now.utc - 5.minutes,
1931 :num_changes => changes)
1932 total_changes -= changes
1935 # create authentication header
1936 auth_header = bearer_authorization_header user
1938 # simple diff to create a node way and relation using placeholders
1942 <node id='-1' lon='0' lat='0' changeset='#{changeset.id}'>
1943 <tag k='foo' v='bar'/>
1944 <tag k='baz' v='bat'/>
1946 <way id='-1' changeset='#{changeset.id}'>
1947 <nd ref='#{node.id}'/>
1951 <relation id='-1' changeset='#{changeset.id}'>
1952 <member type='way' role='some' ref='#{way.id}'/>
1953 <member type='node' role='some' ref='#{node.id}'/>
1954 <member type='relation' role='some' ref='#{relation.id}'/>
1961 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1962 assert_response :too_many_requests, "upload did not hit rate limit"
1966 # test initial size limit
1967 def test_upload_initial_size_limit
1969 user = create(:user)
1971 # create a changeset that puts us near the initial size limit
1972 changeset = create(:changeset, :user => user,
1973 :min_lat => (-0.5 * GeoRecord::SCALE).round, :min_lon => (0.5 * GeoRecord::SCALE).round,
1974 :max_lat => (0.5 * GeoRecord::SCALE).round, :max_lon => (2.5 * GeoRecord::SCALE).round)
1976 # create authentication header
1977 auth_header = bearer_authorization_header user
1979 # simple diff to create a node
1983 <node id='-1' lon='0.9' lat='2.9' changeset='#{changeset.id}'>
1984 <tag k='foo' v='bar'/>
1985 <tag k='baz' v='bat'/>
1992 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
1993 assert_response :payload_too_large, "upload did not hit size limit"
1997 # test size limit after one week
1998 def test_upload_week_size_limit
2000 user = create(:user)
2002 # create a changeset to establish our initial edit time
2003 create(:changeset, :user => user, :created_at => Time.now.utc - 7.days)
2005 # create a changeset that puts us near the initial size limit
2006 changeset = create(:changeset, :user => user, :bbox => [0.5, -0.5, 2.5, 0.5])
2008 # create authentication header
2009 auth_header = bearer_authorization_header user
2011 # simple diff to create a node way and relation using placeholders
2015 <node id='-1' lon='35' lat='35' changeset='#{changeset.id}'>
2016 <tag k='foo' v='bar'/>
2017 <tag k='baz' v='bat'/>
2024 post api_changeset_upload_path(changeset), :params => diff, :headers => auth_header
2025 assert_response :payload_too_large, "upload did not hit size limit"
2029 # when we make some simple changes we get the same changes back from the
2031 def test_diff_download_simple
2032 node = create(:node)
2034 ## First try with a non-public user, which should get a forbidden
2035 auth_header = bearer_authorization_header create(:user, :data_public => false)
2037 # create a temporary changeset
2038 xml = "<osm><changeset>" \
2039 "<tag k='created_by' v='osm test suite checking changesets'/>" \
2040 "</changeset></osm>"
2041 post api_changesets_path, :params => xml, :headers => auth_header
2042 assert_response :forbidden
2044 ## Now try with a normal user
2045 auth_header = bearer_authorization_header
2047 # create a temporary changeset
2048 xml = "<osm><changeset>" \
2049 "<tag k='created_by' v='osm test suite checking changesets'/>" \
2050 "</changeset></osm>"
2051 post api_changesets_path, :params => xml, :headers => auth_header
2052 assert_response :success
2053 changeset_id = @response.body.to_i
2059 <node id='#{node.id}' lon='0.0' lat='0.0' changeset='#{changeset_id}' version='1'/>
2060 <node id='#{node.id}' lon='0.1' lat='0.0' changeset='#{changeset_id}' version='2'/>
2061 <node id='#{node.id}' lon='0.1' lat='0.1' changeset='#{changeset_id}' version='3'/>
2062 <node id='#{node.id}' lon='0.1' lat='0.2' changeset='#{changeset_id}' version='4'/>
2063 <node id='#{node.id}' lon='0.2' lat='0.2' changeset='#{changeset_id}' version='5'/>
2064 <node id='#{node.id}' lon='0.3' lat='0.2' changeset='#{changeset_id}' version='6'/>
2065 <node id='#{node.id}' lon='0.3' lat='0.3' changeset='#{changeset_id}' version='7'/>
2066 <node id='#{node.id}' lon='0.9' lat='0.9' changeset='#{changeset_id}' version='8'/>
2072 post api_changeset_upload_path(changeset_id), :params => diff, :headers => auth_header
2073 assert_response :success,
2074 "can't upload multiple versions of an element in a diff: #{@response.body}"
2076 get api_changeset_download_path(changeset_id)
2077 assert_response :success
2079 assert_select "osmChange", 1
2080 assert_select "osmChange>modify", 8
2081 assert_select "osmChange>modify>node", 8
2085 # culled this from josm to ensure that nothing in the way that josm
2086 # is formatting the request is causing it to fail.
2088 # NOTE: the error turned out to be something else completely!
2089 def test_josm_upload
2090 auth_header = bearer_authorization_header
2092 # create a temporary changeset
2093 xml = "<osm><changeset>" \
2094 "<tag k='created_by' v='osm test suite checking changesets'/>" \
2095 "</changeset></osm>"
2096 post api_changesets_path, :params => xml, :headers => auth_header
2097 assert_response :success
2098 changeset_id = @response.body.to_i
2101 <osmChange version="0.6" generator="JOSM">
2102 <create version="0.6" generator="JOSM">
2103 <node id='-1' visible='true' changeset='#{changeset_id}' lat='51.49619982187321' lon='-0.18722061869438314' />
2104 <node id='-2' visible='true' changeset='#{changeset_id}' lat='51.496359883909605' lon='-0.18653093576241928' />
2105 <node id='-3' visible='true' changeset='#{changeset_id}' lat='51.49598132358285' lon='-0.18719613290981638' />
2106 <node id='-4' visible='true' changeset='#{changeset_id}' lat='51.4961591711078' lon='-0.18629015888084607' />
2107 <node id='-5' visible='true' changeset='#{changeset_id}' lat='51.49582126021711' lon='-0.18708186591517145' />
2108 <node id='-6' visible='true' changeset='#{changeset_id}' lat='51.49591018437858' lon='-0.1861432441734455' />
2109 <node id='-7' visible='true' changeset='#{changeset_id}' lat='51.49560784152179' lon='-0.18694719410005425' />
2110 <node id='-8' visible='true' changeset='#{changeset_id}' lat='51.49567389979617' lon='-0.1860289771788006' />
2111 <node id='-9' visible='true' changeset='#{changeset_id}' lat='51.49543761398892' lon='-0.186820684213126' />
2112 <way id='-10' action='modify' visible='true' changeset='#{changeset_id}'>
2122 <tag k='highway' v='residential' />
2123 <tag k='name' v='Foobar Street' />
2130 post api_changeset_upload_path(changeset_id), :params => diff, :headers => auth_header
2131 assert_response :success,
2132 "can't upload a diff from JOSM: #{@response.body}"
2134 get api_changeset_download_path(changeset_id)
2135 assert_response :success
2137 assert_select "osmChange", 1
2138 assert_select "osmChange>create>node", 9
2139 assert_select "osmChange>create>way", 1
2140 assert_select "osmChange>create>way>nd", 9
2141 assert_select "osmChange>create>way>tag", 2
2145 # when we make some complex changes we get the same changes back from the
2147 def test_diff_download_complex
2148 node = create(:node)
2149 node2 = create(:node)
2151 auth_header = bearer_authorization_header
2153 # create a temporary changeset
2154 xml = "<osm><changeset>" \
2155 "<tag k='created_by' v='osm test suite checking changesets'/>" \
2156 "</changeset></osm>"
2157 post api_changesets_path, :params => xml, :headers => auth_header
2158 assert_response :success
2159 changeset_id = @response.body.to_i
2165 <node id='#{node.id}' lon='0.0' lat='0.0' changeset='#{changeset_id}' version='1'/>
2168 <node id='-1' lon='0.9' lat='0.9' changeset='#{changeset_id}' version='0'/>
2169 <node id='-2' lon='0.8' lat='0.9' changeset='#{changeset_id}' version='0'/>
2170 <node id='-3' lon='0.7' lat='0.9' changeset='#{changeset_id}' version='0'/>
2173 <node id='#{node2.id}' lon='2.0' lat='1.5' changeset='#{changeset_id}' version='1'/>
2174 <way id='#{way.id}' changeset='#{changeset_id}' version='1'>
2175 <nd ref='#{node2.id}'/>
2185 post api_changeset_upload_path(changeset_id), :params => diff, :headers => auth_header
2186 assert_response :success,
2187 "can't upload multiple versions of an element in a diff: #{@response.body}"
2189 get api_changeset_download_path(changeset_id)
2190 assert_response :success
2192 assert_select "osmChange", 1
2193 assert_select "osmChange>create", 3
2194 assert_select "osmChange>delete", 1
2195 assert_select "osmChange>modify", 2
2196 assert_select "osmChange>create>node", 3
2197 assert_select "osmChange>delete>node", 1
2198 assert_select "osmChange>modify>node", 1
2199 assert_select "osmChange>modify>way", 1
2203 # check that the bounding box of a changeset gets updated correctly
2204 # FIXME: This should really be moded to a integration test due to the with_controller
2205 def test_changeset_bbox
2207 create(:way_node, :way => way, :node => create(:node, :lat => 0.3, :lon => 0.3))
2209 auth_header = bearer_authorization_header
2211 # create a new changeset
2212 xml = "<osm><changeset/></osm>"
2213 post api_changesets_path, :params => xml, :headers => auth_header
2214 assert_response :success, "Creating of changeset failed."
2215 changeset_id = @response.body.to_i
2217 # add a single node to it
2218 with_controller(NodesController.new) do
2219 xml = "<osm><node lon='0.1' lat='0.2' changeset='#{changeset_id}'/></osm>"
2220 post api_nodes_path, :params => xml, :headers => auth_header
2221 assert_response :success, "Couldn't create node."
2224 # get the bounding box back from the changeset
2225 get api_changeset_path(changeset_id)
2226 assert_response :success, "Couldn't read back changeset."
2227 assert_select "osm>changeset[min_lon='0.1000000']", 1
2228 assert_select "osm>changeset[max_lon='0.1000000']", 1
2229 assert_select "osm>changeset[min_lat='0.2000000']", 1
2230 assert_select "osm>changeset[max_lat='0.2000000']", 1
2232 # add another node to it
2233 with_controller(NodesController.new) do
2234 xml = "<osm><node lon='0.2' lat='0.1' changeset='#{changeset_id}'/></osm>"
2235 post api_nodes_path, :params => xml, :headers => auth_header
2236 assert_response :success, "Couldn't create second node."
2239 # get the bounding box back from the changeset
2240 get api_changeset_path(changeset_id)
2241 assert_response :success, "Couldn't read back changeset for the second time."
2242 assert_select "osm>changeset[min_lon='0.1000000']", 1
2243 assert_select "osm>changeset[max_lon='0.2000000']", 1
2244 assert_select "osm>changeset[min_lat='0.1000000']", 1
2245 assert_select "osm>changeset[max_lat='0.2000000']", 1
2247 # add (delete) a way to it, which contains a point at (3,3)
2248 with_controller(WaysController.new) do
2249 xml = update_changeset(xml_for_way(way), changeset_id)
2250 delete api_way_path(way), :params => xml.to_s, :headers => auth_header
2251 assert_response :success, "Couldn't delete a way."
2254 # get the bounding box back from the changeset
2255 get api_changeset_path(changeset_id)
2256 assert_response :success, "Couldn't read back changeset for the third time."
2257 assert_select "osm>changeset[min_lon='0.1000000']", 1
2258 assert_select "osm>changeset[max_lon='0.3000000']", 1
2259 assert_select "osm>changeset[min_lat='0.1000000']", 1
2260 assert_select "osm>changeset[max_lat='0.3000000']", 1
2264 # check updating tags on a changeset
2265 def test_changeset_update
2266 private_user = create(:user, :data_public => false)
2267 private_changeset = create(:changeset, :user => private_user)
2268 user = create(:user)
2269 changeset = create(:changeset, :user => user)
2271 ## First try with a non-public user
2272 new_changeset = create_changeset_xml(:user => private_user)
2273 new_tag = XML::Node.new "tag"
2274 new_tag["k"] = "tagtesting"
2275 new_tag["v"] = "valuetesting"
2276 new_changeset.find("//osm/changeset").first << new_tag
2278 # try without any authorization
2279 put api_changeset_path(private_changeset), :params => new_changeset.to_s
2280 assert_response :unauthorized
2282 # try with the wrong authorization
2283 auth_header = bearer_authorization_header
2284 put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
2285 assert_response :conflict
2287 # now this should get an unauthorized
2288 auth_header = bearer_authorization_header private_user
2289 put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
2290 assert_require_public_data "user with their data non-public, shouldn't be able to edit their changeset"
2292 ## Now try with the public user
2293 new_changeset = create_changeset_xml(:id => 1)
2294 new_tag = XML::Node.new "tag"
2295 new_tag["k"] = "tagtesting"
2296 new_tag["v"] = "valuetesting"
2297 new_changeset.find("//osm/changeset").first << new_tag
2299 # try without any authorization
2300 put api_changeset_path(changeset), :params => new_changeset.to_s
2301 assert_response :unauthorized
2303 # try with the wrong authorization
2304 auth_header = bearer_authorization_header
2305 put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
2306 assert_response :conflict
2308 # now this should work...
2309 auth_header = bearer_authorization_header user
2310 put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
2311 assert_response :success
2313 assert_select "osm>changeset[id='#{changeset.id}']", 1
2314 assert_select "osm>changeset>tag", 1
2315 assert_select "osm>changeset>tag[k='tagtesting'][v='valuetesting']", 1
2319 # check that a user different from the one who opened the changeset
2321 def test_changeset_update_invalid
2322 auth_header = bearer_authorization_header
2324 changeset = create(:changeset)
2325 new_changeset = create_changeset_xml(:user => changeset.user, :id => changeset.id)
2326 new_tag = XML::Node.new "tag"
2327 new_tag["k"] = "testing"
2328 new_tag["v"] = "testing"
2329 new_changeset.find("//osm/changeset").first << new_tag
2331 put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
2332 assert_response :conflict
2336 # check that a changeset can contain a certain max number of changes.
2337 ## FIXME should be changed to an integration test due to the with_controller
2338 def test_changeset_limits
2339 user = create(:user)
2340 auth_header = bearer_authorization_header user
2342 # create an old changeset to ensure we have the maximum rate limit
2343 create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
2345 # open a new changeset
2346 xml = "<osm><changeset/></osm>"
2347 post api_changesets_path, :params => xml, :headers => auth_header
2348 assert_response :success, "can't create a new changeset"
2349 cs_id = @response.body.to_i
2351 # start the counter just short of where the changeset should finish.
2353 # alter the database to set the counter on the changeset directly,
2354 # otherwise it takes about 6 minutes to fill all of them.
2355 changeset = Changeset.find(cs_id)
2356 changeset.num_changes = Changeset::MAX_ELEMENTS - offset
2359 with_controller(NodesController.new) do
2361 xml = "<osm><node changeset='#{cs_id}' lat='0.0' lon='0.0'/></osm>"
2362 post api_nodes_path, :params => xml, :headers => auth_header
2363 assert_response :success, "can't create a new node"
2364 node_id = @response.body.to_i
2366 get api_node_path(node_id)
2367 assert_response :success, "can't read back new node"
2368 node_doc = XML::Parser.string(@response.body).parse
2369 node_xml = node_doc.find("//osm/node").first
2371 # loop until we fill the changeset with nodes
2373 node_xml["lat"] = rand.to_s
2374 node_xml["lon"] = rand.to_s
2375 node_xml["version"] = (i + 1).to_s
2377 put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
2378 assert_response :success, "attempt #{i} should have succeeded"
2381 # trying again should fail
2382 node_xml["lat"] = rand.to_s
2383 node_xml["lon"] = rand.to_s
2384 node_xml["version"] = offset.to_s
2386 put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
2387 assert_response :conflict, "final attempt should have failed"
2390 changeset = Changeset.find(cs_id)
2391 assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
2393 # check that the changeset is now closed as well
2394 assert_not(changeset.open?,
2395 "changeset should have been auto-closed by exceeding " \
2402 # check that the output consists of one specific changeset
2403 def assert_single_changeset(changeset, &)
2404 assert_dom "> changeset", 1 do
2405 assert_dom "> @id", changeset.id.to_s
2406 assert_dom "> @created_at", changeset.created_at.xmlschema
2408 assert_dom "> @open", "true"
2409 assert_dom "> @closed_at", 0
2411 assert_dom "> @open", "false"
2412 assert_dom "> @closed_at", changeset.closed_at.xmlschema
2414 assert_dom "> @comments_count", changeset.comments.length.to_s
2415 assert_dom "> @changes_count", changeset.num_changes.to_s
2416 yield if block_given?
2420 def assert_single_changeset_json(changeset, js)
2421 assert_equal changeset.id, js["changeset"]["id"]
2422 assert_equal changeset.created_at.xmlschema, js["changeset"]["created_at"]
2424 assert js["changeset"]["open"]
2425 assert_nil js["changeset"]["closed_at"]
2427 assert_not js["changeset"]["open"]
2428 assert_equal changeset.closed_at.xmlschema, js["changeset"]["closed_at"]
2430 assert_equal changeset.comments.length, js["changeset"]["comments_count"]
2431 assert_equal changeset.num_changes, js["changeset"]["changes_count"]
2435 # check that certain changesets exist in the output in the specified order
2436 def assert_changesets_in_order(changesets)
2437 assert_select "osm>changeset", changesets.size
2438 changesets.each_with_index do |changeset, index|
2439 assert_select "osm>changeset:nth-child(#{index + 1})[id='#{changeset.id}']", 1
2444 # update the changeset_id of a way element
2445 def update_changeset(xml, changeset_id)
2446 xml_attr_rewrite(xml, "changeset", changeset_id)
2450 # update an attribute in a way element
2451 def xml_attr_rewrite(xml, name, value)
2452 xml.find("//osm/way").first[name] = value.to_s
2457 # build XML for changesets
2458 def create_changeset_xml(user: nil, id: nil)
2459 root = XML::Document.new
2460 root.root = XML::Node.new "osm"
2461 cs = XML::Node.new "changeset"
2463 cs["user"] = user.display_name
2464 cs["uid"] = user.id.to_s
2466 cs["id"] = id.to_s if id