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 => "show", :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 => "index" }
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 showing relations.
48 # -------------------------------------
51 # check that a visible relation is returned properly
52 get :show, :params => { :id => create(:relation).id }
53 assert_response :success
55 # check that an invisible relation is not returned
56 get :show, :params => { :id => create(:relation, :deleted).id }
59 # check chat a non-existent relation is not returned
60 get :show, :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 :index, :params => { :relations => "" }
176 assert_response :bad_request
178 # test a working call
179 get :index, :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 :index, :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 xml = "<osm><relation changeset='#{private_changeset.id}'><tag k='test' v='yes' /></relation></osm>"
210 put :create, :body => xml
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 xml = "<osm><relation changeset='#{private_changeset.id}'>" \
219 "<member ref='#{node.id}' type='node' role='some'/>" \
220 "<tag k='test' v='yes' /></relation></osm>"
221 put :create, :body => xml
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 xml = "<osm><relation changeset='#{private_changeset.id}'>" \
230 "<member ref='#{node.id}' type='node'/>" + "<tag k='test' v='yes' /></relation></osm>"
231 put :create, :body => xml
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 xml = "<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>"
242 put :create, :body => xml
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 xml = "<osm><relation changeset='#{changeset.id}'><tag k='test' v='yes' /></relation></osm>"
252 put :create, :body => xml
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 :show, :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 xml = "<osm><relation changeset='#{changeset.id}'>" \
280 "<member ref='#{node.id}' type='node' role='some'/>" \
281 "<tag k='test' v='yes' /></relation></osm>"
282 put :create, :body => xml
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 :show, :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 xml = "<osm><relation changeset='#{changeset.id}'>" \
311 "<member ref='#{node.id}' type='node'/>" + "<tag k='test' v='yes' /></relation></osm>"
312 put :create, :body => xml
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 :show, :params => { :id => relationid }
335 assert_response :success
338 # create an relation with a way and a node as members
339 xml = "<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>"
343 put :create, :body => xml
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 :show, :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)
446 put :update, :params => { :id => other_relation.id }, :body => rel.to_s
447 assert_response :bad_request
451 # -------------------------------------
452 # Test creating some invalid relations.
453 # -------------------------------------
455 def test_create_invalid
457 changeset = create(:changeset, :user => user)
459 basic_authorization user.email, "test"
461 # create a relation with non-existing node as member
462 xml = "<osm><relation changeset='#{changeset.id}'>" \
463 "<member type='node' ref='0'/><tag k='test' v='yes' />" \
465 put :create, :body => xml
467 assert_response :precondition_failed,
468 "relation upload with invalid node did not return 'precondition failed'"
469 assert_equal "Precondition failed: Relation with id cannot be saved due to Node with id 0", @response.body
472 # -------------------------------------
473 # Test creating a relation, with some invalid XML
474 # -------------------------------------
475 def test_create_invalid_xml
477 changeset = create(:changeset, :user => user)
480 basic_authorization user.email, "test"
482 # create some xml that should return an error
483 xml = "<osm><relation changeset='#{changeset.id}'>" \
484 "<member type='type' ref='#{node.id}' role=''/>" \
485 "<tag k='tester' v='yep'/></relation></osm>"
486 put :create, :body => xml
488 assert_response :bad_request
489 assert_match(/Cannot parse valid relation from xml string/, @response.body)
490 assert_match(/The type is not allowed only, /, @response.body)
493 # -------------------------------------
494 # Test deleting relations.
495 # -------------------------------------
498 private_user = create(:user, :data_public => false)
499 private_user_closed_changeset = create(:changeset, :closed, :user => private_user)
501 closed_changeset = create(:changeset, :closed, :user => user)
502 changeset = create(:changeset, :user => user)
503 relation = create(:relation)
504 used_relation = create(:relation)
505 super_relation = create(:relation_member, :member => used_relation).relation
506 deleted_relation = create(:relation, :deleted)
507 multi_tag_relation = create(:relation)
508 create_list(:relation_tag, 4, :relation => multi_tag_relation)
510 ## First try to delete relation without auth
511 delete :delete, :params => { :id => relation.id }
512 assert_response :unauthorized
514 ## Then try with the private user, to make sure that you get a forbidden
515 basic_authorization private_user.email, "test"
517 # this shouldn't work, as we should need the payload...
518 delete :delete, :params => { :id => relation.id }
519 assert_response :forbidden
521 # try to delete without specifying a changeset
522 xml = "<osm><relation id='#{relation.id}'/></osm>"
523 delete :delete, :params => { :id => relation.id }, :body => xml.to_s
524 assert_response :forbidden
526 # try to delete with an invalid (closed) changeset
527 xml = update_changeset(relation.to_xml,
528 private_user_closed_changeset.id)
529 delete :delete, :params => { :id => relation.id }, :body => xml.to_s
530 assert_response :forbidden
532 # try to delete with an invalid (non-existent) changeset
533 xml = update_changeset(relation.to_xml, 0)
534 delete :delete, :params => { :id => relation.id }, :body => xml.to_s
535 assert_response :forbidden
537 # this won't work because the relation is in-use by another relation
538 xml = used_relation.to_xml
539 delete :delete, :params => { :id => used_relation.id }, :body => xml.to_s
540 assert_response :forbidden
542 # this should work when we provide the appropriate payload...
543 xml = relation.to_xml
544 delete :delete, :params => { :id => relation.id }, :body => xml.to_s
545 assert_response :forbidden
547 # this won't work since the relation is already deleted
548 xml = deleted_relation.to_xml
549 delete :delete, :params => { :id => deleted_relation.id }, :body => xml.to_s
550 assert_response :forbidden
552 # this won't work since the relation never existed
553 delete :delete, :params => { :id => 0 }
554 assert_response :forbidden
556 ## now set auth for the public user
557 basic_authorization user.email, "test"
559 # this shouldn't work, as we should need the payload...
560 delete :delete, :params => { :id => relation.id }
561 assert_response :bad_request
563 # try to delete without specifying a changeset
564 xml = "<osm><relation id='#{relation.id}' version='#{relation.version}' /></osm>"
565 delete :delete, :params => { :id => relation.id }, :body => xml.to_s
566 assert_response :bad_request
567 assert_match(/Changeset id is missing/, @response.body)
569 # try to delete with an invalid (closed) changeset
570 xml = update_changeset(relation.to_xml,
572 delete :delete, :params => { :id => relation.id }, :body => xml.to_s
573 assert_response :conflict
575 # try to delete with an invalid (non-existent) changeset
576 xml = update_changeset(relation.to_xml, 0)
577 delete :delete, :params => { :id => relation.id }, :body => xml.to_s
578 assert_response :conflict
580 # this won't work because the relation is in a changeset owned by someone else
581 xml = update_changeset(relation.to_xml, create(:changeset).id)
582 delete :delete, :params => { :id => relation.id }, :body => xml.to_s
583 assert_response :conflict,
584 "shouldn't be able to delete a relation in a changeset owned by someone else (#{@response.body})"
586 # this won't work because the relation in the payload is different to that passed
587 xml = update_changeset(relation.to_xml, changeset.id)
588 delete :delete, :params => { :id => create(:relation).id }, :body => xml.to_s
589 assert_response :bad_request, "shouldn't be able to delete a relation when payload is different to the url"
591 # this won't work because the relation is in-use by another relation
592 xml = update_changeset(used_relation.to_xml, changeset.id)
593 delete :delete, :params => { :id => used_relation.id }, :body => xml.to_s
594 assert_response :precondition_failed,
595 "shouldn't be able to delete a relation used in a relation (#{@response.body})"
596 assert_equal "Precondition failed: The relation #{used_relation.id} is used in relation #{super_relation.id}.", @response.body
598 # this should work when we provide the appropriate payload...
599 xml = update_changeset(multi_tag_relation.to_xml, changeset.id)
600 delete :delete, :params => { :id => multi_tag_relation.id }, :body => xml.to_s
601 assert_response :success
603 # valid delete should return the new version number, which should
604 # be greater than the old version number
605 assert @response.body.to_i > multi_tag_relation.version,
606 "delete request should return a new version number for relation"
608 # this won't work since the relation is already deleted
609 xml = update_changeset(deleted_relation.to_xml, changeset.id)
610 delete :delete, :params => { :id => deleted_relation.id }, :body => xml.to_s
611 assert_response :gone
613 # Public visible relation needs to be deleted
614 xml = update_changeset(super_relation.to_xml, changeset.id)
615 delete :delete, :params => { :id => super_relation.id }, :body => xml.to_s
616 assert_response :success
618 # this works now because the relation which was using this one
620 xml = update_changeset(used_relation.to_xml, changeset.id)
621 delete :delete, :params => { :id => used_relation.id }, :body => xml.to_s
622 assert_response :success,
623 "should be able to delete a relation used in an old relation (#{@response.body})"
625 # this won't work since the relation never existed
626 delete :delete, :params => { :id => 0 }
627 assert_response :not_found
631 # when a relation's tag is modified then it should put the bounding
632 # box of all its members into the changeset.
633 def test_tag_modify_bounding_box
634 relation = create(:relation)
635 node1 = create(:node, :lat => 3, :lon => 3)
636 node2 = create(:node, :lat => 5, :lon => 5)
638 create(:way_node, :way => way, :node => node1)
639 create(:relation_member, :relation => relation, :member => way)
640 create(:relation_member, :relation => relation, :member => node2)
641 # the relation contains nodes1 and node2 (node1
642 # indirectly via the way), so the bbox should be [3,3,5,5].
643 check_changeset_modify(BoundingBox.new(3, 3, 5, 5)) do |changeset_id|
644 # add a tag to an existing relation
645 relation_xml = relation.to_xml
646 relation_element = relation_xml.find("//osm/relation").first
647 new_tag = XML::Node.new("tag")
648 new_tag["k"] = "some_new_tag"
649 new_tag["v"] = "some_new_value"
650 relation_element << new_tag
652 # update changeset ID to point to new changeset
653 update_changeset(relation_xml, changeset_id)
656 put :update, :params => { :id => relation.id }, :body => relation_xml.to_s
657 assert_response :success, "can't update relation for tag/bbox test"
662 # add a member to a relation and check the bounding box is only that
664 def test_add_member_bounding_box
665 relation = create(:relation)
666 node1 = create(:node, :lat => 4, :lon => 4)
667 node2 = create(:node, :lat => 7, :lon => 7)
669 create(:way_node, :way => way1, :node => create(:node, :lat => 8, :lon => 8))
671 create(:way_node, :way => way2, :node => create(:node, :lat => 9, :lon => 9), :sequence_id => 1)
672 create(:way_node, :way => way2, :node => create(:node, :lat => 10, :lon => 10), :sequence_id => 2)
674 [node1, node2, way1, way2].each do |element|
675 bbox = element.bbox.to_unscaled
676 check_changeset_modify(bbox) do |changeset_id|
677 relation_xml = Relation.find(relation.id).to_xml
678 relation_element = relation_xml.find("//osm/relation").first
679 new_member = XML::Node.new("member")
680 new_member["ref"] = element.id.to_s
681 new_member["type"] = element.class.to_s.downcase
682 new_member["role"] = "some_role"
683 relation_element << new_member
685 # update changeset ID to point to new changeset
686 update_changeset(relation_xml, changeset_id)
689 put :update, :params => { :id => relation.id }, :body => relation_xml.to_s
690 assert_response :success, "can't update relation for add #{element.class}/bbox test: #{@response.body}"
692 # get it back and check the ordering
693 get :show, :params => { :id => relation.id }
694 assert_response :success, "can't read back the relation: #{@response.body}"
695 check_ordering(relation_xml, @response.body)
701 # remove a member from a relation and check the bounding box is
703 def test_remove_member_bounding_box
704 relation = create(:relation)
705 node1 = create(:node, :lat => 3, :lon => 3)
706 node2 = create(:node, :lat => 5, :lon => 5)
707 create(:relation_member, :relation => relation, :member => node1)
708 create(:relation_member, :relation => relation, :member => node2)
710 check_changeset_modify(BoundingBox.new(5, 5, 5, 5)) do |changeset_id|
711 # remove node 5 (5,5) from an existing relation
712 relation_xml = relation.to_xml
714 .find("//osm/relation/member[@type='node'][@ref='#{node2.id}']")
717 # update changeset ID to point to new changeset
718 update_changeset(relation_xml, changeset_id)
721 put :update, :params => { :id => relation.id }, :body => relation_xml.to_s
722 assert_response :success, "can't update relation for remove node/bbox test"
727 # check that relations are ordered
728 def test_relation_member_ordering
730 changeset = create(:changeset, :user => user)
731 node1 = create(:node)
732 node2 = create(:node)
733 node3 = create(:node)
734 way1 = create(:way_with_nodes, :nodes_count => 2)
735 way2 = create(:way_with_nodes, :nodes_count => 2)
737 basic_authorization user.email, "test"
739 doc_str = <<OSM.strip_heredoc
741 <relation changeset='#{changeset.id}'>
742 <member ref='#{node1.id}' type='node' role='first'/>
743 <member ref='#{node2.id}' type='node' role='second'/>
744 <member ref='#{way1.id}' type='way' role='third'/>
745 <member ref='#{way2.id}' type='way' role='fourth'/>
749 doc = XML::Parser.string(doc_str).parse
751 put :create, :body => doc.to_s
752 assert_response :success, "can't create a relation: #{@response.body}"
753 relation_id = @response.body.to_i
755 # get it back and check the ordering
756 get :show, :params => { :id => relation_id }
757 assert_response :success, "can't read back the relation: #{@response.body}"
758 check_ordering(doc, @response.body)
760 # insert a member at the front
761 new_member = XML::Node.new "member"
762 new_member["ref"] = node3.id.to_s
763 new_member["type"] = "node"
764 new_member["role"] = "new first"
765 doc.find("//osm/relation").first.child.prev = new_member
766 # update the version, should be 1?
767 doc.find("//osm/relation").first["id"] = relation_id.to_s
768 doc.find("//osm/relation").first["version"] = 1.to_s
770 # upload the next version of the relation
771 put :update, :params => { :id => relation_id }, :body => doc.to_s
772 assert_response :success, "can't update relation: #{@response.body}"
773 assert_equal 2, @response.body.to_i
775 # get it back again and check the ordering again
776 get :show, :params => { :id => relation_id }
777 assert_response :success, "can't read back the relation: #{@response.body}"
778 check_ordering(doc, @response.body)
780 # check the ordering in the history tables:
781 with_controller(OldRelationsController.new) do
782 get :version, :params => { :id => relation_id, :version => 2 }
783 assert_response :success, "can't read back version 2 of the relation #{relation_id}"
784 check_ordering(doc, @response.body)
789 # check that relations can contain duplicate members
790 def test_relation_member_duplicates
791 private_user = create(:user, :data_public => false)
793 changeset = create(:changeset, :user => user)
794 node1 = create(:node)
795 node2 = create(:node)
797 doc_str = <<OSM.strip_heredoc
799 <relation changeset='#{changeset.id}'>
800 <member ref='#{node1.id}' type='node' role='forward'/>
801 <member ref='#{node2.id}' type='node' role='forward'/>
802 <member ref='#{node1.id}' type='node' role='forward'/>
803 <member ref='#{node2.id}' type='node' role='forward'/>
807 doc = XML::Parser.string(doc_str).parse
809 ## First try with the private user
810 basic_authorization private_user.email, "test"
812 put :create, :body => doc.to_s
813 assert_response :forbidden
815 ## Now try with the public user
816 basic_authorization user.email, "test"
818 put :create, :body => doc.to_s
819 assert_response :success, "can't create a relation: #{@response.body}"
820 relation_id = @response.body.to_i
822 # get it back and check the ordering
823 get :show, :params => { :id => relation_id }
824 assert_response :success, "can't read back the relation: #{relation_id}"
825 check_ordering(doc, @response.body)
829 # test that the ordering of elements in the history is the same as in current.
830 def test_history_ordering
832 changeset = create(:changeset, :user => user)
833 node1 = create(:node)
834 node2 = create(:node)
835 node3 = create(:node)
836 node4 = create(:node)
838 doc_str = <<OSM.strip_heredoc
840 <relation changeset='#{changeset.id}'>
841 <member ref='#{node1.id}' type='node' role='forward'/>
842 <member ref='#{node4.id}' type='node' role='forward'/>
843 <member ref='#{node3.id}' type='node' role='forward'/>
844 <member ref='#{node2.id}' type='node' role='forward'/>
848 doc = XML::Parser.string(doc_str).parse
849 basic_authorization user.email, "test"
851 put :create, :body => doc.to_s
852 assert_response :success, "can't create a relation: #{@response.body}"
853 relation_id = @response.body.to_i
855 # check the ordering in the current tables:
856 get :show, :params => { :id => relation_id }
857 assert_response :success, "can't read back the relation: #{@response.body}"
858 check_ordering(doc, @response.body)
860 # check the ordering in the history tables:
861 with_controller(OldRelationsController.new) do
862 get :version, :params => { :id => relation_id, :version => 1 }
863 assert_response :success, "can't read back version 1 of the relation: #{@response.body}"
864 check_ordering(doc, @response.body)
869 # remove all the members from a relation. the result is pretty useless, but
870 # still technically valid.
871 def test_remove_all_members
872 relation = create(:relation)
873 node1 = create(:node, :lat => 3, :lon => 3)
874 node2 = create(:node, :lat => 5, :lon => 5)
876 create(:way_node, :way => way, :node => node1)
877 create(:relation_member, :relation => relation, :member => way)
878 create(:relation_member, :relation => relation, :member => node2)
880 check_changeset_modify(BoundingBox.new(3, 3, 5, 5)) do |changeset_id|
881 relation_xml = relation.to_xml
883 .find("//osm/relation/member")
886 # update changeset ID to point to new changeset
887 update_changeset(relation_xml, changeset_id)
890 put :update, :params => { :id => relation.id }, :body => relation_xml.to_s
891 assert_response :success, "can't update relation for remove all members test"
892 checkrelation = Relation.find(relation.id)
893 assert_not_nil(checkrelation,
894 "uploaded relation not found in database after upload")
895 assert_equal(0, checkrelation.members.length,
896 "relation contains members but they should have all been deleted")
900 # ============================================================
902 # ============================================================
905 # checks that the XML document and the string arguments have
906 # members in the same order.
907 def check_ordering(doc, xml)
908 new_doc = XML::Parser.string(xml).parse
910 doc_members = doc.find("//osm/relation/member").collect do |m|
911 [m["ref"].to_i, m["type"].to_sym, m["role"]]
914 new_members = new_doc.find("//osm/relation/member").collect do |m|
915 [m["ref"].to_i, m["type"].to_sym, m["role"]]
918 doc_members.zip(new_members).each do |d, n|
919 assert_equal d, n, "members are not equal - ordering is wrong? (#{doc}, #{xml})"
924 # create a changeset and yield to the caller to set it up, then assert
925 # that the changeset bounding box is +bbox+.
926 def check_changeset_modify(bbox)
927 ## First test with the private user to check that you get a forbidden
928 basic_authorization create(:user, :data_public => false).email, "test"
930 # create a new changeset for this operation, so we are assured
931 # that the bounding box will be newly-generated.
932 changeset_id = with_controller(ChangesetsController.new) do
933 xml = "<osm><changeset/></osm>"
934 put :create, :body => xml
935 assert_response :forbidden, "shouldn't be able to create changeset for modify test, as should get forbidden"
938 ## Now do the whole thing with the public user
939 basic_authorization create(:user).email, "test"
941 # create a new changeset for this operation, so we are assured
942 # that the bounding box will be newly-generated.
943 changeset_id = with_controller(ChangesetsController.new) do
944 xml = "<osm><changeset/></osm>"
945 put :create, :body => xml
946 assert_response :success, "couldn't create changeset for modify test"
950 # go back to the block to do the actual modifies
953 # now download the changeset to check its bounding box
954 with_controller(ChangesetsController.new) do
955 get :show, :params => { :id => changeset_id }
956 assert_response :success, "can't re-read changeset for modify test"
957 assert_select "osm>changeset", 1, "Changeset element doesn't exist in #{@response.body}"
958 assert_select "osm>changeset[id='#{changeset_id}']", 1, "Changeset id=#{changeset_id} doesn't exist in #{@response.body}"
959 assert_select "osm>changeset[min_lon='#{format('%.7f', bbox.min_lon)}']", 1, "Changeset min_lon wrong in #{@response.body}"
960 assert_select "osm>changeset[min_lat='#{format('%.7f', bbox.min_lat)}']", 1, "Changeset min_lat wrong in #{@response.body}"
961 assert_select "osm>changeset[max_lon='#{format('%.7f', bbox.max_lon)}']", 1, "Changeset max_lon wrong in #{@response.body}"
962 assert_select "osm>changeset[max_lat='#{format('%.7f', bbox.max_lat)}']", 1, "Changeset max_lat wrong in #{@response.body}"
967 # yields the relation with the given +id+ (and optional +version+
968 # to read from the history tables) into the block. the parsed XML
970 def with_relation(id, ver = nil)
972 get :show, :params => { :id => id }
974 with_controller(OldRelationsController.new) do
975 get :version, :params => { :id => id, :version => ver }
978 assert_response :success
979 yield xml_parse(@response.body)
983 # updates the relation (XML) +rel+ and
984 # yields the new version of that relation into the block.
985 # the parsed XML doc is retured.
987 rel_id = rel.find("//osm/relation").first["id"].to_i
988 put :update, :params => { :id => rel_id }, :body => rel.to_s
989 assert_response :success, "can't update relation: #{@response.body}"
990 version = @response.body.to_i
992 # now get the new version
993 get :show, :params => { :id => rel_id }
994 assert_response :success
995 new_rel = xml_parse(@response.body)
1003 # updates the relation (XML) +rel+ via the diff-upload API and
1004 # yields the new version of that relation into the block.
1005 # the parsed XML doc is retured.
1006 def with_update_diff(rel)
1007 rel_id = rel.find("//osm/relation").first["id"].to_i
1008 cs_id = rel.find("//osm/relation").first["changeset"].to_i
1011 with_controller(ChangesetsController.new) do
1012 doc = OSM::API.new.get_xml_doc
1013 change = XML::Node.new "osmChange"
1015 modify = XML::Node.new "modify"
1017 modify << doc.import(rel.find("//osm/relation").first)
1019 post :upload, :params => { :id => cs_id }, :body => doc.to_s
1020 assert_response :success, "can't upload diff relation: #{@response.body}"
1021 version = xml_parse(@response.body).find("//diffResult/relation").first["new_version"].to_i
1024 # now get the new version
1025 get :show, :params => { :id => rel_id }
1026 assert_response :success
1027 new_rel = xml_parse(@response.body)
1035 # returns a k->v hash of tags from an xml doc
1036 def get_tags_as_hash(a)
1037 a.find("//osm/relation/tag").sort_by { |v| v["k"] }.each_with_object({}) do |v, h|
1043 # assert that all tags on relation documents +a+ and +b+
1045 def assert_tags_equal(a, b)
1046 # turn the XML doc into tags hashes
1047 a_tags = get_tags_as_hash(a)
1048 b_tags = get_tags_as_hash(b)
1050 assert_equal a_tags.keys, b_tags.keys, "Tag keys should be identical."
1051 a_tags.each do |k, v|
1052 assert_equal v, b_tags[k],
1053 "Tags which were not altered should be the same. " \
1054 "#{a_tags.inspect} != #{b_tags.inspect}"
1059 # update the changeset_id of a node element
1060 def update_changeset(xml, changeset_id)
1061 xml_attr_rewrite(xml, "changeset", changeset_id)
1065 # update an attribute in the node element
1066 def xml_attr_rewrite(xml, name, value)
1067 xml.find("//osm/relation").first[name] = value.to_s
1074 parser = XML::Parser.string(xml)