source: subversion/sites/rails_port_branches/api06/test/functional/changeset_controller_test.rb @ 14476

Revision 14476, 37.4 KB checked in by smsm1, 5 years ago (diff)

Remove duplication that is in the test helper. Adding tests for the passing of no content, and the wrong method used. Also ensuring that there has been a changeset added to the db when it is created.

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 "test@openstreetmap.org", "test"
13   
14    # Create the first user's changeset
15    content "<osm><changeset>" +
16      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
17      "</changeset></osm>"
18    put :create
19   
20    assert_response :success, "Creation of changeset did not return sucess status"
21    newid = @response.body.to_i
22
23    # check end time, should be an hour ahead of creation time
24    cs = Changeset.find(newid)
25    duration = cs.closed_at - cs.created_at
26    # the difference can either be a rational, or a floating point number
27    # of seconds, depending on the code path taken :-(
28    if duration.class == Rational
29      assert_equal Rational(1,24), duration , "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
30    else
31      # must be number of seconds...
32      assert_equal 3600, duration.round, "initial idle timeout should be an hour (#{cs.created_at} -> #{cs.closed_at})"
33    end
34  end
35 
36  def test_create_invalid
37    basic_authorization "test@openstreetmap.org", "test"
38    content "<osm><changeset></osm>"
39    put :create
40    assert_response :bad_request, "creating a invalid changeset should fail"
41  end
42
43  def test_create_invalid_no_content
44    basic_authorization "test@openstreetmap.org", "test"
45    put :create
46    assert_response :bad_request, "creating a changeset with no content should fail"
47  end
48 
49  def test_create_wrong_method
50    basic_authorization "test@openstreetmap.org", "test"
51    get :create
52    assert_response :method_not_allowed
53  end
54   
55  ##
56  # check that the changeset can be read and returns the correct
57  # document structure.
58  def test_read
59    changeset_id = changesets(:normal_user_first_change).id
60    get :read, :id => changeset_id
61    assert_response :success, "cannot get first changeset"
62   
63    assert_select "osm[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
64    assert_select "osm>changeset[id=#{changeset_id}]", 1
65  end
66 
67  ##
68  # test that the user who opened a change can close it
69  def test_close
70    basic_authorization "test@openstreetmap.org", "test"
71
72    cs_id = changesets(:normal_user_first_change).id
73    put :close, :id => cs_id
74    assert_response :success
75
76    # test that it really is closed now
77    cs = Changeset.find(cs_id)
78    assert(!cs.is_open?, 
79           "changeset should be closed now (#{cs.closed_at} > #{Time.now}.")
80  end
81
82  ##
83  # test that a different user can't close another user's changeset
84  def test_close_invalid
85    basic_authorization "test@example.com", "test"
86
87    put :close, :id => changesets(:normal_user_first_change).id
88    assert_response :conflict
89    assert_equal "The user doesn't own that changeset", @response.body
90  end
91
92  ##
93  # upload something simple, but valid and check that it can
94  # be read back ok.
95  def test_upload_simple_valid
96    basic_authorization "test@openstreetmap.org", "test"
97
98    # simple diff to change a node, way and relation by removing
99    # their tags
100    diff = <<EOF
101<osmChange>
102 <modify>
103  <node id='1' lon='0' lat='0' changeset='1' version='1'/>
104  <way id='1' changeset='1' version='1'>
105   <nd ref='3'/>
106  </way>
107 </modify>
108 <modify>
109  <relation id='1' changeset='1' version='1'>
110   <member type='way' role='some' ref='3'/>
111   <member type='node' role='some' ref='5'/>
112   <member type='relation' role='some' ref='3'/>
113  </relation>
114 </modify>
115</osmChange>
116EOF
117
118    # upload it
119    content diff
120    post :upload, :id => 1
121    assert_response :success, 
122      "can't upload a simple valid diff to changeset: #{@response.body}"
123
124    # check that the changes made it into the database
125    assert_equal 0, Node.find(1).tags.size, "node 1 should now have no tags"
126    assert_equal 0, Way.find(1).tags.size, "way 1 should now have no tags"
127    assert_equal 0, Relation.find(1).tags.size, "relation 1 should now have no tags"
128  end
129   
130  ##
131  # upload something which creates new objects using placeholders
132  def test_upload_create_valid
133    basic_authorization "test@openstreetmap.org", "test"
134
135    # simple diff to create a node way and relation using placeholders
136    diff = <<EOF
137<osmChange>
138 <create>
139  <node id='-1' lon='0' lat='0' changeset='1'>
140   <tag k='foo' v='bar'/>
141   <tag k='baz' v='bat'/>
142  </node>
143  <way id='-1' changeset='1'>
144   <nd ref='3'/>
145  </way>
146 </create>
147 <create>
148  <relation id='-1' changeset='1'>
149   <member type='way' role='some' ref='3'/>
150   <member type='node' role='some' ref='5'/>
151   <member type='relation' role='some' ref='3'/>
152  </relation>
153 </create>
154</osmChange>
155EOF
156
157    # upload it
158    content diff
159    post :upload, :id => 1
160    assert_response :success, 
161      "can't upload a simple valid creation to changeset: #{@response.body}"
162
163    # check the returned payload
164    assert_select "diffResult[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
165    assert_select "diffResult>node", 1
166    assert_select "diffresult>way", 1
167    assert_select "diffResult>relation", 1
168
169    # inspect the response to find out what the new element IDs are
170    doc = XML::Parser.string(@response.body).parse
171    new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
172    new_way_id = doc.find("//diffResult/way").first["new_id"].to_i
173    new_rel_id = doc.find("//diffResult/relation").first["new_id"].to_i
174
175    # check the old IDs are all present and negative one
176    assert_equal -1, doc.find("//diffResult/node").first["old_id"].to_i
177    assert_equal -1, doc.find("//diffResult/way").first["old_id"].to_i
178    assert_equal -1, doc.find("//diffResult/relation").first["old_id"].to_i
179
180    # check the versions are present and equal one
181    assert_equal 1, doc.find("//diffResult/node").first["new_version"].to_i
182    assert_equal 1, doc.find("//diffResult/way").first["new_version"].to_i
183    assert_equal 1, doc.find("//diffResult/relation").first["new_version"].to_i
184
185    # check that the changes made it into the database
186    assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
187    assert_equal 0, Way.find(new_way_id).tags.size, "new way should have no tags"
188    assert_equal 0, Relation.find(new_rel_id).tags.size, "new relation should have no tags"
189  end
190   
191  ##
192  # test a complex delete where we delete elements which rely on eachother
193  # in the same transaction.
194  def test_upload_delete
195    basic_authorization "test@openstreetmap.org", "test"
196
197    diff = XML::Document.new
198    diff.root = XML::Node.new "osmChange"
199    delete = XML::Node.new "delete"
200    diff.root << delete
201    delete << current_relations(:visible_relation).to_xml_node
202    delete << current_relations(:used_relation).to_xml_node
203    delete << current_ways(:used_way).to_xml_node
204    delete << current_nodes(:node_used_by_relationship).to_xml_node
205
206    # upload it
207    content diff
208    post :upload, :id => 1
209    assert_response :success, 
210      "can't upload a deletion diff to changeset: #{@response.body}"
211
212    # check the response is well-formed
213    assert_select "diffResult>node", 1
214    assert_select "diffResult>way", 1
215    assert_select "diffResult>relation", 2
216
217    # check that everything was deleted
218    assert_equal false, Node.find(current_nodes(:node_used_by_relationship).id).visible
219    assert_equal false, Way.find(current_ways(:used_way).id).visible
220    assert_equal false, Relation.find(current_relations(:visible_relation).id).visible
221    assert_equal false, Relation.find(current_relations(:used_relation).id).visible
222  end
223
224  ##
225  # test uploading a delete with no lat/lon, as they are optional in
226  # the osmChange spec.
227  def test_upload_nolatlon_delete
228    basic_authorization "test@openstreetmap.org", "test"
229
230    node = current_nodes(:visible_node)
231    cs = changesets(:normal_user_first_change)
232    diff = "<osmChange><delete><node id='#{node.id}' version='#{node.version}' changeset='#{cs.id}'/></delete></osmChange>"
233
234    # upload it
235    content diff
236    post :upload, :id => cs.id
237    assert_response :success, 
238      "can't upload a deletion diff to changeset: #{@response.body}"
239
240    # check the response is well-formed
241    assert_select "diffResult>node", 1
242
243    # check that everything was deleted
244    assert_equal false, Node.find(node.id).visible
245  end
246
247  def test_repeated_changeset_create
248    30.times do
249      basic_authorization "test@openstreetmap.org", "test"
250   
251      # create a temporary changeset
252      content "<osm><changeset>" +
253        "<tag k='created_by' v='osm test suite checking changesets'/>" + 
254        "</changeset></osm>"
255      assert_difference('Changeset.count', 1) do
256        put :create
257      end
258      assert_response :success
259      changeset_id = @response.body.to_i
260    end
261  end
262
263  ##
264  # test that deleting stuff in a transaction doesn't bypass the checks
265  # to ensure that used elements are not deleted.
266  def test_upload_delete_invalid
267    basic_authorization "test@openstreetmap.org", "test"
268
269    diff = XML::Document.new
270    diff.root = XML::Node.new "osmChange"
271    delete = XML::Node.new "delete"
272    diff.root << delete
273    delete << current_relations(:visible_relation).to_xml_node
274    delete << current_ways(:used_way).to_xml_node
275    delete << current_nodes(:node_used_by_relationship).to_xml_node
276
277    # upload it
278    content diff
279    post :upload, :id => 1
280    assert_response :precondition_failed, 
281      "shouldn't be able to upload a invalid deletion diff: #{@response.body}"
282
283    # check that nothing was, in fact, deleted
284    assert_equal true, Node.find(current_nodes(:node_used_by_relationship).id).visible
285    assert_equal true, Way.find(current_ways(:used_way).id).visible
286    assert_equal true, Relation.find(current_relations(:visible_relation).id).visible
287  end
288
289  ##
290  # upload something which creates new objects and inserts them into
291  # existing containers using placeholders.
292  def test_upload_complex
293    basic_authorization "test@openstreetmap.org", "test"
294
295    # simple diff to create a node way and relation using placeholders
296    diff = <<EOF
297<osmChange>
298 <create>
299  <node id='-1' lon='0' lat='0' changeset='1'>
300   <tag k='foo' v='bar'/>
301   <tag k='baz' v='bat'/>
302  </node>
303 </create>
304 <modify>
305  <way id='1' changeset='1' version='1'>
306   <nd ref='-1'/>
307   <nd ref='3'/>
308  </way>
309  <relation id='1' changeset='1' version='1'>
310   <member type='way' role='some' ref='3'/>
311   <member type='node' role='some' ref='-1'/>
312   <member type='relation' role='some' ref='3'/>
313  </relation>
314 </modify>
315</osmChange>
316EOF
317
318    # upload it
319    content diff
320    post :upload, :id => 1
321    assert_response :success, 
322      "can't upload a complex diff to changeset: #{@response.body}"
323
324    # check the returned payload
325    assert_select "diffResult[version=#{API_VERSION}][generator=\"#{GENERATOR}\"]", 1
326    assert_select "diffResult>node", 1
327    assert_select "diffResult>way", 1
328    assert_select "diffResult>relation", 1
329
330    # inspect the response to find out what the new element IDs are
331    doc = XML::Parser.string(@response.body).parse
332    new_node_id = doc.find("//diffResult/node").first["new_id"].to_i
333
334    # check that the changes made it into the database
335    assert_equal 2, Node.find(new_node_id).tags.size, "new node should have two tags"
336    assert_equal [new_node_id, 3], Way.find(1).nds, "way nodes should match"
337    Relation.find(1).members.each do |type,id,role|
338      if type == 'node'
339        assert_equal new_node_id, id, "relation should contain new node"
340      end
341    end
342  end
343   
344  ##
345  # create a diff which references several changesets, which should cause
346  # a rollback and none of the diff gets committed
347  def test_upload_invalid_changesets
348    basic_authorization "test@openstreetmap.org", "test"
349
350    # simple diff to create a node way and relation using placeholders
351    diff = <<EOF
352<osmChange>
353 <modify>
354  <node id='1' lon='0' lat='0' changeset='1' version='1'/>
355  <way id='1' changeset='1' version='1'>
356   <nd ref='3'/>
357  </way>
358 </modify>
359 <modify>
360  <relation id='1' changeset='1' version='1'>
361   <member type='way' role='some' ref='3'/>
362   <member type='node' role='some' ref='5'/>
363   <member type='relation' role='some' ref='3'/>
364  </relation>
365 </modify>
366 <create>
367  <node id='-1' lon='0' lat='0' changeset='4'>
368   <tag k='foo' v='bar'/>
369   <tag k='baz' v='bat'/>
370  </node>
371 </create>
372</osmChange>
373EOF
374    # cache the objects before uploading them
375    node = current_nodes(:visible_node)
376    way = current_ways(:visible_way)
377    rel = current_relations(:visible_relation)
378
379    # upload it
380    content diff
381    post :upload, :id => 1
382    assert_response :conflict, 
383      "uploading a diff with multiple changsets should have failed"
384
385    # check that objects are unmodified
386    assert_nodes_are_equal(node, Node.find(1))
387    assert_ways_are_equal(way, Way.find(1))
388  end
389   
390  ##
391  # upload multiple versions of the same element in the same diff.
392  def test_upload_multiple_valid
393    basic_authorization "test@openstreetmap.org", "test"
394
395    # change the location of a node multiple times, each time referencing
396    # the last version. doesn't this depend on version numbers being
397    # sequential?
398    diff = <<EOF
399<osmChange>
400 <modify>
401  <node id='1' lon='0' lat='0' changeset='1' version='1'/>
402  <node id='1' lon='1' lat='0' changeset='1' version='2'/>
403  <node id='1' lon='1' lat='1' changeset='1' version='3'/>
404  <node id='1' lon='1' lat='2' changeset='1' version='4'/>
405  <node id='1' lon='2' lat='2' changeset='1' version='5'/>
406  <node id='1' lon='3' lat='2' changeset='1' version='6'/>
407  <node id='1' lon='3' lat='3' changeset='1' version='7'/>
408  <node id='1' lon='9' lat='9' changeset='1' version='8'/>
409 </modify>
410</osmChange>
411EOF
412
413    # upload it
414    content diff
415    post :upload, :id => 1
416    assert_response :success, 
417      "can't upload multiple versions of an element in a diff: #{@response.body}"
418   
419    # check the response is well-formed. its counter-intuitive, but the
420    # API will return multiple elements with the same ID and different
421    # version numbers for each change we made.
422    assert_select "diffResult>node", 8
423  end
424
425  ##
426  # upload multiple versions of the same element in the same diff, but
427  # keep the version numbers the same.
428  def test_upload_multiple_duplicate
429    basic_authorization "test@openstreetmap.org", "test"
430
431    diff = <<EOF
432<osmChange>
433 <modify>
434  <node id='1' lon='0' lat='0' changeset='1' version='1'/>
435  <node id='1' lon='1' lat='1' changeset='1' version='1'/>
436 </modify>
437</osmChange>
438EOF
439
440    # upload it
441    content diff
442    post :upload, :id => 1
443    assert_response :conflict, 
444      "shouldn't be able to upload the same element twice in a diff: #{@response.body}"
445  end
446
447  ##
448  # try to upload some elements without specifying the version
449  def test_upload_missing_version
450    basic_authorization "test@openstreetmap.org", "test"
451
452    diff = <<EOF
453<osmChange>
454 <modify>
455  <node id='1' lon='1' lat='1' changeset='1'/>
456 </modify>
457</osmChange>
458EOF
459
460    # upload it
461    content diff
462    post :upload, :id => 1
463    assert_response :bad_request, 
464      "shouldn't be able to upload an element without version: #{@response.body}"
465  end
466 
467  ##
468  # try to upload with commands other than create, modify, or delete
469  def test_action_upload_invalid
470    basic_authorization "test@openstreetmap.org", "test"
471   
472    diff = <<EOF
473<osmChange>
474  <ping>
475    <node id='1' lon='1' lat='1' changeset='1' />
476  </ping>
477</osmChange>
478EOF
479  content diff
480  post :upload, :id => 1
481  assert_response :bad_request, "Shouldn't be able to upload a diff with the action ping"
482  assert_equal @response.body, "Unknown action ping, choices are create, modify, delete."
483  end
484
485  ##
486  # upload a valid changeset which has a mixture of whitespace
487  # to check a bug reported by ivansanchez (#1565).
488  def test_upload_whitespace_valid
489    basic_authorization "test@openstreetmap.org", "test"
490
491    diff = <<EOF
492<osmChange>
493 <modify><node id='1' lon='0' lat='0' changeset='1'
494  version='1'></node>
495  <node id='1' lon='1' lat='1' changeset='1' version='2'><tag k='k' v='v'/></node></modify>
496 <modify>
497  <relation id='1' changeset='1' version='1'><member
498   type='way' role='some' ref='3'/><member
499    type='node' role='some' ref='5'/>
500   <member type='relation' role='some' ref='3'/>
501  </relation>
502 </modify></osmChange>
503EOF
504
505    # upload it
506    content diff
507    post :upload, :id => 1
508    assert_response :success, 
509      "can't upload a valid diff with whitespace variations to changeset: #{@response.body}"
510
511    # check the response is well-formed
512    assert_select "diffResult>node", 2
513    assert_select "diffResult>relation", 1
514
515    # check that the changes made it into the database
516    assert_equal 1, Node.find(1).tags.size, "node 1 should now have one tag"
517    assert_equal 0, Relation.find(1).tags.size, "relation 1 should now have no tags"
518  end
519
520  ##
521  # upload a valid changeset which has a mixture of whitespace
522  # to check a bug reported by ivansanchez.
523  def test_upload_reuse_placeholder_valid
524    basic_authorization "test@openstreetmap.org", "test"
525
526    diff = <<EOF
527<osmChange>
528 <create>
529  <node id='-1' lon='0' lat='0' changeset='1'>
530   <tag k="foo" v="bar"/>
531  </node>
532 </create>
533 <modify>
534  <node id='-1' lon='1' lat='1' changeset='1' version='1'/>
535 </modify>
536 <delete>
537  <node id='-1' lon='2' lat='2' changeset='1' version='2'/>
538 </delete>
539</osmChange>
540EOF
541
542    # upload it
543    content diff
544    post :upload, :id => 1
545    assert_response :success, 
546      "can't upload a valid diff with re-used placeholders to changeset: #{@response.body}"
547
548    # check the response is well-formed
549    assert_select "diffResult>node", 3
550    assert_select "diffResult>node[old_id=-1]", 3
551  end
552
553  ##
554  # test what happens if a diff upload re-uses placeholder IDs in an
555  # illegal way.
556  def test_upload_placeholder_invalid
557    basic_authorization "test@openstreetmap.org", "test"
558
559    diff = <<EOF
560<osmChange>
561 <create>
562  <node id='-1' lon='0' lat='0' changeset='1' version='1'/>
563  <node id='-1' lon='1' lat='1' changeset='1' version='1'/>
564  <node id='-1' lon='2' lat='2' changeset='1' version='2'/>
565 </create>
566</osmChange>
567EOF
568
569    # upload it
570    content diff
571    post :upload, :id => 1
572    assert_response :bad_request, 
573      "shouldn't be able to re-use placeholder IDs"
574  end
575
576  ##
577  # test what happens if a diff is uploaded containing only a node
578  # move.
579  def test_upload_node_move
580    basic_authorization "test@openstreetmap.org", "test"
581
582    content "<osm><changeset>" +
583      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
584      "</changeset></osm>"
585    put :create
586    assert_response :success
587    changeset_id = @response.body.to_i
588
589    old_node = current_nodes(:visible_node)
590
591    diff = XML::Document.new
592    diff.root = XML::Node.new "osmChange"
593    modify = XML::Node.new "modify"
594    xml_old_node = old_node.to_xml_node
595    xml_old_node["lat"] = (2.0).to_s
596    xml_old_node["lon"] = (2.0).to_s
597    xml_old_node["changeset"] = changeset_id.to_s
598    modify << xml_old_node
599    diff.root << modify
600
601    # upload it
602    content diff
603    post :upload, :id => changeset_id
604    assert_response :success, 
605      "diff should have uploaded OK"
606
607    # check the bbox
608    changeset = Changeset.find(changeset_id)
609    assert_equal 1*SCALE, changeset.min_lon, "min_lon should be 1 degree"
610    assert_equal 2*SCALE, changeset.max_lon, "max_lon should be 2 degrees"
611    assert_equal 1*SCALE, changeset.min_lat, "min_lat should be 1 degree"
612    assert_equal 2*SCALE, changeset.max_lat, "max_lat should be 2 degrees"
613  end
614
615  ##
616  # test what happens if a diff is uploaded adding a node to a way.
617  def test_upload_way_extend
618    basic_authorization "test@openstreetmap.org", "test"
619
620    content "<osm><changeset>" +
621      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
622      "</changeset></osm>"
623    put :create
624    assert_response :success
625    changeset_id = @response.body.to_i
626
627    old_way = current_ways(:visible_way)
628
629    diff = XML::Document.new
630    diff.root = XML::Node.new "osmChange"
631    modify = XML::Node.new "modify"
632    xml_old_way = old_way.to_xml_node
633    nd_ref = XML::Node.new "nd"
634    nd_ref["ref"] = current_nodes(:visible_node).id.to_s
635    xml_old_way << nd_ref
636    xml_old_way["changeset"] = changeset_id.to_s
637    modify << xml_old_way
638    diff.root << modify
639
640    # upload it
641    content diff
642    post :upload, :id => changeset_id
643    assert_response :success, 
644      "diff should have uploaded OK"
645
646    # check the bbox
647    changeset = Changeset.find(changeset_id)
648    assert_equal 1*SCALE, changeset.min_lon, "min_lon should be 1 degree"
649    assert_equal 3*SCALE, changeset.max_lon, "max_lon should be 3 degrees"
650    assert_equal 1*SCALE, changeset.min_lat, "min_lat should be 1 degree"
651    assert_equal 3*SCALE, changeset.max_lat, "max_lat should be 3 degrees"
652  end
653
654  ##
655  # test for more issues in #1568
656  def test_upload_empty_invalid
657    basic_authorization "test@openstreetmap.org", "test"
658
659    [ "<osmChange/>",
660      "<osmChange></osmChange>",
661      "<osmChange><modify/></osmChange>",
662      "<osmChange><modify></modify></osmChange>"
663    ].each do |diff|
664      # upload it
665      content diff
666      post :upload, :id => 1
667      assert_response(:success, "should be able to upload " +
668                      "empty changeset: " + diff)
669    end
670  end
671
672  ##
673  # when we make some simple changes we get the same changes back from the
674  # diff download.
675  def test_diff_download_simple
676    basic_authorization(users(:normal_user).email, "test")
677
678    # create a temporary changeset
679    content "<osm><changeset>" +
680      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
681      "</changeset></osm>"
682    put :create
683    assert_response :success
684    changeset_id = @response.body.to_i
685
686    # add a diff to it
687    diff = <<EOF
688<osmChange>
689 <modify>
690  <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
691  <node id='1' lon='1' lat='0' changeset='#{changeset_id}' version='2'/>
692  <node id='1' lon='1' lat='1' changeset='#{changeset_id}' version='3'/>
693  <node id='1' lon='1' lat='2' changeset='#{changeset_id}' version='4'/>
694  <node id='1' lon='2' lat='2' changeset='#{changeset_id}' version='5'/>
695  <node id='1' lon='3' lat='2' changeset='#{changeset_id}' version='6'/>
696  <node id='1' lon='3' lat='3' changeset='#{changeset_id}' version='7'/>
697  <node id='1' lon='9' lat='9' changeset='#{changeset_id}' version='8'/>
698 </modify>
699</osmChange>
700EOF
701
702    # upload it
703    content diff
704    post :upload, :id => changeset_id
705    assert_response :success, 
706      "can't upload multiple versions of an element in a diff: #{@response.body}"
707   
708    get :download, :id => changeset_id
709    assert_response :success
710
711    assert_select "osmChange", 1
712    assert_select "osmChange>modify", 8
713    assert_select "osmChange>modify>node", 8
714  end
715 
716  ##
717  # culled this from josm to ensure that nothing in the way that josm
718  # is formatting the request is causing it to fail.
719  #
720  # NOTE: the error turned out to be something else completely!
721  def test_josm_upload
722    basic_authorization(users(:normal_user).email, "test")
723
724    # create a temporary changeset
725    content "<osm><changeset>" +
726      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
727      "</changeset></osm>"
728    put :create
729    assert_response :success
730    changeset_id = @response.body.to_i
731
732    diff = <<OSM
733<osmChange version="0.6" generator="JOSM">
734<create version="0.6" generator="JOSM">
735  <node id='-1' visible='true' changeset='#{changeset_id}' lat='51.49619982187321' lon='-0.18722061869438314' />
736  <node id='-2' visible='true' changeset='#{changeset_id}' lat='51.496359883909605' lon='-0.18653093576241928' />
737  <node id='-3' visible='true' changeset='#{changeset_id}' lat='51.49598132358285' lon='-0.18719613290981638' />
738  <node id='-4' visible='true' changeset='#{changeset_id}' lat='51.4961591711078' lon='-0.18629015888084607' />
739  <node id='-5' visible='true' changeset='#{changeset_id}' lat='51.49582126021711' lon='-0.18708186591517145' />
740  <node id='-6' visible='true' changeset='#{changeset_id}' lat='51.49591018437858' lon='-0.1861432441734455' />
741  <node id='-7' visible='true' changeset='#{changeset_id}' lat='51.49560784152179' lon='-0.18694719410005425' />
742  <node id='-8' visible='true' changeset='#{changeset_id}' lat='51.49567389979617' lon='-0.1860289771788006' />
743  <node id='-9' visible='true' changeset='#{changeset_id}' lat='51.49543761398892' lon='-0.186820684213126' />
744  <way id='-10' action='modiy' visible='true' changeset='#{changeset_id}'>
745    <nd ref='-1' />
746    <nd ref='-2' />
747    <nd ref='-3' />
748    <nd ref='-4' />
749    <nd ref='-5' />
750    <nd ref='-6' />
751    <nd ref='-7' />
752    <nd ref='-8' />
753    <nd ref='-9' />
754    <tag k='highway' v='residential' />
755    <tag k='name' v='Foobar Street' />
756  </way>
757</create>
758</osmChange>
759OSM
760
761    # upload it
762    content diff
763    post :upload, :id => changeset_id
764    assert_response :success, 
765      "can't upload a diff from JOSM: #{@response.body}"
766   
767    get :download, :id => changeset_id
768    assert_response :success
769
770    assert_select "osmChange", 1
771    assert_select "osmChange>create>node", 9
772    assert_select "osmChange>create>way", 1
773    assert_select "osmChange>create>way>nd", 9
774    assert_select "osmChange>create>way>tag", 2
775  end
776
777  ##
778  # when we make some complex changes we get the same changes back from the
779  # diff download.
780  def test_diff_download_complex
781    basic_authorization(users(:normal_user).email, "test")
782
783    # create a temporary changeset
784    content "<osm><changeset>" +
785      "<tag k='created_by' v='osm test suite checking changesets'/>" + 
786      "</changeset></osm>"
787    put :create
788    assert_response :success
789    changeset_id = @response.body.to_i
790
791    # add a diff to it
792    diff = <<EOF
793<osmChange>
794 <delete>
795  <node id='1' lon='0' lat='0' changeset='#{changeset_id}' version='1'/>
796 </delete>
797 <create>
798  <node id='-1' lon='9' lat='9' changeset='#{changeset_id}' version='0'/>
799  <node id='-2' lon='8' lat='9' changeset='#{changeset_id}' version='0'/>
800  <node id='-3' lon='7' lat='9' changeset='#{changeset_id}' version='0'/>
801 </create>
802 <modify>
803  <node id='3' lon='20' lat='15' changeset='#{changeset_id}' version='1'/>
804  <way id='1' changeset='#{changeset_id}' version='1'>
805   <nd ref='3'/>
806   <nd ref='-1'/>
807   <nd ref='-2'/>
808   <nd ref='-3'/>
809  </way>
810 </modify>
811</osmChange>
812EOF
813
814    # upload it
815    content diff
816    post :upload, :id => changeset_id
817    assert_response :success, 
818      "can't upload multiple versions of an element in a diff: #{@response.body}"
819   
820    get :download, :id => changeset_id
821    assert_response :success
822
823    assert_select "osmChange", 1
824    assert_select "osmChange>create", 3
825    assert_select "osmChange>delete", 1
826    assert_select "osmChange>modify", 2
827    assert_select "osmChange>create>node", 3
828    assert_select "osmChange>delete>node", 1 
829    assert_select "osmChange>modify>node", 1
830    assert_select "osmChange>modify>way", 1
831  end
832
833  ##
834  # check that the bounding box of a changeset gets updated correctly
835  def test_changeset_bbox
836    basic_authorization "test@openstreetmap.org", "test"
837
838    # create a new changeset
839    content "<osm><changeset/></osm>"
840    put :create
841    assert_response :success, "Creating of changeset failed."
842    changeset_id = @response.body.to_i
843   
844    # add a single node to it
845    with_controller(NodeController.new) do
846      content "<osm><node lon='1' lat='2' changeset='#{changeset_id}'/></osm>"
847      put :create
848      assert_response :success, "Couldn't create node."
849    end
850
851    # get the bounding box back from the changeset
852    get :read, :id => changeset_id
853    assert_response :success, "Couldn't read back changeset."
854    assert_select "osm>changeset[min_lon=1.0]", 1
855    assert_select "osm>changeset[max_lon=1.0]", 1
856    assert_select "osm>changeset[min_lat=2.0]", 1
857    assert_select "osm>changeset[max_lat=2.0]", 1
858
859    # add another node to it
860    with_controller(NodeController.new) do
861      content "<osm><node lon='2' lat='1' changeset='#{changeset_id}'/></osm>"
862      put :create
863      assert_response :success, "Couldn't create second node."
864    end
865
866    # get the bounding box back from the changeset
867    get :read, :id => changeset_id
868    assert_response :success, "Couldn't read back changeset for the second time."
869    assert_select "osm>changeset[min_lon=1.0]", 1
870    assert_select "osm>changeset[max_lon=2.0]", 1
871    assert_select "osm>changeset[min_lat=1.0]", 1
872    assert_select "osm>changeset[max_lat=2.0]", 1
873
874    # add (delete) a way to it, which contains a point at (3,3)
875    with_controller(WayController.new) do
876      content update_changeset(current_ways(:visible_way).to_xml,
877                               changeset_id)
878      put :delete, :id => current_ways(:visible_way).id
879      assert_response :success, "Couldn't delete a way."
880    end
881
882    # get the bounding box back from the changeset
883    get :read, :id => changeset_id
884    assert_response :success, "Couldn't read back changeset for the third time."
885    # note that the 3.1 here is because of the bbox overexpansion
886    assert_select "osm>changeset[min_lon=1.0]", 1
887    assert_select "osm>changeset[max_lon=3.1]", 1
888    assert_select "osm>changeset[min_lat=1.0]", 1
889    assert_select "osm>changeset[max_lat=3.1]", 1   
890  end
891
892  ##
893  # test that the changeset :include method works as it should
894  def test_changeset_include
895    basic_authorization "test@openstreetmap.org", "test"
896
897    # create a new changeset
898    content "<osm><changeset/></osm>"
899    put :create
900    assert_response :success, "Creating of changeset failed."
901    changeset_id = @response.body.to_i
902
903    # NOTE: the include method doesn't over-expand, like inserting
904    # a real method does. this is because we expect the client to
905    # know what it is doing!
906    check_after_include(changeset_id,  1,  1, [ 1,  1,  1,  1])
907    check_after_include(changeset_id,  3,  3, [ 1,  1,  3,  3])
908    check_after_include(changeset_id,  4,  2, [ 1,  1,  4,  3])
909    check_after_include(changeset_id,  2,  2, [ 1,  1,  4,  3])
910    check_after_include(changeset_id, -1, -1, [-1, -1,  4,  3])
911    check_after_include(changeset_id, -2,  5, [-2, -1,  4,  5])
912  end
913
914  ##
915  # test the query functionality of changesets
916  def test_query
917    get :query, :bbox => "-10,-10, 10, 10"
918    assert_response :success, "can't get changesets in bbox"
919    assert_changesets [1,4,6]
920
921    get :query, :bbox => "4.5,4.5,4.6,4.6"
922    assert_response :success, "can't get changesets in bbox"
923    assert_changesets [1]
924
925    # can't get changesets of user 1 without authenticating
926    get :query, :user => users(:normal_user).id
927    assert_response :not_found, "shouldn't be able to get changesets by non-public user"
928
929    # but this should work
930    basic_authorization "test@openstreetmap.org", "test"
931    get :query, :user => users(:normal_user).id
932    assert_response :success, "can't get changesets by user"
933    assert_changesets [1,3,4,6]
934
935    get :query, :user => users(:normal_user).id, :open => true
936    assert_response :success, "can't get changesets by user and open"
937    assert_changesets [1,4]
938
939    get :query, :time => '2007-12-31'
940    assert_response :success, "can't get changesets by time-since"
941    assert_changesets [1,2,4,5,6]
942
943    get :query, :time => '2008-01-01T12:34Z'
944    assert_response :success, "can't get changesets by time-since with hour"
945    assert_changesets [1,2,4,5,6]
946
947    get :query, :time => '2007-12-31T23:59Z,2008-01-01T00:01Z'
948    assert_response :success, "can't get changesets by time-range"
949    assert_changesets [1,4,5,6]
950
951    get :query, :open => 'true'
952    assert_response :success, "can't get changesets by open-ness"
953    assert_changesets [1,2,4]
954  end
955
956  ##
957  # check that errors are returned if garbage is inserted
958  # into query strings
959  def test_query_invalid
960    [ "abracadabra!",
961      "1,2,3,F",
962      ";drop table users;"
963      ].each do |bbox|
964      get :query, :bbox => bbox
965      assert_response :bad_request, "'#{bbox}' isn't a bbox"
966    end
967
968    [ "now()",
969      "00-00-00",
970      ";drop table users;",
971      ",",
972      "-,-"
973      ].each do |time|
974      get :query, :time => time
975      assert_response :bad_request, "'#{time}' isn't a valid time range"
976    end
977
978    [ "me",
979      "foobar",
980      "-1",
981      "0"
982      ].each do |uid|
983      get :query, :user => uid
984      assert_response :bad_request, "'#{uid}' isn't a valid user ID"
985    end
986  end
987
988  ##
989  # check updating tags on a changeset
990  def test_changeset_update
991    changeset = changesets(:normal_user_first_change)
992    new_changeset = changeset.to_xml
993    new_tag = XML::Node.new "tag"
994    new_tag['k'] = "tagtesting"
995    new_tag['v'] = "valuetesting"
996    new_changeset.find("//osm/changeset").first << new_tag
997    content new_changeset
998
999    # try without any authorization
1000    put :update, :id => changeset.id
1001    assert_response :unauthorized
1002
1003    # try with the wrong authorization
1004    basic_authorization "test@example.com", "test"
1005    put :update, :id => changeset.id
1006    assert_response :conflict
1007
1008    # now this should work...
1009    basic_authorization "test@openstreetmap.org", "test"
1010    put :update, :id => changeset.id
1011    assert_response :success
1012
1013    assert_select "osm>changeset[id=#{changeset.id}]", 1
1014    assert_select "osm>changeset>tag", 2
1015    assert_select "osm>changeset>tag[k=tagtesting][v=valuetesting]", 1
1016  end
1017 
1018  ##
1019  # check that a user different from the one who opened the changeset
1020  # can't modify it.
1021  def test_changeset_update_invalid
1022    basic_authorization "test@example.com", "test"
1023
1024    changeset = changesets(:normal_user_first_change)
1025    new_changeset = changeset.to_xml
1026    new_tag = XML::Node.new "tag"
1027    new_tag['k'] = "testing"
1028    new_tag['v'] = "testing"
1029    new_changeset.find("//osm/changeset").first << new_tag
1030
1031    content new_changeset
1032    put :update, :id => changeset.id
1033    assert_response :conflict
1034  end
1035
1036  ##
1037  # check that a changeset can contain a certain max number of changes.
1038  def test_changeset_limits
1039    basic_authorization "test@openstreetmap.org", "test"
1040
1041    # open a new changeset
1042    content "<osm><changeset/></osm>"
1043    put :create
1044    assert_response :success, "can't create a new changeset"
1045    cs_id = @response.body.to_i
1046
1047    # start the counter just short of where the changeset should finish.
1048    offset = 10
1049    # alter the database to set the counter on the changeset directly,
1050    # otherwise it takes about 6 minutes to fill all of them.
1051    changeset = Changeset.find(cs_id)
1052    changeset.num_changes = Changeset::MAX_ELEMENTS - offset
1053    changeset.save!
1054
1055    with_controller(NodeController.new) do
1056      # create a new node
1057      content "<osm><node changeset='#{cs_id}' lat='0.0' lon='0.0'/></osm>"
1058      put :create
1059      assert_response :success, "can't create a new node"
1060      node_id = @response.body.to_i
1061
1062      get :read, :id => node_id
1063      assert_response :success, "can't read back new node"
1064      node_doc = XML::Parser.string(@response.body).parse
1065      node_xml = node_doc.find("//osm/node").first
1066
1067      # loop until we fill the changeset with nodes
1068      offset.times do |i|
1069        node_xml['lat'] = rand.to_s
1070        node_xml['lon'] = rand.to_s
1071        node_xml['version'] = (i+1).to_s
1072
1073        content node_doc
1074        put :update, :id => node_id
1075        assert_response :success, "attempt #{i} should have succeeded"
1076      end
1077
1078      # trying again should fail
1079      node_xml['lat'] = rand.to_s
1080      node_xml['lon'] = rand.to_s
1081      node_xml['version'] = offset.to_s
1082     
1083      content node_doc
1084      put :update, :id => node_id
1085      assert_response :conflict, "final attempt should have failed"
1086    end
1087
1088    changeset = Changeset.find(cs_id)
1089    assert_equal Changeset::MAX_ELEMENTS + 1, changeset.num_changes
1090
1091    # check that the changeset is now closed as well
1092    assert(!changeset.is_open?, 
1093           "changeset should have been auto-closed by exceeding " + 
1094           "element limit.")
1095  end
1096 
1097  # This should display the last 20 changesets closed.
1098  def test_list
1099    @changesets = Changeset.find(:all, :order => "created_at DESC", :conditions => ['min_lat IS NOT NULL'], :limit=> 20)
1100    assert @changesets.size <= 20
1101    get :list
1102    assert_response :success
1103    assert_template "list"
1104    # Now check that all 20 (or however many were returned) changesets are in the html
1105    assert_select "h1", :text => "Recent Changes", :count => 1
1106    assert_select "table[id='keyvalue'] tr", :count => @changesets.size + 1
1107    @changesets.each do |changeset|
1108      # FIXME this test needs rewriting - test for table contents
1109    end
1110  end
1111 
1112  #------------------------------------------------------------
1113  # utility functions
1114  #------------------------------------------------------------
1115
1116  ##
1117  # boilerplate for checking that certain changesets exist in the
1118  # output.
1119  def assert_changesets(ids)
1120    assert_select "osm>changeset", ids.size
1121    ids.each do |id|
1122      assert_select "osm>changeset[id=#{id}]", 1
1123    end
1124  end
1125
1126  ##
1127  # call the include method and assert properties of the bbox
1128  def check_after_include(changeset_id, lon, lat, bbox)
1129    content "<osm><node lon='#{lon}' lat='#{lat}'/></osm>"
1130    post :expand_bbox, :id => changeset_id
1131    assert_response :success, "Setting include of changeset failed: #{@response.body}"
1132
1133    # check exactly one changeset
1134    assert_select "osm>changeset", 1
1135    assert_select "osm>changeset[id=#{changeset_id}]", 1
1136
1137    # check the bbox
1138    doc = XML::Parser.string(@response.body).parse
1139    changeset = doc.find("//osm/changeset").first
1140    assert_equal bbox[0], changeset['min_lon'].to_f, "min lon"
1141    assert_equal bbox[1], changeset['min_lat'].to_f, "min lat"
1142    assert_equal bbox[2], changeset['max_lon'].to_f, "max lon"
1143    assert_equal bbox[3], changeset['max_lat'].to_f, "max lat"
1144  end
1145
1146  ##
1147  # update the changeset_id of a way element
1148  def update_changeset(xml, changeset_id)
1149    xml_attr_rewrite(xml, 'changeset', changeset_id)
1150  end
1151
1152  ##
1153  # update an attribute in a way element
1154  def xml_attr_rewrite(xml, name, value)
1155    xml.find("//osm/way").first[name] = value.to_s
1156    return xml
1157  end
1158
1159end
Note: See TracBrowser for help on using the repository browser.