]> git.openstreetmap.org Git - rails.git/blob - test/controllers/changeset_controller_test.rb
c3fd0fadc923cea4b52855604cdd22aa06e17260
[rails.git] / test / controllers / changeset_controller_test.rb
1 require 'test_helper'
2 require 'changeset_controller'
3
4 class ChangesetControllerTest < ActionController::TestCase
5   api_fixtures
6   fixtures :changeset_comments
7
8   ##
9   # test all routes which lead to this controller
10   def test_routes
11     assert_routing(
12       { :path => "/api/0.6/changeset/create", :method => :put },
13       { :controller => "changeset", :action => "create" }
14     )
15     assert_routing(
16       { :path => "/api/0.6/changeset/1/upload", :method => :post },
17       { :controller => "changeset", :action => "upload", :id => "1" }
18     )
19     assert_routing(
20       { :path => "/api/0.6/changeset/1/download", :method => :get },
21       { :controller => "changeset", :action => "download", :id => "1" }
22     )
23     assert_routing(
24       { :path => "/api/0.6/changeset/1/expand_bbox", :method => :post },
25       { :controller => "changeset", :action => "expand_bbox", :id => "1" }
26     )
27     assert_routing(
28       { :path => "/api/0.6/changeset/1", :method => :get },
29       { :controller => "changeset", :action => "read", :id => "1" }
30     )
31     assert_routing(
32       { :path => "/api/0.6/changeset/1", :method => :put },
33       { :controller => "changeset", :action => "update", :id => "1" }
34     )
35     assert_routing(
36       { :path => "/api/0.6/changeset/1/close", :method => :put },
37       { :controller => "changeset", :action => "close", :id => "1" }
38     )
39     assert_routing(
40         { :path => "/api/0.6/changeset/1/subscribe", :method => :post },
41         { :controller => "changeset", :action => "subscribe", :id => "1" }
42     )
43     assert_routing(
44         { :path => "/api/0.6/changeset/1/unsubscribe", :method => :post },
45         { :controller => "changeset", :action => "unsubscribe", :id => "1" }
46     )
47     assert_routing(
48         { :path => "/api/0.6/changeset/comment/1/hide", :method => :post },
49         { :controller => "changeset", :action => "hide_comment", :id => "1" }
50     )
51     assert_routing(
52         { :path => "/api/0.6/changeset/comment/1/unhide", :method => :post },
53         { :controller => "changeset", :action => "unhide_comment", :id => "1" }
54     )
55     assert_routing(
56         { :path => "/api/0.6/changeset/comments/feed", :method => :get },
57         { :controller => "changeset", :action => "comments_feed", :format =>"rss" }
58     )
59     assert_routing(
60         { :path => "/api/0.6/changeset/1/comments/feed", :method => :get },
61         { :controller => "changeset", :action => "comments_feed", :id => "1", :format =>"rss" }
62     )
63     assert_routing(
64       { :path => "/api/0.6/changesets", :method => :get },
65       { :controller => "changeset", :action => "query" }
66     )
67     assert_routing(
68       { :path => "/user/name/history", :method => :get },
69       { :controller => "changeset", :action => "list", :display_name => "name" }
70     )
71     assert_routing(
72       { :path => "/user/name/history/feed", :method => :get },
73       { :controller => "changeset", :action => "feed", :display_name => "name", :format => :atom }
74     )
75     assert_routing(
76       { :path => "/history/friends", :method => :get },
77       { :controller => "changeset", :action => "list", :friends => true }
78     )
79     assert_routing(
80       { :path => "/history/nearby", :method => :get },
81       { :controller => "changeset", :action => "list", :nearby => true }
82     )
83     assert_routing(
84       { :path => "/history", :method => :get },
85       { :controller => "changeset", :action => "list" }
86     )
87     assert_routing(
88       { :path => "/history/feed", :method => :get },
89       { :controller => "changeset", :action => "feed", :format => :atom }
90     )
91   end
92
93   # -----------------------
94   # Test simple changeset creation
95   # -----------------------
96
97   def test_create
98     basic_authorization users(:normal_user).email, "test"
99     # Create the first user's changeset
100     content "<osm><changeset>" +
101       "<tag k='created_by' v='osm test suite checking changesets'/>" +
102       "</changeset></osm>"
103     put :create
104     assert_require_public_data
105
106
107     basic_authorization users(:public_user).email, "test"
108     # Create the first user's changeset
109     content "<osm><changeset>" +
110       "<tag k='created_by' v='osm test suite checking changesets'/>" +
111       "</changeset></osm>"
112     put :create
113
114     assert_response :success, "Creation of changeset did not return sucess status"
115     newid = @response.body.to_i
116
117     # check end time, should be an hour ahead of creation time
118     cs = Changeset.find(newid)
119     duration = cs.closed_at - cs.created_at
120     # the difference can either be a rational, or a floating point number
121     # of seconds, depending on the code path taken :-(
122     if duration.class == Rational
123       assert_equal Rational(1,24), duration , "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
124     else
125       # must be number of seconds...
126       assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
127     end
128
129     # checks if uploader was subscribed
130     assert_equal 1, cs.subscribers.length
131   end
132
133   def test_create_invalid
134     basic_authorization users(:normal_user).email, "test"
135     content "<osm><changeset></osm>"
136     put :create
137     assert_require_public_data
138
139     ## Try the public user
140     basic_authorization users(:public_user).email, "test"
141     content "<osm><changeset></osm>"
142     put :create
143     assert_response :bad_request, "creating a invalid changeset should fail"
144   end
145
146   def test_create_invalid_no_content
147     ## First check with no auth
148     put :create
149     assert_response :unauthorized, "shouldn't be able to create a changeset with no auth"
150
151     ## Now try to with the non-public user
152     basic_authorization users(:normal_user).email, "test"
153     put :create
154     assert_require_public_data
155
156     ## Try the inactive user
157     basic_authorization users(:inactive_user).email, "test"
158     put :create
159     assert_inactive_user
160
161     ## Now try to use the public user
162     basic_authorization users(:public_user).email, "test"
163     put :create
164     assert_response :bad_request, "creating a changeset with no content should fail"
165   end
166
167   def test_create_wrong_method
168     basic_authorization users(:public_user).email, "test"
169     get :create
170     assert_response :method_not_allowed
171     post :create
172     assert_response :method_not_allowed
173   end
174
175   ##
176   # check that the changeset can be read and returns the correct
177   # document structure.
178   def test_read
179     changeset_id = changesets(:normal_user_first_change).id
180     get :read, :id => changeset_id, :format => :xml
181     assert_response :success, "cannot get first changeset"
182
183     assert_select "osm[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
184     assert_select "osm>changeset[id=#{changeset_id}]", 1
185     assert_select "osm>changeset>discussion", 0
186
187     get :read, :id => changeset_id, :format => :xml, :include_discussion => true
188     assert_select "osm>changeset>discussion", 1
189   end
190
191   ##
192   # check that a changeset that doesn't exist returns an appropriate message
193   def test_read_not_found
194     [0, -32, 233455644, "afg", "213"].each do |id|
195       begin
196         get :read, :id => id
197         assert_response :not_found, "should get a not found"
198       rescue ActionController::UrlGenerationError => ex
199         assert_match /No route matches/, ex.to_s
200       end
201     end
202   end
203
204   ##
205   # test that the user who opened a change can close it
206   def test_close
207     ## Try without authentication
208     put :close, :id => changesets(:public_user_first_change).id
209     assert_response :unauthorized
210
211
212     ## Try using the non-public user
213     basic_authorization users(:normal_user).email, "test"
214     put :close, :id => changesets(:normal_user_first_change).id
215     assert_require_public_data
216
217
218     ## The try with the public user
219     basic_authorization users(:public_user).email, "test"
220
221     cs_id = changesets(:public_user_first_change).id
222     put :close, :id => cs_id
223     assert_response :success
224
225     # test that it really is closed now
226     cs = Changeset.find(cs_id)
227     assert(!cs.is_open?,
228            "changeset should be closed now (#{cs.closed_at} > #{Time.now.getutc}.")
229   end
230
231   ##
232   # test that a different user can't close another user's changeset
233   def test_close_invalid
234     basic_authorization users(:public_user).email, "test"
235
236     put :close, :id => changesets(:normal_user_first_change).id
237     assert_response :conflict
238     assert_equal "The user doesn't own that changeset", @response.body
239   end
240
241   ##
242   # test that you can't close using another method
243   def test_close_method_invalid
244     basic_authorization users(:public_user).email, "test"
245
246     cs_id = changesets(:public_user_first_change).id
247     get :close, :id => cs_id
248     assert_response :method_not_allowed
249
250     post :close, :id => cs_id
251     assert_response :method_not_allowed
252   end
253
254   ##
255   # check that you can't close a changeset that isn't found
256   def test_close_not_found
257     cs_ids = [0, -132, "123"]
258
259     # First try to do it with no auth
260     cs_ids.each do |id|
261       begin
262         put :close, :id => id
263         assert_response :unauthorized, "Shouldn't be able close the non-existant changeset #{id}, when not authorized"
264       rescue ActionController::UrlGenerationError => ex
265         assert_match /No route matches/, ex.to_s
266       end
267     end
268
269     # Now try with auth
270     basic_authorization users(:public_user).email, "test"
271     cs_ids.each do |id|
272       begin
273         put :close, :id => id
274         assert_response :not_found, "The changeset #{id} doesn't exist, so can't be closed"
275       rescue ActionController::UrlGenerationError => ex
276         assert_match /No route matches/, ex.to_s
277       end
278     end
279   end
280
281   ##
282   # upload something simple, but valid and check that it can
283   # be read back ok
284   # Also try without auth and another user.
285   def test_upload_simple_valid
286     ## Try with no auth
287     changeset_id = changesets(:public_user_first_change).id
288
289     # simple diff to change a node, way and relation by removing
290     # their tags
291     diff = <<EOF
292 <osmChange>
293  <modify>
294   <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
295   <way id='1' changeset='#{changeset_id}' version='1'>
296    <nd ref='3'/>
297   </way>
298  </modify>
299  <modify>
300   <relation id='1' changeset='#{changeset_id}' version='1'>
301    <member type='way' role='some' ref='3'/>
302    <member type='node' role='some' ref='5'/>
303    <member type='relation' role='some' ref='3'/>
304   </relation>
305  </modify>
306 </osmChange>
307 EOF
308
309     # upload it
310     content diff
311     post :upload, :id => changeset_id
312     assert_response :unauthorized,
313       "shouldnn't be able to upload a simple valid diff to changeset: #{@response.body}"
314
315
316
317     ## Now try with a private user
318     basic_authorization users(:normal_user).email, "test"
319     changeset_id = changesets(:normal_user_first_change).id
320
321     # simple diff to change a node, way and relation by removing
322     # their tags
323     diff = <<EOF
324 <osmChange>
325  <modify>
326   <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
327   <way id='1' changeset='#{changeset_id}' version='1'>
328    <nd ref='3'/>
329   </way>
330  </modify>
331  <modify>
332   <relation id='1' changeset='#{changeset_id}' version='1'>
333    <member type='way' role='some' ref='3'/>
334    <member type='node' role='some' ref='5'/>
335    <member type='relation' role='some' ref='3'/>
336   </relation>
337  </modify>
338 </osmChange>
339 EOF
340
341     # upload it
342     content diff
343     post :upload, :id => changeset_id
344     assert_response :forbidden,
345       "can't upload a simple valid diff to changeset: #{@response.body}"
346
347
348
349     ## Now try with the public user
350     basic_authorization users(:public_user).email, "test"
351     changeset_id = changesets(:public_user_first_change).id
352
353     # simple diff to change a node, way and relation by removing
354     # their tags
355     diff = <<EOF
356 <osmChange>
357  <modify>
358   <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
359   <way id='1' changeset='#{changeset_id}' version='1'>
360    <nd ref='3'/>
361   </way>
362  </modify>
363  <modify>
364   <relation id='1' changeset='#{changeset_id}' version='1'>
365    <member type='way' role='some' ref='3'/>
366    <member type='node' role='some' ref='5'/>
367    <member type='relation' role='some' ref='3'/>
368   </relation>
369  </modify>
370 </osmChange>
371 EOF
372
373     # upload it
374     content diff
375     post :upload, :id => changeset_id
376     assert_response :success,
377       "can't upload a simple valid diff to changeset: #{@response.body}"
378
379     # check that the changes made it into the database
380     assert_equal 0, Node.find(1).tags.size, "node 1 should now have no tags"
381     assert_equal 0, Way.find(1).tags.size, "way 1 should now have no tags"
382     assert_equal 0, Relation.find(1).tags.size, "relation 1 should now have no tags"
383   end
384
385   ##
386   # upload something which creates new objects using placeholders
387   def test_upload_create_valid
388     basic_authorization users(:public_user).email, "test"
389     cs_id = changesets(:public_user_first_change).id
390
391     # simple diff to create a node way and relation using placeholders
392     diff = <<EOF
393 <osmChange>
394  <create>
395   <node id='-1' lon='0' lat='0' changeset='#{cs_id}'>
396    <tag k='foo' v='bar'/>
397    <tag k='baz' v='bat'/>
398   </node>
399   <way id='-1' changeset='#{cs_id}'>
400    <nd ref='3'/>
401   </way>
402  </create>
403  <create>
404   <relation id='-1' changeset='#{cs_id}'>
405    <member type='way' role='some' ref='3'/>
406    <member type='node' role='some' ref='5'/>
407    <member type='relation' role='some' ref='3'/>
408   </relation>
409  </create>
410 </osmChange>
411 EOF
412
413     # upload it
414     content diff
415     post :upload, :id => cs_id
416     assert_response :success,
417       "can't upload a simple valid creation to changeset: #{@response.body}"
418
419     # check the returned payload
420     assert_select "diffResult[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
421     assert_select "diffResult>node", 1
422     assert_select "diffresult>way", 1
423     assert_select "diffResult>relation", 1
424
425     # inspect the response to find out what the new element IDs are
426     doc = XML::Parser.string(@response.body).parse
427     new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
428     new_way_id = doc.find("//diffResult/way").first["new_id"].to_i
429     new_rel_id = doc.find("//diffResult/relation").first["new_id"].to_i
430
431     # check the old IDs are all present and negative one
432     assert_equal -1, doc.find("//diffResult/node").first["old_id"].to_i
433     assert_equal -1, doc.find("//diffResult/way").first["old_id"].to_i
434     assert_equal -1, doc.find("//diffResult/relation").first["old_id"].to_i
435
436     # check the versions are present and equal one
437     assert_equal 1, doc.find("//diffResult/node").first["new_version"].to_i
438     assert_equal 1, doc.find("//diffResult/way").first["new_version"].to_i
439     assert_equal 1, doc.find("//diffResult/relation").first["new_version"].to_i
440
441     # check that the changes made it into the database
442     assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
443     assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
444     assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
445   end
446
447   ##
448   # test a complex delete where we delete elements which rely on eachother
449   # in the same transaction.
450   def test_upload_delete
451     basic_authorization users(:public_user).display_name, "test"
452
453     diff = XML::Document.new
454     diff.root = XML::Node.new "osmChange"
455     delete = XML::Node.new "delete"
456     diff.root << delete
457     delete << current_relations(:visible_relation).to_xml_node
458     delete << current_relations(:used_relation).to_xml_node
459     delete << current_ways(:used_way).to_xml_node
460     delete << current_nodes(:node_used_by_relationship).to_xml_node
461
462     # update the changeset to one that this user owns
463     changeset_id = changesets(:public_user_first_change).id
464     ["node", "way", "relation"].each do |type|
465       delete.find("//osmChange/delete/#{type}").each do |n|
466         n['changeset'] = changeset_id.to_s
467       end
468     end
469
470     # upload it
471     content diff
472     post :upload, :id => changeset_id
473     assert_response :success,
474       "can't upload a deletion diff to changeset: #{@response.body}"
475
476     # check the response is well-formed
477     assert_select "diffResult>node", 1
478     assert_select "diffResult>way", 1
479     assert_select "diffResult>relation", 2
480
481     # check that everything was deleted
482     assert_equal false, Node.find(current_nodes(:node_used_by_relationship).id).visible
483     assert_equal false, Way.find(current_ways(:used_way).id).visible
484     assert_equal false, Relation.find(current_relations(:visible_relation).id).visible
485     assert_equal false, Relation.find(current_relations(:used_relation).id).visible
486   end
487
488   ##
489   # test uploading a delete with no lat/lon, as they are optional in
490   # the osmChange spec.
491   def test_upload_nolatlon_delete
492     basic_authorization users(:public_user).display_name, "test"
493
494     node = current_nodes(:public_visible_node)
495     cs = changesets(:public_user_first_change)
496     diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{cs.id}'/></delete></osmChange>"
497
498     # upload it
499     content diff
500     post :upload, :id => cs.id
501     assert_response :success,
502       "can't upload a deletion diff to changeset: #{@response.body}"
503
504     # check the response is well-formed
505     assert_select "diffResult>node", 1
506
507     # check that everything was deleted
508     assert_equal false, Node.find(node.id).visible
509   end
510
511   def test_repeated_changeset_create
512     30.times do
513       basic_authorization users(:public_user).email, "test"
514
515       # create a temporary changeset
516       content "<osm><changeset>" +
517         "<tag k='created_by' v='osm test suite checking changesets'/>" +
518         "</changeset></osm>"
519       assert_difference('Changeset.count', 1) do
520         put :create
521       end
522       assert_response :success
523       changeset_id = @response.body.to_i
524     end
525   end
526
527   def test_upload_large_changeset
528     basic_authorization users(:public_user).email, "test"
529
530     # create a changeset
531     content "<osm><changeset/></osm>"
532     put :create
533     assert_response :success, "Should be able to create a changeset: #{@response.body}"
534     changeset_id = @response.body.to_i
535
536     # upload some widely-spaced nodes, spiralling positive and negative to cause
537     # largest bbox over-expansion possible.
538     diff = <<EOF
539 <osmChange>
540  <create>
541   <node id='-1' lon='-20' lat='-10' changeset='#{changeset_id}'/>
542   <node id='-10' lon='20'  lat='10' changeset='#{changeset_id}'/>
543   <node id='-2' lon='-40' lat='-20' changeset='#{changeset_id}'/>
544   <node id='-11' lon='40'  lat='20' changeset='#{changeset_id}'/>
545   <node id='-3' lon='-60' lat='-30' changeset='#{changeset_id}'/>
546   <node id='-12' lon='60'  lat='30' changeset='#{changeset_id}'/>
547   <node id='-4' lon='-80' lat='-40' changeset='#{changeset_id}'/>
548   <node id='-13' lon='80'  lat='40' changeset='#{changeset_id}'/>
549   <node id='-5' lon='-100' lat='-50' changeset='#{changeset_id}'/>
550   <node id='-14' lon='100'  lat='50' changeset='#{changeset_id}'/>
551   <node id='-6' lon='-120' lat='-60' changeset='#{changeset_id}'/>
552   <node id='-15' lon='120'  lat='60' changeset='#{changeset_id}'/>
553   <node id='-7' lon='-140' lat='-70' changeset='#{changeset_id}'/>
554   <node id='-16' lon='140'  lat='70' changeset='#{changeset_id}'/>
555   <node id='-8' lon='-160' lat='-80' changeset='#{changeset_id}'/>
556   <node id='-17' lon='160'  lat='80' changeset='#{changeset_id}'/>
557   <node id='-9' lon='-179.9' lat='-89.9' changeset='#{changeset_id}'/>
558   <node id='-18' lon='179.9'  lat='89.9' changeset='#{changeset_id}'/>
559  </create>
560 </osmChange>
561 EOF
562
563     # upload it, which used to cause an error like "PGError: ERROR:
564     # integer out of range" (bug #2152). but shouldn't any more.
565     content diff
566     post :upload, :id => changeset_id
567     assert_response :success,
568       "can't upload a spatially-large diff to changeset: #{@response.body}"
569
570     # check that the changeset bbox is within bounds
571     cs = Changeset.find(changeset_id)
572     assert cs.min_lon >= -180 * GeoRecord::SCALE, "Minimum longitude (#{cs.min_lon / GeoRecord::SCALE}) should be >= -180 to be valid."
573     assert cs.max_lon <=  180 * GeoRecord::SCALE, "Maximum longitude (#{cs.max_lon / GeoRecord::SCALE}) should be <= 180 to be valid."
574     assert cs.min_lat >=  -90 * GeoRecord::SCALE, "Minimum latitude (#{cs.min_lat / GeoRecord::SCALE}) should be >= -90 to be valid."
575     assert cs.max_lat >=   90 * GeoRecord::SCALE, "Maximum latitude (#{cs.max_lat / GeoRecord::SCALE}) should be <= 90 to be valid."
576   end
577
578   ##
579   # test that deleting stuff in a transaction doesn't bypass the checks
580   # to ensure that used elements are not deleted.
581   def test_upload_delete_invalid
582     basic_authorization users(:public_user).email, "test"
583
584     diff = XML::Document.new
585     diff.root = XML::Node.new "osmChange"
586     delete = XML::Node.new "delete"
587     diff.root << delete
588     delete << current_relations(:public_visible_relation).to_xml_node
589     delete << current_ways(:used_way).to_xml_node
590     delete << current_nodes(:node_used_by_relationship).to_xml_node
591
592     # upload it
593     content diff
594     post :upload, :id => 2
595     assert_response :precondition_failed,
596       "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
597     assert_equal "Precondition failed: Way 3 is still used by relations 1.", @response.body
598
599     # check that nothing was, in fact, deleted
600     assert_equal true, Node.find(current_nodes(:node_used_by_relationship).id).visible
601     assert_equal true, Way.find(current_ways(:used_way).id).visible
602     assert_equal true, Relation.find(current_relations(:visible_relation).id).visible
603   end
604
605   ##
606   # test that a conditional delete of an in use object works.
607   def test_upload_delete_if_unused
608     basic_authorization users(:public_user).email, "test"
609
610     diff = XML::Document.new
611     diff.root = XML::Node.new "osmChange"
612     delete = XML::Node.new "delete"
613     diff.root << delete
614     delete["if-unused"] = ""
615     delete << current_relations(:public_used_relation).to_xml_node
616     delete << current_ways(:used_way).to_xml_node
617     delete << current_nodes(:node_used_by_relationship).to_xml_node
618
619     # upload it
620     content diff
621     post :upload, :id => 2
622     assert_response :success,
623       "can't do a conditional delete of in use objects: #{@response.body}"
624
625     # check the returned payload
626     assert_select "diffResult[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
627     assert_select "diffResult>node", 1
628     assert_select "diffresult>way", 1
629     assert_select "diffResult>relation", 1
630
631     # parse the response
632     doc = XML::Parser.string(@response.body).parse
633
634     # check the old IDs are all present and what we expect
635     assert_equal current_nodes(:node_used_by_relationship).id, doc.find("//diffResult/node").first["old_id"].to_i
636     assert_equal current_ways(:used_way).id, doc.find("//diffResult/way").first["old_id"].to_i
637     assert_equal current_relations(:public_used_relation).id, doc.find("//diffResult/relation").first["old_id"].to_i
638
639     # check the new IDs are all present and unchanged
640     assert_equal current_nodes(:node_used_by_relationship).id, doc.find("//diffResult/node").first["new_id"].to_i
641     assert_equal current_ways(:used_way).id, doc.find("//diffResult/way").first["new_id"].to_i
642     assert_equal current_relations(:public_used_relation).id, doc.find("//diffResult/relation").first["new_id"].to_i
643
644     # check the new versions are all present and unchanged
645     assert_equal current_nodes(:node_used_by_relationship).version, doc.find("//diffResult/node").first["new_version"].to_i
646     assert_equal current_ways(:used_way).version, doc.find("//diffResult/way").first["new_version"].to_i
647     assert_equal current_relations(:public_used_relation).version, doc.find("//diffResult/relation").first["new_version"].to_i
648
649     # check that nothing was, in fact, deleted
650     assert_equal true, Node.find(current_nodes(:node_used_by_relationship).id).visible
651     assert_equal true, Way.find(current_ways(:used_way).id).visible
652     assert_equal true, Relation.find(current_relations(:public_used_relation).id).visible
653   end
654
655   ##
656   # upload an element with a really long tag value
657   def test_upload_invalid_too_long_tag
658     basic_authorization users(:public_user).email, "test"
659     cs_id = changesets(:public_user_first_change).id
660
661     # simple diff to create a node way and relation using placeholders
662     diff = <<EOF
663 <osmChange>
664  <create>
665   <node id='-1' lon='0' lat='0' changeset='#{cs_id}'>
666    <tag k='foo' v='#{"x"*256}'/>
667   </node>
668  </create>
669 </osmChange>
670 EOF
671
672     # upload it
673     content diff
674     post :upload, :id => cs_id
675     assert_response :bad_request,
676       "shoudln't be able to upload too long a tag to changeset: #{@response.body}"
677
678   end
679
680   ##
681   # upload something which creates new objects and inserts them into
682   # existing containers using placeholders.
683   def test_upload_complex
684     basic_authorization users(:public_user).email, "test"
685     cs_id = changesets(:public_user_first_change).id
686
687     # simple diff to create a node way and relation using placeholders
688     diff = <<EOF
689 <osmChange>
690  <create>
691   <node id='-1' lon='0' lat='0' changeset='#{cs_id}'>
692    <tag k='foo' v='bar'/>
693    <tag k='baz' v='bat'/>
694   </node>
695  </create>
696  <modify>
697   <way id='1' changeset='#{cs_id}' version='1'>
698    <nd ref='-1'/>
699    <nd ref='3'/>
700   </way>
701   <relation id='1' changeset='#{cs_id}' version='1'>
702    <member type='way' role='some' ref='3'/>
703    <member type='node' role='some' ref='-1'/>
704    <member type='relation' role='some' ref='3'/>
705   </relation>
706  </modify>
707 </osmChange>
708 EOF
709
710     # upload it
711     content diff
712     post :upload, :id => cs_id
713     assert_response :success,
714       "can't upload a complex diff to changeset: #{@response.body}"
715
716     # check the returned payload
717     assert_select "diffResult[version=#{API_VERSION}][generator=\"#{GENERATOR}\"]", 1
718     assert_select "diffResult>node", 1
719     assert_select "diffResult>way", 1
720     assert_select "diffResult>relation", 1
721
722     # inspect the response to find out what the new element IDs are
723     doc = XML::Parser.string(@response.body).parse
724     new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
725
726     # check that the changes made it into the database
727     assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
728     assert_equal [new_node_id, 3], Way.find(1).nds, "way nodes should match"
729     Relation.find(1).members.each do |type,id,role|
730       if type == 'node'
731         assert_equal new_node_id, id, "relation should contain new node"
732       end
733     end
734   end
735
736   ##
737   # create a diff which references several changesets, which should cause
738   # a rollback and none of the diff gets committed
739   def test_upload_invalid_changesets
740     basic_authorization users(:public_user).email, "test"
741     cs_id = changesets(:public_user_first_change).id
742
743     # simple diff to create a node way and relation using placeholders
744     diff = <<EOF
745 <osmChange>
746  <modify>
747   <node id='1' lon='0' lat='0' changeset='#{cs_id}' version='1'/>
748   <way id='1' changeset='#{cs_id}' version='1'>
749    <nd ref='3'/>
750   </way>
751  </modify>
752  <modify>
753   <relation id='1' changeset='#{cs_id}' version='1'>
754    <member type='way' role='some' ref='3'/>
755    <member type='node' role='some' ref='5'/>
756    <member type='relation' role='some' ref='3'/>
757   </relation>
758  </modify>
759  <create>
760   <node id='-1' lon='0' lat='0' changeset='4'>
761    <tag k='foo' v='bar'/>
762    <tag k='baz' v='bat'/>
763   </node>
764  </create>
765 </osmChange>
766 EOF
767     # cache the objects before uploading them
768     node = current_nodes(:visible_node)
769     way = current_ways(:visible_way)
770     rel = current_relations(:visible_relation)
771
772     # upload it
773     content diff
774     post :upload, :id => cs_id
775     assert_response :conflict,
776       "uploading a diff with multiple changsets should have failed"
777
778     # check that objects are unmodified
779     assert_nodes_are_equal(node, Node.find(1))
780     assert_ways_are_equal(way, Way.find(1))
781   end
782
783   ##
784   # upload multiple versions of the same element in the same diff.
785   def test_upload_multiple_valid
786     basic_authorization users(:public_user).email, "test"
787     cs_id = changesets(:public_user_first_change).id
788
789     # change the location of a node multiple times, each time referencing
790     # the last version. doesn't this depend on version numbers being
791     # sequential?
792     diff = <<EOF
793 <osmChange>
794  <modify>
795   <node id='1' lon='0' lat='0' changeset='#{cs_id}' version='1'/>
796   <node id='1' lon='1' lat='0' changeset='#{cs_id}' version='2'/>
797   <node id='1' lon='1' lat='1' changeset='#{cs_id}' version='3'/>
798   <node id='1' lon='1' lat='2' changeset='#{cs_id}' version='4'/>
799   <node id='1' lon='2' lat='2' changeset='#{cs_id}' version='5'/>
800   <node id='1' lon='3' lat='2' changeset='#{cs_id}' version='6'/>
801   <node id='1' lon='3' lat='3' changeset='#{cs_id}' version='7'/>
802   <node id='1' lon='9' lat='9' changeset='#{cs_id}' version='8'/>
803  </modify>
804 </osmChange>
805 EOF
806
807     # upload it
808     content diff
809     post :upload, :id => cs_id
810     assert_response :success,
811       "can't upload multiple versions of an element in a diff: #{@response.body}"
812
813     # check the response is well-formed. its counter-intuitive, but the
814     # API will return multiple elements with the same ID and different
815     # version numbers for each change we made.
816     assert_select "diffResult>node", 8
817   end
818
819   ##
820   # upload multiple versions of the same element in the same diff, but
821   # keep the version numbers the same.
822   def test_upload_multiple_duplicate
823     basic_authorization users(:public_user).email, "test"
824     cs_id = changesets(:public_user_first_change).id
825
826     diff = <<EOF
827 <osmChange>
828  <modify>
829   <node id='1' lon='0' lat='0' changeset='#{cs_id}' version='1'/>
830   <node id='1' lon='1' lat='1' changeset='#{cs_id}' version='1'/>
831  </modify>
832 </osmChange>
833 EOF
834
835     # upload it
836     content diff
837     post :upload, :id => cs_id
838     assert_response :conflict,
839       "shouldn't be able to upload the same element twice in a diff: #{@response.body}"
840   end
841
842   ##
843   # try to upload some elements without specifying the version
844   def test_upload_missing_version
845     basic_authorization users(:public_user).email, "test"
846     cs_id = changesets(:public_user_first_change).id
847
848     diff = <<EOF
849 <osmChange>
850  <modify>
851  <node id='1' lon='1' lat='1' changeset='cs_id'/>
852  </modify>
853 </osmChange>
854 EOF
855
856     # upload it
857     content diff
858     post :upload, :id => cs_id
859     assert_response :bad_request,
860       "shouldn't be able to upload an element without version: #{@response.body}"
861   end
862
863   ##
864   # try to upload with commands other than create, modify, or delete
865   def test_action_upload_invalid
866     basic_authorization users(:public_user).email, "test"
867     cs_id = changesets(:public_user_first_change).id
868
869     diff = <<EOF
870 <osmChange>
871   <ping>
872    <node id='1' lon='1' lat='1' changeset='#{cs_id}' />
873   </ping>
874 </osmChange>
875 EOF
876   content diff
877   post :upload, :id => cs_id
878   assert_response :bad_request, "Shouldn't be able to upload a diff with the action ping"
879   assert_equal @response.body, "Unknown action ping, choices are create, modify, delete"
880   end
881
882   ##
883   # upload a valid changeset which has a mixture of whitespace
884   # to check a bug reported by ivansanchez (#1565).
885   def test_upload_whitespace_valid
886     basic_authorization users(:public_user).email, "test"
887     changeset_id = changesets(:public_user_first_change).id
888
889     diff = <<EOF
890 <osmChange>
891  <modify><node id='1' lon='0' lat='0' changeset='#{changeset_id}'
892   version='1'></node>
893   <node id='1' lon='1' lat='1' changeset='#{changeset_id}' version='2'><tag k='k' v='v'/></node></modify>
894  <modify>
895  <relation id='1' changeset='#{changeset_id}' version='1'><member
896    type='way' role='some' ref='3'/><member
897     type='node' role='some' ref='5'/>
898    <member type='relation' role='some' ref='3'/>
899   </relation>
900  </modify></osmChange>
901 EOF
902
903     # upload it
904     content diff
905     post :upload, :id => changeset_id
906     assert_response :success,
907       "can't upload a valid diff with whitespace variations to changeset: #{@response.body}"
908
909     # check the response is well-formed
910     assert_select "diffResult>node", 2
911     assert_select "diffResult>relation", 1
912
913     # check that the changes made it into the database
914     assert_equal 1, Node.find(1).tags.size, "node 1 should now have one tag"
915     assert_equal 0, Relation.find(1).tags.size, "relation 1 should now have no tags"
916   end
917
918   ##
919   # upload a valid changeset which has a mixture of whitespace
920   # to check a bug reported by ivansanchez.
921   def test_upload_reuse_placeholder_valid
922     basic_authorization users(:public_user).email, "test"
923     changeset_id = changesets(:public_user_first_change).id
924
925     diff = <<EOF
926 <osmChange>
927  <create>
928   <node id='-1' lon='0' lat='0' changeset='#{changeset_id}'>
929    <tag k="foo" v="bar"/>
930   </node>
931  </create>
932  <modify>
933   <node id='-1' lon='1' lat='1' changeset='#{changeset_id}' version='1'/>
934  </modify>
935  <delete>
936   <node id='-1' lon='2' lat='2' changeset='#{changeset_id}' version='2'/>
937  </delete>
938 </osmChange>
939 EOF
940
941     # upload it
942     content diff
943     post :upload, :id => changeset_id
944     assert_response :success,
945       "can't upload a valid diff with re-used placeholders to changeset: #{@response.body}"
946
947     # check the response is well-formed
948     assert_select "diffResult>node", 3
949     assert_select "diffResult>node[old_id=-1]", 3
950   end
951
952   ##
953   # test what happens if a diff upload re-uses placeholder IDs in an
954   # illegal way.
955   def test_upload_placeholder_invalid
956     basic_authorization users(:public_user).email, "test"
957     changeset_id = changesets(:public_user_first_change).id
958
959     diff = <<EOF
960 <osmChange>
961  <create>
962   <node id='-1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
963   <node id='-1' lon='1' lat='1' changeset='#{changeset_id}' version='1'/>
964   <node id='-1' lon='2' lat='2' changeset='#{changeset_id}' version='2'/>
965  </create>
966 </osmChange>
967 EOF
968
969     # upload it
970     content diff
971     post :upload, :id => changeset_id
972     assert_response :bad_request,
973       "shouldn't be able to re-use placeholder IDs"
974   end
975
976   ##
977   # test that uploading a way referencing invalid placeholders gives a
978   # proper error, not a 500.
979   def test_upload_placeholder_invalid_way
980     basic_authorization users(:public_user).email, "test"
981     changeset_id = changesets(:public_user_first_change).id
982
983     diff = <<EOF
984 <osmChange>
985  <create>
986   <node id="-1" lon="0" lat="0" changeset="#{changeset_id}" version="1"/>
987   <node id="-2" lon="1" lat="1" changeset="#{changeset_id}" version="1"/>
988   <node id="-3" lon="2" lat="2" changeset="#{changeset_id}" version="1"/>
989   <way id="-1" changeset="#{changeset_id}" version="1">
990    <nd ref="-1"/>
991    <nd ref="-2"/>
992    <nd ref="-3"/>
993    <nd ref="-4"/>
994   </way>
995  </create>
996 </osmChange>
997 EOF
998
999     # upload it
1000     content diff
1001     post :upload, :id => changeset_id
1002     assert_response :bad_request,
1003       "shouldn't be able to use invalid placeholder IDs"
1004     assert_equal "Placeholder node not found for reference -4 in way -1", @response.body
1005
1006     # the same again, but this time use an existing way
1007     diff = <<EOF
1008 <osmChange>
1009  <create>
1010   <node id="-1" lon="0" lat="0" changeset="#{changeset_id}" version="1"/>
1011   <node id="-2" lon="1" lat="1" changeset="#{changeset_id}" version="1"/>
1012   <node id="-3" lon="2" lat="2" changeset="#{changeset_id}" version="1"/>
1013   <way id="1" changeset="#{changeset_id}" version="1">
1014    <nd ref="-1"/>
1015    <nd ref="-2"/>
1016    <nd ref="-3"/>
1017    <nd ref="-4"/>
1018   </way>
1019  </create>
1020 </osmChange>
1021 EOF
1022
1023     # upload it
1024     content diff
1025     post :upload, :id => changeset_id
1026     assert_response :bad_request,
1027       "shouldn't be able to use invalid placeholder IDs"
1028     assert_equal "Placeholder node not found for reference -4 in way 1", @response.body
1029   end
1030
1031   ##
1032   # test that uploading a relation referencing invalid placeholders gives a
1033   # proper error, not a 500.
1034   def test_upload_placeholder_invalid_relation
1035     basic_authorization users(:public_user).email, "test"
1036     changeset_id = changesets(:public_user_first_change).id
1037
1038     diff = <<EOF
1039 <osmChange>
1040  <create>
1041   <node id="-1" lon="0" lat="0" changeset="#{changeset_id}" version="1"/>
1042   <node id="-2" lon="1" lat="1" changeset="#{changeset_id}" version="1"/>
1043   <node id="-3" lon="2" lat="2" changeset="#{changeset_id}" version="1"/>
1044   <relation id="-1" changeset="#{changeset_id}" version="1">
1045    <member type="node" role="foo" ref="-1"/>
1046    <member type="node" role="foo" ref="-2"/>
1047    <member type="node" role="foo" ref="-3"/>
1048    <member type="node" role="foo" ref="-4"/>
1049   </relation>
1050  </create>
1051 </osmChange>
1052 EOF
1053
1054     # upload it
1055     content diff
1056     post :upload, :id => changeset_id
1057     assert_response :bad_request,
1058       "shouldn't be able to use invalid placeholder IDs"
1059     assert_equal "Placeholder Node not found for reference -4 in relation -1.", @response.body
1060
1061     # the same again, but this time use an existing way
1062     diff = <<EOF
1063 <osmChange>
1064  <create>
1065   <node id="-1" lon="0" lat="0" changeset="#{changeset_id}" version="1"/>
1066   <node id="-2" lon="1" lat="1" changeset="#{changeset_id}" version="1"/>
1067   <node id="-3" lon="2" lat="2" changeset="#{changeset_id}" version="1"/>
1068   <relation id="1" changeset="#{changeset_id}" version="1">
1069    <member type="node" role="foo" ref="-1"/>
1070    <member type="node" role="foo" ref="-2"/>
1071    <member type="node" role="foo" ref="-3"/>
1072    <member type="way" role="bar" ref="-1"/>
1073   </relation>
1074  </create>
1075 </osmChange>
1076 EOF
1077
1078     # upload it
1079     content diff
1080     post :upload, :id => changeset_id
1081     assert_response :bad_request,
1082       "shouldn't be able to use invalid placeholder IDs"
1083     assert_equal "Placeholder Way not found for reference -1 in relation 1.", @response.body
1084   end
1085
1086   ##
1087   # test what happens if a diff is uploaded containing only a node
1088   # move.
1089   def test_upload_node_move
1090     basic_authorization users(:public_user).email, "test"
1091
1092     content "<osm><changeset>" +
1093       "<tag k='created_by' v='osm test suite checking changesets'/>" +
1094       "</changeset></osm>"
1095     put :create
1096     assert_response :success
1097     changeset_id = @response.body.to_i
1098
1099     old_node = current_nodes(:visible_node)
1100
1101     diff = XML::Document.new
1102     diff.root = XML::Node.new "osmChange"
1103     modify = XML::Node.new "modify"
1104     xml_old_node = old_node.to_xml_node
1105     xml_old_node["lat"] = (2.0).to_s
1106     xml_old_node["lon"] = (2.0).to_s
1107     xml_old_node["changeset"] = changeset_id.to_s
1108     modify << xml_old_node
1109     diff.root << modify
1110
1111     # upload it
1112     content diff
1113     post :upload, :id => changeset_id
1114     assert_response :success,
1115       "diff should have uploaded OK"
1116
1117     # check the bbox
1118     changeset = Changeset.find(changeset_id)
1119     assert_equal 1*GeoRecord::SCALE, changeset.min_lon, "min_lon should be 1 degree"
1120     assert_equal 2*GeoRecord::SCALE, changeset.max_lon, "max_lon should be 2 degrees"
1121     assert_equal 1*GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1 degree"
1122     assert_equal 2*GeoRecord::SCALE, changeset.max_lat, "max_lat should be 2 degrees"
1123   end
1124
1125   ##
1126   # test what happens if a diff is uploaded adding a node to a way.
1127   def test_upload_way_extend
1128     basic_authorization users(:public_user).email, "test"
1129
1130     content "<osm><changeset>" +
1131       "<tag k='created_by' v='osm test suite checking changesets'/>" +
1132       "</changeset></osm>"
1133     put :create
1134     assert_response :success
1135     changeset_id = @response.body.to_i
1136
1137     old_way = current_ways(:visible_way)
1138
1139     diff = XML::Document.new
1140     diff.root = XML::Node.new "osmChange"
1141     modify = XML::Node.new "modify"
1142     xml_old_way = old_way.to_xml_node
1143     nd_ref = XML::Node.new "nd"
1144     nd_ref["ref"] = current_nodes(:visible_node).id.to_s
1145     xml_old_way << nd_ref
1146     xml_old_way["changeset"] = changeset_id.to_s
1147     modify << xml_old_way
1148     diff.root << modify
1149
1150     # upload it
1151     content diff
1152     post :upload, :id => changeset_id
1153     assert_response :success,
1154       "diff should have uploaded OK"
1155
1156     # check the bbox
1157     changeset = Changeset.find(changeset_id)
1158     assert_equal 1*GeoRecord::SCALE, changeset.min_lon, "min_lon should be 1 degree"
1159     assert_equal 3*GeoRecord::SCALE, changeset.max_lon, "max_lon should be 3 degrees"
1160     assert_equal 1*GeoRecord::SCALE, changeset.min_lat, "min_lat should be 1 degree"
1161     assert_equal 3*GeoRecord::SCALE, changeset.max_lat, "max_lat should be 3 degrees"
1162   end
1163
1164   ##
1165   # test for more issues in #1568
1166   def test_upload_empty_invalid
1167     basic_authorization users(:public_user).email, "test"
1168
1169     [ "<osmChange/>",
1170       "<osmChange></osmChange>",
1171       "<osmChange><modify/></osmChange>",
1172       "<osmChange><modify></modify></osmChange>"
1173     ].each do |diff|
1174       # upload it
1175       content diff
1176       post :upload, :id => changesets(:public_user_first_change).id
1177       assert_response(:success, "should be able to upload " +
1178                       "empty changeset: " + diff)
1179     end
1180   end
1181
1182   ##
1183   # test that the X-Error-Format header works to request XML errors
1184   def test_upload_xml_errors
1185     basic_authorization users(:public_user).email, "test"
1186
1187     # try and delete a node that is in use
1188     diff = XML::Document.new
1189     diff.root = XML::Node.new "osmChange"
1190     delete = XML::Node.new "delete"
1191     diff.root << delete
1192     delete << current_nodes(:node_used_by_relationship).to_xml_node
1193
1194     # upload it
1195     content diff
1196     error_format "xml"
1197     post :upload, :id => 2
1198     assert_response :success,
1199       "failed to return error in XML format"
1200
1201     # check the returned payload
1202     assert_select "osmError[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
1203     assert_select "osmError>status", 1
1204     assert_select "osmError>message", 1
1205
1206   end
1207
1208   ##
1209   # when we make some simple changes we get the same changes back from the
1210   # diff download.
1211   def test_diff_download_simple
1212     ## First try with the normal user, which should get a forbidden
1213     basic_authorization(users(:normal_user).email, "test")
1214
1215     # create a temporary changeset
1216     content "<osm><changeset>" +
1217       "<tag k='created_by' v='osm test suite checking changesets'/>" +
1218       "</changeset></osm>"
1219     put :create
1220     assert_response :forbidden
1221
1222
1223
1224     ## Now try with the public user
1225     basic_authorization(users(:public_user).email, "test")
1226
1227     # create a temporary changeset
1228     content "<osm><changeset>" +
1229       "<tag k='created_by' v='osm test suite checking changesets'/>" +
1230       "</changeset></osm>"
1231     put :create
1232     assert_response :success
1233     changeset_id = @response.body.to_i
1234
1235     # add a diff to it
1236     diff = <<EOF
1237 <osmChange>
1238  <modify>
1239   <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
1240   <node id='1' lon='1' lat='0' changeset='#{changeset_id}' version='2'/>
1241   <node id='1' lon='1' lat='1' changeset='#{changeset_id}' version='3'/>
1242   <node id='1' lon='1' lat='2' changeset='#{changeset_id}' version='4'/>
1243   <node id='1' lon='2' lat='2' changeset='#{changeset_id}' version='5'/>
1244   <node id='1' lon='3' lat='2' changeset='#{changeset_id}' version='6'/>
1245   <node id='1' lon='3' lat='3' changeset='#{changeset_id}' version='7'/>
1246   <node id='1' lon='9' lat='9' changeset='#{changeset_id}' version='8'/>
1247  </modify>
1248 </osmChange>
1249 EOF
1250
1251     # upload it
1252     content diff
1253     post :upload, :id => changeset_id
1254     assert_response :success,
1255       "can't upload multiple versions of an element in a diff: #{@response.body}"
1256
1257     get :download, :id => changeset_id
1258     assert_response :success
1259
1260     assert_select "osmChange", 1
1261     assert_select "osmChange>modify", 8
1262     assert_select "osmChange>modify>node", 8
1263   end
1264
1265   ##
1266   # culled this from josm to ensure that nothing in the way that josm
1267   # is formatting the request is causing it to fail.
1268   #
1269   # NOTE: the error turned out to be something else completely!
1270   def test_josm_upload
1271     basic_authorization(users(:public_user).email, "test")
1272
1273     # create a temporary changeset
1274     content "<osm><changeset>" +
1275       "<tag k='created_by' v='osm test suite checking changesets'/>" +
1276       "</changeset></osm>"
1277     put :create
1278     assert_response :success
1279     changeset_id = @response.body.to_i
1280
1281     diff = <<OSMFILE
1282 <osmChange version="0.6" generator="JOSM">
1283 <create version="0.6" generator="JOSM">
1284   <node id='-1' visible='true' changeset='#{changeset_id}' lat='51.49619982187321' lon='-0.18722061869438314' />
1285   <node id='-2' visible='true' changeset='#{changeset_id}' lat='51.496359883909605' lon='-0.18653093576241928' />
1286   <node id='-3' visible='true' changeset='#{changeset_id}' lat='51.49598132358285' lon='-0.18719613290981638' />
1287   <node id='-4' visible='true' changeset='#{changeset_id}' lat='51.4961591711078' lon='-0.18629015888084607' />
1288   <node id='-5' visible='true' changeset='#{changeset_id}' lat='51.49582126021711' lon='-0.18708186591517145' />
1289   <node id='-6' visible='true' changeset='#{changeset_id}' lat='51.49591018437858' lon='-0.1861432441734455' />
1290   <node id='-7' visible='true' changeset='#{changeset_id}' lat='51.49560784152179' lon='-0.18694719410005425' />
1291   <node id='-8' visible='true' changeset='#{changeset_id}' lat='51.49567389979617' lon='-0.1860289771788006' />
1292   <node id='-9' visible='true' changeset='#{changeset_id}' lat='51.49543761398892' lon='-0.186820684213126' />
1293   <way id='-10' action='modiy' visible='true' changeset='#{changeset_id}'>
1294     <nd ref='-1' />
1295     <nd ref='-2' />
1296     <nd ref='-3' />
1297     <nd ref='-4' />
1298     <nd ref='-5' />
1299     <nd ref='-6' />
1300     <nd ref='-7' />
1301     <nd ref='-8' />
1302     <nd ref='-9' />
1303     <tag k='highway' v='residential' />
1304     <tag k='name' v='Foobar Street' />
1305   </way>
1306 </create>
1307 </osmChange>
1308 OSMFILE
1309
1310     # upload it
1311     content diff
1312     post :upload, :id => changeset_id
1313     assert_response :success,
1314       "can't upload a diff from JOSM: #{@response.body}"
1315
1316     get :download, :id => changeset_id
1317     assert_response :success
1318
1319     assert_select "osmChange", 1
1320     assert_select "osmChange>create>node", 9
1321     assert_select "osmChange>create>way", 1
1322     assert_select "osmChange>create>way>nd", 9
1323     assert_select "osmChange>create>way>tag", 2
1324   end
1325
1326   ##
1327   # when we make some complex changes we get the same changes back from the
1328   # diff download.
1329   def test_diff_download_complex
1330     basic_authorization(users(:public_user).email, "test")
1331
1332     # create a temporary changeset
1333     content "<osm><changeset>" +
1334       "<tag k='created_by' v='osm test suite checking changesets'/>" +
1335       "</changeset></osm>"
1336     put :create
1337     assert_response :success
1338     changeset_id = @response.body.to_i
1339
1340     # add a diff to it
1341     diff = <<EOF
1342 <osmChange>
1343  <delete>
1344   <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
1345  </delete>
1346  <create>
1347   <node id='-1' lon='9' lat='9' changeset='#{changeset_id}' version='0'/>
1348   <node id='-2' lon='8' lat='9' changeset='#{changeset_id}' version='0'/>
1349   <node id='-3' lon='7' lat='9' changeset='#{changeset_id}' version='0'/>
1350  </create>
1351  <modify>
1352   <node id='3' lon='20' lat='15' changeset='#{changeset_id}' version='1'/>
1353   <way id='1' changeset='#{changeset_id}' version='1'>
1354    <nd ref='3'/>
1355    <nd ref='-1'/>
1356    <nd ref='-2'/>
1357    <nd ref='-3'/>
1358   </way>
1359  </modify>
1360 </osmChange>
1361 EOF
1362
1363     # upload it
1364     content diff
1365     post :upload, :id => changeset_id
1366     assert_response :success,
1367       "can't upload multiple versions of an element in a diff: #{@response.body}"
1368
1369     get :download, :id => changeset_id
1370     assert_response :success
1371
1372     assert_select "osmChange", 1
1373     assert_select "osmChange>create", 3
1374     assert_select "osmChange>delete", 1
1375     assert_select "osmChange>modify", 2
1376     assert_select "osmChange>create>node", 3
1377     assert_select "osmChange>delete>node", 1
1378     assert_select "osmChange>modify>node", 1
1379     assert_select "osmChange>modify>way", 1
1380   end
1381
1382   def test_changeset_download
1383     get :download, :id => changesets(:normal_user_first_change).id
1384     assert_response :success
1385     assert_template nil
1386     #print @response.body
1387     # FIXME needs more assert_select tests
1388     assert_select "osmChange[version='#{API_VERSION}'][generator='#{GENERATOR}']" do
1389       assert_select "create", :count => 5
1390       assert_select "create>node[id=#{nodes(:used_node_2).node_id}][visible=#{nodes(:used_node_2).visible?}][version=#{nodes(:used_node_2).version}]" do
1391         assert_select "tag[k=#{node_tags(:t3).k}][v=#{node_tags(:t3).v}]"
1392       end
1393       assert_select "create>node[id=#{nodes(:visible_node).node_id}]"
1394     end
1395   end
1396
1397   ##
1398   # check that the bounding box of a changeset gets updated correctly
1399   ## FIXME: This should really be moded to a integration test due to the with_controller
1400   def test_changeset_bbox
1401     basic_authorization users(:public_user).email, "test"
1402
1403     # create a new changeset
1404     content "<osm><changeset/></osm>"
1405     put :create
1406     assert_response :success, "Creating of changeset failed."
1407     changeset_id = @response.body.to_i
1408
1409     # add a single node to it
1410     with_controller(NodeController.new) do
1411       content "<osm><node lon='1' lat='2' changeset='#{changeset_id}'/></osm>"
1412       put :create
1413       assert_response :success, "Couldn't create node."
1414     end
1415
1416     # get the bounding box back from the changeset
1417     get :read, :id => changeset_id, :format => :xml
1418
1419     assert_response :success, "Couldn't read back changeset."
1420     assert_select "osm>changeset[min_lon=1.0]", 1
1421     assert_select "osm>changeset[max_lon=1.0]", 1
1422     assert_select "osm>changeset[min_lat=2.0]", 1
1423     assert_select "osm>changeset[max_lat=2.0]", 1
1424
1425     # add another node to it
1426     with_controller(NodeController.new) do
1427       content "<osm><node lon='2' lat='1' changeset='#{changeset_id}'/></osm>"
1428       put :create
1429       assert_response :success, "Couldn't create second node."
1430     end
1431
1432     # get the bounding box back from the changeset
1433     get :read, :id => changeset_id, :format => :xml
1434     assert_response :success, "Couldn't read back changeset for the second time."
1435     assert_select "osm>changeset[min_lon=1.0]", 1
1436     assert_select "osm>changeset[max_lon=2.0]", 1
1437     assert_select "osm>changeset[min_lat=1.0]", 1
1438     assert_select "osm>changeset[max_lat=2.0]", 1
1439
1440     # add (delete) a way to it, which contains a point at (3,3)
1441     with_controller(WayController.new) do
1442       content update_changeset(current_ways(:visible_way).to_xml,
1443                                changeset_id)
1444       put :delete, :id => current_ways(:visible_way).id
1445       assert_response :success, "Couldn't delete a way."
1446     end
1447
1448     # get the bounding box back from the changeset
1449     get :read, :id => changeset_id, :format => 'xml'
1450     assert_response :success, "Couldn't read back changeset for the third time."
1451     # note that the 3.1 here is because of the bbox overexpansion
1452     assert_select "osm>changeset[min_lon=1.0]", 1
1453     assert_select "osm>changeset[max_lon=3.1]", 1
1454     assert_select "osm>changeset[min_lat=1.0]", 1
1455     assert_select "osm>changeset[max_lat=3.1]", 1
1456   end
1457
1458   ##
1459   # test that the changeset :include method works as it should
1460   def test_changeset_include
1461     basic_authorization users(:public_user).display_name, "test"
1462
1463     # create a new changeset
1464     content "<osm><changeset/></osm>"
1465     put :create
1466     assert_response :success, "Creating of changeset failed."
1467     changeset_id = @response.body.to_i
1468
1469     # NOTE: the include method doesn't over-expand, like inserting
1470     # a real method does. this is because we expect the client to
1471     # know what it is doing!
1472     check_after_include(changeset_id,  1,  1, [ 1,  1,  1,  1])
1473     check_after_include(changeset_id,  3,  3, [ 1,  1,  3,  3])
1474     check_after_include(changeset_id,  4,  2, [ 1,  1,  4,  3])
1475     check_after_include(changeset_id,  2,  2, [ 1,  1,  4,  3])
1476     check_after_include(changeset_id, -1, -1, [-1, -1,  4,  3])
1477     check_after_include(changeset_id, -2,  5, [-2, -1,  4,  5])
1478   end
1479
1480   ##
1481   # test that a not found, wrong method with the expand bbox works as expected
1482   def test_changeset_expand_bbox_error
1483     basic_authorization users(:public_user).display_name, "test"
1484
1485     # create a new changeset
1486     content "<osm><changeset/></osm>"
1487     put :create
1488     assert_response :success, "Creating of changeset failed."
1489     changeset_id = @response.body.to_i
1490
1491     lon=58.2
1492     lat=-0.45
1493
1494     # Try and put
1495     content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
1496     put :expand_bbox, :id => changeset_id
1497     assert_response :method_not_allowed, "shouldn't be able to put a bbox expand"
1498
1499     # Try to get the update
1500     content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
1501     get :expand_bbox, :id => changeset_id
1502     assert_response :method_not_allowed, "shouldn't be able to get a bbox expand"
1503
1504     # Try to use a hopefully missing changeset
1505     content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
1506     post :expand_bbox, :id => changeset_id+13245
1507     assert_response :not_found, "shouldn't be able to do a bbox expand on a nonexistant changeset"
1508
1509   end
1510
1511   ##
1512   # test the query functionality of changesets
1513   def test_query
1514     get :query, :bbox => "-10,-10, 10, 10"
1515     assert_response :success, "can't get changesets in bbox"
1516     assert_changesets [1,4,6]
1517
1518     get :query, :bbox => "4.5,4.5,4.6,4.6"
1519     assert_response :success, "can't get changesets in bbox"
1520     assert_changesets [1]
1521
1522     # not found when looking for changesets of non-existing users
1523     get :query, :user => User.maximum(:id) + 1
1524     assert_response :not_found
1525     get :query, :display_name => " "
1526     assert_response :not_found
1527
1528     # can't get changesets of user 1 without authenticating
1529     get :query, :user => users(:normal_user).id
1530     assert_response :not_found, "shouldn't be able to get changesets by non-public user (ID)"
1531     get :query, :display_name => users(:normal_user).display_name
1532     assert_response :not_found, "shouldn't be able to get changesets by non-public user (name)"
1533
1534     # but this should work
1535     basic_authorization "test@openstreetmap.org", "test"
1536     get :query, :user => users(:normal_user).id
1537     assert_response :success, "can't get changesets by user ID"
1538     assert_changesets [1,3,6]
1539
1540     get :query, :display_name => users(:normal_user).display_name
1541     assert_response :success, "can't get changesets by user name"
1542     assert_changesets [1,3,6]
1543
1544     # check that the correct error is given when we provide both UID and name
1545     get :query, :user => users(:normal_user).id, :display_name => users(:normal_user).display_name
1546     assert_response :bad_request, "should be a bad request to have both ID and name specified"
1547
1548     get :query, :user => users(:normal_user).id, :open => true
1549     assert_response :success, "can't get changesets by user and open"
1550     assert_changesets [1]
1551
1552     get :query, :time => '2007-12-31'
1553     assert_response :success, "can't get changesets by time-since"
1554     assert_changesets [1,2,4,5,6]
1555
1556     get :query, :time => '2008-01-01T12:34Z'
1557     assert_response :success, "can't get changesets by time-since with hour"
1558     assert_changesets [1,2,4,5,6]
1559
1560     get :query, :time => '2007-12-31T23:59Z,2008-01-01T00:01Z'
1561     assert_response :success, "can't get changesets by time-range"
1562     assert_changesets [1,5,6]
1563
1564     get :query, :open => 'true'
1565     assert_response :success, "can't get changesets by open-ness"
1566     assert_changesets [1,2,4]
1567
1568     get :query, :closed => 'true'
1569     assert_response :success, "can't get changesets by closed-ness"
1570     assert_changesets [3,5,6,7]
1571
1572     get :query, :closed => 'true', :user => users(:normal_user).id
1573     assert_response :success, "can't get changesets by closed-ness and user"
1574     assert_changesets [3,6]
1575
1576     get :query, :closed => 'true', :user => users(:public_user).id
1577     assert_response :success, "can't get changesets by closed-ness and user"
1578     assert_changesets [7]
1579
1580     get :query, :changesets => '1,2,3'
1581     assert_response :success, "can't get changesets by id (as comma-separated string)"
1582     assert_changesets [1,2,3]
1583
1584     get :query, :changesets => ''
1585     assert_response :bad_request, "should be a bad request since changesets is empty"
1586   end
1587
1588   ##
1589   # check that errors are returned if garbage is inserted
1590   # into query strings
1591   def test_query_invalid
1592     [ "abracadabra!",
1593       "1,2,3,F",
1594       ";drop table users;"
1595       ].each do |bbox|
1596       get :query, :bbox => bbox
1597       assert_response :bad_request, "'#{bbox}' isn't a bbox"
1598     end
1599
1600     [ "now()",
1601       "00-00-00",
1602       ";drop table users;",
1603       ",",
1604       "-,-"
1605       ].each do |time|
1606       get :query, :time => time
1607       assert_response :bad_request, "'#{time}' isn't a valid time range"
1608     end
1609
1610     [ "me",
1611       "foobar",
1612       "-1",
1613       "0"
1614       ].each do |uid|
1615       get :query, :user => uid
1616       assert_response :bad_request, "'#{uid}' isn't a valid user ID"
1617     end
1618   end
1619
1620   ##
1621   # check updating tags on a changeset
1622   def test_changeset_update
1623     ## First try with the non-public user
1624     changeset = changesets(:normal_user_first_change)
1625     new_changeset = changeset.to_xml
1626     new_tag = XML::Node.new "tag"
1627     new_tag['k'] = "tagtesting"
1628     new_tag['v'] = "valuetesting"
1629     new_changeset.find("//osm/changeset").first << new_tag
1630     content new_changeset
1631
1632     # try without any authorization
1633     put :update, :id => changeset.id
1634     assert_response :unauthorized
1635
1636     # try with the wrong authorization
1637     basic_authorization users(:public_user).email, "test"
1638     put :update, :id => changeset.id
1639     assert_response :conflict
1640
1641     # now this should get an unauthorized
1642     basic_authorization users(:normal_user).email, "test"
1643     put :update, :id => changeset.id
1644     assert_require_public_data "user with their data non-public, shouldn't be able to edit their changeset"
1645
1646
1647     ## Now try with the public user
1648     changeset = changesets(:public_user_first_change)
1649     new_changeset = changeset.to_xml
1650     new_tag = XML::Node.new "tag"
1651     new_tag['k'] = "tagtesting"
1652     new_tag['v'] = "valuetesting"
1653     new_changeset.find("//osm/changeset").first << new_tag
1654     content new_changeset
1655
1656     # try without any authorization
1657     @request.env["HTTP_AUTHORIZATION"] = nil
1658     put :update, :id => changeset.id
1659     assert_response :unauthorized
1660
1661     # try with the wrong authorization
1662     basic_authorization users(:second_public_user).email, "test"
1663     put :update, :id => changeset.id
1664     assert_response :conflict
1665
1666     # now this should work...
1667     basic_authorization users(:public_user).email, "test"
1668     put :update, :id => changeset.id
1669     assert_response :success
1670
1671     assert_select "osm>changeset[id=#{changeset.id}]", 1
1672     assert_select "osm>changeset>tag", 2
1673     assert_select "osm>changeset>tag[k=tagtesting][v=valuetesting]", 1
1674   end
1675
1676   ##
1677   # check that a user different from the one who opened the changeset
1678   # can't modify it.
1679   def test_changeset_update_invalid
1680     basic_authorization users(:public_user).email, "test"
1681
1682     changeset = changesets(:normal_user_first_change)
1683     new_changeset = changeset.to_xml
1684     new_tag = XML::Node.new "tag"
1685     new_tag['k'] = "testing"
1686     new_tag['v'] = "testing"
1687     new_changeset.find("//osm/changeset").first << new_tag
1688
1689     content new_changeset
1690     put :update, :id => changeset.id
1691     assert_response :conflict
1692   end
1693
1694   ##
1695   # check that a changeset can contain a certain max number of changes.
1696   ## FIXME should be changed to an integration test due to the with_controller
1697   def test_changeset_limits
1698     basic_authorization users(:public_user).email, "test"
1699
1700     # open a new changeset
1701     content "<osm><changeset/></osm>"
1702     put :create
1703     assert_response :success, "can't create a new changeset"
1704     cs_id = @response.body.to_i
1705
1706     # start the counter just short of where the changeset should finish.
1707     offset = 10
1708     # alter the database to set the counter on the changeset directly,
1709     # otherwise it takes about 6 minutes to fill all of them.
1710     changeset = Changeset.find(cs_id)
1711     changeset.num_changes = Changeset::MAX_ELEMENTS - offset
1712     changeset.save!
1713
1714     with_controller(NodeController.new) do
1715       # create a new node
1716       content "<osm><node changeset='#{cs_id}' lat='0.0' lon='0.0'/></osm>"
1717       put :create
1718       assert_response :success, "can't create a new node"
1719       node_id = @response.body.to_i
1720
1721       get :read, :id => node_id
1722       assert_response :success, "can't read back new node"
1723       node_doc = XML::Parser.string(@response.body).parse
1724       node_xml = node_doc.find("//osm/node").first
1725
1726       # loop until we fill the changeset with nodes
1727       offset.times do |i|
1728         node_xml['lat'] = rand.to_s
1729         node_xml['lon'] = rand.to_s
1730         node_xml['version'] = (i+1).to_s
1731
1732         content node_doc
1733         put :update, :id => node_id
1734         assert_response :success, "attempt #{i} should have succeeded"
1735       end
1736
1737       # trying again should fail
1738       node_xml['lat'] = rand.to_s
1739       node_xml['lon'] = rand.to_s
1740       node_xml['version'] = offset.to_s
1741
1742       content node_doc
1743       put :update, :id => node_id
1744       assert_response :conflict, "final attempt should have failed"
1745     end
1746
1747     changeset = Changeset.find(cs_id)
1748     assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
1749
1750     # check that the changeset is now closed as well
1751     assert(!changeset.is_open?,
1752            "changeset should have been auto-closed by exceeding " +
1753            "element limit.")
1754   end
1755
1756   ##
1757   # This should display the last 20 changesets closed.
1758   def test_list
1759     get :list, {:format => "html"}
1760     assert_response :success
1761     assert_template "history"
1762     assert_template :layout => "map"
1763     assert_select "h2", :text => "Changesets", :count => 1
1764
1765     get :list, {:format => "html", :list => '1', :bbox => '-180,-90,90,180'}
1766     assert_response :success
1767     assert_template "list"
1768
1769     changesets = Changeset.
1770         where("num_changes > 0 and min_lon is not null").
1771         order(:created_at => :desc).
1772         limit(20)
1773     assert changesets.size <= 20
1774
1775     # Now check that all 20 (or however many were returned) changesets are in the html
1776     assert_select "li", :count => changesets.size
1777     changesets.each do |changeset|
1778       # FIXME this test needs rewriting - test for table contents
1779     end
1780   end
1781
1782   ##
1783   # This should display the last 20 changesets closed.
1784   def test_list_xhr
1785     xhr :get, :list, {:format => "html"}
1786     assert_response :success
1787     assert_template "history"
1788     assert_template :layout => "xhr"
1789     assert_select "h2", :text => "Changesets", :count => 1
1790
1791     get :list, {:format => "html", :list => '1', :bbox => '-180,-90,90,180'}
1792     assert_response :success
1793     assert_template "list"
1794
1795     changesets = Changeset.
1796         where("num_changes > 0 and min_lon is not null").
1797         order(:created_at => :desc).
1798         limit(20)
1799     assert changesets.size <= 20
1800
1801     # Now check that all 20 (or however many were returned) changesets are in the html
1802     assert_select "li", :count => changesets.size
1803     changesets.each do |changeset|
1804       # FIXME this test needs rewriting - test for table contents
1805     end
1806   end
1807
1808   ##
1809   # Checks the display of the user changesets listing
1810   def test_list_user
1811     user = users(:public_user)
1812     get :list, {:format => "html", :display_name => user.display_name}
1813     assert_response :success
1814     assert_template "history"
1815     ## FIXME need to add more checks to see which if edits are actually shown if your data is public
1816   end
1817
1818   ##
1819   # Check the not found of the list user changesets
1820   def test_list_user_not_found
1821     get :list, {:format => "html", :display_name => "Some random user"}
1822     assert_response :not_found
1823     assert_template 'user/no_such_user'
1824   end
1825
1826   ##
1827   # This should display the last 20 changesets closed.
1828   def test_feed
1829     changesets = Changeset.where("num_changes > 0").order(:created_at => :desc).limit(20)
1830     assert changesets.size <= 20
1831     get :feed, {:format => "atom"}
1832     assert_response :success
1833     assert_template "list"
1834     # Now check that all 20 (or however many were returned) changesets are in the html
1835     assert_select "feed", :count => 1
1836     assert_select "entry", :count => changesets.size
1837     changesets.each do |changeset|
1838       # FIXME this test needs rewriting - test for feed contents
1839     end
1840   end
1841
1842   ##
1843   # Checks the display of the user changesets feed
1844   def test_feed_user
1845     user = users(:public_user)
1846     get :feed, {:format => "atom", :display_name => user.display_name}
1847     assert_response :success
1848     assert_template "list"
1849     assert_equal "application/atom+xml", response.content_type
1850     ## FIXME need to add more checks to see which if edits are actually shown if your data is public
1851   end
1852
1853   ##
1854   # Check the not found of the user changesets feed
1855   def test_feed_user_not_found
1856     get :feed, {:format => "atom", :display_name => "Some random user"}
1857     assert_response :not_found
1858   end
1859
1860   ##
1861   # check that the changeset download for a changeset with a redacted
1862   # element in it doesn't contain that element.
1863   def test_diff_download_redacted
1864     changeset_id = changesets(:public_user_first_change).id
1865
1866     get :download, :id => changeset_id
1867     assert_response :success
1868
1869     assert_select "osmChange", 1
1870     # this changeset contains node 17 in versions 1 & 2, but 1 should
1871     # be hidden.
1872     assert_select "osmChange node[id=17]", 1
1873     assert_select "osmChange node[id=17][version=1]", 0
1874   end
1875
1876   ##
1877   # create comment success
1878   def test_create_comment_success
1879     basic_authorization(users(:public_user).email, 'test')
1880
1881     assert_difference('ChangesetComment.count') do
1882       post :comment, { :id => changesets(:normal_user_closed_change).id, :text => 'This is a comment', :format => :xml }
1883     end
1884     assert_response :success
1885   end
1886
1887   ##
1888   # create comment fail
1889   def test_create_comment_fail
1890     # unauthorized
1891     post :comment, { :id => changesets(:normal_user_closed_change).id, :text => 'This is a comment' }
1892     assert_response :unauthorized
1893
1894     basic_authorization(users(:public_user).email, 'test')
1895
1896     # bad changeset id
1897     assert_no_difference('ChangesetComment.count') do
1898       post :comment, { :id => 999111, :text => 'This is a comment' }
1899     end
1900     assert_response :not_found
1901
1902     # not closed changeset
1903     assert_no_difference('ChangesetComment.count') do
1904       post :comment, { :id => changesets(:normal_user_first_change).id, :text => 'This is a comment' }
1905     end
1906     assert_response :conflict
1907
1908     # no text
1909     assert_no_difference('ChangesetComment.count') do
1910       post :comment, { :id => changesets(:normal_user_closed_change).id }
1911     end
1912     assert_response :bad_request
1913
1914     # empty text
1915     assert_no_difference('ChangesetComment.count') do
1916       post :comment, { :id => changesets(:normal_user_closed_change).id, :text => '' }
1917     end
1918     assert_response :bad_request    
1919   end
1920
1921   ##
1922   # test subscribe success
1923   def test_subscribe_success
1924     basic_authorization(users(:public_user).email, 'test')
1925     changeset = changesets(:normal_user_closed_change)
1926
1927     assert_difference('changeset.subscribers.count') do
1928       post :subscribe, { :id => changeset.id, :format => :xml }
1929     end
1930     assert_response :success
1931   end
1932
1933   ##
1934   # test subscribe fail
1935   def test_subscribe_fail
1936     changeset = changesets(:normal_user_closed_change)
1937     assert_no_difference('changeset.subscribers.count') do
1938       post :subscribe, { :id => changeset.id, :format => :xml }
1939     end
1940     assert_response :unauthorized
1941
1942     basic_authorization(users(:public_user).email, 'test')
1943
1944     assert_no_difference('changeset.subscribers.count') do
1945       post :subscribe, { :id => 999111 }
1946     end
1947     assert_response :not_found
1948
1949     changeset = changesets(:normal_user_first_change)
1950     assert_no_difference('changeset.subscribers.count') do
1951       post :subscribe, { :id => changeset.id }
1952     end
1953     assert_response :conflict
1954
1955     # subscribing
1956     changeset = changesets(:normal_user_closed_change)
1957     post :subscribe, { :id => changeset.id, :format => :xml }
1958     assert_response :success
1959
1960     # trying to subsrcirbe one more time
1961     assert_no_difference('changeset.subscribers.count') do
1962       post :subscribe, { :id => changeset.id, :format => :xml }
1963     end
1964     assert_response :conflict
1965   end
1966
1967   ##
1968   # test unsubscribe success
1969   def test_unsubscribe_success
1970     basic_authorization(users(:public_user).email, 'test')
1971     changeset = changesets(:normal_user_closed_change)
1972     post :subscribe, { :id => changeset.id, :format => :xml }
1973     # unsubscribe
1974     assert_difference('changeset.subscribers.count', -1) do
1975       post :unsubscribe, { :id => changeset.id, :format => :xml }
1976     end
1977     assert_response :success
1978   end
1979
1980   ##
1981   # test unsubscribe fail
1982   def test_unsubscribe_fail
1983     changeset = changesets(:normal_user_closed_change)
1984     assert_no_difference('changeset.subscribers.count') do
1985       post :unsubscribe, { :id => changeset.id }
1986     end
1987     assert_response :unauthorized
1988
1989     basic_authorization(users(:public_user).email, 'test')
1990
1991     assert_no_difference('changeset.subscribers.count', -1) do
1992       post :unsubscribe, { :id => 999111 }
1993     end
1994     assert_response :not_found
1995
1996     changeset = changesets(:normal_user_first_change)
1997     assert_no_difference('changeset.subscribers.count', -1) do
1998       post :unsubscribe, { :id => changeset.id }
1999     end
2000     assert_response :conflict
2001
2002     # trying to unsubscribe when not subscribed
2003     changeset = changesets(:normal_user_closed_change)
2004     assert_no_difference('changeset.subscribers.count') do
2005       post :unsubscribe, { :id => changeset.id }
2006     end
2007     assert_response :not_found
2008   end
2009
2010   ##
2011   # test hide comment fail
2012   def test_hide_comment_fail
2013     comment = changeset_comments(:normal_comment_1)
2014     assert('comment.visible') do
2015       post :hide_comment, { :id => comment.id, :format => "xml" }
2016       assert_response :unauthorized
2017     end
2018     
2019
2020     basic_authorization(users(:public_user).email, 'test')
2021
2022     assert('comment.visible') do
2023       post :hide_comment, { :id => comment.id, :format => "xml" }
2024       assert_response :forbidden
2025     end
2026
2027     basic_authorization(users(:moderator_user).email, 'test')
2028
2029     post :hide_comment, { :id => 999111, :format => "xml" }
2030     assert_response :not_found
2031   end
2032
2033   ##
2034   # test hide comment succes
2035   def test_hide_comment_success
2036     comment = changeset_comments(:normal_comment_1)
2037
2038     basic_authorization(users(:moderator_user).email, 'test')
2039
2040     assert('!comment.visible') do
2041       post :hide_comment, { :id => comment.id, :format => "xml" }
2042     end
2043     assert_response :success
2044   end
2045
2046   ##
2047   # test unhide comment fail
2048   def test_unhide_comment_fail
2049     comment = changeset_comments(:normal_comment_1)
2050     assert('comment.visible') do
2051       post :unhide_comment, { :id => comment.id, :format => "xml" }
2052       assert_response :unauthorized
2053     end
2054     
2055
2056     basic_authorization(users(:public_user).email, 'test')
2057
2058     assert('comment.visible') do
2059       post :unhide_comment, { :id => comment.id, :format => "xml" }
2060       assert_response :forbidden
2061     end
2062
2063     basic_authorization(users(:moderator_user).email, 'test')
2064
2065     post :unhide_comment, { :id => 999111, :format => "xml" }
2066     assert_response :not_found
2067   end
2068
2069   ##
2070   # test unhide comment succes
2071   def test_unhide_comment_success
2072     comment = changeset_comments(:normal_comment_1)
2073
2074     basic_authorization(users(:moderator_user).email, 'test')
2075
2076     assert('!comment.visible') do
2077       post :unhide_comment, { :id => comment.id, :format => "xml" }
2078     end
2079     assert_response :success
2080   end
2081
2082   ##
2083   # test comments feed
2084   def test_comments_feed
2085     get :comments_feed, {:format => "rss"}
2086     assert_response :success
2087     assert_equal "application/rss+xml", @response.content_type
2088     assert_select "rss", :count => 1 do
2089       assert_select "channel", :count => 1 do
2090         assert_select "item", :count => 3
2091       end
2092     end
2093
2094     get :comments_feed, { :id => changesets(:normal_user_closed_change), :format => "rss"}
2095     assert_response :success
2096     assert_equal "application/rss+xml", @response.content_type
2097     assert_select "rss", :count => 1 do
2098       assert_select "channel", :count => 1 do
2099         assert_select "item", :count => 3
2100       end
2101     end
2102   end
2103
2104   #------------------------------------------------------------
2105   # utility functions
2106   #------------------------------------------------------------
2107
2108   ##
2109   # boilerplate for checking that certain changesets exist in the
2110   # output.
2111   def assert_changesets(ids)
2112     assert_select "osm>changeset", ids.size
2113     ids.each do |id|
2114       assert_select "osm>changeset[id=#{id}]", 1
2115     end
2116   end
2117
2118   ##
2119   # call the include method and assert properties of the bbox
2120   def check_after_include(changeset_id, lon, lat, bbox)
2121     content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
2122     post :expand_bbox, :id => changeset_id
2123     assert_response :success, "Setting include of changeset failed: #{@response.body}"
2124
2125     # check exactly one changeset
2126     assert_select "osm>changeset", 1
2127     assert_select "osm>changeset[id=#{changeset_id}]", 1
2128
2129     # check the bbox
2130     doc = XML::Parser.string(@response.body).parse
2131     changeset = doc.find("//osm/changeset").first
2132     assert_equal bbox[0], changeset['min_lon'].to_f, "min lon"
2133     assert_equal bbox[1], changeset['min_lat'].to_f, "min lat"
2134     assert_equal bbox[2], changeset['max_lon'].to_f, "max lon"
2135     assert_equal bbox[3], changeset['max_lat'].to_f, "max lat"
2136   end
2137
2138   ##
2139   # update the changeset_id of a way element
2140   def update_changeset(xml, changeset_id)
2141     xml_attr_rewrite(xml, 'changeset', changeset_id)
2142   end
2143
2144   ##
2145   # update an attribute in a way element
2146   def xml_attr_rewrite(xml, name, value)
2147     xml.find("//osm/way").first[name] = value.to_s
2148     return xml
2149   end
2150 end