source: subversion/sites/rails_port/test/functional/changeset_controller_test.rb @ 17044

Last change on this file since 17044 was 16913, checked in by zere, 10 years ago

Fix test to reflect change to changeset templates.

File size: 51.1 KB
Line 
1require File.dirname(__FILE__) + '/../test_helper'
2require 'changeset_controller'
3
4class ChangesetControllerTest < ActionController::TestCase
5  api_fixtures
6
7  # -----------------------
8  # Test simple changeset creation
9  # -----------------------
10 
11  def test_create
12    basic_authorization users(:normal_user).email, "test"
13    # Create the first user's changeset
14    content "<osm><changeset>" +
15      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
16      "</changeset></osm>"
17    put :create
18    assert_require_public_data
19   
20   
21    basic_authorization users(:public_user).email, "test"
22    # Create the first user's changeset
23    content "<osm><changeset>" +
24      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
25      "</changeset></osm>"
26    put :create
27   
28    assert_response :success, "Creation of changeset did not return sucess status"
29    newid = @response.body.to_i
30
31    # check end time, should be an hour ahead of creation time
32    cs = Changeset.find(newid)
33    duration = cs.closed_at - cs.created_at
34    # the difference can either be a rational, or a floating point number
35    # of seconds, depending on the code path taken :-(
36    if duration.class == Rational
37      assert_equal Rational(1,24), duration , "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
38    else
39      # must be number of seconds...
40      assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
41    end
42  end
43 
44  def test_create_invalid
45    basic_authorization users(:normal_user).email, "test"
46    content "<osm><changeset></osm>"
47    put :create
48    assert_require_public_data
49
50    ## Try the public user
51    basic_authorization users(:public_user).email, "test"
52    content "<osm><changeset></osm>"
53    put :create
54    assert_response :bad_request, "creating a invalid changeset should fail"
55  end
56
57  def test_create_invalid_no_content
58    ## First check with no auth
59    put :create
60    assert_response :unauthorized, "shouldn't be able to create a changeset with no auth"
61   
62    ## Now try to with the non-public user
63    basic_authorization users(:normal_user).email, "test"
64    put :create
65    assert_require_public_data
66   
67    ## Try the inactive user
68    basic_authorization users(:inactive_user).email, "test"
69    put :create
70    assert_inactive_user
71   
72    ## Now try to use the public user
73    basic_authorization users(:public_user).email, "test"
74    put :create
75    assert_response :bad_request, "creating a changeset with no content should fail"
76  end
77 
78  def test_create_wrong_method
79    basic_authorization users(:public_user).email, "test"
80    get :create
81    assert_response :method_not_allowed
82    post :create
83    assert_response :method_not_allowed
84  end
85
86  ##
87  # check that the changeset can be read and returns the correct
88  # document structure.
89  def test_read
90    changeset_id = changesets(:normal_user_first_change).id
91    get :read, :id => changeset_id
92    assert_response :success, "cannot get first changeset"
93   
94    assert_select "osm[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
95    assert_select "osm>changeset[id=#{changeset_id}]", 1
96  end
97 
98  ##
99  # check that a changeset that doesn't exist returns an appropriate message
100  def test_read_not_found
101    [0, -32, 233455644, "afg", "213"].each do |id|
102      get :read, :id => id
103      assert_response :not_found, "should get a not found"
104    end
105  end
106 
107  ##
108  # test that the user who opened a change can close it
109  def test_close
110    ## Try without authentication
111    put :close, :id => changesets(:public_user_first_change).id
112    assert_response :unauthorized
113   
114   
115    ## Try using the non-public user
116    basic_authorization users(:normal_user).email, "test"
117    put :close, :id => changesets(:normal_user_first_change).id
118    assert_require_public_data
119   
120   
121    ## The try with the public user
122    basic_authorization users(:public_user).email, "test"
123
124    cs_id = changesets(:public_user_first_change).id
125    put :close, :id => cs_id
126    assert_response :success
127
128    # test that it really is closed now
129    cs = Changeset.find(cs_id)
130    assert(!cs.is_open?, 
131           "changeset should be closed now (#{cs.closed_at} > #{Time.now.getutc}.")
132  end
133
134  ##
135  # test that a different user can't close another user's changeset
136  def test_close_invalid
137    basic_authorization users(:public_user).email, "test"
138
139    put :close, :id => changesets(:normal_user_first_change).id
140    assert_response :conflict
141    assert_equal "The user doesn't own that changeset", @response.body
142  end
143 
144  ##
145  # test that you can't close using another method
146  def test_close_method_invalid
147    basic_authorization users(:public_user).email, "test"
148   
149    cs_id = changesets(:public_user_first_change).id
150    get :close, :id => cs_id
151    assert_response :method_not_allowed
152   
153    post :close, :id => cs_id
154    assert_response :method_not_allowed
155  end
156 
157  ##
158  # check that you can't close a changeset that isn't found
159  def test_close_not_found
160    cs_ids = [0, -132, "123"]
161   
162    # First try to do it with no auth
163    cs_ids.each do |id|
164      put :close, :id => id
165      assert_response :unauthorized, "Shouldn't be able close the non-existant changeset #{id}, when not authorized"
166    end
167   
168    # Now try with auth
169    basic_authorization users(:public_user).email, "test"
170    cs_ids.each do |id|
171      put :close, :id => id
172      assert_response :not_found, "The changeset #{id} doesn't exist, so can't be closed"
173    end
174  end
175
176  ##
177  # upload something simple, but valid and check that it can
178  # be read back ok
179  # Also try without auth and another user.
180  def test_upload_simple_valid
181    ## Try with no auth
182    changeset_id = changesets(:public_user_first_change).id
183
184    # simple diff to change a node, way and relation by removing
185    # their tags
186    diff = <<EOF
187<osmChange>
188 <modify>
189  <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
190  <way id='1' changeset='#{changeset_id}' version='1'>
191   <nd ref='3'/>
192  </way>
193 </modify>
194 <modify>
195  <relation id='1' changeset='#{changeset_id}' version='1'>
196   <member type='way' role='some' ref='3'/>
197   <member type='node' role='some' ref='5'/>
198   <member type='relation' role='some' ref='3'/>
199  </relation>
200 </modify>
201</osmChange>
202EOF
203
204    # upload it
205    content diff
206    post :upload, :id => changeset_id
207    assert_response :unauthorized, 
208      "shouldnn't be able to upload a simple valid diff to changeset: #{@response.body}"
209     
210     
211   
212    ## Now try with a private user
213    basic_authorization users(:normal_user).email, "test"
214    changeset_id = changesets(:normal_user_first_change).id
215
216    # simple diff to change a node, way and relation by removing
217    # their tags
218    diff = <<EOF
219<osmChange>
220 <modify>
221  <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
222  <way id='1' changeset='#{changeset_id}' version='1'>
223   <nd ref='3'/>
224  </way>
225 </modify>
226 <modify>
227  <relation id='1' changeset='#{changeset_id}' version='1'>
228   <member type='way' role='some' ref='3'/>
229   <member type='node' role='some' ref='5'/>
230   <member type='relation' role='some' ref='3'/>
231  </relation>
232 </modify>
233</osmChange>
234EOF
235
236    # upload it
237    content diff
238    post :upload, :id => changeset_id
239    assert_response :forbidden, 
240      "can't upload a simple valid diff to changeset: #{@response.body}"   
241   
242     
243     
244    ## Now try with the public user
245    basic_authorization users(:public_user).email, "test"
246    changeset_id = changesets(:public_user_first_change).id
247
248    # simple diff to change a node, way and relation by removing
249    # their tags
250    diff = <<EOF
251<osmChange>
252 <modify>
253  <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
254  <way id='1' changeset='#{changeset_id}' version='1'>
255   <nd ref='3'/>
256  </way>
257 </modify>
258 <modify>
259  <relation id='1' changeset='#{changeset_id}' version='1'>
260   <member type='way' role='some' ref='3'/>
261   <member type='node' role='some' ref='5'/>
262   <member type='relation' role='some' ref='3'/>
263  </relation>
264 </modify>
265</osmChange>
266EOF
267
268    # upload it
269    content diff
270    post :upload, :id => changeset_id
271    assert_response :success, 
272      "can't upload a simple valid diff to changeset: #{@response.body}"
273
274    # check that the changes made it into the database
275    assert_equal 0, Node.find(1).tags.size, "node 1 should now have no tags"
276    assert_equal 0, Way.find(1).tags.size, "way 1 should now have no tags"
277    assert_equal 0, Relation.find(1).tags.size, "relation 1 should now have no tags"
278  end
279   
280  ##
281  # upload something which creates new objects using placeholders
282  def test_upload_create_valid
283    basic_authorization users(:public_user).email, "test"
284    cs_id = changesets(:public_user_first_change).id
285
286    # simple diff to create a node way and relation using placeholders
287    diff = <<EOF
288<osmChange>
289 <create>
290  <node id='-1' lon='0' lat='0' changeset='#{cs_id}'>
291   <tag k='foo' v='bar'/>
292   <tag k='baz' v='bat'/>
293  </node>
294  <way id='-1' changeset='#{cs_id}'>
295   <nd ref='3'/>
296  </way>
297 </create>
298 <create>
299  <relation id='-1' changeset='#{cs_id}'>
300   <member type='way' role='some' ref='3'/>
301   <member type='node' role='some' ref='5'/>
302   <member type='relation' role='some' ref='3'/>
303  </relation>
304 </create>
305</osmChange>
306EOF
307
308    # upload it
309    content diff
310    post :upload, :id => cs_id
311    assert_response :success, 
312      "can't upload a simple valid creation to changeset: #{@response.body}"
313
314    # check the returned payload
315    assert_select "diffResult[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
316    assert_select "diffResult>node", 1
317    assert_select "diffresult>way", 1
318    assert_select "diffResult>relation", 1
319
320    # inspect the response to find out what the new element IDs are
321    doc = XML::Parser.string(@response.body).parse
322    new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
323    new_way_id = doc.find("//diffResult/way").first["new_id"].to_i
324    new_rel_id = doc.find("//diffResult/relation").first["new_id"].to_i
325
326    # check the old IDs are all present and negative one
327    assert_equal -1, doc.find("//diffResult/node").first["old_id"].to_i
328    assert_equal -1, doc.find("//diffResult/way").first["old_id"].to_i
329    assert_equal -1, doc.find("//diffResult/relation").first["old_id"].to_i
330
331    # check the versions are present and equal one
332    assert_equal 1, doc.find("//diffResult/node").first["new_version"].to_i
333    assert_equal 1, doc.find("//diffResult/way").first["new_version"].to_i
334    assert_equal 1, doc.find("//diffResult/relation").first["new_version"].to_i
335
336    # check that the changes made it into the database
337    assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
338    assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
339    assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
340  end
341   
342  ##
343  # test a complex delete where we delete elements which rely on eachother
344  # in the same transaction.
345  def test_upload_delete
346    basic_authorization users(:public_user).display_name, "test"
347
348    diff = XML::Document.new
349    diff.root = XML::Node.new "osmChange"
350    delete = XML::Node.new "delete"
351    diff.root << delete
352    delete << current_relations(:visible_relation).to_xml_node
353    delete << current_relations(:used_relation).to_xml_node
354    delete << current_ways(:used_way).to_xml_node
355    delete << current_nodes(:node_used_by_relationship).to_xml_node
356
357    # update the changeset to one that this user owns
358    changeset_id = changesets(:public_user_first_change).id
359    ["node", "way", "relation"].each do |type|
360      delete.find("//osmChange/delete/#{type}").each do |n| 
361        n['changeset'] = changeset_id.to_s
362      end
363    end
364
365    # upload it
366    content diff
367    post :upload, :id => changeset_id
368    assert_response :success, 
369      "can't upload a deletion diff to changeset: #{@response.body}"
370
371    # check the response is well-formed
372    assert_select "diffResult>node", 1
373    assert_select "diffResult>way", 1
374    assert_select "diffResult>relation", 2
375
376    # check that everything was deleted
377    assert_equal false, Node.find(current_nodes(:node_used_by_relationship).id).visible
378    assert_equal false, Way.find(current_ways(:used_way).id).visible
379    assert_equal false, Relation.find(current_relations(:visible_relation).id).visible
380    assert_equal false, Relation.find(current_relations(:used_relation).id).visible
381  end
382
383  ##
384  # test uploading a delete with no lat/lon, as they are optional in
385  # the osmChange spec.
386  def test_upload_nolatlon_delete
387    basic_authorization users(:public_user).display_name, "test"
388
389    node = current_nodes(:public_visible_node)
390    cs = changesets(:public_user_first_change)
391    diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{cs.id}'/></delete></osmChange>"
392
393    # upload it
394    content diff
395    post :upload, :id => cs.id
396    assert_response :success, 
397      "can't upload a deletion diff to changeset: #{@response.body}"
398
399    # check the response is well-formed
400    assert_select "diffResult>node", 1
401
402    # check that everything was deleted
403    assert_equal false, Node.find(node.id).visible
404  end
405
406  def test_repeated_changeset_create
407    30.times do
408      basic_authorization users(:public_user).email, "test"
409   
410      # create a temporary changeset
411      content "<osm><changeset>" +
412        "<tag k='created_by' v='osm test suite checking changesets'/>" + 
413        "</changeset></osm>"
414      assert_difference('Changeset.count', 1) do
415        put :create
416      end
417      assert_response :success
418      changeset_id = @response.body.to_i
419    end
420  end
421
422  ##
423  # test that deleting stuff in a transaction doesn't bypass the checks
424  # to ensure that used elements are not deleted.
425  def test_upload_delete_invalid
426    basic_authorization users(:public_user).email, "test"
427
428    diff = XML::Document.new
429    diff.root = XML::Node.new "osmChange"
430    delete = XML::Node.new "delete"
431    diff.root << delete
432    delete << current_relations(:public_visible_relation).to_xml_node
433    delete << current_ways(:used_way).to_xml_node
434    delete << current_nodes(:node_used_by_relationship).to_xml_node
435
436    # upload it
437    content diff
438    post :upload, :id => 2
439    assert_response :precondition_failed, 
440      "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
441    assert_equal "Precondition failed: Way 3 still used by relation 1.", @response.body
442
443    # check that nothing was, in fact, deleted
444    assert_equal true, Node.find(current_nodes(:node_used_by_relationship).id).visible
445    assert_equal true, Way.find(current_ways(:used_way).id).visible
446    assert_equal true, Relation.find(current_relations(:visible_relation).id).visible
447  end
448
449  ##
450  # upload an element with a really long tag value
451  def test_upload_invalid_too_long_tag
452    basic_authorization users(:public_user).email, "test"
453    cs_id = changesets(:public_user_first_change).id
454
455    # simple diff to create a node way and relation using placeholders
456    diff = <<EOF
457<osmChange>
458 <create>
459  <node id='-1' lon='0' lat='0' changeset='#{cs_id}'>
460   <tag k='foo' v='#{"x"*256}'/>
461  </node>
462 </create>
463</osmChange>
464EOF
465
466    # upload it
467    content diff
468    post :upload, :id => cs_id
469    assert_response :bad_request, 
470      "shoudln't be able to upload too long a tag to changeset: #{@response.body}"
471
472  end
473   
474  ##
475  # upload something which creates new objects and inserts them into
476  # existing containers using placeholders.
477  def test_upload_complex
478    basic_authorization users(:public_user).email, "test"
479    cs_id = changesets(:public_user_first_change).id
480
481    # simple diff to create a node way and relation using placeholders
482    diff = <<EOF
483<osmChange>
484 <create>
485  <node id='-1' lon='0' lat='0' changeset='#{cs_id}'>
486   <tag k='foo' v='bar'/>
487   <tag k='baz' v='bat'/>
488  </node>
489 </create>
490 <modify>
491  <way id='1' changeset='#{cs_id}' version='1'>
492   <nd ref='-1'/>
493   <nd ref='3'/>
494  </way>
495  <relation id='1' changeset='#{cs_id}' version='1'>
496   <member type='way' role='some' ref='3'/>
497   <member type='node' role='some' ref='-1'/>
498   <member type='relation' role='some' ref='3'/>
499  </relation>
500 </modify>
501</osmChange>
502EOF
503
504    # upload it
505    content diff
506    post :upload, :id => cs_id
507    assert_response :success, 
508      "can't upload a complex diff to changeset: #{@response.body}"
509
510    # check the returned payload
511    assert_select "diffResult[version=#{API_VERSION}][generator=\"#{GENERATOR}\"]", 1
512    assert_select "diffResult>node", 1
513    assert_select "diffResult>way", 1
514    assert_select "diffResult>relation", 1
515
516    # inspect the response to find out what the new element IDs are
517    doc = XML::Parser.string(@response.body).parse
518    new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
519
520    # check that the changes made it into the database
521    assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
522    assert_equal [new_node_id, 3], Way.find(1).nds, "way nodes should match"
523    Relation.find(1).members.each do |type,id,role|
524      if type == 'node'
525        assert_equal new_node_id, id, "relation should contain new node"
526      end
527    end
528  end
529   
530  ##
531  # create a diff which references several changesets, which should cause
532  # a rollback and none of the diff gets committed
533  def test_upload_invalid_changesets
534    basic_authorization users(:public_user).email, "test"
535    cs_id = changesets(:public_user_first_change).id
536
537    # simple diff to create a node way and relation using placeholders
538    diff = <<EOF
539<osmChange>
540 <modify>
541  <node id='1' lon='0' lat='0' changeset='#{cs_id}' version='1'/>
542  <way id='1' changeset='#{cs_id}' version='1'>
543   <nd ref='3'/>
544  </way>
545 </modify>
546 <modify>
547  <relation id='1' changeset='#{cs_id}' version='1'>
548   <member type='way' role='some' ref='3'/>
549   <member type='node' role='some' ref='5'/>
550   <member type='relation' role='some' ref='3'/>
551  </relation>
552 </modify>
553 <create>
554  <node id='-1' lon='0' lat='0' changeset='4'>
555   <tag k='foo' v='bar'/>
556   <tag k='baz' v='bat'/>
557  </node>
558 </create>
559</osmChange>
560EOF
561    # cache the objects before uploading them
562    node = current_nodes(:visible_node)
563    way = current_ways(:visible_way)
564    rel = current_relations(:visible_relation)
565
566    # upload it
567    content diff
568    post :upload, :id => cs_id
569    assert_response :conflict, 
570      "uploading a diff with multiple changsets should have failed"
571
572    # check that objects are unmodified
573    assert_nodes_are_equal(node, Node.find(1))
574    assert_ways_are_equal(way, Way.find(1))
575  end
576   
577  ##
578  # upload multiple versions of the same element in the same diff.
579  def test_upload_multiple_valid
580    basic_authorization users(:public_user).email, "test"
581    cs_id = changesets(:public_user_first_change).id
582
583    # change the location of a node multiple times, each time referencing
584    # the last version. doesn't this depend on version numbers being
585    # sequential?
586    diff = <<EOF
587<osmChange>
588 <modify>
589  <node id='1' lon='0' lat='0' changeset='#{cs_id}' version='1'/>
590  <node id='1' lon='1' lat='0' changeset='#{cs_id}' version='2'/>
591  <node id='1' lon='1' lat='1' changeset='#{cs_id}' version='3'/>
592  <node id='1' lon='1' lat='2' changeset='#{cs_id}' version='4'/>
593  <node id='1' lon='2' lat='2' changeset='#{cs_id}' version='5'/>
594  <node id='1' lon='3' lat='2' changeset='#{cs_id}' version='6'/>
595  <node id='1' lon='3' lat='3' changeset='#{cs_id}' version='7'/>
596  <node id='1' lon='9' lat='9' changeset='#{cs_id}' version='8'/>
597 </modify>
598</osmChange>
599EOF
600
601    # upload it
602    content diff
603    post :upload, :id => cs_id
604    assert_response :success, 
605      "can't upload multiple versions of an element in a diff: #{@response.body}"
606   
607    # check the response is well-formed. its counter-intuitive, but the
608    # API will return multiple elements with the same ID and different
609    # version numbers for each change we made.
610    assert_select "diffResult>node", 8
611  end
612
613  ##
614  # upload multiple versions of the same element in the same diff, but
615  # keep the version numbers the same.
616  def test_upload_multiple_duplicate
617    basic_authorization users(:public_user).email, "test"
618    cs_id = changesets(:public_user_first_change).id
619
620    diff = <<EOF
621<osmChange>
622 <modify>
623  <node id='1' lon='0' lat='0' changeset='#{cs_id}' version='1'/>
624  <node id='1' lon='1' lat='1' changeset='#{cs_id}' version='1'/>
625 </modify>
626</osmChange>
627EOF
628
629    # upload it
630    content diff
631    post :upload, :id => cs_id
632    assert_response :conflict, 
633      "shouldn't be able to upload the same element twice in a diff: #{@response.body}"
634  end
635
636  ##
637  # try to upload some elements without specifying the version
638  def test_upload_missing_version
639    basic_authorization users(:public_user).email, "test"
640    cs_id = changesets(:public_user_first_change).id
641
642    diff = <<EOF
643<osmChange>
644 <modify>
645 <node id='1' lon='1' lat='1' changeset='cs_id'/>
646 </modify>
647</osmChange>
648EOF
649
650    # upload it
651    content diff
652    post :upload, :id => cs_id
653    assert_response :bad_request, 
654      "shouldn't be able to upload an element without version: #{@response.body}"
655  end
656 
657  ##
658  # try to upload with commands other than create, modify, or delete
659  def test_action_upload_invalid
660    basic_authorization users(:public_user).email, "test"
661    cs_id = changesets(:public_user_first_change).id
662   
663    diff = <<EOF
664<osmChange>
665  <ping>
666   <node id='1' lon='1' lat='1' changeset='#{cs_id}' />
667  </ping>
668</osmChange>
669EOF
670  content diff
671  post :upload, :id => cs_id
672  assert_response :bad_request, "Shouldn't be able to upload a diff with the action ping"
673  assert_equal @response.body, "Unknown action ping, choices are create, modify, delete"
674  end
675
676  ##
677  # upload a valid changeset which has a mixture of whitespace
678  # to check a bug reported by ivansanchez (#1565).
679  def test_upload_whitespace_valid
680    basic_authorization users(:public_user).email, "test"
681    changeset_id = changesets(:public_user_first_change).id
682
683    diff = <<EOF
684<osmChange>
685 <modify><node id='1' lon='0' lat='0' changeset='#{changeset_id}'
686  version='1'></node>
687  <node id='1' lon='1' lat='1' changeset='#{changeset_id}' version='2'><tag k='k' v='v'/></node></modify>
688 <modify>
689 <relation id='1' changeset='#{changeset_id}' version='1'><member
690   type='way' role='some' ref='3'/><member
691    type='node' role='some' ref='5'/>
692   <member type='relation' role='some' ref='3'/>
693  </relation>
694 </modify></osmChange>
695EOF
696
697    # upload it
698    content diff
699    post :upload, :id => changeset_id
700    assert_response :success, 
701      "can't upload a valid diff with whitespace variations to changeset: #{@response.body}"
702
703    # check the response is well-formed
704    assert_select "diffResult>node", 2
705    assert_select "diffResult>relation", 1
706
707    # check that the changes made it into the database
708    assert_equal 1, Node.find(1).tags.size, "node 1 should now have one tag"
709    assert_equal 0, Relation.find(1).tags.size, "relation 1 should now have no tags"
710  end
711
712  ##
713  # upload a valid changeset which has a mixture of whitespace
714  # to check a bug reported by ivansanchez.
715  def test_upload_reuse_placeholder_valid
716    basic_authorization users(:public_user).email, "test"
717    changeset_id = changesets(:public_user_first_change).id
718
719    diff = <<EOF
720<osmChange>
721 <create>
722  <node id='-1' lon='0' lat='0' changeset='#{changeset_id}'>
723   <tag k="foo" v="bar"/>
724  </node>
725 </create>
726 <modify>
727  <node id='-1' lon='1' lat='1' changeset='#{changeset_id}' version='1'/>
728 </modify>
729 <delete>
730  <node id='-1' lon='2' lat='2' changeset='#{changeset_id}' version='2'/>
731 </delete>
732</osmChange>
733EOF
734
735    # upload it
736    content diff
737    post :upload, :id => changeset_id
738    assert_response :success, 
739      "can't upload a valid diff with re-used placeholders to changeset: #{@response.body}"
740
741    # check the response is well-formed
742    assert_select "diffResult>node", 3
743    assert_select "diffResult>node[old_id=-1]", 3
744  end
745
746  ##
747  # test what happens if a diff upload re-uses placeholder IDs in an
748  # illegal way.
749  def test_upload_placeholder_invalid
750    basic_authorization users(:public_user).email, "test"
751    changeset_id = changesets(:public_user_first_change).id
752
753    diff = <<EOF
754<osmChange>
755 <create>
756  <node id='-1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
757  <node id='-1' lon='1' lat='1' changeset='#{changeset_id}' version='1'/>
758  <node id='-1' lon='2' lat='2' changeset='#{changeset_id}' version='2'/>
759 </create>
760</osmChange>
761EOF
762
763    # upload it
764    content diff
765    post :upload, :id => changeset_id
766    assert_response :bad_request, 
767      "shouldn't be able to re-use placeholder IDs"
768  end
769
770  ##
771  # test that uploading a way referencing invalid placeholders gives a
772  # proper error, not a 500.
773  def test_upload_placeholder_invalid_way
774    basic_authorization users(:public_user).email, "test"
775    changeset_id = changesets(:public_user_first_change).id
776
777    diff = <<EOF
778<osmChange>
779 <create>
780  <node id="-1" lon="0" lat="0" changeset="#{changeset_id}" version="1"/>
781  <node id="-2" lon="1" lat="1" changeset="#{changeset_id}" version="1"/>
782  <node id="-3" lon="2" lat="2" changeset="#{changeset_id}" version="1"/>
783  <way id="-1" changeset="#{changeset_id}" version="1">
784   <nd ref="-1"/>
785   <nd ref="-2"/>
786   <nd ref="-3"/>
787   <nd ref="-4"/>
788  </way>
789 </create>
790</osmChange>
791EOF
792
793    # upload it
794    content diff
795    post :upload, :id => changeset_id
796    assert_response :bad_request, 
797      "shouldn't be able to use invalid placeholder IDs"
798    assert_equal "Placeholder node not found for reference -4 in way -1", @response.body
799
800    # the same again, but this time use an existing way
801    diff = <<EOF
802<osmChange>
803 <create>
804  <node id="-1" lon="0" lat="0" changeset="#{changeset_id}" version="1"/>
805  <node id="-2" lon="1" lat="1" changeset="#{changeset_id}" version="1"/>
806  <node id="-3" lon="2" lat="2" changeset="#{changeset_id}" version="1"/>
807  <way id="1" changeset="#{changeset_id}" version="1">
808   <nd ref="-1"/>
809   <nd ref="-2"/>
810   <nd ref="-3"/>
811   <nd ref="-4"/>
812  </way>
813 </create>
814</osmChange>
815EOF
816
817    # upload it
818    content diff
819    post :upload, :id => changeset_id
820    assert_response :bad_request, 
821      "shouldn't be able to use invalid placeholder IDs"
822    assert_equal "Placeholder node not found for reference -4 in way 1", @response.body
823  end
824
825  ##
826  # test that uploading a relation referencing invalid placeholders gives a
827  # proper error, not a 500.
828  def test_upload_placeholder_invalid_relation
829    basic_authorization users(:public_user).email, "test"
830    changeset_id = changesets(:public_user_first_change).id
831
832    diff = <<EOF
833<osmChange>
834 <create>
835  <node id="-1" lon="0" lat="0" changeset="#{changeset_id}" version="1"/>
836  <node id="-2" lon="1" lat="1" changeset="#{changeset_id}" version="1"/>
837  <node id="-3" lon="2" lat="2" changeset="#{changeset_id}" version="1"/>
838  <relation id="-1" changeset="#{changeset_id}" version="1">
839   <member type="node" role="foo" ref="-1"/>
840   <member type="node" role="foo" ref="-2"/>
841   <member type="node" role="foo" ref="-3"/>
842   <member type="node" role="foo" ref="-4"/>
843  </relation>
844 </create>
845</osmChange>
846EOF
847
848    # upload it
849    content diff
850    post :upload, :id => changeset_id
851    assert_response :bad_request, 
852      "shouldn't be able to use invalid placeholder IDs"
853    assert_equal "Placeholder Node not found for reference -4 in relation -1.", @response.body
854
855    # the same again, but this time use an existing way
856    diff = <<EOF
857<osmChange>
858 <create>
859  <node id="-1" lon="0" lat="0" changeset="#{changeset_id}" version="1"/>
860  <node id="-2" lon="1" lat="1" changeset="#{changeset_id}" version="1"/>
861  <node id="-3" lon="2" lat="2" changeset="#{changeset_id}" version="1"/>
862  <relation id="1" changeset="#{changeset_id}" version="1">
863   <member type="node" role="foo" ref="-1"/>
864   <member type="node" role="foo" ref="-2"/>
865   <member type="node" role="foo" ref="-3"/>
866   <member type="way" role="bar" ref="-1"/>
867  </relation>
868 </create>
869</osmChange>
870EOF
871
872    # upload it
873    content diff
874    post :upload, :id => changeset_id
875    assert_response :bad_request, 
876      "shouldn't be able to use invalid placeholder IDs"
877    assert_equal "Placeholder Way not found for reference -1 in relation 1.", @response.body
878  end
879
880  ##
881  # test what happens if a diff is uploaded containing only a node
882  # move.
883  def test_upload_node_move
884    basic_authorization users(:public_user).email, "test"
885
886    content "<osm><changeset>" +
887      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
888      "</changeset></osm>"
889    put :create
890    assert_response :success
891    changeset_id = @response.body.to_i
892
893    old_node = current_nodes(:visible_node)
894
895    diff = XML::Document.new
896    diff.root = XML::Node.new "osmChange"
897    modify = XML::Node.new "modify"
898    xml_old_node = old_node.to_xml_node
899    xml_old_node["lat"] = (2.0).to_s
900    xml_old_node["lon"] = (2.0).to_s
901    xml_old_node["changeset"] = changeset_id.to_s
902    modify << xml_old_node
903    diff.root << modify
904
905    # upload it
906    content diff
907    post :upload, :id => changeset_id
908    assert_response :success, 
909      "diff should have uploaded OK"
910
911    # check the bbox
912    changeset = Changeset.find(changeset_id)
913    assert_equal 1*SCALE, changeset.min_lon, "min_lon should be 1 degree"
914    assert_equal 2*SCALE, changeset.max_lon, "max_lon should be 2 degrees"
915    assert_equal 1*SCALE, changeset.min_lat, "min_lat should be 1 degree"
916    assert_equal 2*SCALE, changeset.max_lat, "max_lat should be 2 degrees"
917  end
918
919  ##
920  # test what happens if a diff is uploaded adding a node to a way.
921  def test_upload_way_extend
922    basic_authorization users(:public_user).email, "test"
923
924    content "<osm><changeset>" +
925      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
926      "</changeset></osm>"
927    put :create
928    assert_response :success
929    changeset_id = @response.body.to_i
930
931    old_way = current_ways(:visible_way)
932
933    diff = XML::Document.new
934    diff.root = XML::Node.new "osmChange"
935    modify = XML::Node.new "modify"
936    xml_old_way = old_way.to_xml_node
937    nd_ref = XML::Node.new "nd"
938    nd_ref["ref"] = current_nodes(:visible_node).id.to_s
939    xml_old_way << nd_ref
940    xml_old_way["changeset"] = changeset_id.to_s
941    modify << xml_old_way
942    diff.root << modify
943
944    # upload it
945    content diff
946    post :upload, :id => changeset_id
947    assert_response :success, 
948      "diff should have uploaded OK"
949
950    # check the bbox
951    changeset = Changeset.find(changeset_id)
952    assert_equal 1*SCALE, changeset.min_lon, "min_lon should be 1 degree"
953    assert_equal 3*SCALE, changeset.max_lon, "max_lon should be 3 degrees"
954    assert_equal 1*SCALE, changeset.min_lat, "min_lat should be 1 degree"
955    assert_equal 3*SCALE, changeset.max_lat, "max_lat should be 3 degrees"
956  end
957
958  ##
959  # test for more issues in #1568
960  def test_upload_empty_invalid
961    basic_authorization users(:public_user).email, "test"
962
963    [ "<osmChange/>",
964      "<osmChange></osmChange>",
965      "<osmChange><modify/></osmChange>",
966      "<osmChange><modify></modify></osmChange>"
967    ].each do |diff|
968      # upload it
969      content diff
970      post :upload, :id => changesets(:public_user_first_change).id
971      assert_response(:success, "should be able to upload " +
972                      "empty changeset: " + diff)
973    end
974  end
975
976  ##
977  # when we make some simple changes we get the same changes back from the
978  # diff download.
979  def test_diff_download_simple
980    ## First try with the normal user, which should get a forbidden
981    basic_authorization(users(:normal_user).email, "test")
982
983    # create a temporary changeset
984    content "<osm><changeset>" +
985      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
986      "</changeset></osm>"
987    put :create
988    assert_response :forbidden
989   
990   
991   
992    ## Now try with the public user
993    basic_authorization(users(:public_user).email, "test")
994
995    # create a temporary changeset
996    content "<osm><changeset>" +
997      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
998      "</changeset></osm>"
999    put :create
1000    assert_response :success
1001    changeset_id = @response.body.to_i
1002
1003    # add a diff to it
1004    diff = <<EOF
1005<osmChange>
1006 <modify>
1007  <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
1008  <node id='1' lon='1' lat='0' changeset='#{changeset_id}' version='2'/>
1009  <node id='1' lon='1' lat='1' changeset='#{changeset_id}' version='3'/>
1010  <node id='1' lon='1' lat='2' changeset='#{changeset_id}' version='4'/>
1011  <node id='1' lon='2' lat='2' changeset='#{changeset_id}' version='5'/>
1012  <node id='1' lon='3' lat='2' changeset='#{changeset_id}' version='6'/>
1013  <node id='1' lon='3' lat='3' changeset='#{changeset_id}' version='7'/>
1014  <node id='1' lon='9' lat='9' changeset='#{changeset_id}' version='8'/>
1015 </modify>
1016</osmChange>
1017EOF
1018
1019    # upload it
1020    content diff
1021    post :upload, :id => changeset_id
1022    assert_response :success, 
1023      "can't upload multiple versions of an element in a diff: #{@response.body}"
1024   
1025    get :download, :id => changeset_id
1026    assert_response :success
1027
1028    assert_select "osmChange", 1
1029    assert_select "osmChange>modify", 8
1030    assert_select "osmChange>modify>node", 8
1031  end
1032 
1033  ##
1034  # culled this from josm to ensure that nothing in the way that josm
1035  # is formatting the request is causing it to fail.
1036  #
1037  # NOTE: the error turned out to be something else completely!
1038  def test_josm_upload
1039    basic_authorization(users(:public_user).email, "test")
1040
1041    # create a temporary changeset
1042    content "<osm><changeset>" +
1043      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
1044      "</changeset></osm>"
1045    put :create
1046    assert_response :success
1047    changeset_id = @response.body.to_i
1048
1049    diff = <<OSMFILE
1050<osmChange version="0.6" generator="JOSM">
1051<create version="0.6" generator="JOSM">
1052  <node id='-1' visible='true' changeset='#{changeset_id}' lat='51.49619982187321' lon='-0.18722061869438314' />
1053  <node id='-2' visible='true' changeset='#{changeset_id}' lat='51.496359883909605' lon='-0.18653093576241928' />
1054  <node id='-3' visible='true' changeset='#{changeset_id}' lat='51.49598132358285' lon='-0.18719613290981638' />
1055  <node id='-4' visible='true' changeset='#{changeset_id}' lat='51.4961591711078' lon='-0.18629015888084607' />
1056  <node id='-5' visible='true' changeset='#{changeset_id}' lat='51.49582126021711' lon='-0.18708186591517145' />
1057  <node id='-6' visible='true' changeset='#{changeset_id}' lat='51.49591018437858' lon='-0.1861432441734455' />
1058  <node id='-7' visible='true' changeset='#{changeset_id}' lat='51.49560784152179' lon='-0.18694719410005425' />
1059  <node id='-8' visible='true' changeset='#{changeset_id}' lat='51.49567389979617' lon='-0.1860289771788006' />
1060  <node id='-9' visible='true' changeset='#{changeset_id}' lat='51.49543761398892' lon='-0.186820684213126' />
1061  <way id='-10' action='modiy' visible='true' changeset='#{changeset_id}'>
1062    <nd ref='-1' />
1063    <nd ref='-2' />
1064    <nd ref='-3' />
1065    <nd ref='-4' />
1066    <nd ref='-5' />
1067    <nd ref='-6' />
1068    <nd ref='-7' />
1069    <nd ref='-8' />
1070    <nd ref='-9' />
1071    <tag k='highway' v='residential' />
1072    <tag k='name' v='Foobar Street' />
1073  </way>
1074</create>
1075</osmChange>
1076OSMFILE
1077
1078    # upload it
1079    content diff
1080    post :upload, :id => changeset_id
1081    assert_response :success, 
1082      "can't upload a diff from JOSM: #{@response.body}"
1083   
1084    get :download, :id => changeset_id
1085    assert_response :success
1086
1087    assert_select "osmChange", 1
1088    assert_select "osmChange>create>node", 9
1089    assert_select "osmChange>create>way", 1
1090    assert_select "osmChange>create>way>nd", 9
1091    assert_select "osmChange>create>way>tag", 2
1092  end
1093
1094  ##
1095  # when we make some complex changes we get the same changes back from the
1096  # diff download.
1097  def test_diff_download_complex
1098    basic_authorization(users(:public_user).email, "test")
1099
1100    # create a temporary changeset
1101    content "<osm><changeset>" +
1102      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
1103      "</changeset></osm>"
1104    put :create
1105    assert_response :success
1106    changeset_id = @response.body.to_i
1107
1108    # add a diff to it
1109    diff = <<EOF
1110<osmChange>
1111 <delete>
1112  <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
1113 </delete>
1114 <create>
1115  <node id='-1' lon='9' lat='9' changeset='#{changeset_id}' version='0'/>
1116  <node id='-2' lon='8' lat='9' changeset='#{changeset_id}' version='0'/>
1117  <node id='-3' lon='7' lat='9' changeset='#{changeset_id}' version='0'/>
1118 </create>
1119 <modify>
1120  <node id='3' lon='20' lat='15' changeset='#{changeset_id}' version='1'/>
1121  <way id='1' changeset='#{changeset_id}' version='1'>
1122   <nd ref='3'/>
1123   <nd ref='-1'/>
1124   <nd ref='-2'/>
1125   <nd ref='-3'/>
1126  </way>
1127 </modify>
1128</osmChange>
1129EOF
1130
1131    # upload it
1132    content diff
1133    post :upload, :id => changeset_id
1134    assert_response :success, 
1135      "can't upload multiple versions of an element in a diff: #{@response.body}"
1136   
1137    get :download, :id => changeset_id
1138    assert_response :success
1139
1140    assert_select "osmChange", 1
1141    assert_select "osmChange>create", 3
1142    assert_select "osmChange>delete", 1
1143    assert_select "osmChange>modify", 2
1144    assert_select "osmChange>create>node", 3
1145    assert_select "osmChange>delete>node", 1 
1146    assert_select "osmChange>modify>node", 1
1147    assert_select "osmChange>modify>way", 1
1148  end
1149
1150  def test_changeset_download
1151    get :download, :id => changesets(:normal_user_first_change).id
1152    assert_response :success
1153    assert_template nil
1154    #print @response.body
1155    # FIXME needs more assert_select tests
1156    assert_select "osmChange[version='#{API_VERSION}'][generator='#{GENERATOR}']" do
1157      assert_select "create", :count => 5
1158      assert_select "create>node[id=#{nodes(:used_node_2).id}][visible=#{nodes(:used_node_2).visible?}][version=#{nodes(:used_node_2).version}]" do
1159        assert_select "tag[k=#{node_tags(:t3).k}][v=#{node_tags(:t3).v}]"
1160      end
1161      assert_select "create>node[id=#{nodes(:visible_node).id}]"
1162    end
1163  end
1164 
1165  ##
1166  # check that the bounding box of a changeset gets updated correctly
1167  ## FIXME: This should really be moded to a integration test due to the with_controller
1168  def test_changeset_bbox
1169    basic_authorization users(:public_user).email, "test"
1170
1171    # create a new changeset
1172    content "<osm><changeset/></osm>"
1173    put :create
1174    assert_response :success, "Creating of changeset failed."
1175    changeset_id = @response.body.to_i
1176   
1177    # add a single node to it
1178    with_controller(NodeController.new) do
1179      content "<osm><node lon='1' lat='2' changeset='#{changeset_id}'/></osm>"
1180      put :create
1181      assert_response :success, "Couldn't create node."
1182    end
1183
1184    # get the bounding box back from the changeset
1185    get :read, :id => changeset_id
1186    assert_response :success, "Couldn't read back changeset."
1187    assert_select "osm>changeset[min_lon=1.0]", 1
1188    assert_select "osm>changeset[max_lon=1.0]", 1
1189    assert_select "osm>changeset[min_lat=2.0]", 1
1190    assert_select "osm>changeset[max_lat=2.0]", 1
1191
1192    # add another node to it
1193    with_controller(NodeController.new) do
1194      content "<osm><node lon='2' lat='1' changeset='#{changeset_id}'/></osm>"
1195      put :create
1196      assert_response :success, "Couldn't create second node."
1197    end
1198
1199    # get the bounding box back from the changeset
1200    get :read, :id => changeset_id
1201    assert_response :success, "Couldn't read back changeset for the second time."
1202    assert_select "osm>changeset[min_lon=1.0]", 1
1203    assert_select "osm>changeset[max_lon=2.0]", 1
1204    assert_select "osm>changeset[min_lat=1.0]", 1
1205    assert_select "osm>changeset[max_lat=2.0]", 1
1206
1207    # add (delete) a way to it, which contains a point at (3,3)
1208    with_controller(WayController.new) do
1209      content update_changeset(current_ways(:visible_way).to_xml,
1210                               changeset_id)
1211      put :delete, :id => current_ways(:visible_way).id
1212      assert_response :success, "Couldn't delete a way."
1213    end
1214
1215    # get the bounding box back from the changeset
1216    get :read, :id => changeset_id
1217    assert_response :success, "Couldn't read back changeset for the third time."
1218    # note that the 3.1 here is because of the bbox overexpansion
1219    assert_select "osm>changeset[min_lon=1.0]", 1
1220    assert_select "osm>changeset[max_lon=3.1]", 1
1221    assert_select "osm>changeset[min_lat=1.0]", 1
1222    assert_select "osm>changeset[max_lat=3.1]", 1   
1223  end
1224
1225  ##
1226  # test that the changeset :include method works as it should
1227  def test_changeset_include
1228    basic_authorization users(:public_user).display_name, "test"
1229
1230    # create a new changeset
1231    content "<osm><changeset/></osm>"
1232    put :create
1233    assert_response :success, "Creating of changeset failed."
1234    changeset_id = @response.body.to_i
1235
1236    # NOTE: the include method doesn't over-expand, like inserting
1237    # a real method does. this is because we expect the client to
1238    # know what it is doing!
1239    check_after_include(changeset_id,  1,  1, [ 1,  1,  1,  1])
1240    check_after_include(changeset_id,  3,  3, [ 1,  1,  3,  3])
1241    check_after_include(changeset_id,  4,  2, [ 1,  1,  4,  3])
1242    check_after_include(changeset_id,  2,  2, [ 1,  1,  4,  3])
1243    check_after_include(changeset_id, -1, -1, [-1, -1,  4,  3])
1244    check_after_include(changeset_id, -2,  5, [-2, -1,  4,  5])
1245  end
1246 
1247  ##
1248  # test that a not found, wrong method with the expand bbox works as expected
1249  def test_changeset_expand_bbox_error
1250    basic_authorization users(:public_user).display_name, "test"
1251   
1252    # create a new changeset
1253    content "<osm><changeset/></osm>"
1254    put :create
1255    assert_response :success, "Creating of changeset failed."
1256    changeset_id = @response.body.to_i
1257   
1258    lon=58.2
1259    lat=-0.45
1260   
1261    # Try and put
1262    content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
1263    put :expand_bbox, :id => changeset_id
1264    assert_response :method_not_allowed, "shouldn't be able to put a bbox expand"
1265
1266    # Try to get the update
1267    content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
1268    get :expand_bbox, :id => changeset_id
1269    assert_response :method_not_allowed, "shouldn't be able to get a bbox expand"
1270   
1271    # Try to use a hopefully missing changeset
1272    content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
1273    post :expand_bbox, :id => changeset_id+13245
1274    assert_response :not_found, "shouldn't be able to do a bbox expand on a nonexistant changeset"
1275
1276  end
1277
1278  ##
1279  # test the query functionality of changesets
1280  def test_query
1281    get :query, :bbox => "-10,-10, 10, 10"
1282    assert_response :success, "can't get changesets in bbox"
1283    assert_changesets [1,4,6]
1284
1285    get :query, :bbox => "4.5,4.5,4.6,4.6"
1286    assert_response :success, "can't get changesets in bbox"
1287    assert_changesets [1]
1288
1289    # can't get changesets of user 1 without authenticating
1290    get :query, :user => users(:normal_user).id
1291    assert_response :not_found, "shouldn't be able to get changesets by non-public user"
1292
1293    # but this should work
1294    basic_authorization "test@openstreetmap.org", "test"
1295    get :query, :user => users(:normal_user).id
1296    assert_response :success, "can't get changesets by user"
1297    assert_changesets [1,3,6]
1298
1299    get :query, :user => users(:normal_user).id, :open => true
1300    assert_response :success, "can't get changesets by user and open"
1301    assert_changesets [1]
1302
1303    get :query, :time => '2007-12-31'
1304    assert_response :success, "can't get changesets by time-since"
1305    assert_changesets [1,2,4,5,6]
1306
1307    get :query, :time => '2008-01-01T12:34Z'
1308    assert_response :success, "can't get changesets by time-since with hour"
1309    assert_changesets [1,2,4,5,6]
1310
1311    get :query, :time => '2007-12-31T23:59Z,2008-01-01T00:01Z'
1312    assert_response :success, "can't get changesets by time-range"
1313    assert_changesets [1,5,6]
1314
1315    get :query, :open => 'true'
1316    assert_response :success, "can't get changesets by open-ness"
1317    assert_changesets [1,2,4]
1318  end
1319
1320  ##
1321  # check that errors are returned if garbage is inserted
1322  # into query strings
1323  def test_query_invalid
1324    [ "abracadabra!",
1325      "1,2,3,F",
1326      ";drop table users;"
1327      ].each do |bbox|
1328      get :query, :bbox => bbox
1329      assert_response :bad_request, "'#{bbox}' isn't a bbox"
1330    end
1331
1332    [ "now()",
1333      "00-00-00",
1334      ";drop table users;",
1335      ",",
1336      "-,-"
1337      ].each do |time|
1338      get :query, :time => time
1339      assert_response :bad_request, "'#{time}' isn't a valid time range"
1340    end
1341
1342    [ "me",
1343      "foobar",
1344      "-1",
1345      "0"
1346      ].each do |uid|
1347      get :query, :user => uid
1348      assert_response :bad_request, "'#{uid}' isn't a valid user ID"
1349    end
1350  end
1351
1352  ##
1353  # check updating tags on a changeset
1354  def test_changeset_update
1355    ## First try with the non-public user
1356    changeset = changesets(:normal_user_first_change)
1357    new_changeset = changeset.to_xml
1358    new_tag = XML::Node.new "tag"
1359    new_tag['k'] = "tagtesting"
1360    new_tag['v'] = "valuetesting"
1361    new_changeset.find("//osm/changeset").first << new_tag
1362    content new_changeset
1363
1364    # try without any authorization
1365    put :update, :id => changeset.id
1366    assert_response :unauthorized
1367
1368    # try with the wrong authorization
1369    basic_authorization users(:public_user).email, "test"
1370    put :update, :id => changeset.id
1371    assert_response :conflict
1372
1373    # now this should get an unauthorized
1374    basic_authorization users(:normal_user).email, "test"
1375    put :update, :id => changeset.id
1376    assert_require_public_data "user with their data non-public, shouldn't be able to edit their changeset"
1377   
1378   
1379    ## Now try with the public user
1380    changeset = changesets(:public_user_first_change)
1381    new_changeset = changeset.to_xml
1382    new_tag = XML::Node.new "tag"
1383    new_tag['k'] = "tagtesting"
1384    new_tag['v'] = "valuetesting"
1385    new_changeset.find("//osm/changeset").first << new_tag
1386    content new_changeset
1387   
1388    # try without any authorization
1389    @request.env["HTTP_AUTHORIZATION"] = nil
1390    put :update, :id => changeset.id
1391    assert_response :unauthorized
1392
1393    # try with the wrong authorization
1394    basic_authorization users(:second_public_user).email, "test"
1395    put :update, :id => changeset.id
1396    assert_response :conflict
1397
1398    # now this should work...
1399    basic_authorization users(:public_user).email, "test"
1400    put :update, :id => changeset.id
1401    assert_response :success
1402
1403    assert_select "osm>changeset[id=#{changeset.id}]", 1
1404    assert_select "osm>changeset>tag", 2
1405    assert_select "osm>changeset>tag[k=tagtesting][v=valuetesting]", 1
1406  end
1407 
1408  ##
1409  # check that a user different from the one who opened the changeset
1410  # can't modify it.
1411  def test_changeset_update_invalid
1412    basic_authorization users(:public_user).email, "test"
1413
1414    changeset = changesets(:normal_user_first_change)
1415    new_changeset = changeset.to_xml
1416    new_tag = XML::Node.new "tag"
1417    new_tag['k'] = "testing"
1418    new_tag['v'] = "testing"
1419    new_changeset.find("//osm/changeset").first << new_tag
1420
1421    content new_changeset
1422    put :update, :id => changeset.id
1423    assert_response :conflict
1424  end
1425
1426  ##
1427  # check that a changeset can contain a certain max number of changes.
1428  ## FIXME should be changed to an integration test due to the with_controller
1429  def test_changeset_limits
1430    basic_authorization users(:public_user).email, "test"
1431
1432    # open a new changeset
1433    content "<osm><changeset/></osm>"
1434    put :create
1435    assert_response :success, "can't create a new changeset"
1436    cs_id = @response.body.to_i
1437
1438    # start the counter just short of where the changeset should finish.
1439    offset = 10
1440    # alter the database to set the counter on the changeset directly,
1441    # otherwise it takes about 6 minutes to fill all of them.
1442    changeset = Changeset.find(cs_id)
1443    changeset.num_changes = Changeset::MAX_ELEMENTS - offset
1444    changeset.save!
1445
1446    with_controller(NodeController.new) do
1447      # create a new node
1448      content "<osm><node changeset='#{cs_id}' lat='0.0' lon='0.0'/></osm>"
1449      put :create
1450      assert_response :success, "can't create a new node"
1451      node_id = @response.body.to_i
1452
1453      get :read, :id => node_id
1454      assert_response :success, "can't read back new node"
1455      node_doc = XML::Parser.string(@response.body).parse
1456      node_xml = node_doc.find("//osm/node").first
1457
1458      # loop until we fill the changeset with nodes
1459      offset.times do |i|
1460        node_xml['lat'] = rand.to_s
1461        node_xml['lon'] = rand.to_s
1462        node_xml['version'] = (i+1).to_s
1463
1464        content node_doc
1465        put :update, :id => node_id
1466        assert_response :success, "attempt #{i} should have succeeded"
1467      end
1468
1469      # trying again should fail
1470      node_xml['lat'] = rand.to_s
1471      node_xml['lon'] = rand.to_s
1472      node_xml['version'] = offset.to_s
1473     
1474      content node_doc
1475      put :update, :id => node_id
1476      assert_response :conflict, "final attempt should have failed"
1477    end
1478
1479    changeset = Changeset.find(cs_id)
1480    assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
1481
1482    # check that the changeset is now closed as well
1483    assert(!changeset.is_open?, 
1484           "changeset should have been auto-closed by exceeding " + 
1485           "element limit.")
1486  end
1487 
1488  ##
1489  # This should display the last 20 changesets closed.
1490  def test_list
1491    changesets = Changeset.find(:all, :order => "created_at DESC", :conditions => ['min_lat IS NOT NULL'], :limit=> 20)
1492    assert changesets.size <= 20
1493    get :list, {:format => "html"}
1494    assert_response :success
1495    assert_template "list"
1496    # Now check that all 20 (or however many were returned) changesets are in the html
1497    assert_select "h1", :text => "Changesets", :count => 1
1498    assert_select "table[id='changeset_list'] tr", :count => changesets.size + 1
1499    changesets.each do |changeset|
1500      # FIXME this test needs rewriting - test for table contents
1501    end
1502  end
1503 
1504  ##
1505  # Checks the display of the user changesets listing
1506  def test_list_user
1507    user = users(:public_user)
1508    get :list, {:format => "html", :display_name => user.display_name}
1509    assert_response :success
1510    assert_template "changeset/_user"
1511    ## FIXME need to add more checks to see which if edits are actually shown if your data is public
1512  end
1513 
1514  ##
1515  # Check the not found of the list user changesets
1516  def test_list_user_not_found
1517    get :list, {:format => "html", :display_name => "Some random user"}
1518    assert_response :not_found
1519    assert_template 'user/no_such_user'
1520  end
1521 
1522  #------------------------------------------------------------
1523  # utility functions
1524  #------------------------------------------------------------
1525
1526  ##
1527  # boilerplate for checking that certain changesets exist in the
1528  # output.
1529  def assert_changesets(ids)
1530    assert_select "osm>changeset", ids.size
1531    ids.each do |id|
1532      assert_select "osm>changeset[id=#{id}]", 1
1533    end
1534  end
1535
1536  ##
1537  # call the include method and assert properties of the bbox
1538  def check_after_include(changeset_id, lon, lat, bbox)
1539    content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
1540    post :expand_bbox, :id => changeset_id
1541    assert_response :success, "Setting include of changeset failed: #{@response.body}"
1542
1543    # check exactly one changeset
1544    assert_select "osm>changeset", 1
1545    assert_select "osm>changeset[id=#{changeset_id}]", 1
1546
1547    # check the bbox
1548    doc = XML::Parser.string(@response.body).parse
1549    changeset = doc.find("//osm/changeset").first
1550    assert_equal bbox[0], changeset['min_lon'].to_f, "min lon"
1551    assert_equal bbox[1], changeset['min_lat'].to_f, "min lat"
1552    assert_equal bbox[2], changeset['max_lon'].to_f, "max lon"
1553    assert_equal bbox[3], changeset['max_lat'].to_f, "max lat"
1554  end
1555
1556  ##
1557  # update the changeset_id of a way element
1558  def update_changeset(xml, changeset_id)
1559    xml_attr_rewrite(xml, 'changeset', changeset_id)
1560  end
1561
1562  ##
1563  # update an attribute in a way element
1564  def xml_attr_rewrite(xml, name, value)
1565    xml.find("//osm/way").first[name] = value.to_s
1566    return xml
1567  end
1568
1569end
Note: See TracBrowser for help on using the repository browser.