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

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

Fixing the create relation test, which now also tests to make sure that private users cannot edit.

File size: 30.2 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  def test_update_relation_tags
273    basic_authorization "test@example.com", "test"
274    rel_id = current_relations(:multi_tag_relation).id
275    cs_id = changesets(:public_user_first_change).id
276
277    with_relation(rel_id) do |rel|
278      # alter one of the tags
279      tag = rel.find("//osm/relation/tag").first
280      tag['v'] = 'some changed value'
281      update_changeset(rel, cs_id)
282
283      # check that the downloaded tags are the same as the uploaded tags...
284      new_version = with_update(rel) do |new_rel|
285        assert_tags_equal rel, new_rel
286      end
287
288      # check the original one in the current_* table again
289      with_relation(rel_id) { |r| assert_tags_equal rel, r }
290
291      # now check the version in the history
292      with_relation(rel_id, new_version) { |r| assert_tags_equal rel, r }
293    end
294  end
295
296  ##
297  # test that, when tags are updated on a relation when using the diff
298  # upload function, the correct things happen to the correct tables
299  # and the API gives sensible results. this is to test a case that
300  # gregory marler noticed and posted to josm-dev.
301  def test_update_relation_tags_via_upload
302    basic_authorization "test@example.com", "test"
303    rel_id = current_relations(:multi_tag_relation).id
304    cs_id = changesets(:public_user_first_change).id
305
306    with_relation(rel_id) do |rel|
307      # alter one of the tags
308      tag = rel.find("//osm/relation/tag").first
309      tag['v'] = 'some changed value'
310      update_changeset(rel, cs_id)
311
312      # check that the downloaded tags are the same as the uploaded tags...
313      new_version = with_update_diff(rel) do |new_rel|
314        assert_tags_equal rel, new_rel
315      end
316
317      # check the original one in the current_* table again
318      with_relation(rel_id) { |r| assert_tags_equal rel, r }
319
320      # now check the version in the history
321      with_relation(rel_id, new_version) { |r| assert_tags_equal rel, r }
322    end
323  end
324
325  # -------------------------------------
326  # Test creating some invalid relations.
327  # -------------------------------------
328
329  def test_create_invalid
330    basic_authorization "test@openstreetmap.org", "test"
331
332    # put the relation in a dummy fixture changset
333    changeset_id = changesets(:normal_user_first_change).id
334
335    # create a relation with non-existing node as member
336    content "<osm><relation changeset='#{changeset_id}'>" +
337      "<member type='node' ref='0'/><tag k='test' v='yes' />" +
338      "</relation></osm>"
339    put :create
340    # expect failure
341    assert_response :precondition_failed, 
342        "relation upload with invalid node did not return 'precondition failed'"
343  end
344
345  # -------------------------------------
346  # Test creating a relation, with some invalid XML
347  # -------------------------------------
348  def test_create_invalid_xml
349    basic_authorization "test@openstreetmap.org", "test"
350   
351    # put the relation in a dummy fixture changeset that works
352    changeset_id = changesets(:normal_user_first_change).id
353   
354    # create some xml that should return an error
355    content "<osm><relation changeset='#{changeset_id}'>" +
356    "<member type='type' ref='#{current_nodes(:used_node_1).id}' role=''/>" +
357    "<tag k='tester' v='yep'/></relation></osm>"
358    put :create
359    # expect failure
360    assert_response :bad_request
361    assert_match(/Cannot parse valid relation from xml string/, @response.body)
362    assert_match(/The type is not allowed only, /, @response.body)
363  end
364 
365 
366  # -------------------------------------
367  # Test deleting relations.
368  # -------------------------------------
369 
370  def test_delete
371    # first try to delete relation without auth
372    delete :delete, :id => current_relations(:visible_relation).id
373    assert_response :unauthorized
374   
375    ## First try with the private user, to make sure that you get a forbidden
376    basic_authorization(users(:normal_user).email, "test")
377   
378    # this shouldn't work, as we should need the payload...
379    delete :delete, :id => current_relations(:visible_relation).id
380    assert_response :forbidden
381
382    # try to delete without specifying a changeset
383    content "<osm><relation id='#{current_relations(:visible_relation).id}'/></osm>"
384    delete :delete, :id => current_relations(:visible_relation).id
385    assert_response :forbidden
386
387    # try to delete with an invalid (closed) changeset
388    content update_changeset(current_relations(:visible_relation).to_xml,
389                             changesets(:normal_user_closed_change).id)
390    delete :delete, :id => current_relations(:visible_relation).id
391    assert_response :forbidden
392
393    # try to delete with an invalid (non-existent) changeset
394    content update_changeset(current_relations(:visible_relation).to_xml,0)
395    delete :delete, :id => current_relations(:visible_relation).id
396    assert_response :forbidden
397
398    # this won't work because the relation is in-use by another relation
399    content(relations(:used_relation).to_xml)
400    delete :delete, :id => current_relations(:used_relation).id
401    assert_response :forbidden
402
403    # this should work when we provide the appropriate payload...
404    content(relations(:visible_relation).to_xml)
405    delete :delete, :id => current_relations(:visible_relation).id
406    assert_response :forbidden
407
408    # this won't work since the relation is already deleted
409    content(relations(:invisible_relation).to_xml)
410    delete :delete, :id => current_relations(:invisible_relation).id
411    assert_response :forbidden
412
413    # this works now because the relation which was using this one
414    # has been deleted.
415    content(relations(:used_relation).to_xml)
416    delete :delete, :id => current_relations(:used_relation).id
417    assert_response :forbidden
418
419    # this won't work since the relation never existed
420    delete :delete, :id => 0
421    assert_response :forbidden
422
423   
424
425    # now set auth for the private user
426    basic_authorization(users(:public_user).email, "test"); 
427
428    # this shouldn't work, as we should need the payload...
429    delete :delete, :id => current_relations(:visible_relation).id
430    assert_response :bad_request
431
432    # try to delete without specifying a changeset
433    content "<osm><relation id='#{current_relations(:visible_relation).id}'/></osm>"
434    delete :delete, :id => current_relations(:visible_relation).id
435    assert_response :bad_request
436    assert_match(/You are missing the required changeset in the relation/, @response.body)
437
438    # try to delete with an invalid (closed) changeset
439    content update_changeset(current_relations(:visible_relation).to_xml,
440                             changesets(:normal_user_closed_change).id)
441    delete :delete, :id => current_relations(:visible_relation).id
442    assert_response :conflict
443
444    # try to delete with an invalid (non-existent) changeset
445    content update_changeset(current_relations(:visible_relation).to_xml,0)
446    delete :delete, :id => current_relations(:visible_relation).id
447    assert_response :conflict
448
449    # this won't work because the relation is in a changeset owned by someone else
450    content(relations(:used_relation).to_xml)
451    delete :delete, :id => current_relations(:used_relation).id
452    assert_response :conflict, 
453    "shouldn't be able to delete a relation in a changeset owned by someone else (#{@response.body})"
454
455    # this won't work because the relation in the payload is different to that passed
456    content(relations(:public_used_relation).to_xml)
457    delete :delete, :id => current_relations(:used_relation).id
458    assert_not_equal relations(:public_used_relation).id, current_relations(:used_relation).id
459    assert_response :bad_request, "shouldn't be able to delete a relation when payload is different to the url"
460   
461    # this won't work because the relation is in-use by another relation
462    content(relations(:public_used_relation).to_xml)
463    delete :delete, :id => current_relations(:public_used_relation).id
464    assert_response :precondition_failed, 
465       "shouldn't be able to delete a relation used in a relation (#{@response.body})"
466
467    # this should work when we provide the appropriate payload...
468    content(relations(:multi_tag_relation).to_xml)
469    delete :delete, :id => current_relations(:multi_tag_relation).id
470    assert_response :success
471
472    # valid delete should return the new version number, which should
473    # be greater than the old version number
474    assert @response.body.to_i > current_relations(:visible_relation).version,
475       "delete request should return a new version number for relation"
476
477    # this won't work since the relation is already deleted
478    content(relations(:invisible_relation).to_xml)
479    delete :delete, :id => current_relations(:invisible_relation).id
480    assert_response :gone
481
482    # this works now because the relation which was using this one
483    # has been deleted.
484    content(relations(:public_used_relation).to_xml)
485    delete :delete, :id => current_relations(:public_used_relation).id
486    assert_response :success, 
487       "should be able to delete a relation used in an old relation (#{@response.body})"
488
489    # this won't work since the relation never existed
490    delete :delete, :id => 0
491    assert_response :not_found
492  end
493
494  ##
495  # when a relation's tag is modified then it should put the bounding
496  # box of all its members into the changeset.
497  def test_tag_modify_bounding_box
498    # in current fixtures, relation 5 contains nodes 3 and 5 (node 3
499    # indirectly via way 3), so the bbox should be [3,3,5,5].
500    check_changeset_modify([3,3,5,5]) do |changeset_id|
501      # add a tag to an existing relation
502      relation_xml = current_relations(:visible_relation).to_xml
503      relation_element = relation_xml.find("//osm/relation").first
504      new_tag = XML::Node.new("tag")
505      new_tag['k'] = "some_new_tag"
506      new_tag['v'] = "some_new_value"
507      relation_element << new_tag
508     
509      # update changeset ID to point to new changeset
510      update_changeset(relation_xml, changeset_id)
511     
512      # upload the change
513      content relation_xml
514      put :update, :id => current_relations(:visible_relation).id
515      assert_response :success, "can't update relation for tag/bbox test"
516    end
517  end
518
519  ##
520  # add a member to a relation and check the bounding box is only that
521  # element.
522  def test_add_member_bounding_box
523    check_changeset_modify([4,4,4,4]) do |changeset_id|
524      # add node 4 (4,4) to an existing relation
525      relation_xml = current_relations(:visible_relation).to_xml
526      relation_element = relation_xml.find("//osm/relation").first
527      new_member = XML::Node.new("member")
528      new_member['ref'] = current_nodes(:used_node_2).id.to_s
529      new_member['type'] = "node"
530      new_member['role'] = "some_role"
531      relation_element << new_member
532     
533      # update changeset ID to point to new changeset
534      update_changeset(relation_xml, changeset_id)
535     
536      # upload the change
537      content relation_xml
538      put :update, :id => current_relations(:visible_relation).id
539      assert_response :success, "can't update relation for add node/bbox test"
540    end
541  end
542 
543  ##
544  # remove a member from a relation and check the bounding box is
545  # only that element.
546  def test_remove_member_bounding_box
547    check_changeset_modify([5,5,5,5]) do |changeset_id|
548      # remove node 5 (5,5) from an existing relation
549      relation_xml = current_relations(:visible_relation).to_xml
550      relation_xml.
551        find("//osm/relation/member[@type='node'][@ref='5']").
552        first.remove!
553     
554      # update changeset ID to point to new changeset
555      update_changeset(relation_xml, changeset_id)
556     
557      # upload the change
558      content relation_xml
559      put :update, :id => current_relations(:visible_relation).id
560      assert_response :success, "can't update relation for remove node/bbox test"
561    end
562  end
563 
564  ##
565  # check that relations are ordered
566  def test_relation_member_ordering
567    basic_authorization(users(:public_user).email, "test")
568   
569    doc_str = <<OSM
570<osm>
571 <relation changeset='4'>
572  <member ref='1' type='node' role='first'/>
573  <member ref='3' type='node' role='second'/>
574  <member ref='1' type='way' role='third'/>
575  <member ref='3' type='way' role='fourth'/>
576 </relation>
577</osm>
578OSM
579    doc = XML::Parser.string(doc_str).parse
580
581    content doc
582    put :create
583    assert_response :success, "can't create a relation: #{@response.body}"
584    relation_id = @response.body.to_i
585
586    # get it back and check the ordering
587    get :read, :id => relation_id
588    assert_response :success, "can't read back the relation: #{@response.body}"
589    check_ordering(doc, @response.body)
590
591    # insert a member at the front
592    new_member = XML::Node.new "member"
593    new_member['ref'] = 5.to_s
594    new_member['type'] = 'node'
595    new_member['role'] = 'new first'
596    doc.find("//osm/relation").first.child.prev = new_member
597    # update the version, should be 1?
598    doc.find("//osm/relation").first['id'] = relation_id.to_s
599    doc.find("//osm/relation").first['version'] = 1.to_s
600
601    # upload the next version of the relation
602    content doc
603    put :update, :id => relation_id
604    assert_response :success, "can't update relation: #{@response.body}"
605    new_version = @response.body.to_i
606
607    # get it back again and check the ordering again
608    get :read, :id => relation_id
609    assert_response :success, "can't read back the relation: #{@response.body}"
610    check_ordering(doc, @response.body)
611  end
612
613  ##
614  # check that relations can contain duplicate members
615  def test_relation_member_duplicates
616    ## First try with the private user
617    basic_authorization(users(:normal_user).email, "test"); 
618
619    doc_str = <<OSM
620<osm>
621 <relation changeset='4'>
622  <member ref='1' type='node' role='forward'/>
623  <member ref='3' type='node' role='forward'/>
624  <member ref='1' type='node' role='forward'/>
625  <member ref='3' type='node' role='forward'/>
626 </relation>
627</osm>
628OSM
629    doc = XML::Parser.string(doc_str).parse
630
631    content doc
632    put :create
633    assert_response :forbidden
634
635
636    ## Now try with the public user
637    basic_authorization(users(:public_user).email, "test"); 
638
639    doc_str = <<OSM
640<osm>
641 <relation changeset='4'>
642  <member ref='1' type='node' role='forward'/>
643  <member ref='3' type='node' role='forward'/>
644  <member ref='1' type='node' role='forward'/>
645  <member ref='3' type='node' role='forward'/>
646 </relation>
647</osm>
648OSM
649    doc = XML::Parser.string(doc_str).parse
650
651    content doc
652    put :create
653    assert_response :success, "can't create a relation: #{@response.body}"
654    relation_id = @response.body.to_i
655
656    # get it back and check the ordering
657    get :read, :id => relation_id
658    assert_response :success, "can't read back the relation: #{@response.body}"
659    check_ordering(doc, @response.body)
660  end
661
662  # ============================================================
663  # utility functions
664  # ============================================================
665
666  ##
667  # checks that the XML document and the string arguments have
668  # members in the same order.
669  def check_ordering(doc, xml)
670    new_doc = XML::Parser.string(xml).parse
671
672    doc_members = doc.find("//osm/relation/member").collect do |m|
673      [m['ref'].to_i, m['type'].to_sym, m['role']]
674    end
675
676    new_members = new_doc.find("//osm/relation/member").collect do |m|
677      [m['ref'].to_i, m['type'].to_sym, m['role']]
678    end
679
680    doc_members.zip(new_members).each do |d, n|
681      assert_equal d, n, "members are not equal - ordering is wrong? (#{doc}, #{xml})"
682    end
683  end
684
685  ##
686  # create a changeset and yield to the caller to set it up, then assert
687  # that the changeset bounding box is +bbox+.
688  def check_changeset_modify(bbox)
689    ## First test with the private user to check that you get a forbidden
690    basic_authorization(users(:normal_user).email, "test"); 
691
692    # create a new changeset for this operation, so we are assured
693    # that the bounding box will be newly-generated.
694    changeset_id = with_controller(ChangesetController.new) do
695      content "<osm><changeset/></osm>"
696      put :create
697      assert_response :forbidden, "shouldn't be able to create changeset for modify test, as should get forbidden"
698    end
699
700   
701    ## Now do the whole thing with the public user
702    basic_authorization(users(:public_user).email, "test")
703   
704    # create a new changeset for this operation, so we are assured
705    # that the bounding box will be newly-generated.
706    changeset_id = with_controller(ChangesetController.new) do
707      content "<osm><changeset/></osm>"
708      put :create
709      assert_response :success, "couldn't create changeset for modify test"
710      @response.body.to_i
711    end
712
713    # go back to the block to do the actual modifies
714    yield changeset_id
715
716    # now download the changeset to check its bounding box
717    with_controller(ChangesetController.new) do
718      get :read, :id => changeset_id
719      assert_response :success, "can't re-read changeset for modify test"
720      assert_select "osm>changeset", 1
721      assert_select "osm>changeset[id=#{changeset_id}]", 1
722      assert_select "osm>changeset[min_lon=#{bbox[0].to_f}]", 1
723      assert_select "osm>changeset[min_lat=#{bbox[1].to_f}]", 1
724      assert_select "osm>changeset[max_lon=#{bbox[2].to_f}]", 1
725      assert_select "osm>changeset[max_lat=#{bbox[3].to_f}]", 1
726    end
727  end
728
729  ##
730  # yields the relation with the given +id+ (and optional +version+
731  # to read from the history tables) into the block. the parsed XML
732  # doc is returned.
733  def with_relation(id, ver = nil)
734    if ver.nil?
735      get :read, :id => id
736    else
737      with_controller(OldRelationController.new) do
738        get :version, :id => id, :version => ver
739      end
740    end
741    assert_response :success
742    yield xml_parse(@response.body)
743  end
744
745  ##
746  # updates the relation (XML) +rel+ and
747  # yields the new version of that relation into the block.
748  # the parsed XML doc is retured.
749  def with_update(rel)
750    rel_id = rel.find("//osm/relation").first["id"].to_i
751    content rel
752    put :update, :id => rel_id
753    assert_response :success, "can't update relation: #{@response.body}"
754    version = @response.body.to_i
755
756    # now get the new version
757    get :read, :id => rel_id
758    assert_response :success
759    new_rel = xml_parse(@response.body)
760
761    yield new_rel
762
763    return version
764  end
765
766  ##
767  # updates the relation (XML) +rel+ via the diff-upload API and
768  # yields the new version of that relation into the block.
769  # the parsed XML doc is retured.
770  def with_update_diff(rel)
771    rel_id = rel.find("//osm/relation").first["id"].to_i
772    cs_id = rel.find("//osm/relation").first['changeset'].to_i
773    version = nil
774
775    with_controller(ChangesetController.new) do
776      doc = OSM::API.new.get_xml_doc
777      change = XML::Node.new 'osmChange'
778      doc.root = change
779      modify = XML::Node.new 'modify'
780      change << modify
781      modify << doc.import(rel.find("//osm/relation").first)
782
783      content doc.to_s
784      post :upload, :id => cs_id
785      assert_response :success, "can't upload diff relation: #{@response.body}"
786      version = xml_parse(@response.body).find("//diffResult/relation").first["new_version"].to_i
787    end     
788   
789    # now get the new version
790    get :read, :id => rel_id
791    assert_response :success
792    new_rel = xml_parse(@response.body)
793   
794    yield new_rel
795   
796    return version
797  end
798
799  ##
800  # returns a k->v hash of tags from an xml doc
801  def get_tags_as_hash(a) 
802    a.find("//osm/relation/tag").inject({}) do |h,v|
803      h[v['k']] = v['v']
804      h
805    end
806  end
807 
808  ##
809  # assert that all tags on relation documents +a+ and +b+
810  # are equal
811  def assert_tags_equal(a, b)
812    # turn the XML doc into tags hashes
813    a_tags = get_tags_as_hash(a)
814    b_tags = get_tags_as_hash(b)
815
816    assert_equal a_tags.keys, b_tags.keys, "Tag keys should be identical."
817    a_tags.each do |k, v|
818      assert_equal v, b_tags[k], 
819        "Tags which were not altered should be the same. " +
820        "#{a_tags.inspect} != #{b_tags.inspect}"
821    end
822  end
823
824  ##
825  # update the changeset_id of a node element
826  def update_changeset(xml, changeset_id)
827    xml_attr_rewrite(xml, 'changeset', changeset_id)
828  end
829
830  ##
831  # update an attribute in the node element
832  def xml_attr_rewrite(xml, name, value)
833    xml.find("//osm/relation").first[name] = value.to_s
834    return xml
835  end
836
837  ##
838  # parse some xml
839  def xml_parse(xml)
840    parser = XML::Parser.string(xml)
841    parser.parse
842  end
843end
Note: See TracBrowser for help on using the repository browser.