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

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

fixing some of the relation tests. Some adjustments to the fixtures.

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