1 require File.dirname(__FILE__) + '/../test_helper'
3 class TraceControllerTest < ActionController::TestCase
4 fixtures :users, :gpx_files
5 set_fixture_class :gpx_files => 'Trace'
8 @gpx_trace_dir = Object.send("remove_const", "GPX_TRACE_DIR")
9 Object.const_set("GPX_TRACE_DIR", File.dirname(__FILE__) + "/../traces")
13 Object.send("remove_const", "GPX_TRACE_DIR")
14 Object.const_set("GPX_TRACE_DIR", @gpx_trace_dir)
18 # test all routes which lead to this controller
21 { :path => "/api/0.6/gpx/create", :method => :post },
22 { :controller => "trace", :action => "api_create" }
25 { :path => "/api/0.6/gpx/1", :method => :get },
26 { :controller => "trace", :action => "api_read", :id => "1" }
29 { :path => "/api/0.6/gpx/1", :method => :put },
30 { :controller => "trace", :action => "api_update", :id => "1" }
33 { :path => "/api/0.6/gpx/1", :method => :delete },
34 { :controller => "trace", :action => "api_delete", :id => "1" }
37 { :controller => "trace", :action => "api_read", :id => "1" },
38 { :path => "/api/0.6/gpx/1/details", :method => :get }
41 { :path => "/api/0.6/gpx/1/data", :method => :get },
42 { :controller => "trace", :action => "api_data", :id => "1" }
45 { :path => "/api/0.6/gpx/1/data.xml", :method => :get },
46 { :controller => "trace", :action => "api_data", :id => "1", :format => "xml" }
50 { :path => "/traces", :method => :get },
51 { :controller => "trace", :action => "list" }
54 { :path => "/traces/page/1", :method => :get },
55 { :controller => "trace", :action => "list", :page => "1" }
58 { :path => "/traces/tag/tagname", :method => :get },
59 { :controller => "trace", :action => "list", :tag => "tagname" }
62 { :path => "/traces/tag/tagname/page/1", :method => :get },
63 { :controller => "trace", :action => "list", :tag => "tagname", :page => "1" }
66 { :path => "/user/username/traces", :method => :get },
67 { :controller => "trace", :action => "list", :display_name => "username" }
70 { :path => "/user/username/traces/page/1", :method => :get },
71 { :controller => "trace", :action => "list", :display_name => "username", :page => "1" }
74 { :path => "/user/username/traces/tag/tagname", :method => :get },
75 { :controller => "trace", :action => "list", :display_name => "username", :tag => "tagname" }
78 { :path => "/user/username/traces/tag/tagname/page/1", :method => :get },
79 { :controller => "trace", :action => "list", :display_name => "username", :tag => "tagname", :page => "1" }
83 { :path => "/traces/mine", :method => :get },
84 { :controller => "trace", :action => "mine" }
87 { :path => "/traces/mine/page/1", :method => :get },
88 { :controller => "trace", :action => "mine", :page => "1" }
91 { :path => "/traces/mine/tag/tagname", :method => :get },
92 { :controller => "trace", :action => "mine", :tag => "tagname" }
95 { :path => "/traces/mine/tag/tagname/page/1", :method => :get },
96 { :controller => "trace", :action => "mine", :tag => "tagname", :page => "1" }
100 { :path => "/traces/rss", :method => :get },
101 { :controller => "trace", :action => "georss", :format => :rss }
104 { :path => "/traces/tag/tagname/rss", :method => :get },
105 { :controller => "trace", :action => "georss", :tag => "tagname", :format => :rss }
108 { :path => "/user/username/traces/rss", :method => :get },
109 { :controller => "trace", :action => "georss", :display_name => "username", :format => :rss }
112 { :path => "/user/username/traces/tag/tagname/rss", :method => :get },
113 { :controller => "trace", :action => "georss", :display_name => "username", :tag => "tagname", :format => :rss }
117 { :path => "/user/username/traces/1", :method => :get },
118 { :controller => "trace", :action => "view", :display_name => "username", :id => "1" }
121 { :path => "/user/username/traces/1/picture", :method => :get },
122 { :controller => "trace", :action => "picture", :display_name => "username", :id => "1" }
125 { :path => "/user/username/traces/1/icon", :method => :get },
126 { :controller => "trace", :action => "icon", :display_name => "username", :id => "1" }
130 { :path => "/trace/create", :method => :get },
131 { :controller => "trace", :action => "create" }
134 { :path => "/trace/create", :method => :post },
135 { :controller => "trace", :action => "create" }
138 { :path => "/trace/1/data", :method => :get },
139 { :controller => "trace", :action => "data", :id => "1" }
142 { :path => "/trace/1/data.xml", :method => :get },
143 { :controller => "trace", :action => "data", :id => "1", :format => "xml" }
146 { :path => "/trace/1/edit", :method => :get },
147 { :controller => "trace", :action => "edit", :id => "1" }
150 { :path => "/trace/1/edit", :method => :post },
151 { :controller => "trace", :action => "edit", :id => "1" }
154 { :path => "/trace/1/edit", :method => :patch },
155 { :controller => "trace", :action => "edit", :id => "1" }
158 { :path => "/trace/1/delete", :method => :post },
159 { :controller => "trace", :action => "delete", :id => "1" }
163 # Check that the list of changesets is displayed
166 check_trace_list Trace.public
168 get :list, :tag => "London"
169 check_trace_list Trace.tagged("London").public
172 # Check that I can get mine
174 @request.cookies["_osm_username"] = users(:public_user).display_name
176 # First try to get it when not logged in
178 assert_redirected_to :controller => 'user', :action => 'login', :referer => '/traces/mine'
180 # Now try when logged in
181 get :mine, {}, {:user => users(:public_user).id}
182 assert_redirected_to :controller => 'trace', :action => 'list', :display_name => users(:public_user).display_name
184 # Fetch the actual list
185 get :list, {:display_name => users(:public_user).display_name}, {:user => users(:public_user).id}
186 check_trace_list users(:public_user).traces
189 # Check the list of changesets for a specific user
191 # Test a user with no traces
192 get :list, :display_name => users(:second_public_user).display_name
193 check_trace_list users(:second_public_user).traces.public
195 # Test a user with some traces - should see only public ones
196 get :list, :display_name => users(:public_user).display_name
197 check_trace_list users(:public_user).traces.public
199 @request.cookies["_osm_username"] = users(:normal_user).display_name
201 # Should still see only public ones when authenticated as another user
202 get :list, {:display_name => users(:public_user).display_name}, {:user => users(:normal_user).id}
203 check_trace_list users(:public_user).traces.public
205 @request.cookies["_osm_username"] = users(:public_user).display_name
207 # Should see all traces when authenticated as the target user
208 get :list, {:display_name => users(:public_user).display_name}, {:user => users(:public_user).id}
209 check_trace_list users(:public_user).traces
211 # Should only see traces with the correct tag when a tag is specified
212 get :list, {:display_name => users(:public_user).display_name, :tag => "London"}, {:user => users(:public_user).id}
213 check_trace_list users(:public_user).traces.tagged("London")
216 # Check that the rss loads
218 get :georss, :format => :rss
219 check_trace_feed Trace.public
221 get :georss, :tag => "London", :format => :rss
222 check_trace_feed Trace.tagged("London").public
224 get :georss, :display_name => users(:public_user).display_name, :format => :rss
225 check_trace_feed users(:public_user).traces.public
227 get :georss, :display_name => users(:public_user).display_name, :tag => "Birmingham", :format => :rss
228 check_trace_feed users(:public_user).traces.tagged("Birmingham").public
231 # Test viewing a trace
233 # First with no auth, which should work since the trace is public
234 get :view, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}
235 check_trace_view gpx_files(:public_trace_file)
237 @request.cookies["_osm_username"] = users(:public_user).display_name
239 # Now with some other user, which should work since the trace is public
240 get :view, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:public_user).id}
241 check_trace_view gpx_files(:public_trace_file)
243 @request.cookies["_osm_username"] = users(:normal_user).display_name
245 # And finally we should be able to do it with the owner of the trace
246 get :view, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:normal_user).id}
247 check_trace_view gpx_files(:public_trace_file)
250 # Check an anonymous trace can't be viewed by another user
253 get :view, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}
254 assert_response :redirect
255 assert_redirected_to :action => :list
257 @request.cookies["_osm_username"] = users(:normal_user).display_name
259 # Now with some other user, which should work since the trace is anon
260 get :view, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}, {:user => users(:normal_user).id}
261 assert_response :redirect
262 assert_redirected_to :action => :list
264 @request.cookies["_osm_username"] = users(:public_user).display_name
266 # And finally we should be able to do it with the owner of the trace
267 get :view, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}, {:user => users(:public_user).id}
268 check_trace_view gpx_files(:anon_trace_file)
271 # Test viewing a trace that doesn't exist
272 def test_view_not_found
273 # First with no auth, which should work since the trace is public
274 get :view, {:display_name => users(:public_user).display_name, :id => 0}
275 assert_response :redirect
276 assert_redirected_to :action => :list
278 @request.cookies["_osm_username"] = users(:public_user).display_name
280 # Now with some other user, which should work since the trace is public
281 get :view, {:display_name => users(:public_user).display_name, :id => 0}, {:user => users(:public_user).id}
282 assert_response :redirect
283 assert_redirected_to :action => :list
285 # And finally we should be able to do it with the owner of the trace
286 get :view, {:display_name => users(:public_user).display_name, :id => 5}, {:user => users(:public_user).id}
287 assert_response :redirect
288 assert_redirected_to :action => :list
291 # Test downloading a trace
293 # First with no auth, which should work since the trace is public
294 get :data, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}
295 check_trace_data gpx_files(:public_trace_file)
297 @request.cookies["_osm_username"] = users(:public_user).display_name
299 # Now with some other user, which should work since the trace is public
300 get :data, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:public_user).id}
301 check_trace_data gpx_files(:public_trace_file)
303 @request.cookies["_osm_username"] = users(:normal_user).display_name
305 # And finally we should be able to do it with the owner of the trace
306 get :data, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:normal_user).id}
307 check_trace_data gpx_files(:public_trace_file)
310 # Test downloading a compressed trace
311 def test_data_compressed
312 # First get the data as is
313 get :data, {:display_name => users(:public_user).display_name, :id => gpx_files(:identifiable_trace_file).id}
314 check_trace_data gpx_files(:identifiable_trace_file), "application/x-gzip", "gpx.gz"
316 # Now ask explicitly for XML format
317 get :data, {:display_name => users(:public_user).display_name, :id => gpx_files(:identifiable_trace_file).id, :format => "xml"}
318 check_trace_data gpx_files(:identifiable_trace_file), "application/xml", "xml"
320 # Now ask explicitly for GPX format
321 get :data, {:display_name => users(:public_user).display_name, :id => gpx_files(:identifiable_trace_file).id, :format => "gpx"}
322 check_trace_data gpx_files(:identifiable_trace_file)
325 # Check an anonymous trace can't be downloaded by another user
328 get :data, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}
329 assert_response :not_found
331 @request.cookies["_osm_username"] = users(:normal_user).display_name
333 # Now with some other user, which should work since the trace is anon
334 get :data, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}, {:user => users(:normal_user).id}
335 assert_response :not_found
337 @request.cookies["_osm_username"] = users(:public_user).display_name
339 # And finally we should be able to do it with the owner of the trace
340 get :data, {:display_name => users(:public_user).display_name, :id => gpx_files(:anon_trace_file).id}, {:user => users(:public_user).id}
341 check_trace_data gpx_files(:anon_trace_file)
344 # Test downloading a trace that doesn't exist
345 def test_data_not_found
346 # First with no auth, which should work since the trace is public
347 get :data, {:display_name => users(:public_user).display_name, :id => 0}
348 assert_response :not_found
350 @request.cookies["_osm_username"] = users(:public_user).display_name
352 # Now with some other user, which should work since the trace is public
353 get :data, {:display_name => users(:public_user).display_name, :id => 0}, {:user => users(:public_user).id}
354 assert_response :not_found
356 # And finally we should be able to do it with the owner of the trace
357 get :data, {:display_name => users(:public_user).display_name, :id => 5}, {:user => users(:public_user).id}
358 assert_response :not_found
361 # Test fetching the edit page for a trace
364 get :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}
365 assert_response :redirect
366 assert_redirected_to :controller => :user, :action => :login, :referer => trace_edit_path(:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id)
368 @request.cookies["_osm_username"] = users(:public_user).display_name
370 # Now with some other user, which should fail
371 get :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:public_user).id}
372 assert_response :forbidden
374 # Now with a trace which doesn't exist
375 get :edit, {:display_name => users(:public_user).display_name, :id => 0}, {:user => users(:public_user).id}
376 assert_response :not_found
378 # Now with a trace which has been deleted
379 get :edit, {:display_name => users(:public_user).display_name, :id => gpx_files(:deleted_trace_file).id}, {:user => users(:public_user).id}
380 assert_response :not_found
382 @request.cookies["_osm_username"] = users(:normal_user).display_name
384 # Finally with a trace that we are allowed to edit
385 get :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:normal_user).id}
386 assert_response :success
389 # Test saving edits to a trace
392 new_details = { :description => "Changed description", :tagstring => "new_tag", :visibility => "private" }
395 post :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id, :trace => new_details}
396 assert_response :forbidden
398 @request.cookies["_osm_username"] = users(:public_user).display_name
400 # Now with some other user, which should fail
401 post :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id, :trace => new_details}, {:user => users(:public_user).id}
402 assert_response :forbidden
404 # Now with a trace which doesn't exist
405 post :edit, {:display_name => users(:public_user).display_name, :id => 0}, {:user => users(:public_user).id, :trace => new_details}
406 assert_response :not_found
408 # Now with a trace which has been deleted
409 post :edit, {:display_name => users(:public_user).display_name, :id => gpx_files(:deleted_trace_file).id, :trace => new_details}, {:user => users(:public_user).id}
410 assert_response :not_found
412 @request.cookies["_osm_username"] = users(:normal_user).display_name
414 # Finally with a trace that we are allowed to edit
415 post :edit, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id, :trace => new_details}, {:user => users(:normal_user).id}
416 assert_response :redirect
417 assert_redirected_to :action => :view, :display_name => users(:normal_user).display_name
418 trace = Trace.find(gpx_files(:public_trace_file).id)
419 assert_equal new_details[:description], trace.description
420 assert_equal new_details[:tagstring], trace.tagstring
421 assert_equal new_details[:visibility], trace.visibility
424 # Test deleting a trace
427 post :delete, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id,}
428 assert_response :forbidden
430 @request.cookies["_osm_username"] = users(:public_user).display_name
432 # Now with some other user, which should fail
433 post :delete, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:public_user).id}
434 assert_response :forbidden
436 # Now with a trace which doesn't exist
437 post :delete, {:display_name => users(:public_user).display_name, :id => 0}, {:user => users(:public_user).id}
438 assert_response :not_found
440 # Now with a trace has already been deleted
441 post :delete, {:display_name => users(:public_user).display_name, :id => gpx_files(:deleted_trace_file).id}, {:user => users(:public_user).id}
442 assert_response :not_found
444 @request.cookies["_osm_username"] = users(:normal_user).display_name
446 # Finally with a trace that we are allowed to delete
447 post :delete, {:display_name => users(:normal_user).display_name, :id => gpx_files(:public_trace_file).id}, {:user => users(:normal_user).id}
448 assert_response :redirect
449 assert_redirected_to :action => :list, :display_name => users(:normal_user).display_name
450 trace = Trace.find(gpx_files(:public_trace_file).id)
451 assert_equal false, trace.visible
454 # Check getting a specific trace through the api
457 get :api_read, :id => gpx_files(:public_trace_file).id
458 assert_response :unauthorized
460 # Now with some other user, which should work since the trace is public
461 basic_authorization(users(:public_user).display_name, "test")
462 get :api_read, :id => gpx_files(:public_trace_file).id
463 assert_response :success
465 # And finally we should be able to do it with the owner of the trace
466 basic_authorization(users(:normal_user).display_name, "test")
467 get :api_read, :id => gpx_files(:public_trace_file).id
468 assert_response :success
471 # Check an anoymous trace can't be specifically fetched by another user
472 def test_api_read_anon
474 get :api_read, :id => gpx_files(:anon_trace_file).id
475 assert_response :unauthorized
477 # Now try with another user, which shouldn't work since the trace is anon
478 basic_authorization(users(:normal_user).display_name, "test")
479 get :api_read, :id => gpx_files(:anon_trace_file).id
480 assert_response :forbidden
482 # And finally we should be able to get the trace details with the trace owner
483 basic_authorization(users(:public_user).display_name, "test")
484 get :api_read, :id => gpx_files(:anon_trace_file).id
485 assert_response :success
488 # Check the api details for a trace that doesn't exist
489 def test_api_read_not_found
490 # Try first with no auth, as it should requure it
491 get :api_read, :id => 0
492 assert_response :unauthorized
494 # Login, and try again
495 basic_authorization(users(:public_user).display_name, "test")
496 get :api_read, :id => 0
497 assert_response :not_found
499 # Now try a trace which did exist but has been deleted
500 basic_authorization(users(:public_user).display_name, "test")
501 get :api_read, :id => 5
502 assert_response :not_found
505 # Check updating a trace through the api
508 content gpx_files(:public_trace_file).to_xml
509 put :api_update, :id => gpx_files(:public_trace_file).id
510 assert_response :unauthorized
512 # Now with some other user, which should fail
513 basic_authorization(users(:public_user).display_name, "test")
514 content gpx_files(:public_trace_file).to_xml
515 put :api_update, :id => gpx_files(:public_trace_file).id
516 assert_response :forbidden
518 # Now with a trace which doesn't exist
519 basic_authorization(users(:public_user).display_name, "test")
520 content gpx_files(:public_trace_file).to_xml
521 put :api_update, :id => 0
522 assert_response :not_found
524 # Now with a trace which did exist but has been deleted
525 basic_authorization(users(:public_user).display_name, "test")
526 content gpx_files(:deleted_trace_file).to_xml
527 put :api_update, :id => gpx_files(:deleted_trace_file).id
528 assert_response :not_found
530 # Now try an update with the wrong ID
531 basic_authorization(users(:normal_user).display_name, "test")
532 content gpx_files(:anon_trace_file).to_xml
533 put :api_update, :id => gpx_files(:public_trace_file).id
534 assert_response :bad_request,
535 "should not be able to update a trace with a different ID from the XML"
537 # And finally try an update that should work
538 basic_authorization(users(:normal_user).display_name, "test")
539 t = gpx_files(:public_trace_file)
540 t.description = "Changed description"
541 t.visibility = "private"
543 put :api_update, :id => t.id
544 assert_response :success
545 nt = Trace.find(t.id)
546 assert_equal nt.description, t.description
547 assert_equal nt.visibility, t.visibility
550 # Check deleting a trace through the api
553 delete :api_delete, :id => gpx_files(:public_trace_file).id
554 assert_response :unauthorized
556 # Now with some other user, which should fail
557 basic_authorization(users(:public_user).display_name, "test")
558 delete :api_delete, :id => gpx_files(:public_trace_file).id
559 assert_response :forbidden
561 # Now with a trace which doesn't exist
562 basic_authorization(users(:public_user).display_name, "test")
563 delete :api_delete, :id => 0
564 assert_response :not_found
566 # And finally we should be able to do it with the owner of the trace
567 basic_authorization(users(:normal_user).display_name, "test")
568 delete :api_delete, :id => gpx_files(:public_trace_file).id
569 assert_response :success
571 # Try it a second time, which should fail
572 basic_authorization(users(:normal_user).display_name, "test")
573 delete :api_delete, :id => gpx_files(:public_trace_file).id
574 assert_response :not_found
579 def check_trace_feed(traces)
580 assert_response :success
581 assert_template "georss"
582 assert_equal "application/rss+xml", @response.content_type
583 assert_select "rss", :count => 1 do
584 assert_select "channel", :count => 1 do
585 assert_select "title"
586 assert_select "description"
588 assert_select "image"
589 assert_select "item", :count => traces.visible.count do |items|
590 traces.visible.order("timestamp DESC").zip(items).each do |trace,item|
591 assert_select item, "title", trace.name
592 assert_select item, "link", "http://test.host/user/#{trace.user.display_name}/traces/#{trace.id}"
593 assert_select item, "guid", "http://test.host/user/#{trace.user.display_name}/traces/#{trace.id}"
594 assert_select item, "description"
595 # assert_select item, "dc:creator", trace.user.display_name
596 assert_select item, "pubDate", trace.timestamp.rfc822
603 def check_trace_list(traces)
604 assert_response :success
605 assert_template "list"
608 assert_select "table#trace_list tbody", :count => 1 do
609 assert_select "tr", :count => traces.visible.count do |rows|
610 traces.visible.order("timestamp DESC").zip(rows).each do |trace,row|
611 assert_select row, "span.trace_summary", Regexp.new(Regexp.escape("(#{trace.size} points)"))
612 assert_select row, "td", Regexp.new(Regexp.escape(trace.description))
613 assert_select row, "td", Regexp.new(Regexp.escape("by #{trace.user.display_name}"))
618 assert_select "h4", /Nothing here yet/
622 def check_trace_view(trace)
623 assert_response :success
624 assert_template "view"
626 assert_select "table", :count => 1 do
627 assert_select "td", /^#{Regexp.quote(trace.name)} /
628 assert_select "td", trace.user.display_name
629 assert_select "td", trace.description
633 def check_trace_data(trace, content_type = "application/gpx+xml", extension = "gpx")
634 assert_response :success
635 assert_equal content_type, @response.content_type
636 assert_equal "attachment; filename=\"#{trace.id}.#{extension}\"", @response.header["Content-Disposition"]