3 class RelationsControllerTest < ActionController::TestCase
5 # test all routes which lead to this controller
8 { :path => "/api/0.6/relation/create", :method => :put },
9 { :controller => "relations", :action => "create" }
12 { :path => "/api/0.6/relation/1/full", :method => :get },
13 { :controller => "relations", :action => "full", :id => "1" }
16 { :path => "/api/0.6/relation/1", :method => :get },
17 { :controller => "relations", :action => "read", :id => "1" }
20 { :path => "/api/0.6/relation/1", :method => :put },
21 { :controller => "relations", :action => "update", :id => "1" }
24 { :path => "/api/0.6/relation/1", :method => :delete },
25 { :controller => "relations", :action => "delete", :id => "1" }
28 { :path => "/api/0.6/relations", :method => :get },
29 { :controller => "relations", :action => "relations" }
33 { :path => "/api/0.6/node/1/relations", :method => :get },
34 { :controller => "relations", :action => "relations_for_node", :id => "1" }
37 { :path => "/api/0.6/way/1/relations", :method => :get },
38 { :controller => "relations", :action => "relations_for_way", :id => "1" }
41 { :path => "/api/0.6/relation/1/relations", :method => :get },
42 { :controller => "relations", :action => "relations_for_relation", :id => "1" }
46 # -------------------------------------
47 # Test reading relations.
48 # -------------------------------------
51 # check that a visible relation is returned properly
52 get :read, :params => { :id => create(:relation).id }
53 assert_response :success
55 # check that an invisible relation is not returned
56 get :read, :params => { :id => create(:relation, :deleted).id }
59 # check chat a non-existent relation is not returned
60 get :read, :params => { :id => 0 }
61 assert_response :not_found
65 # check that all relations containing a particular node, and no extra
66 # relations, are returned from the relations_for_node call.
67 def test_relations_for_node
69 # should include relations with that node as a member
70 relation_with_node = create(:relation_member, :member => node).relation
71 # should ignore relations without that node as a member
72 _relation_without_node = create(:relation_member).relation
73 # should ignore relations with the node involved indirectly, via a way
74 way = create(:way_node, :node => node).way
75 _relation_with_way = create(:relation_member, :member => way).relation
76 # should ignore relations with the node involved indirectly, via a relation
77 second_relation = create(:relation_member, :member => node).relation
78 _super_relation = create(:relation_member, :member => second_relation).relation
79 # should combine multiple relation_member references into just one relation entry
80 create(:relation_member, :member => node, :relation => relation_with_node, :sequence_id => 2)
81 # should not include deleted relations
82 deleted_relation = create(:relation, :deleted)
83 create(:relation_member, :member => node, :relation => deleted_relation)
85 check_relations_for_element(:relations_for_node, "node",
87 [relation_with_node, second_relation])
90 def test_relations_for_way
92 # should include relations with that way as a member
93 relation_with_way = create(:relation_member, :member => way).relation
94 # should ignore relations without that way as a member
95 _relation_without_way = create(:relation_member).relation
96 # should ignore relations with the way involved indirectly, via a relation
97 second_relation = create(:relation_member, :member => way).relation
98 _super_relation = create(:relation_member, :member => second_relation).relation
99 # should combine multiple relation_member references into just one relation entry
100 create(:relation_member, :member => way, :relation => relation_with_way, :sequence_id => 2)
101 # should not include deleted relations
102 deleted_relation = create(:relation, :deleted)
103 create(:relation_member, :member => way, :relation => deleted_relation)
105 check_relations_for_element(:relations_for_way, "way",
107 [relation_with_way, second_relation])
110 def test_relations_for_relation
111 relation = create(:relation)
112 # should include relations with that relation as a member
113 relation_with_relation = create(:relation_member, :member => relation).relation
114 # should ignore any relation without that relation as a member
115 _relation_without_relation = create(:relation_member).relation
116 # should ignore relations with the relation involved indirectly, via a relation
117 second_relation = create(:relation_member, :member => relation).relation
118 _super_relation = create(:relation_member, :member => second_relation).relation
119 # should combine multiple relation_member references into just one relation entry
120 create(:relation_member, :member => relation, :relation => relation_with_relation, :sequence_id => 2)
121 # should not include deleted relations
122 deleted_relation = create(:relation, :deleted)
123 create(:relation_member, :member => relation, :relation => deleted_relation)
124 check_relations_for_element(:relations_for_relation, "relation",
126 [relation_with_relation, second_relation])
129 def check_relations_for_element(method, type, id, expected_relations)
130 # check the "relations for relation" mode
131 get method, :params => { :id => id }
132 assert_response :success
134 # count one osm element
135 assert_select "osm[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
137 # we should have only the expected number of relations
138 assert_select "osm>relation", expected_relations.size
140 # and each of them should contain the element we originally searched for
141 expected_relations.each do |relation|
142 # The relation should appear once, but the element could appear multiple times
143 assert_select "osm>relation[id='#{relation.id}']", 1
144 assert_select "osm>relation[id='#{relation.id}']>member[type='#{type}'][ref='#{id}']"
149 # check the "full" mode
150 get :full, :params => { :id => 999999 }
151 assert_response :not_found
153 get :full, :params => { :id => create(:relation, :deleted).id }
154 assert_response :gone
156 get :full, :params => { :id => create(:relation).id }
157 assert_response :success
158 # FIXME: check whether this contains the stuff we want!
162 # test fetching multiple relations
164 relation1 = create(:relation)
165 relation2 = create(:relation, :deleted)
166 relation3 = create(:relation, :with_history, :version => 2)
167 relation4 = create(:relation, :with_history, :version => 2)
168 relation4.old_relations.find_by(:version => 1).redact!(create(:redaction))
170 # check error when no parameter provided
172 assert_response :bad_request
174 # check error when no parameter value provided
175 get :relations, :params => { :relations => "" }
176 assert_response :bad_request
178 # test a working call
179 get :relations, :params => { :relations => "#{relation1.id},#{relation2.id},#{relation3.id},#{relation4.id}" }
180 assert_response :success
181 assert_select "osm" do
182 assert_select "relation", :count => 4
183 assert_select "relation[id='#{relation1.id}'][visible='true']", :count => 1
184 assert_select "relation[id='#{relation2.id}'][visible='false']", :count => 1
185 assert_select "relation[id='#{relation3.id}'][visible='true']", :count => 1
186 assert_select "relation[id='#{relation4.id}'][visible='true']", :count => 1
189 # check error when a non-existent relation is included
190 get :relations, :params => { :relations => "#{relation1.id},#{relation2.id},#{relation3.id},#{relation4.id},0" }
191 assert_response :not_found
194 # -------------------------------------
195 # Test simple relation creation.
196 # -------------------------------------
199 private_user = create(:user, :data_public => false)
200 private_changeset = create(:changeset, :user => private_user)
202 changeset = create(:changeset, :user => user)
204 way = create(:way_with_nodes, :nodes_count => 2)
206 basic_authorization private_user.email, "test"
208 # create an relation without members
209 content "<osm><relation changeset='#{private_changeset.id}'><tag k='test' v='yes' /></relation></osm>"
211 # hope for forbidden, due to user
212 assert_response :forbidden,
213 "relation upload should have failed with forbidden"
216 # create an relation with a node as member
217 # This time try with a role attribute in the relation
218 content "<osm><relation changeset='#{private_changeset.id}'>" \
219 "<member ref='#{node.id}' type='node' role='some'/>" \
220 "<tag k='test' v='yes' /></relation></osm>"
222 # hope for forbidden due to user
223 assert_response :forbidden,
224 "relation upload did not return forbidden status"
227 # create an relation with a node as member, this time test that we don't
228 # need a role attribute to be included
229 content "<osm><relation changeset='#{private_changeset.id}'>" \
230 "<member ref='#{node.id}' type='node'/>" + "<tag k='test' v='yes' /></relation></osm>"
232 # hope for forbidden due to user
233 assert_response :forbidden,
234 "relation upload did not return forbidden status"
237 # create an relation with a way and a node as members
238 content "<osm><relation changeset='#{private_changeset.id}'>" \
239 "<member type='node' ref='#{node.id}' role='some'/>" \
240 "<member type='way' ref='#{way.id}' role='other'/>" \
241 "<tag k='test' v='yes' /></relation></osm>"
243 # hope for forbidden, due to user
244 assert_response :forbidden,
245 "relation upload did not return success status"
247 ## Now try with the public user
248 basic_authorization user.email, "test"
250 # create an relation without members
251 content "<osm><relation changeset='#{changeset.id}'><tag k='test' v='yes' /></relation></osm>"
254 assert_response :success,
255 "relation upload did not return success status"
256 # read id of created relation and search for it
257 relationid = @response.body
258 checkrelation = Relation.find(relationid)
259 assert_not_nil checkrelation,
260 "uploaded relation not found in data base after upload"
262 assert_equal checkrelation.members.length, 0,
263 "saved relation contains members but should not"
264 assert_equal checkrelation.tags.length, 1,
265 "saved relation does not contain exactly one tag"
266 assert_equal changeset.id, checkrelation.changeset.id,
267 "saved relation does not belong in the changeset it was assigned to"
268 assert_equal user.id, checkrelation.changeset.user_id,
269 "saved relation does not belong to user that created it"
270 assert_equal true, checkrelation.visible,
271 "saved relation is not visible"
272 # ok the relation is there but can we also retrieve it?
273 get :read, :params => { :id => relationid }
274 assert_response :success
277 # create an relation with a node as member
278 # This time try with a role attribute in the relation
279 content "<osm><relation changeset='#{changeset.id}'>" \
280 "<member ref='#{node.id}' type='node' role='some'/>" \
281 "<tag k='test' v='yes' /></relation></osm>"
284 assert_response :success,
285 "relation upload did not return success status"
286 # read id of created relation and search for it
287 relationid = @response.body
288 checkrelation = Relation.find(relationid)
289 assert_not_nil checkrelation,
290 "uploaded relation not found in data base after upload"
292 assert_equal checkrelation.members.length, 1,
293 "saved relation does not contain exactly one member"
294 assert_equal checkrelation.tags.length, 1,
295 "saved relation does not contain exactly one tag"
296 assert_equal changeset.id, checkrelation.changeset.id,
297 "saved relation does not belong in the changeset it was assigned to"
298 assert_equal user.id, checkrelation.changeset.user_id,
299 "saved relation does not belong to user that created it"
300 assert_equal true, checkrelation.visible,
301 "saved relation is not visible"
302 # ok the relation is there but can we also retrieve it?
304 get :read, :params => { :id => relationid }
305 assert_response :success
308 # create an relation with a node as member, this time test that we don't
309 # need a role attribute to be included
310 content "<osm><relation changeset='#{changeset.id}'>" \
311 "<member ref='#{node.id}' type='node'/>" + "<tag k='test' v='yes' /></relation></osm>"
314 assert_response :success,
315 "relation upload did not return success status"
316 # read id of created relation and search for it
317 relationid = @response.body
318 checkrelation = Relation.find(relationid)
319 assert_not_nil checkrelation,
320 "uploaded relation not found in data base after upload"
322 assert_equal checkrelation.members.length, 1,
323 "saved relation does not contain exactly one member"
324 assert_equal checkrelation.tags.length, 1,
325 "saved relation does not contain exactly one tag"
326 assert_equal changeset.id, checkrelation.changeset.id,
327 "saved relation does not belong in the changeset it was assigned to"
328 assert_equal user.id, checkrelation.changeset.user_id,
329 "saved relation does not belong to user that created it"
330 assert_equal true, checkrelation.visible,
331 "saved relation is not visible"
332 # ok the relation is there but can we also retrieve it?
334 get :read, :params => { :id => relationid }
335 assert_response :success
338 # create an relation with a way and a node as members
339 content "<osm><relation changeset='#{changeset.id}'>" \
340 "<member type='node' ref='#{node.id}' role='some'/>" \
341 "<member type='way' ref='#{way.id}' role='other'/>" \
342 "<tag k='test' v='yes' /></relation></osm>"
345 assert_response :success,
346 "relation upload did not return success status"
347 # read id of created relation and search for it
348 relationid = @response.body
349 checkrelation = Relation.find(relationid)
350 assert_not_nil checkrelation,
351 "uploaded relation not found in data base after upload"
353 assert_equal checkrelation.members.length, 2,
354 "saved relation does not have exactly two members"
355 assert_equal checkrelation.tags.length, 1,
356 "saved relation does not contain exactly one tag"
357 assert_equal changeset.id, checkrelation.changeset.id,
358 "saved relation does not belong in the changeset it was assigned to"
359 assert_equal user.id, checkrelation.changeset.user_id,
360 "saved relation does not belong to user that created it"
361 assert_equal true, checkrelation.visible,
362 "saved relation is not visible"
363 # ok the relation is there but can we also retrieve it?
364 get :read, :params => { :id => relationid }
365 assert_response :success
368 # ------------------------------------
369 # Test updating relations
370 # ------------------------------------
373 # test that, when tags are updated on a relation, the correct things
374 # happen to the correct tables and the API gives sensible results.
375 # this is to test a case that gregory marler noticed and posted to
377 ## FIXME Move this to an integration test
378 def test_update_relation_tags
380 changeset = create(:changeset, :user => user)
381 relation = create(:relation)
382 create_list(:relation_tag, 4, :relation => relation)
384 basic_authorization user.email, "test"
386 with_relation(relation.id) do |rel|
387 # alter one of the tags
388 tag = rel.find("//osm/relation/tag").first
389 tag["v"] = "some changed value"
390 update_changeset(rel, changeset.id)
392 # check that the downloaded tags are the same as the uploaded tags...
393 new_version = with_update(rel) do |new_rel|
394 assert_tags_equal rel, new_rel
397 # check the original one in the current_* table again
398 with_relation(relation.id) { |r| assert_tags_equal rel, r }
400 # now check the version in the history
401 with_relation(relation.id, new_version) { |r| assert_tags_equal rel, r }
406 # test that, when tags are updated on a relation when using the diff
407 # upload function, the correct things happen to the correct tables
408 # and the API gives sensible results. this is to test a case that
409 # gregory marler noticed and posted to josm-dev.
410 def test_update_relation_tags_via_upload
412 changeset = create(:changeset, :user => user)
413 relation = create(:relation)
414 create_list(:relation_tag, 4, :relation => relation)
416 basic_authorization user.email, "test"
418 with_relation(relation.id) do |rel|
419 # alter one of the tags
420 tag = rel.find("//osm/relation/tag").first
421 tag["v"] = "some changed value"
422 update_changeset(rel, changeset.id)
424 # check that the downloaded tags are the same as the uploaded tags...
425 new_version = with_update_diff(rel) do |new_rel|
426 assert_tags_equal rel, new_rel
429 # check the original one in the current_* table again
430 with_relation(relation.id) { |r| assert_tags_equal rel, r }
432 # now check the version in the history
433 with_relation(relation.id, new_version) { |r| assert_tags_equal rel, r }
437 def test_update_wrong_id
439 changeset = create(:changeset, :user => user)
440 relation = create(:relation)
441 other_relation = create(:relation)
443 basic_authorization user.email, "test"
444 with_relation(relation.id) do |rel|
445 update_changeset(rel, changeset.id)
447 put :update, :params => { :id => other_relation.id }
448 assert_response :bad_request
452 # -------------------------------------
453 # Test creating some invalid relations.
454 # -------------------------------------
456 def test_create_invalid
458 changeset = create(:changeset, :user => user)
460 basic_authorization user.email, "test"
462 # create a relation with non-existing node as member
463 content "<osm><relation changeset='#{changeset.id}'>" \
464 "<member type='node' ref='0'/><tag k='test' v='yes' />" \
468 assert_response :precondition_failed,
469 "relation upload with invalid node did not return 'precondition failed'"
470 assert_equal "Precondition failed: Relation with id cannot be saved due to Node with id 0", @response.body
473 # -------------------------------------
474 # Test creating a relation, with some invalid XML
475 # -------------------------------------
476 def test_create_invalid_xml
478 changeset = create(:changeset, :user => user)
481 basic_authorization user.email, "test"
483 # create some xml that should return an error
484 content "<osm><relation changeset='#{changeset.id}'>" \
485 "<member type='type' ref='#{node.id}' role=''/>" \
486 "<tag k='tester' v='yep'/></relation></osm>"
489 assert_response :bad_request
490 assert_match(/Cannot parse valid relation from xml string/, @response.body)
491 assert_match(/The type is not allowed only, /, @response.body)
494 # -------------------------------------
495 # Test deleting relations.
496 # -------------------------------------
499 private_user = create(:user, :data_public => false)
500 private_user_closed_changeset = create(:changeset, :closed, :user => private_user)
502 closed_changeset = create(:changeset, :closed, :user => user)
503 changeset = create(:changeset, :user => user)
504 relation = create(:relation)
505 used_relation = create(:relation)
506 super_relation = create(:relation_member, :member => used_relation).relation
507 deleted_relation = create(:relation, :deleted)
508 multi_tag_relation = create(:relation)
509 create_list(:relation_tag, 4, :relation => multi_tag_relation)
511 ## First try to delete relation without auth
512 delete :delete, :params => { :id => relation.id }
513 assert_response :unauthorized
515 ## Then try with the private user, to make sure that you get a forbidden
516 basic_authorization private_user.email, "test"
518 # this shouldn't work, as we should need the payload...
519 delete :delete, :params => { :id => relation.id }
520 assert_response :forbidden
522 # try to delete without specifying a changeset
523 content "<osm><relation id='#{relation.id}'/></osm>"
524 delete :delete, :params => { :id => relation.id }
525 assert_response :forbidden
527 # try to delete with an invalid (closed) changeset
528 content update_changeset(relation.to_xml,
529 private_user_closed_changeset.id)
530 delete :delete, :params => { :id => relation.id }
531 assert_response :forbidden
533 # try to delete with an invalid (non-existent) changeset
534 content update_changeset(relation.to_xml, 0)
535 delete :delete, :params => { :id => relation.id }
536 assert_response :forbidden
538 # this won't work because the relation is in-use by another relation
539 content(used_relation.to_xml)
540 delete :delete, :params => { :id => used_relation.id }
541 assert_response :forbidden
543 # this should work when we provide the appropriate payload...
544 content(relation.to_xml)
545 delete :delete, :params => { :id => relation.id }
546 assert_response :forbidden
548 # this won't work since the relation is already deleted
549 content(deleted_relation.to_xml)
550 delete :delete, :params => { :id => deleted_relation.id }
551 assert_response :forbidden
553 # this won't work since the relation never existed
554 delete :delete, :params => { :id => 0 }
555 assert_response :forbidden
557 ## now set auth for the public user
558 basic_authorization user.email, "test"
560 # this shouldn't work, as we should need the payload...
561 delete :delete, :params => { :id => relation.id }
562 assert_response :bad_request
564 # try to delete without specifying a changeset
565 content "<osm><relation id='#{relation.id}' version='#{relation.version}' /></osm>"
566 delete :delete, :params => { :id => relation.id }
567 assert_response :bad_request
568 assert_match(/Changeset id is missing/, @response.body)
570 # try to delete with an invalid (closed) changeset
571 content update_changeset(relation.to_xml,
573 delete :delete, :params => { :id => relation.id }
574 assert_response :conflict
576 # try to delete with an invalid (non-existent) changeset
577 content update_changeset(relation.to_xml, 0)
578 delete :delete, :params => { :id => relation.id }
579 assert_response :conflict
581 # this won't work because the relation is in a changeset owned by someone else
582 content update_changeset(relation.to_xml, create(:changeset).id)
583 delete :delete, :params => { :id => relation.id }
584 assert_response :conflict,
585 "shouldn't be able to delete a relation in a changeset owned by someone else (#{@response.body})"
587 # this won't work because the relation in the payload is different to that passed
588 content update_changeset(relation.to_xml, changeset.id)
589 delete :delete, :params => { :id => create(:relation).id }
590 assert_response :bad_request, "shouldn't be able to delete a relation when payload is different to the url"
592 # this won't work because the relation is in-use by another relation
593 content update_changeset(used_relation.to_xml, changeset.id)
594 delete :delete, :params => { :id => used_relation.id }
595 assert_response :precondition_failed,
596 "shouldn't be able to delete a relation used in a relation (#{@response.body})"
597 assert_equal "Precondition failed: The relation #{used_relation.id} is used in relation #{super_relation.id}.", @response.body
599 # this should work when we provide the appropriate payload...
600 content update_changeset(multi_tag_relation.to_xml, changeset.id)
601 delete :delete, :params => { :id => multi_tag_relation.id }
602 assert_response :success
604 # valid delete should return the new version number, which should
605 # be greater than the old version number
606 assert @response.body.to_i > multi_tag_relation.version,
607 "delete request should return a new version number for relation"
609 # this won't work since the relation is already deleted
610 content update_changeset(deleted_relation.to_xml, changeset.id)
611 delete :delete, :params => { :id => deleted_relation.id }
612 assert_response :gone
614 # Public visible relation needs to be deleted
615 content update_changeset(super_relation.to_xml, changeset.id)
616 delete :delete, :params => { :id => super_relation.id }
617 assert_response :success
619 # this works now because the relation which was using this one
621 content update_changeset(used_relation.to_xml, changeset.id)
622 delete :delete, :params => { :id => used_relation.id }
623 assert_response :success,
624 "should be able to delete a relation used in an old relation (#{@response.body})"
626 # this won't work since the relation never existed
627 delete :delete, :params => { :id => 0 }
628 assert_response :not_found
632 # when a relation's tag is modified then it should put the bounding
633 # box of all its members into the changeset.
634 def test_tag_modify_bounding_box
635 relation = create(:relation)
636 node1 = create(:node, :lat => 3, :lon => 3)
637 node2 = create(:node, :lat => 5, :lon => 5)
639 create(:way_node, :way => way, :node => node1)
640 create(:relation_member, :relation => relation, :member => way)
641 create(:relation_member, :relation => relation, :member => node2)
642 # the relation contains nodes1 and node2 (node1
643 # indirectly via the way), so the bbox should be [3,3,5,5].
644 check_changeset_modify(BoundingBox.new(3, 3, 5, 5)) do |changeset_id|
645 # add a tag to an existing relation
646 relation_xml = relation.to_xml
647 relation_element = relation_xml.find("//osm/relation").first
648 new_tag = XML::Node.new("tag")
649 new_tag["k"] = "some_new_tag"
650 new_tag["v"] = "some_new_value"
651 relation_element << new_tag
653 # update changeset ID to point to new changeset
654 update_changeset(relation_xml, changeset_id)
658 put :update, :params => { :id => relation.id }
659 assert_response :success, "can't update relation for tag/bbox test"
664 # add a member to a relation and check the bounding box is only that
666 def test_add_member_bounding_box
667 relation = create(:relation)
668 node1 = create(:node, :lat => 4, :lon => 4)
669 node2 = create(:node, :lat => 7, :lon => 7)
671 create(:way_node, :way => way1, :node => create(:node, :lat => 8, :lon => 8))
673 create(:way_node, :way => way2, :node => create(:node, :lat => 9, :lon => 9), :sequence_id => 1)
674 create(:way_node, :way => way2, :node => create(:node, :lat => 10, :lon => 10), :sequence_id => 2)
676 [node1, node2, way1, way2].each do |element|
677 bbox = element.bbox.to_unscaled
678 check_changeset_modify(bbox) do |changeset_id|
679 relation_xml = Relation.find(relation.id).to_xml
680 relation_element = relation_xml.find("//osm/relation").first
681 new_member = XML::Node.new("member")
682 new_member["ref"] = element.id.to_s
683 new_member["type"] = element.class.to_s.downcase
684 new_member["role"] = "some_role"
685 relation_element << new_member
687 # update changeset ID to point to new changeset
688 update_changeset(relation_xml, changeset_id)
692 put :update, :params => { :id => relation.id }
693 assert_response :success, "can't update relation for add #{element.class}/bbox test: #{@response.body}"
695 # get it back and check the ordering
696 get :read, :params => { :id => relation.id }
697 assert_response :success, "can't read back the relation: #{@response.body}"
698 check_ordering(relation_xml, @response.body)
704 # remove a member from a relation and check the bounding box is
706 def test_remove_member_bounding_box
707 relation = create(:relation)
708 node1 = create(:node, :lat => 3, :lon => 3)
709 node2 = create(:node, :lat => 5, :lon => 5)
710 create(:relation_member, :relation => relation, :member => node1)
711 create(:relation_member, :relation => relation, :member => node2)
713 check_changeset_modify(BoundingBox.new(5, 5, 5, 5)) do |changeset_id|
714 # remove node 5 (5,5) from an existing relation
715 relation_xml = relation.to_xml
717 .find("//osm/relation/member[@type='node'][@ref='#{node2.id}']")
720 # update changeset ID to point to new changeset
721 update_changeset(relation_xml, changeset_id)
725 put :update, :params => { :id => relation.id }
726 assert_response :success, "can't update relation for remove node/bbox test"
731 # check that relations are ordered
732 def test_relation_member_ordering
734 changeset = create(:changeset, :user => user)
735 node1 = create(:node)
736 node2 = create(:node)
737 node3 = create(:node)
738 way1 = create(:way_with_nodes, :nodes_count => 2)
739 way2 = create(:way_with_nodes, :nodes_count => 2)
741 basic_authorization user.email, "test"
743 doc_str = <<OSM.strip_heredoc
745 <relation changeset='#{changeset.id}'>
746 <member ref='#{node1.id}' type='node' role='first'/>
747 <member ref='#{node2.id}' type='node' role='second'/>
748 <member ref='#{way1.id}' type='way' role='third'/>
749 <member ref='#{way2.id}' type='way' role='fourth'/>
753 doc = XML::Parser.string(doc_str).parse
757 assert_response :success, "can't create a relation: #{@response.body}"
758 relation_id = @response.body.to_i
760 # get it back and check the ordering
761 get :read, :params => { :id => relation_id }
762 assert_response :success, "can't read back the relation: #{@response.body}"
763 check_ordering(doc, @response.body)
765 # insert a member at the front
766 new_member = XML::Node.new "member"
767 new_member["ref"] = node3.id.to_s
768 new_member["type"] = "node"
769 new_member["role"] = "new first"
770 doc.find("//osm/relation").first.child.prev = new_member
771 # update the version, should be 1?
772 doc.find("//osm/relation").first["id"] = relation_id.to_s
773 doc.find("//osm/relation").first["version"] = 1.to_s
775 # upload the next version of the relation
777 put :update, :params => { :id => relation_id }
778 assert_response :success, "can't update relation: #{@response.body}"
779 assert_equal 2, @response.body.to_i
781 # get it back again and check the ordering again
782 get :read, :params => { :id => relation_id }
783 assert_response :success, "can't read back the relation: #{@response.body}"
784 check_ordering(doc, @response.body)
786 # check the ordering in the history tables:
787 with_controller(OldRelationsController.new) do
788 get :version, :params => { :id => relation_id, :version => 2 }
789 assert_response :success, "can't read back version 2 of the relation #{relation_id}"
790 check_ordering(doc, @response.body)
795 # check that relations can contain duplicate members
796 def test_relation_member_duplicates
797 private_user = create(:user, :data_public => false)
799 changeset = create(:changeset, :user => user)
800 node1 = create(:node)
801 node2 = create(:node)
803 doc_str = <<OSM.strip_heredoc
805 <relation changeset='#{changeset.id}'>
806 <member ref='#{node1.id}' type='node' role='forward'/>
807 <member ref='#{node2.id}' type='node' role='forward'/>
808 <member ref='#{node1.id}' type='node' role='forward'/>
809 <member ref='#{node2.id}' type='node' role='forward'/>
813 doc = XML::Parser.string(doc_str).parse
815 ## First try with the private user
816 basic_authorization private_user.email, "test"
820 assert_response :forbidden
822 ## Now try with the public user
823 basic_authorization user.email, "test"
827 assert_response :success, "can't create a relation: #{@response.body}"
828 relation_id = @response.body.to_i
830 # get it back and check the ordering
831 get :read, :params => { :id => relation_id }
832 assert_response :success, "can't read back the relation: #{relation_id}"
833 check_ordering(doc, @response.body)
837 # test that the ordering of elements in the history is the same as in current.
838 def test_history_ordering
840 changeset = create(:changeset, :user => user)
841 node1 = create(:node)
842 node2 = create(:node)
843 node3 = create(:node)
844 node4 = create(:node)
846 doc_str = <<OSM.strip_heredoc
848 <relation changeset='#{changeset.id}'>
849 <member ref='#{node1.id}' type='node' role='forward'/>
850 <member ref='#{node4.id}' type='node' role='forward'/>
851 <member ref='#{node3.id}' type='node' role='forward'/>
852 <member ref='#{node2.id}' type='node' role='forward'/>
856 doc = XML::Parser.string(doc_str).parse
857 basic_authorization user.email, "test"
861 assert_response :success, "can't create a relation: #{@response.body}"
862 relation_id = @response.body.to_i
864 # check the ordering in the current tables:
865 get :read, :params => { :id => relation_id }
866 assert_response :success, "can't read back the relation: #{@response.body}"
867 check_ordering(doc, @response.body)
869 # check the ordering in the history tables:
870 with_controller(OldRelationsController.new) do
871 get :version, :params => { :id => relation_id, :version => 1 }
872 assert_response :success, "can't read back version 1 of the relation: #{@response.body}"
873 check_ordering(doc, @response.body)
878 # remove all the members from a relation. the result is pretty useless, but
879 # still technically valid.
880 def test_remove_all_members
881 relation = create(:relation)
882 node1 = create(:node, :lat => 3, :lon => 3)
883 node2 = create(:node, :lat => 5, :lon => 5)
885 create(:way_node, :way => way, :node => node1)
886 create(:relation_member, :relation => relation, :member => way)
887 create(:relation_member, :relation => relation, :member => node2)
889 check_changeset_modify(BoundingBox.new(3, 3, 5, 5)) do |changeset_id|
890 relation_xml = relation.to_xml
892 .find("//osm/relation/member")
895 # update changeset ID to point to new changeset
896 update_changeset(relation_xml, changeset_id)
900 put :update, :params => { :id => relation.id }
901 assert_response :success, "can't update relation for remove all members test"
902 checkrelation = Relation.find(relation.id)
903 assert_not_nil(checkrelation,
904 "uploaded relation not found in database after upload")
905 assert_equal(0, checkrelation.members.length,
906 "relation contains members but they should have all been deleted")
910 # ============================================================
912 # ============================================================
915 # checks that the XML document and the string arguments have
916 # members in the same order.
917 def check_ordering(doc, xml)
918 new_doc = XML::Parser.string(xml).parse
920 doc_members = doc.find("//osm/relation/member").collect do |m|
921 [m["ref"].to_i, m["type"].to_sym, m["role"]]
924 new_members = new_doc.find("//osm/relation/member").collect do |m|
925 [m["ref"].to_i, m["type"].to_sym, m["role"]]
928 doc_members.zip(new_members).each do |d, n|
929 assert_equal d, n, "members are not equal - ordering is wrong? (#{doc}, #{xml})"
934 # create a changeset and yield to the caller to set it up, then assert
935 # that the changeset bounding box is +bbox+.
936 def check_changeset_modify(bbox)
937 ## First test with the private user to check that you get a forbidden
938 basic_authorization create(:user, :data_public => false).email, "test"
940 # create a new changeset for this operation, so we are assured
941 # that the bounding box will be newly-generated.
942 changeset_id = with_controller(ChangesetsController.new) do
943 content "<osm><changeset/></osm>"
945 assert_response :forbidden, "shouldn't be able to create changeset for modify test, as should get forbidden"
948 ## Now do the whole thing with the public user
949 basic_authorization create(:user).email, "test"
951 # create a new changeset for this operation, so we are assured
952 # that the bounding box will be newly-generated.
953 changeset_id = with_controller(ChangesetsController.new) do
954 content "<osm><changeset/></osm>"
956 assert_response :success, "couldn't create changeset for modify test"
960 # go back to the block to do the actual modifies
963 # now download the changeset to check its bounding box
964 with_controller(ChangesetsController.new) do
965 get :read, :params => { :id => changeset_id }
966 assert_response :success, "can't re-read changeset for modify test"
967 assert_select "osm>changeset", 1, "Changeset element doesn't exist in #{@response.body}"
968 assert_select "osm>changeset[id='#{changeset_id}']", 1, "Changeset id=#{changeset_id} doesn't exist in #{@response.body}"
969 assert_select "osm>changeset[min_lon='#{format('%.7f', bbox.min_lon)}']", 1, "Changeset min_lon wrong in #{@response.body}"
970 assert_select "osm>changeset[min_lat='#{format('%.7f', bbox.min_lat)}']", 1, "Changeset min_lat wrong in #{@response.body}"
971 assert_select "osm>changeset[max_lon='#{format('%.7f', bbox.max_lon)}']", 1, "Changeset max_lon wrong in #{@response.body}"
972 assert_select "osm>changeset[max_lat='#{format('%.7f', bbox.max_lat)}']", 1, "Changeset max_lat wrong in #{@response.body}"
977 # yields the relation with the given +id+ (and optional +version+
978 # to read from the history tables) into the block. the parsed XML
980 def with_relation(id, ver = nil)
982 get :read, :params => { :id => id }
984 with_controller(OldRelationsController.new) do
985 get :version, :params => { :id => id, :version => ver }
988 assert_response :success
989 yield xml_parse(@response.body)
993 # updates the relation (XML) +rel+ and
994 # yields the new version of that relation into the block.
995 # the parsed XML doc is retured.
997 rel_id = rel.find("//osm/relation").first["id"].to_i
999 put :update, :params => { :id => rel_id }
1000 assert_response :success, "can't update relation: #{@response.body}"
1001 version = @response.body.to_i
1003 # now get the new version
1004 get :read, :params => { :id => rel_id }
1005 assert_response :success
1006 new_rel = xml_parse(@response.body)
1014 # updates the relation (XML) +rel+ via the diff-upload API and
1015 # yields the new version of that relation into the block.
1016 # the parsed XML doc is retured.
1017 def with_update_diff(rel)
1018 rel_id = rel.find("//osm/relation").first["id"].to_i
1019 cs_id = rel.find("//osm/relation").first["changeset"].to_i
1022 with_controller(ChangesetsController.new) do
1023 doc = OSM::API.new.get_xml_doc
1024 change = XML::Node.new "osmChange"
1026 modify = XML::Node.new "modify"
1028 modify << doc.import(rel.find("//osm/relation").first)
1031 post :upload, :params => { :id => cs_id }
1032 assert_response :success, "can't upload diff relation: #{@response.body}"
1033 version = xml_parse(@response.body).find("//diffResult/relation").first["new_version"].to_i
1036 # now get the new version
1037 get :read, :params => { :id => rel_id }
1038 assert_response :success
1039 new_rel = xml_parse(@response.body)
1047 # returns a k->v hash of tags from an xml doc
1048 def get_tags_as_hash(a)
1049 a.find("//osm/relation/tag").sort_by { |v| v["k"] }.each_with_object({}) do |v, h|
1055 # assert that all tags on relation documents +a+ and +b+
1057 def assert_tags_equal(a, b)
1058 # turn the XML doc into tags hashes
1059 a_tags = get_tags_as_hash(a)
1060 b_tags = get_tags_as_hash(b)
1062 assert_equal a_tags.keys, b_tags.keys, "Tag keys should be identical."
1063 a_tags.each do |k, v|
1064 assert_equal v, b_tags[k],
1065 "Tags which were not altered should be the same. " \
1066 "#{a_tags.inspect} != #{b_tags.inspect}"
1071 # update the changeset_id of a node element
1072 def update_changeset(xml, changeset_id)
1073 xml_attr_rewrite(xml, "changeset", changeset_id)
1077 # update an attribute in the node element
1078 def xml_attr_rewrite(xml, name, value)
1079 xml.find("//osm/relation").first[name] = value.to_s
1086 parser = XML::Parser.string(xml)