source: subversion/sites/rails_port/test/functional/relation_controller_test.rb @ 14769

Last change on this file since 14769 was 14769, checked in by Shaun McDonald, 10 years ago

Make node update work with the new require data public to edit policy. Added convenience testing method for the require data public. Add 2 new fixtures that are owned by the public user.

File size: 30.3 KB
Line 
1require File.dirname(__FILE__) + '/../test_helper'
2require 'relation_controller'
3
4class RelationControllerTest < ActionController::TestCase
5  api_fixtures
6
7  # -------------------------------------
8  # Test reading relations.
9  # -------------------------------------
10
11  def test_read
12    # check that a visible relation is returned properly
13    get :read, :id => current_relations(:visible_relation).id
14    assert_response :success
15
16    # check that an invisible relation is not returned
17    get :read, :id => current_relations(:invisible_relation).id
18    assert_response :gone
19
20    # check chat a non-existent relation is not returned
21    get :read, :id => 0
22    assert_response :not_found
23  end
24
25  ##
26  # check that all relations containing a particular node, and no extra
27  # relations, are returned from the relations_for_node call.
28  def test_relations_for_node
29    check_relations_for_element(:relations_for_node, "node", 
30                                current_nodes(:node_used_by_relationship).id,
31                                [ :visible_relation, :used_relation ])
32  end
33
34  def test_relations_for_way
35    check_relations_for_element(:relations_for_way, "way",
36                                current_ways(:used_way).id,
37                                [ :visible_relation ])
38  end
39
40  def test_relations_for_relation
41    check_relations_for_element(:relations_for_relation, "relation",
42                                current_relations(:used_relation).id,
43                                [ :visible_relation ])
44  end
45
46  def check_relations_for_element(method, type, id, expected_relations)
47    # check the "relations for relation" mode
48    get method, :id => id
49    assert_response :success
50
51    # count one osm element
52    assert_select "osm[version=#{API_VERSION}][generator=\"OpenStreetMap server\"]", 1
53
54    # we should have only the expected number of relations
55    assert_select "osm>relation", expected_relations.size
56
57    # and each of them should contain the node we originally searched for
58    expected_relations.each do |r|
59      relation_id = current_relations(r).id
60      assert_select "osm>relation#?", relation_id
61      assert_select "osm>relation#?>member[type=\"#{type}\"][ref=#{id}]", relation_id
62    end
63  end
64
65  def test_full
66    # check the "full" mode
67    get :full, :id => current_relations(:visible_relation).id
68    assert_response :success
69    # FIXME check whether this contains the stuff we want!
70    if $VERBOSE
71        print @response.body
72    end
73  end
74
75  # -------------------------------------
76  # Test simple relation creation.
77  # -------------------------------------
78
79  def test_create
80    basic_authorization users(:normal_user).email, "test"
81   
82    # put the relation in a dummy fixture changset
83    changeset_id = changesets(:normal_user_first_change).id
84
85    # create an relation without members
86    content "<osm><relation changeset='#{changeset_id}'><tag k='test' v='yes' /></relation></osm>"
87    put :create
88    # hope for forbidden, due to user
89    assert_response :forbidden, 
90    "relation upload should have failed with forbidden"
91
92    ###
93    # create an relation with a node as member
94    # This time try with a role attribute in the relation
95    nid = current_nodes(:used_node_1).id
96    content "<osm><relation changeset='#{changeset_id}'>" +
97      "<member  ref='#{nid}' type='node' role='some'/>" +
98      "<tag k='test' v='yes' /></relation></osm>"
99    put :create
100    # hope for forbidden due to user
101    assert_response :forbidden, 
102    "relation upload did not return forbidden status"
103   
104    ###
105    # create an relation with a node as member, this time test that we don't
106    # need a role attribute to be included
107    nid = current_nodes(:used_node_1).id
108    content "<osm><relation changeset='#{changeset_id}'>" +
109      "<member  ref='#{nid}' type='node'/>"+
110      "<tag k='test' v='yes' /></relation></osm>"
111    put :create
112    # hope for forbidden due to user
113    assert_response :forbidden, 
114    "relation upload did not return forbidden status"
115
116    ###
117    # create an relation with a way and a node as members
118    nid = current_nodes(:used_node_1).id
119    wid = current_ways(:used_way).id
120    content "<osm><relation changeset='#{changeset_id}'>" +
121      "<member type='node' ref='#{nid}' role='some'/>" +
122      "<member type='way' ref='#{wid}' role='other'/>" +
123      "<tag k='test' v='yes' /></relation></osm>"
124    put :create
125    # hope for forbidden, due to user
126    assert_response :forbidden, 
127        "relation upload did not return success status"
128
129
130
131    ## Now try with the public user
132    basic_authorization users(:public_user).email, "test"
133   
134    # put the relation in a dummy fixture changset
135    changeset_id = changesets(:public_user_first_change).id
136
137    # create an relation without members
138    content "<osm><relation changeset='#{changeset_id}'><tag k='test' v='yes' /></relation></osm>"
139    put :create
140    # hope for success
141    assert_response :success, 
142        "relation upload did not return success status"
143    # read id of created relation and search for it
144    relationid = @response.body
145    checkrelation = Relation.find(relationid)
146    assert_not_nil checkrelation, 
147        "uploaded relation not found in data base after upload"
148    # compare values
149    assert_equal checkrelation.members.length, 0, 
150        "saved relation contains members but should not"
151    assert_equal checkrelation.tags.length, 1, 
152        "saved relation does not contain exactly one tag"
153    assert_equal changeset_id, checkrelation.changeset.id,
154        "saved relation does not belong in the changeset it was assigned to"
155    assert_equal users(:public_user).id, checkrelation.changeset.user_id, 
156        "saved relation does not belong to user that created it"
157    assert_equal true, checkrelation.visible, 
158        "saved relation is not visible"
159    # ok the relation is there but can we also retrieve it?
160    get :read, :id => relationid
161    assert_response :success
162
163
164    ###
165    # create an relation with a node as member
166    # This time try with a role attribute in the relation
167    nid = current_nodes(:used_node_1).id
168    content "<osm><relation changeset='#{changeset_id}'>" +
169      "<member  ref='#{nid}' type='node' role='some'/>" +
170      "<tag k='test' v='yes' /></relation></osm>"
171    put :create
172    # hope for success
173    assert_response :success, 
174        "relation upload did not return success status"
175    # read id of created relation and search for it
176    relationid = @response.body
177    checkrelation = Relation.find(relationid)
178    assert_not_nil checkrelation, 
179        "uploaded relation not found in data base after upload"
180    # compare values
181    assert_equal checkrelation.members.length, 1, 
182        "saved relation does not contain exactly one member"
183    assert_equal checkrelation.tags.length, 1, 
184        "saved relation does not contain exactly one tag"
185    assert_equal changeset_id, checkrelation.changeset.id,
186        "saved relation does not belong in the changeset it was assigned to"
187    assert_equal users(:public_user).id, checkrelation.changeset.user_id, 
188        "saved relation does not belong to user that created it"
189    assert_equal true, checkrelation.visible, 
190        "saved relation is not visible"
191    # ok the relation is there but can we also retrieve it?
192   
193    get :read, :id => relationid
194    assert_response :success
195   
196   
197    ###
198    # create an relation with a node as member, this time test that we don't
199    # need a role attribute to be included
200    nid = current_nodes(:used_node_1).id
201    content "<osm><relation changeset='#{changeset_id}'>" +
202      "<member  ref='#{nid}' type='node'/>"+
203      "<tag k='test' v='yes' /></relation></osm>"
204    put :create
205    # hope for success
206    assert_response :success, 
207        "relation upload did not return success status"
208    # read id of created relation and search for it
209    relationid = @response.body
210    checkrelation = Relation.find(relationid)
211    assert_not_nil checkrelation, 
212        "uploaded relation not found in data base after upload"
213    # compare values
214    assert_equal checkrelation.members.length, 1, 
215        "saved relation does not contain exactly one member"
216    assert_equal checkrelation.tags.length, 1, 
217        "saved relation does not contain exactly one tag"
218    assert_equal changeset_id, checkrelation.changeset.id,
219        "saved relation does not belong in the changeset it was assigned to"
220    assert_equal users(:public_user).id, checkrelation.changeset.user_id, 
221        "saved relation does not belong to user that created it"
222    assert_equal true, checkrelation.visible, 
223        "saved relation is not visible"
224    # ok the relation is there but can we also retrieve it?
225   
226    get :read, :id => relationid
227    assert_response :success
228
229    ###
230    # create an relation with a way and a node as members
231    nid = current_nodes(:used_node_1).id
232    wid = current_ways(:used_way).id
233    content "<osm><relation changeset='#{changeset_id}'>" +
234      "<member type='node' ref='#{nid}' role='some'/>" +
235      "<member type='way' ref='#{wid}' role='other'/>" +
236      "<tag k='test' v='yes' /></relation></osm>"
237    put :create
238    # hope for success
239    assert_response :success, 
240        "relation upload did not return success status"
241    # read id of created relation and search for it
242    relationid = @response.body
243    checkrelation = Relation.find(relationid)
244    assert_not_nil checkrelation, 
245        "uploaded relation not found in data base after upload"
246    # compare values
247    assert_equal checkrelation.members.length, 2, 
248        "saved relation does not have exactly two members"
249    assert_equal checkrelation.tags.length, 1, 
250        "saved relation does not contain exactly one tag"
251    assert_equal changeset_id, checkrelation.changeset.id,
252        "saved relation does not belong in the changeset it was assigned to"
253    assert_equal users(:public_user).id, checkrelation.changeset.user_id, 
254        "saved relation does not belong to user that created it"
255    assert_equal true, checkrelation.visible, 
256        "saved relation is not visible"
257    # ok the relation is there but can we also retrieve it?
258    get :read, :id => relationid
259    assert_response :success
260
261  end
262
263  # ------------------------------------
264  # Test updating relations
265  # ------------------------------------
266
267  ##
268  # test that, when tags are updated on a relation, the correct things
269  # happen to the correct tables and the API gives sensible results.
270  # this is to test a case that gregory marler noticed and posted to
271  # josm-dev.
272  ## FIXME Move this to an integration test
273  def test_update_relation_tags
274    basic_authorization "test@example.com", "test"
275    rel_id = current_relations(:multi_tag_relation).id
276    cs_id = changesets(:public_user_first_change).id
277
278    with_relation(rel_id) do |rel|
279      # alter one of the tags
280      tag = rel.find("//osm/relation/tag").first
281      tag['v'] = 'some changed value'
282      update_changeset(rel, cs_id)
283
284      # check that the downloaded tags are the same as the uploaded tags...
285      new_version = with_update(rel) do |new_rel|
286        assert_tags_equal rel, new_rel
287      end
288
289      # check the original one in the current_* table again
290      with_relation(rel_id) { |r| assert_tags_equal rel, r }
291
292      # now check the version in the history
293      with_relation(rel_id, new_version) { |r| assert_tags_equal rel, r }
294    end
295  end
296
297  ##
298  # test that, when tags are updated on a relation when using the diff
299  # upload function, the correct things happen to the correct tables
300  # and the API gives sensible results. this is to test a case that
301  # gregory marler noticed and posted to josm-dev.
302  def test_update_relation_tags_via_upload
303    basic_authorization "test@example.com", "test"
304    rel_id = current_relations(:multi_tag_relation).id
305    cs_id = changesets(:public_user_first_change).id
306
307    with_relation(rel_id) do |rel|
308      # alter one of the tags
309      tag = rel.find("//osm/relation/tag").first
310      tag['v'] = 'some changed value'
311      update_changeset(rel, cs_id)
312
313      # check that the downloaded tags are the same as the uploaded tags...
314      new_version = with_update_diff(rel) do |new_rel|
315        assert_tags_equal rel, new_rel
316      end
317
318      # check the original one in the current_* table again
319      with_relation(rel_id) { |r| assert_tags_equal rel, r }
320
321      # now check the version in the history
322      with_relation(rel_id, new_version) { |r| assert_tags_equal rel, r }
323    end
324  end
325
326  # -------------------------------------
327  # Test creating some invalid relations.
328  # -------------------------------------
329
330  def test_create_invalid
331    basic_authorization "test@openstreetmap.org", "test"
332
333    # put the relation in a dummy fixture changset
334    changeset_id = changesets(:normal_user_first_change).id
335
336    # create a relation with non-existing node as member
337    content "<osm><relation changeset='#{changeset_id}'>" +
338      "<member type='node' ref='0'/><tag k='test' v='yes' />" +
339      "</relation></osm>"
340    put :create
341    # expect failure
342    assert_response :precondition_failed, 
343        "relation upload with invalid node did not return 'precondition failed'"
344  end
345
346  # -------------------------------------
347  # Test creating a relation, with some invalid XML
348  # -------------------------------------
349  def test_create_invalid_xml
350    basic_authorization "test@openstreetmap.org", "test"
351   
352    # put the relation in a dummy fixture changeset that works
353    changeset_id = changesets(:normal_user_first_change).id
354   
355    # create some xml that should return an error
356    content "<osm><relation changeset='#{changeset_id}'>" +
357    "<member type='type' ref='#{current_nodes(:used_node_1).id}' role=''/>" +
358    "<tag k='tester' v='yep'/></relation></osm>"
359    put :create
360    # expect failure
361    assert_response :bad_request
362    assert_match(/Cannot parse valid relation from xml string/, @response.body)
363    assert_match(/The type is not allowed only, /, @response.body)
364  end
365 
366 
367  # -------------------------------------
368  # Test deleting relations.
369  # -------------------------------------
370 
371  def test_delete
372    # first try to delete relation without auth
373    delete :delete, :id => current_relations(:visible_relation).id
374    assert_response :unauthorized
375   
376    ## First try with the private user, to make sure that you get a forbidden
377    basic_authorization(users(:normal_user).email, "test")
378   
379    # this shouldn't work, as we should need the payload...
380    delete :delete, :id => current_relations(:visible_relation).id
381    assert_response :forbidden
382
383    # try to delete without specifying a changeset
384    content "<osm><relation id='#{current_relations(:visible_relation).id}'/></osm>"
385    delete :delete, :id => current_relations(:visible_relation).id
386    assert_response :forbidden
387
388    # try to delete with an invalid (closed) changeset
389    content update_changeset(current_relations(:visible_relation).to_xml,
390                             changesets(:normal_user_closed_change).id)
391    delete :delete, :id => current_relations(:visible_relation).id
392    assert_response :forbidden
393
394    # try to delete with an invalid (non-existent) changeset
395    content update_changeset(current_relations(:visible_relation).to_xml,0)
396    delete :delete, :id => current_relations(:visible_relation).id
397    assert_response :forbidden
398
399    # this won't work because the relation is in-use by another relation
400    content(relations(:used_relation).to_xml)
401    delete :delete, :id => current_relations(:used_relation).id
402    assert_response :forbidden
403
404    # this should work when we provide the appropriate payload...
405    content(relations(:visible_relation).to_xml)
406    delete :delete, :id => current_relations(:visible_relation).id
407    assert_response :forbidden
408
409    # this won't work since the relation is already deleted
410    content(relations(:invisible_relation).to_xml)
411    delete :delete, :id => current_relations(:invisible_relation).id
412    assert_response :forbidden
413
414    # this works now because the relation which was using this one
415    # has been deleted.
416    content(relations(:used_relation).to_xml)
417    delete :delete, :id => current_relations(:used_relation).id
418    assert_response :forbidden
419
420    # this won't work since the relation never existed
421    delete :delete, :id => 0
422    assert_response :forbidden
423
424   
425
426    # now set auth for the private user
427    basic_authorization(users(:public_user).email, "test"); 
428
429    # this shouldn't work, as we should need the payload...
430    delete :delete, :id => current_relations(:visible_relation).id
431    assert_response :bad_request
432
433    # try to delete without specifying a changeset
434    content "<osm><relation id='#{current_relations(:visible_relation).id}'/></osm>"
435    delete :delete, :id => current_relations(:visible_relation).id
436    assert_response :bad_request
437    assert_match(/You are missing the required changeset in the relation/, @response.body)
438
439    # try to delete with an invalid (closed) changeset
440    content update_changeset(current_relations(:visible_relation).to_xml,
441                             changesets(:normal_user_closed_change).id)
442    delete :delete, :id => current_relations(:visible_relation).id
443    assert_response :conflict
444
445    # try to delete with an invalid (non-existent) changeset
446    content update_changeset(current_relations(:visible_relation).to_xml,0)
447    delete :delete, :id => current_relations(:visible_relation).id
448    assert_response :conflict
449
450    # this won't work because the relation is in a changeset owned by someone else
451    content(relations(:used_relation).to_xml)
452    delete :delete, :id => current_relations(:used_relation).id
453    assert_response :conflict, 
454    "shouldn't be able to delete a relation in a changeset owned by someone else (#{@response.body})"
455
456    # this won't work because the relation in the payload is different to that passed
457    content(relations(:public_used_relation).to_xml)
458    delete :delete, :id => current_relations(:used_relation).id
459    assert_not_equal relations(:public_used_relation).id, current_relations(:used_relation).id
460    assert_response :bad_request, "shouldn't be able to delete a relation when payload is different to the url"
461   
462    # this won't work because the relation is in-use by another relation
463    content(relations(:public_used_relation).to_xml)
464    delete :delete, :id => current_relations(:public_used_relation).id
465    assert_response :precondition_failed, 
466       "shouldn't be able to delete a relation used in a relation (#{@response.body})"
467
468    # this should work when we provide the appropriate payload...
469    content(relations(:multi_tag_relation).to_xml)
470    delete :delete, :id => current_relations(:multi_tag_relation).id
471    assert_response :success
472
473    # valid delete should return the new version number, which should
474    # be greater than the old version number
475    assert @response.body.to_i > current_relations(:visible_relation).version,
476       "delete request should return a new version number for relation"
477
478    # this won't work since the relation is already deleted
479    content(relations(:invisible_relation).to_xml)
480    delete :delete, :id => current_relations(:invisible_relation).id
481    assert_response :gone
482
483    # this works now because the relation which was using this one
484    # has been deleted.
485    content(relations(:public_used_relation).to_xml)
486    delete :delete, :id => current_relations(:public_used_relation).id
487    assert_response :success, 
488       "should be able to delete a relation used in an old relation (#{@response.body})"
489
490    # this won't work since the relation never existed
491    delete :delete, :id => 0
492    assert_response :not_found
493  end
494
495  ##
496  # when a relation's tag is modified then it should put the bounding
497  # box of all its members into the changeset.
498  def test_tag_modify_bounding_box
499    # in current fixtures, relation 5 contains nodes 3 and 5 (node 3
500    # indirectly via way 3), so the bbox should be [3,3,5,5].
501    check_changeset_modify([3,3,5,5]) do |changeset_id|
502      # add a tag to an existing relation
503      relation_xml = current_relations(:visible_relation).to_xml
504      relation_element = relation_xml.find("//osm/relation").first
505      new_tag = XML::Node.new("tag")
506      new_tag['k'] = "some_new_tag"
507      new_tag['v'] = "some_new_value"
508      relation_element << new_tag
509     
510      # update changeset ID to point to new changeset
511      update_changeset(relation_xml, changeset_id)
512     
513      # upload the change
514      content relation_xml
515      put :update, :id => current_relations(:visible_relation).id
516      assert_response :success, "can't update relation for tag/bbox test"
517    end
518  end
519
520  ##
521  # add a member to a relation and check the bounding box is only that
522  # element.
523  def test_add_member_bounding_box
524    check_changeset_modify([4,4,4,4]) do |changeset_id|
525      # add node 4 (4,4) to an existing relation
526      relation_xml = current_relations(:visible_relation).to_xml
527      relation_element = relation_xml.find("//osm/relation").first
528      new_member = XML::Node.new("member")
529      new_member['ref'] = current_nodes(:used_node_2).id.to_s
530      new_member['type'] = "node"
531      new_member['role'] = "some_role"
532      relation_element << new_member
533     
534      # update changeset ID to point to new changeset
535      update_changeset(relation_xml, changeset_id)
536     
537      # upload the change
538      content relation_xml
539      put :update, :id => current_relations(:visible_relation).id
540      assert_response :success, "can't update relation for add node/bbox test"
541    end
542  end
543 
544  ##
545  # remove a member from a relation and check the bounding box is
546  # only that element.
547  def test_remove_member_bounding_box
548    check_changeset_modify([5,5,5,5]) do |changeset_id|
549      # remove node 5 (5,5) from an existing relation
550      relation_xml = current_relations(:visible_relation).to_xml
551      relation_xml.
552        find("//osm/relation/member[@type='node'][@ref='5']").
553        first.remove!
554     
555      # update changeset ID to point to new changeset
556      update_changeset(relation_xml, changeset_id)
557     
558      # upload the change
559      content relation_xml
560      put :update, :id => current_relations(:visible_relation).id
561      assert_response :success, "can't update relation for remove node/bbox test"
562    end
563  end
564 
565  ##
566  # check that relations are ordered
567  def test_relation_member_ordering
568    basic_authorization(users(:public_user).email, "test")
569   
570    doc_str = <<OSM
571<osm>
572 <relation changeset='4'>
573  <member ref='1' type='node' role='first'/>
574  <member ref='3' type='node' role='second'/>
575  <member ref='1' type='way' role='third'/>
576  <member ref='3' type='way' role='fourth'/>
577 </relation>
578</osm>
579OSM
580    doc = XML::Parser.string(doc_str).parse
581
582    content doc
583    put :create
584    assert_response :success, "can't create a relation: #{@response.body}"
585    relation_id = @response.body.to_i
586
587    # get it back and check the ordering
588    get :read, :id => relation_id
589    assert_response :success, "can't read back the relation: #{@response.body}"
590    check_ordering(doc, @response.body)
591
592    # insert a member at the front
593    new_member = XML::Node.new "member"
594    new_member['ref'] = 5.to_s
595    new_member['type'] = 'node'
596    new_member['role'] = 'new first'
597    doc.find("//osm/relation").first.child.prev = new_member
598    # update the version, should be 1?
599    doc.find("//osm/relation").first['id'] = relation_id.to_s
600    doc.find("//osm/relation").first['version'] = 1.to_s
601
602    # upload the next version of the relation
603    content doc
604    put :update, :id => relation_id
605    assert_response :success, "can't update relation: #{@response.body}"
606    new_version = @response.body.to_i
607
608    # get it back again and check the ordering again
609    get :read, :id => relation_id
610    assert_response :success, "can't read back the relation: #{@response.body}"
611    check_ordering(doc, @response.body)
612  end
613
614  ##
615  # check that relations can contain duplicate members
616  def test_relation_member_duplicates
617    ## First try with the private user
618    basic_authorization(users(:normal_user).email, "test"); 
619
620    doc_str = <<OSM
621<osm>
622 <relation changeset='4'>
623  <member ref='1' type='node' role='forward'/>
624  <member ref='3' type='node' role='forward'/>
625  <member ref='1' type='node' role='forward'/>
626  <member ref='3' type='node' role='forward'/>
627 </relation>
628</osm>
629OSM
630    doc = XML::Parser.string(doc_str).parse
631
632    content doc
633    put :create
634    assert_response :forbidden
635
636
637    ## Now try with the public user
638    basic_authorization(users(:public_user).email, "test"); 
639
640    doc_str = <<OSM
641<osm>
642 <relation changeset='4'>
643  <member ref='1' type='node' role='forward'/>
644  <member ref='3' type='node' role='forward'/>
645  <member ref='1' type='node' role='forward'/>
646  <member ref='3' type='node' role='forward'/>
647 </relation>
648</osm>
649OSM
650    doc = XML::Parser.string(doc_str).parse
651
652    content doc
653    put :create
654    assert_response :success, "can't create a relation: #{@response.body}"
655    relation_id = @response.body.to_i
656
657    # get it back and check the ordering
658    get :read, :id => relation_id
659    assert_response :success, "can't read back the relation: #{@response.body}"
660    check_ordering(doc, @response.body)
661  end
662
663  # ============================================================
664  # utility functions
665  # ============================================================
666
667  ##
668  # checks that the XML document and the string arguments have
669  # members in the same order.
670  def check_ordering(doc, xml)
671    new_doc = XML::Parser.string(xml).parse
672
673    doc_members = doc.find("//osm/relation/member").collect do |m|
674      [m['ref'].to_i, m['type'].to_sym, m['role']]
675    end
676
677    new_members = new_doc.find("//osm/relation/member").collect do |m|
678      [m['ref'].to_i, m['type'].to_sym, m['role']]
679    end
680
681    doc_members.zip(new_members).each do |d, n|
682      assert_equal d, n, "members are not equal - ordering is wrong? (#{doc}, #{xml})"
683    end
684  end
685
686  ##
687  # create a changeset and yield to the caller to set it up, then assert
688  # that the changeset bounding box is +bbox+.
689  def check_changeset_modify(bbox)
690    ## First test with the private user to check that you get a forbidden
691    basic_authorization(users(:normal_user).email, "test"); 
692
693    # create a new changeset for this operation, so we are assured
694    # that the bounding box will be newly-generated.
695    changeset_id = with_controller(ChangesetController.new) do
696      content "<osm><changeset/></osm>"
697      put :create
698      assert_response :forbidden, "shouldn't be able to create changeset for modify test, as should get forbidden"
699    end
700
701   
702    ## Now do the whole thing with the public user
703    basic_authorization(users(:public_user).email, "test")
704   
705    # create a new changeset for this operation, so we are assured
706    # that the bounding box will be newly-generated.
707    changeset_id = with_controller(ChangesetController.new) do
708      content "<osm><changeset/></osm>"
709      put :create
710      assert_response :success, "couldn't create changeset for modify test"
711      @response.body.to_i
712    end
713
714    # go back to the block to do the actual modifies
715    yield changeset_id
716
717    # now download the changeset to check its bounding box
718    with_controller(ChangesetController.new) do
719      get :read, :id => changeset_id
720      assert_response :success, "can't re-read changeset for modify test"
721      assert_select "osm>changeset", 1
722      assert_select "osm>changeset[id=#{changeset_id}]", 1
723      assert_select "osm>changeset[min_lon=#{bbox[0].to_f}]", 1
724      assert_select "osm>changeset[min_lat=#{bbox[1].to_f}]", 1
725      assert_select "osm>changeset[max_lon=#{bbox[2].to_f}]", 1
726      assert_select "osm>changeset[max_lat=#{bbox[3].to_f}]", 1
727    end
728  end
729
730  ##
731  # yields the relation with the given +id+ (and optional +version+
732  # to read from the history tables) into the block. the parsed XML
733  # doc is returned.
734  def with_relation(id, ver = nil)
735    if ver.nil?
736      get :read, :id => id
737    else
738      with_controller(OldRelationController.new) do
739        get :version, :id => id, :version => ver
740      end
741    end
742    assert_response :success
743    yield xml_parse(@response.body)
744  end
745
746  ##
747  # updates the relation (XML) +rel+ and
748  # yields the new version of that relation into the block.
749  # the parsed XML doc is retured.
750  def with_update(rel)
751    rel_id = rel.find("//osm/relation").first["id"].to_i
752    content rel
753    put :update, :id => rel_id
754    assert_response :success, "can't update relation: #{@response.body}"
755    version = @response.body.to_i
756
757    # now get the new version
758    get :read, :id => rel_id
759    assert_response :success
760    new_rel = xml_parse(@response.body)
761
762    yield new_rel
763
764    return version
765  end
766
767  ##
768  # updates the relation (XML) +rel+ via the diff-upload API and
769  # yields the new version of that relation into the block.
770  # the parsed XML doc is retured.
771  def with_update_diff(rel)
772    rel_id = rel.find("//osm/relation").first["id"].to_i
773    cs_id = rel.find("//osm/relation").first['changeset'].to_i
774    version = nil
775
776    with_controller(ChangesetController.new) do
777      doc = OSM::API.new.get_xml_doc
778      change = XML::Node.new 'osmChange'
779      doc.root = change
780      modify = XML::Node.new 'modify'
781      change << modify
782      modify << doc.import(rel.find("//osm/relation").first)
783
784      content doc.to_s
785      post :upload, :id => cs_id
786      assert_response :success, "can't upload diff relation: #{@response.body}"
787      version = xml_parse(@response.body).find("//diffResult/relation").first["new_version"].to_i
788    end     
789   
790    # now get the new version
791    get :read, :id => rel_id
792    assert_response :success
793    new_rel = xml_parse(@response.body)
794   
795    yield new_rel
796   
797    return version
798  end
799
800  ##
801  # returns a k->v hash of tags from an xml doc
802  def get_tags_as_hash(a) 
803    a.find("//osm/relation/tag").inject({}) do |h,v|
804      h[v['k']] = v['v']
805      h
806    end
807  end
808 
809  ##
810  # assert that all tags on relation documents +a+ and +b+
811  # are equal
812  def assert_tags_equal(a, b)
813    # turn the XML doc into tags hashes
814    a_tags = get_tags_as_hash(a)
815    b_tags = get_tags_as_hash(b)
816
817    assert_equal a_tags.keys, b_tags.keys, "Tag keys should be identical."
818    a_tags.each do |k, v|
819      assert_equal v, b_tags[k], 
820        "Tags which were not altered should be the same. " +
821        "#{a_tags.inspect} != #{b_tags.inspect}"
822    end
823  end
824
825  ##
826  # update the changeset_id of a node element
827  def update_changeset(xml, changeset_id)
828    xml_attr_rewrite(xml, 'changeset', changeset_id)
829  end
830
831  ##
832  # update an attribute in the node element
833  def xml_attr_rewrite(xml, name, value)
834    xml.find("//osm/relation").first[name] = value.to_s
835    return xml
836  end
837
838  ##
839  # parse some xml
840  def xml_parse(xml)
841    parser = XML::Parser.string(xml)
842    parser.parse
843  end
844end
Note: See TracBrowser for help on using the repository browser.