]> git.openstreetmap.org Git - rails.git/blob - test/controllers/api/changesets_controller_test.rb
Add frozen_string_literal comments to ruby files
[rails.git] / test / controllers / api / changesets_controller_test.rb
1 # frozen_string_literal: true
2
3 require "test_helper"
4
5 module Api
6   class ChangesetsControllerTest < ActionDispatch::IntegrationTest
7     ##
8     # test all routes which lead to this controller
9     def test_routes
10       assert_routing(
11         { :path => "/api/0.6/changesets", :method => :get },
12         { :controller => "api/changesets", :action => "index" }
13       )
14       assert_routing(
15         { :path => "/api/0.6/changesets.json", :method => :get },
16         { :controller => "api/changesets", :action => "index", :format => "json" }
17       )
18       assert_routing(
19         { :path => "/api/0.6/changesets", :method => :post },
20         { :controller => "api/changesets", :action => "create" }
21       )
22       assert_routing(
23         { :path => "/api/0.6/changeset/1", :method => :get },
24         { :controller => "api/changesets", :action => "show", :id => "1" }
25       )
26       assert_routing(
27         { :path => "/api/0.6/changeset/1.json", :method => :get },
28         { :controller => "api/changesets", :action => "show", :id => "1", :format => "json" }
29       )
30       assert_routing(
31         { :path => "/api/0.6/changeset/1", :method => :put },
32         { :controller => "api/changesets", :action => "update", :id => "1" }
33       )
34
35       assert_recognizes(
36         { :controller => "api/changesets", :action => "create" },
37         { :path => "/api/0.6/changeset/create", :method => :put }
38       )
39     end
40
41     ##
42     # test the query functionality of changesets
43     def test_index
44       private_user = create(:user, :data_public => false)
45       private_user_changeset = create(:changeset, :user => private_user)
46       private_user_closed_changeset = create(:changeset, :closed, :user => private_user)
47       user = create(:user)
48       changeset = create(:changeset, :user => user)
49       closed_changeset = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 1, 1, 0, 0, 0), :closed_at => Time.utc(2008, 1, 2, 0, 0, 0))
50       changeset2 = create(:changeset, :bbox => [5, 5, 15, 15])
51       changeset3 = create(:changeset, :bbox => [4.5, 4.5, 5, 5])
52
53       get api_changesets_path(:bbox => "-10,-10, 10, 10")
54       assert_response :success, "can't get changesets in bbox"
55       assert_changesets_in_order [changeset3, changeset2]
56
57       get api_changesets_path(:bbox => "4.5,4.5,4.6,4.6")
58       assert_response :success, "can't get changesets in bbox"
59       assert_changesets_in_order [changeset3]
60
61       # not found when looking for changesets of non-existing users
62       get api_changesets_path(:user => User.maximum(:id) + 1)
63       assert_response :not_found
64       assert_equal "text/plain", @response.media_type
65       get api_changesets_path(:display_name => " ")
66       assert_response :not_found
67       assert_equal "text/plain", @response.media_type
68
69       # can't get changesets of user 1 without authenticating
70       get api_changesets_path(:user => private_user.id)
71       assert_response :not_found, "shouldn't be able to get changesets by non-public user (ID)"
72       get api_changesets_path(:display_name => private_user.display_name)
73       assert_response :not_found, "shouldn't be able to get changesets by non-public user (name)"
74
75       # but this should work
76       auth_header = bearer_authorization_header private_user
77       get api_changesets_path(:user => private_user.id), :headers => auth_header
78       assert_response :success, "can't get changesets by user ID"
79       assert_changesets_in_order [private_user_changeset, private_user_closed_changeset]
80
81       get api_changesets_path(:display_name => private_user.display_name), :headers => auth_header
82       assert_response :success, "can't get changesets by user name"
83       assert_changesets_in_order [private_user_changeset, private_user_closed_changeset]
84
85       # test json endpoint
86       get api_changesets_path(:display_name => private_user.display_name), :headers => auth_header, :params => { :format => "json" }
87       assert_response :success, "can't get changesets by user name"
88
89       js = ActiveSupport::JSON.decode(@response.body)
90       assert_not_nil js
91
92       assert_equal Settings.api_version, js["version"]
93       assert_equal Settings.generator, js["generator"]
94       assert_equal 2, js["changesets"].count
95
96       # check that the correct error is given when we provide both UID and name
97       get api_changesets_path(:user => private_user.id,
98                               :display_name => private_user.display_name), :headers => auth_header
99       assert_response :bad_request, "should be a bad request to have both ID and name specified"
100
101       get api_changesets_path(:user => private_user.id, :open => true), :headers => auth_header
102       assert_response :success, "can't get changesets by user and open"
103       assert_changesets_in_order [private_user_changeset]
104
105       get api_changesets_path(:time => "2007-12-31"), :headers => auth_header
106       assert_response :success, "can't get changesets by time-since"
107       assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset, private_user_closed_changeset, closed_changeset]
108
109       get api_changesets_path(:time => "2008-01-01T12:34Z"), :headers => auth_header
110       assert_response :success, "can't get changesets by time-since with hour"
111       assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset, private_user_closed_changeset, closed_changeset]
112
113       get api_changesets_path(:time => "2007-12-31T23:59Z,2008-01-02T00:01Z"), :headers => auth_header
114       assert_response :success, "can't get changesets by time-range"
115       assert_changesets_in_order [closed_changeset]
116
117       get api_changesets_path(:open => "true"), :headers => auth_header
118       assert_response :success, "can't get changesets by open-ness"
119       assert_changesets_in_order [changeset3, changeset2, changeset, private_user_changeset]
120
121       get api_changesets_path(:closed => "true"), :headers => auth_header
122       assert_response :success, "can't get changesets by closed-ness"
123       assert_changesets_in_order [private_user_closed_changeset, closed_changeset]
124
125       get api_changesets_path(:closed => "true", :user => private_user.id), :headers => auth_header
126       assert_response :success, "can't get changesets by closed-ness and user"
127       assert_changesets_in_order [private_user_closed_changeset]
128
129       get api_changesets_path(:closed => "true", :user => user.id), :headers => auth_header
130       assert_response :success, "can't get changesets by closed-ness and user"
131       assert_changesets_in_order [closed_changeset]
132
133       get api_changesets_path(:changesets => "#{private_user_changeset.id},#{changeset.id},#{closed_changeset.id}"), :headers => auth_header
134       assert_response :success, "can't get changesets by id (as comma-separated string)"
135       assert_changesets_in_order [changeset, private_user_changeset, closed_changeset]
136
137       get api_changesets_path(:changesets => ""), :headers => auth_header
138       assert_response :bad_request, "should be a bad request since changesets is empty"
139     end
140
141     ##
142     # test the query functionality of changesets with the limit parameter
143     def test_index_limit
144       user = create(:user)
145       changeset1 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 1, 1, 0, 0, 0), :closed_at => Time.utc(2008, 1, 2, 0, 0, 0))
146       changeset2 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 2, 1, 0, 0, 0), :closed_at => Time.utc(2008, 2, 2, 0, 0, 0))
147       changeset3 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 3, 1, 0, 0, 0), :closed_at => Time.utc(2008, 3, 2, 0, 0, 0))
148       changeset4 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 4, 1, 0, 0, 0), :closed_at => Time.utc(2008, 4, 2, 0, 0, 0))
149       changeset5 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 5, 1, 0, 0, 0), :closed_at => Time.utc(2008, 5, 2, 0, 0, 0))
150
151       get api_changesets_path
152       assert_response :success
153       assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
154
155       get api_changesets_path(:limit => "3")
156       assert_response :success
157       assert_changesets_in_order [changeset5, changeset4, changeset3]
158
159       get api_changesets_path(:limit => "0")
160       assert_response :bad_request
161
162       get api_changesets_path(:limit => Settings.max_changeset_query_limit)
163       assert_response :success
164       assert_changesets_in_order [changeset5, changeset4, changeset3, changeset2, changeset1]
165
166       get api_changesets_path(:limit => Settings.max_changeset_query_limit + 1)
167       assert_response :bad_request
168     end
169
170     ##
171     # test the query functionality of sequential changesets with order and time parameters
172     def test_index_order
173       user = create(:user)
174       changeset1 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 1, 1, 0, 0, 0), :closed_at => Time.utc(2008, 1, 2, 0, 0, 0))
175       changeset2 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 2, 1, 0, 0, 0), :closed_at => Time.utc(2008, 2, 2, 0, 0, 0))
176       changeset3 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 3, 1, 0, 0, 0), :closed_at => Time.utc(2008, 3, 2, 0, 0, 0))
177       changeset4 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 4, 1, 0, 0, 0), :closed_at => Time.utc(2008, 4, 2, 0, 0, 0))
178       changeset5 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 5, 1, 0, 0, 0), :closed_at => Time.utc(2008, 5, 2, 0, 0, 0))
179       changeset6 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2008, 6, 1, 0, 0, 0), :closed_at => Time.utc(2008, 6, 2, 0, 0, 0))
180
181       get api_changesets_path
182       assert_response :success
183       assert_changesets_in_order [changeset6, changeset5, changeset4, changeset3, changeset2, changeset1]
184
185       get api_changesets_path(:order => "oldest")
186       assert_response :success
187       assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4, changeset5, changeset6]
188
189       [
190         # lower time bound at the opening time of a changeset
191         ["2008-02-01T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3, changeset2]],
192         # lower time bound in the middle of a changeset
193         ["2008-02-01T12:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
194         # lower time bound at the closing time of a changeset
195         ["2008-02-02T00:00:00Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3, changeset2], [changeset5, changeset4, changeset3]],
196         # lower time bound after the closing time of a changeset
197         ["2008-02-02T00:00:01Z", "2008-05-15T00:00:00Z", [changeset5, changeset4, changeset3], [changeset5, changeset4, changeset3]],
198         # upper time bound in the middle of a changeset
199         ["2007-09-09T12:00:00Z", "2008-04-01T12:00:00Z", [changeset4, changeset3, changeset2, changeset1], [changeset4, changeset3, changeset2, changeset1]],
200         # empty range
201         ["2009-02-02T00:00:01Z", "2018-05-15T00:00:00Z", [], []]
202       ].each do |from, to, interval_changesets, point_changesets|
203         get api_changesets_path(:time => "#{from},#{to}")
204         assert_response :success
205         assert_changesets_in_order interval_changesets
206
207         get api_changesets_path(:from => from, :to => to)
208         assert_response :success
209         assert_changesets_in_order point_changesets
210
211         get api_changesets_path(:from => from, :to => to, :order => "oldest")
212         assert_response :success
213         assert_changesets_in_order point_changesets.reverse
214       end
215     end
216
217     ##
218     # test the query functionality of overlapping changesets with order and time parameters
219     def test_index_order_overlapping
220       user = create(:user)
221       changeset1 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 4, 17, 0, 0), :closed_at => Time.utc(2015, 6, 4, 17, 0, 0))
222       changeset2 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 4, 16, 0, 0), :closed_at => Time.utc(2015, 6, 4, 18, 0, 0))
223       changeset3 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 4, 14, 0, 0), :closed_at => Time.utc(2015, 6, 4, 20, 0, 0))
224       changeset4 = create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 3, 23, 0, 0), :closed_at => Time.utc(2015, 6, 4, 23, 0, 0))
225       create(:changeset, :closed, :user => user, :created_at => Time.utc(2015, 6, 2, 23, 0, 0), :closed_at => Time.utc(2015, 6, 3, 23, 0, 0))
226
227       get api_changesets_path(:time => "2015-06-04T00:00:00Z")
228       assert_response :success
229       assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
230
231       get api_changesets_path(:from => "2015-06-04T00:00:00Z")
232       assert_response :success
233       assert_changesets_in_order [changeset1, changeset2, changeset3]
234
235       get api_changesets_path(:from => "2015-06-04T00:00:00Z", :order => "oldest")
236       assert_response :success
237       assert_changesets_in_order [changeset3, changeset2, changeset1]
238
239       get api_changesets_path(:time => "2015-06-04T16:00:00Z,2015-06-04T17:30:00Z")
240       assert_response :success
241       assert_changesets_in_order [changeset1, changeset2, changeset3, changeset4]
242
243       get api_changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z")
244       assert_response :success
245       assert_changesets_in_order [changeset1, changeset2]
246
247       get api_changesets_path(:from => "2015-06-04T16:00:00Z", :to => "2015-06-04T17:30:00Z", :order => "oldest")
248       assert_response :success
249       assert_changesets_in_order [changeset2, changeset1]
250     end
251
252     ##
253     # check that errors are returned if garbage is inserted
254     # into query strings
255     def test_index_invalid
256       ["abracadabra!",
257        "1,2,3,F",
258        ";drop table users;"].each do |bbox|
259         get api_changesets_path(:bbox => bbox)
260         assert_response :bad_request, "'#{bbox}' isn't a bbox"
261       end
262
263       ["now()",
264        "00-00-00",
265        ";drop table users;",
266        ",",
267        "-,-"].each do |time|
268         get api_changesets_path(:time => time)
269         assert_response :bad_request, "'#{time}' isn't a valid time range"
270       end
271
272       ["me",
273        "foobar",
274        "-1",
275        "0"].each do |uid|
276         get api_changesets_path(:user => uid)
277         assert_response :bad_request, "'#{uid}' isn't a valid user ID"
278       end
279
280       get api_changesets_path(:order => "oldest", :time => "2008-01-01T00:00Z,2018-01-01T00:00Z")
281       assert_response :bad_request, "cannot use order=oldest with time"
282     end
283
284     # -----------------------
285     # Test simple changeset creation
286     # -----------------------
287
288     def test_create
289       user = create(:user)
290       auth_header = bearer_authorization_header user
291       # Create the first user's changeset
292       xml = "<osm><changeset>" \
293             "<tag k='created_by' v='osm test suite checking changesets'/>" \
294             "</changeset></osm>"
295
296       assert_difference "Changeset.count", 1 do
297         post api_changesets_path, :params => xml, :headers => auth_header
298         assert_response :success, "Creation of changeset did not return success status"
299       end
300       newid = @response.body.to_i
301
302       # check end time, should be an hour ahead of creation time
303       changeset = Changeset.find(newid)
304       duration = changeset.closed_at - changeset.created_at
305       # the difference can either be a rational, or a floating point number
306       # of seconds, depending on the code path taken :-(
307       if duration.instance_of?(Rational)
308         assert_equal Rational(1, 24), duration, "initial idle timeout should be an hour (#{changeset.created_at} -> #{changeset.closed_at})"
309       else
310         # must be number of seconds...
311         assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{changeset.created_at} -> #{changeset.closed_at})"
312       end
313
314       assert_equal [user], changeset.subscribers
315       assert_predicate changeset, :num_type_changes_in_sync?
316     end
317
318     def test_create_invalid
319       auth_header = bearer_authorization_header create(:user, :data_public => false)
320       xml = "<osm><changeset></osm>"
321       post api_changesets_path, :params => xml, :headers => auth_header
322       assert_require_public_data
323
324       ## Try the public user
325       auth_header = bearer_authorization_header
326       xml = "<osm><changeset></osm>"
327       post api_changesets_path, :params => xml, :headers => auth_header
328       assert_response :bad_request, "creating a invalid changeset should fail"
329     end
330
331     def test_create_invalid_no_content
332       ## First check with no auth
333       post api_changesets_path
334       assert_response :unauthorized, "shouldn't be able to create a changeset with no auth"
335
336       ## Now try to with a non-public user
337       auth_header = bearer_authorization_header create(:user, :data_public => false)
338       post api_changesets_path, :headers => auth_header
339       assert_require_public_data
340
341       ## Try an inactive user
342       auth_header = bearer_authorization_header create(:user, :pending)
343       post api_changesets_path, :headers => auth_header
344       assert_inactive_user
345
346       ## Now try to use a normal user
347       auth_header = bearer_authorization_header
348       post api_changesets_path, :headers => auth_header
349       assert_response :bad_request, "creating a changeset with no content should fail"
350     end
351
352     def test_create_wrong_method
353       auth_header = bearer_authorization_header
354
355       put api_changesets_path, :headers => auth_header
356       assert_response :not_found
357       assert_template "rescues/routing_error"
358     end
359
360     def test_create_legacy_path
361       auth_header = bearer_authorization_header
362       xml = "<osm><changeset></changeset></osm>"
363
364       assert_difference "Changeset.count", 1 do
365         put "/api/0.6/changeset/create", :params => xml, :headers => auth_header
366       end
367
368       assert_response :success, "Creation of changeset did not return success status"
369       assert_equal Changeset.last.id, @response.body.to_i
370     end
371
372     ##
373     # check that the changeset can be shown and returns the correct
374     # document structure.
375     def test_show
376       changeset = create(:changeset)
377
378       get api_changeset_path(changeset)
379       assert_response :success, "cannot get first changeset"
380
381       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
382       assert_single_changeset changeset do
383         assert_dom "> discussion", 0
384       end
385
386       get api_changeset_path(changeset, :include_discussion => true)
387       assert_response :success, "cannot get first changeset with comments"
388
389       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
390       assert_single_changeset changeset do
391         assert_dom "> discussion", 1
392         assert_dom "> discussion > comment", 0
393       end
394     end
395
396     def test_show_comments
397       # all comments visible
398       changeset = create(:changeset, :closed)
399       comment1, comment2, comment3 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
400
401       get api_changeset_path(changeset, :include_discussion => true)
402       assert_response :success, "cannot get closed changeset with comments"
403
404       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1 do
405         assert_single_changeset changeset do
406           assert_dom "> discussion", 1 do
407             assert_dom "> comment", 3 do |dom_comments|
408               assert_dom dom_comments[0], "> @id", comment1.id.to_s
409               assert_dom dom_comments[0], "> @visible", "true"
410               assert_dom dom_comments[1], "> @id", comment2.id.to_s
411               assert_dom dom_comments[1], "> @visible", "true"
412               assert_dom dom_comments[2], "> @id", comment3.id.to_s
413               assert_dom dom_comments[2], "> @visible", "true"
414             end
415           end
416         end
417       end
418
419       # one hidden comment not included because not asked for
420       comment2.update(:visible => false)
421       changeset.reload
422
423       get api_changeset_path(changeset, :include_discussion => true)
424       assert_response :success, "cannot get closed changeset with comments"
425
426       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
427       assert_single_changeset changeset do
428         assert_dom "> discussion", 1 do
429           assert_dom "> comment", 2 do |dom_comments|
430             assert_dom dom_comments[0], "> @id", comment1.id.to_s
431             assert_dom dom_comments[0], "> @visible", "true"
432             assert_dom dom_comments[1], "> @id", comment3.id.to_s
433             assert_dom dom_comments[1], "> @visible", "true"
434           end
435         end
436       end
437
438       # one hidden comment not included because no permissions
439       get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true)
440       assert_response :success, "cannot get closed changeset with comments"
441
442       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
443       assert_single_changeset changeset do
444         assert_dom "> discussion", 1 do
445           assert_dom "> comment", 2 do |dom_comments|
446             assert_dom dom_comments[0], "> @id", comment1.id.to_s
447             assert_dom dom_comments[0], "> @visible", "true"
448             # maybe will show an empty comment element with visible=false in the future
449             assert_dom dom_comments[1], "> @id", comment3.id.to_s
450             assert_dom dom_comments[1], "> @visible", "true"
451           end
452         end
453       end
454
455       # one hidden comment shown to moderators
456       moderator_user = create(:moderator_user)
457       auth_header = bearer_authorization_header moderator_user
458       get api_changeset_path(changeset, :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
459       assert_response :success, "cannot get closed changeset with comments"
460
461       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
462       assert_single_changeset changeset do
463         assert_dom "> discussion", 1 do
464           assert_dom "> comment", 3 do |dom_comments|
465             assert_dom dom_comments[0], "> @id", comment1.id.to_s
466             assert_dom dom_comments[0], "> @visible", "true"
467             assert_dom dom_comments[1], "> @id", comment2.id.to_s
468             assert_dom dom_comments[1], "> @visible", "false"
469             assert_dom dom_comments[2], "> @id", comment3.id.to_s
470             assert_dom dom_comments[2], "> @visible", "true"
471           end
472         end
473       end
474     end
475
476     def test_show_tags
477       changeset = create(:changeset, :closed)
478       create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
479       create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
480
481       get api_changeset_path(changeset)
482
483       assert_response :success
484       assert_dom "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
485       assert_single_changeset changeset do
486         assert_dom "> tag", 2
487         assert_dom "> tag[k='created_by'][v='JOSM/1.5 (18364)']", 1
488         assert_dom "> tag[k='comment'][v='changeset comment']", 1
489       end
490     end
491
492     def test_show_json
493       changeset = create(:changeset)
494
495       get api_changeset_path(changeset, :format => "json")
496       assert_response :success, "cannot get first changeset"
497
498       js = ActiveSupport::JSON.decode(@response.body)
499       assert_not_nil js
500
501       assert_equal Settings.api_version, js["version"]
502       assert_equal Settings.generator, js["generator"]
503       assert_single_changeset_json changeset, js
504       assert_nil js["changeset"]["tags"]
505       assert_nil js["changeset"]["comments"]
506       assert_equal changeset.user.id, js["changeset"]["uid"]
507       assert_equal changeset.user.display_name, js["changeset"]["user"]
508
509       get api_changeset_path(changeset, :format => "json", :include_discussion => true)
510       assert_response :success, "cannot get first changeset with comments"
511
512       js = ActiveSupport::JSON.decode(@response.body)
513       assert_not_nil js
514       assert_equal Settings.api_version, js["version"]
515       assert_equal Settings.generator, js["generator"]
516       assert_single_changeset_json changeset, js
517       assert_nil js["changeset"]["tags"]
518       assert_nil js["changeset"]["min_lat"]
519       assert_nil js["changeset"]["min_lon"]
520       assert_nil js["changeset"]["max_lat"]
521       assert_nil js["changeset"]["max_lon"]
522       assert_equal 0, js["changeset"]["comments"].count
523     end
524
525     def test_show_comments_json
526       # all comments visible
527       changeset = create(:changeset, :closed)
528       comment0, comment1, comment2 = create_list(:changeset_comment, 3, :changeset_id => changeset.id)
529
530       get api_changeset_path(changeset, :format => "json", :include_discussion => true)
531       assert_response :success, "cannot get closed changeset with comments"
532
533       js = ActiveSupport::JSON.decode(@response.body)
534       assert_not_nil js
535       assert_equal Settings.api_version, js["version"]
536       assert_equal Settings.generator, js["generator"]
537       assert_single_changeset_json changeset, js
538       assert_equal 3, js["changeset"]["comments"].count
539       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
540       assert js["changeset"]["comments"][0]["visible"]
541       assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
542       assert js["changeset"]["comments"][1]["visible"]
543       assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
544       assert js["changeset"]["comments"][2]["visible"]
545
546       # one hidden comment not included because not asked for
547       comment1.update(:visible => false)
548       changeset.reload
549
550       get api_changeset_path(changeset, :format => "json", :include_discussion => true)
551       assert_response :success, "cannot get closed changeset with comments"
552
553       js = ActiveSupport::JSON.decode(@response.body)
554       assert_not_nil js
555       assert_equal Settings.api_version, js["version"]
556       assert_equal Settings.generator, js["generator"]
557       assert_single_changeset_json changeset, js
558       assert_equal 2, js["changeset"]["comments"].count
559       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
560       assert js["changeset"]["comments"][0]["visible"]
561       assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
562       assert js["changeset"]["comments"][1]["visible"]
563
564       # one hidden comment not included because no permissions
565       get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true)
566       assert_response :success, "cannot get closed changeset with comments"
567
568       js = ActiveSupport::JSON.decode(@response.body)
569       assert_not_nil js
570       assert_equal Settings.api_version, js["version"]
571       assert_equal Settings.generator, js["generator"]
572       assert_single_changeset_json changeset, js
573       assert_equal 2, js["changeset"]["comments"].count
574       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
575       assert js["changeset"]["comments"][0]["visible"]
576       # maybe will show an empty comment element with visible=false in the future
577       assert_equal comment2.id, js["changeset"]["comments"][1]["id"]
578       assert js["changeset"]["comments"][1]["visible"]
579
580       # one hidden comment shown to moderators
581       moderator_user = create(:moderator_user)
582       auth_header = bearer_authorization_header moderator_user
583       get api_changeset_path(changeset, :format => "json", :include_discussion => true, :show_hidden_comments => true), :headers => auth_header
584       assert_response :success, "cannot get closed changeset with comments"
585
586       js = ActiveSupport::JSON.decode(@response.body)
587       assert_not_nil js
588       assert_equal Settings.api_version, js["version"]
589       assert_equal Settings.generator, js["generator"]
590       assert_single_changeset_json changeset, js
591       assert_equal 3, js["changeset"]["comments"].count
592       assert_equal comment0.id, js["changeset"]["comments"][0]["id"]
593       assert js["changeset"]["comments"][0]["visible"]
594       assert_equal comment1.id, js["changeset"]["comments"][1]["id"]
595       assert_not js["changeset"]["comments"][1]["visible"]
596       assert_equal comment2.id, js["changeset"]["comments"][2]["id"]
597       assert js["changeset"]["comments"][2]["visible"]
598     end
599
600     def test_show_tags_json
601       changeset = create(:changeset, :closed)
602       create(:changeset_tag, :changeset => changeset, :k => "created_by", :v => "JOSM/1.5 (18364)")
603       create(:changeset_tag, :changeset => changeset, :k => "comment", :v => "changeset comment")
604
605       get api_changeset_path(changeset, :format => "json")
606
607       assert_response :success
608       js = ActiveSupport::JSON.decode(@response.body)
609       assert_not_nil js
610       assert_equal Settings.api_version, js["version"]
611       assert_equal Settings.generator, js["generator"]
612       assert_single_changeset_json changeset, js
613       assert_equal 2, js["changeset"]["tags"].count
614       assert_equal "JOSM/1.5 (18364)", js["changeset"]["tags"]["created_by"]
615       assert_equal "changeset comment", js["changeset"]["tags"]["comment"]
616     end
617
618     def test_show_bbox_json
619       changeset = create(:changeset, :bbox => [5, -5, 12, 15])
620
621       get api_changeset_path(changeset, :format => "json")
622       assert_response :success, "cannot get first changeset"
623
624       js = ActiveSupport::JSON.decode(@response.body)
625       assert_not_nil js
626       assert_equal(-5, js["changeset"]["min_lat"])
627       assert_equal 5, js["changeset"]["min_lon"]
628       assert_equal 15, js["changeset"]["max_lat"]
629       assert_equal 12, js["changeset"]["max_lon"]
630     end
631
632     ##
633     # check that a changeset that doesn't exist returns an appropriate message
634     def test_show_not_found
635       [0, -32, 233455644, "afg", "213"].each do |id|
636         get api_changeset_path(id)
637         assert_response :not_found, "should get a not found"
638       rescue ActionController::UrlGenerationError => e
639         assert_match(/No route matches/, e.to_s)
640       end
641     end
642
643     def test_repeated_changeset_create
644       3.times do
645         auth_header = bearer_authorization_header
646
647         # create a temporary changeset
648         xml = "<osm><changeset>" \
649               "<tag k='created_by' v='osm test suite checking changesets'/>" \
650               "</changeset></osm>"
651         assert_difference "Changeset.count", 1 do
652           post api_changesets_path, :params => xml, :headers => auth_header
653         end
654         assert_response :success
655       end
656     end
657
658     ##
659     # check updating tags on a changeset
660     def test_changeset_update
661       private_user = create(:user, :data_public => false)
662       private_changeset = create(:changeset, :user => private_user)
663       user = create(:user)
664       changeset = create(:changeset, :user => user)
665
666       ## First try with a non-public user
667       new_changeset = create_changeset_xml(:user => private_user)
668       new_tag = XML::Node.new "tag"
669       new_tag["k"] = "tagtesting"
670       new_tag["v"] = "valuetesting"
671       new_changeset.find("//osm/changeset").first << new_tag
672
673       # try without any authorization
674       put api_changeset_path(private_changeset), :params => new_changeset.to_s
675       assert_response :unauthorized
676
677       # try with the wrong authorization
678       auth_header = bearer_authorization_header
679       put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
680       assert_response :conflict
681
682       # now this should get an unauthorized
683       auth_header = bearer_authorization_header private_user
684       put api_changeset_path(private_changeset), :params => new_changeset.to_s, :headers => auth_header
685       assert_require_public_data "user with their data non-public, shouldn't be able to edit their changeset"
686
687       ## Now try with the public user
688       new_changeset = create_changeset_xml(:id => 1)
689       new_tag = XML::Node.new "tag"
690       new_tag["k"] = "tagtesting"
691       new_tag["v"] = "valuetesting"
692       new_changeset.find("//osm/changeset").first << new_tag
693
694       # try without any authorization
695       put api_changeset_path(changeset), :params => new_changeset.to_s
696       assert_response :unauthorized
697
698       # try with the wrong authorization
699       auth_header = bearer_authorization_header
700       put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
701       assert_response :conflict
702
703       # now this should work...
704       auth_header = bearer_authorization_header user
705       put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
706       assert_response :success
707
708       assert_select "osm>changeset[id='#{changeset.id}']", 1
709       assert_select "osm>changeset>tag", 1
710       assert_select "osm>changeset>tag[k='tagtesting'][v='valuetesting']", 1
711     end
712
713     ##
714     # check that a user different from the one who opened the changeset
715     # can't modify it.
716     def test_changeset_update_invalid
717       auth_header = bearer_authorization_header
718
719       changeset = create(:changeset)
720       new_changeset = create_changeset_xml(:user => changeset.user, :id => changeset.id)
721       new_tag = XML::Node.new "tag"
722       new_tag["k"] = "testing"
723       new_tag["v"] = "testing"
724       new_changeset.find("//osm/changeset").first << new_tag
725
726       put api_changeset_path(changeset), :params => new_changeset.to_s, :headers => auth_header
727       assert_response :conflict
728     end
729
730     ##
731     # check that a changeset can contain a certain max number of changes.
732     ## FIXME should be changed to an integration test due to the with_controller
733     def test_changeset_limits
734       user = create(:user)
735       auth_header = bearer_authorization_header user
736
737       # create an old changeset to ensure we have the maximum rate limit
738       create(:changeset, :user => user, :created_at => Time.now.utc - 28.days)
739
740       # open a new changeset
741       xml = "<osm><changeset/></osm>"
742       post api_changesets_path, :params => xml, :headers => auth_header
743       assert_response :success, "can't create a new changeset"
744       changeset_id = @response.body.to_i
745
746       # start the counter just short of where the changeset should finish.
747       offset = 10
748       # alter the database to set the counter on the changeset directly,
749       # otherwise it takes about 6 minutes to fill all of them.
750       changeset = Changeset.find(changeset_id)
751       changeset.num_changes = Changeset::MAX_ELEMENTS - offset
752       changeset.save!
753
754       with_controller(NodesController.new) do
755         # create a new node
756         xml = "<osm><node changeset='#{changeset_id}' lat='0.0' lon='0.0'/></osm>"
757         post api_nodes_path, :params => xml, :headers => auth_header
758         assert_response :success, "can't create a new node"
759         node_id = @response.body.to_i
760
761         get api_node_path(node_id)
762         assert_response :success, "can't read back new node"
763         node_doc = XML::Parser.string(@response.body).parse
764         node_xml = node_doc.find("//osm/node").first
765
766         # loop until we fill the changeset with nodes
767         offset.times do |i|
768           node_xml["lat"] = rand.to_s
769           node_xml["lon"] = rand.to_s
770           node_xml["version"] = (i + 1).to_s
771
772           put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
773           assert_response :success, "attempt #{i} should have succeeded"
774         end
775
776         # trying again should fail
777         node_xml["lat"] = rand.to_s
778         node_xml["lon"] = rand.to_s
779         node_xml["version"] = offset.to_s
780
781         put api_node_path(node_id), :params => node_doc.to_s, :headers => auth_header
782         assert_response :conflict, "final attempt should have failed"
783       end
784
785       changeset = Changeset.find(changeset_id)
786       assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
787
788       # check that the changeset is now closed as well
789       assert_not(changeset.open?,
790                  "changeset should have been auto-closed by exceeding " \
791                  "element limit.")
792     end
793
794     private
795
796     ##
797     # check that the output consists of one specific changeset
798     def assert_single_changeset(changeset, &)
799       assert_dom "> changeset", 1 do
800         assert_dom "> @id", changeset.id.to_s
801         assert_dom "> @created_at", changeset.created_at.xmlschema
802         if changeset.open?
803           assert_dom "> @open", "true"
804           assert_dom "> @closed_at", 0
805         else
806           assert_dom "> @open", "false"
807           assert_dom "> @closed_at", changeset.closed_at.xmlschema
808         end
809         assert_dom "> @comments_count", changeset.comments.length.to_s
810         assert_dom "> @changes_count", changeset.num_changes.to_s
811         yield if block_given?
812       end
813     end
814
815     def assert_single_changeset_json(changeset, js)
816       assert_equal changeset.id, js["changeset"]["id"]
817       assert_equal changeset.created_at.xmlschema, js["changeset"]["created_at"]
818       if changeset.open?
819         assert js["changeset"]["open"]
820         assert_nil js["changeset"]["closed_at"]
821       else
822         assert_not js["changeset"]["open"]
823         assert_equal changeset.closed_at.xmlschema, js["changeset"]["closed_at"]
824       end
825       assert_equal changeset.comments.length, js["changeset"]["comments_count"]
826       assert_equal changeset.num_changes, js["changeset"]["changes_count"]
827     end
828
829     ##
830     # check that certain changesets exist in the output in the specified order
831     def assert_changesets_in_order(changesets)
832       assert_select "osm>changeset", changesets.size
833       changesets.each_with_index do |changeset, index|
834         assert_select "osm>changeset:nth-child(#{index + 1})[id='#{changeset.id}']", 1
835       end
836     end
837
838     ##
839     # build XML for changesets
840     def create_changeset_xml(user: nil, id: nil)
841       root = XML::Document.new
842       root.root = XML::Node.new "osm"
843       changeset = XML::Node.new "changeset"
844       if user
845         changeset["user"] = user.display_name
846         changeset["uid"] = user.id.to_s
847       end
848       changeset["id"] = id.to_s if id
849       root.root << changeset
850       root
851     end
852   end
853 end