3 class TracesControllerTest < ActionDispatch::IntegrationTest
 
   5   # test all routes which lead to this controller
 
   8       { :path => "/traces", :method => :get },
 
   9       { :controller => "traces", :action => "index" }
 
  12       { :path => "/traces/tag/tagname", :method => :get },
 
  13       { :controller => "traces", :action => "index", :tag => "tagname" }
 
  16       { :path => "/user/username/traces", :method => :get },
 
  17       { :controller => "traces", :action => "index", :display_name => "username" }
 
  20       { :path => "/user/username/traces/tag/tagname", :method => :get },
 
  21       { :controller => "traces", :action => "index", :display_name => "username", :tag => "tagname" }
 
  25       { :path => "/traces/mine", :method => :get },
 
  26       { :controller => "traces", :action => "mine" }
 
  29       { :path => "/traces/mine/tag/tagname", :method => :get },
 
  30       { :controller => "traces", :action => "mine", :tag => "tagname" }
 
  34       { :path => "/user/username/traces/1", :method => :get },
 
  35       { :controller => "traces", :action => "show", :display_name => "username", :id => "1" }
 
  39       { :path => "/traces/new", :method => :get },
 
  40       { :controller => "traces", :action => "new" }
 
  43       { :path => "/traces", :method => :post },
 
  44       { :controller => "traces", :action => "create" }
 
  47       { :path => "/traces/1/edit", :method => :get },
 
  48       { :controller => "traces", :action => "edit", :id => "1" }
 
  51       { :path => "/traces/1", :method => :put },
 
  52       { :controller => "traces", :action => "update", :id => "1" }
 
  55       { :path => "/traces/1", :method => :delete },
 
  56       { :controller => "traces", :action => "destroy", :id => "1" }
 
  60     assert_redirected_to "/traces"
 
  62     get "/traces/tag/tagname/page/1"
 
  63     assert_redirected_to "/traces/tag/tagname"
 
  65     get "/user/username/traces/page/1"
 
  66     assert_redirected_to "/user/username/traces"
 
  68     get "/user/username/traces/tag/tagname/page/1"
 
  69     assert_redirected_to "/user/username/traces/tag/tagname"
 
  71     get "/traces/mine/page/1"
 
  72     assert_redirected_to "/traces/mine"
 
  74     get "/traces/mine/tag/tagname/page/1"
 
  75     assert_redirected_to "/traces/mine/tag/tagname"
 
  78   # Check that the index of traces is displayed
 
  81     # The fourth test below is surprisingly sensitive to timestamp ordering when the timestamps are equal.
 
  82     trace_a = create(:trace, :visibility => "public", :timestamp => 4.seconds.ago) do |trace|
 
  83       create(:tracetag, :trace => trace, :tag => "London")
 
  85     trace_b = create(:trace, :visibility => "public", :timestamp => 3.seconds.ago) do |trace|
 
  86       create(:tracetag, :trace => trace, :tag => "Birmingham")
 
  88     trace_c = create(:trace, :visibility => "private", :user => user, :timestamp => 2.seconds.ago) do |trace|
 
  89       create(:tracetag, :trace => trace, :tag => "London")
 
  91     trace_d = create(:trace, :visibility => "private", :user => user, :timestamp => 1.second.ago) do |trace|
 
  92       create(:tracetag, :trace => trace, :tag => "Birmingham")
 
  95     # First with the public index
 
  97     check_trace_index [trace_b, trace_a]
 
  99     # Restrict traces to those with a given tag
 
 100     get traces_path(:tag => "London")
 
 101     check_trace_index [trace_a]
 
 105     # Should see more when we are logged in
 
 107     check_trace_index [trace_d, trace_c, trace_b, trace_a]
 
 109     # Again, we should see more when we are logged in
 
 110     get traces_path(:tag => "London")
 
 111     check_trace_index [trace_c, trace_a]
 
 114   # Check that I can get mine
 
 117     create(:trace, :visibility => "public") do |trace|
 
 118       create(:tracetag, :trace => trace, :tag => "Birmingham")
 
 120     trace_b = create(:trace, :visibility => "private", :user => user) do |trace|
 
 121       create(:tracetag, :trace => trace, :tag => "London")
 
 124     # First try to get it when not logged in
 
 126     assert_redirected_to login_path(:referer => "/traces/mine")
 
 130     # Now try when logged in
 
 132     assert_redirected_to :action => "index", :display_name => user.display_name
 
 134     # Fetch the actual index
 
 135     get traces_path(:display_name => user.display_name)
 
 136     check_trace_index [trace_b]
 
 139   # Check the index of traces for a specific user
 
 142     checked_user_traces_path = url_for :only_path => true, :controller => "traces", :action => "index", :display_name => user.display_name
 
 143     second_user = create(:user)
 
 144     third_user = create(:user)
 
 146     trace_b = create(:trace, :visibility => "public", :user => user)
 
 147     trace_c = create(:trace, :visibility => "private", :user => user) do |trace|
 
 148       create(:tracetag, :trace => trace, :tag => "London")
 
 151     # Test a user with no traces
 
 152     get traces_path(:display_name => second_user.display_name)
 
 155     # Test the user with the traces - should see only public ones
 
 156     get traces_path(:display_name => user.display_name)
 
 157     check_trace_index [trace_b]
 
 158     assert_dom ".nav-tabs" do
 
 159       assert_dom "a[href='#{traces_path}']", :text => "All Traces", :count => 1
 
 160       assert_dom "a[href='#{traces_mine_path}']", :text => "My Traces", :count => 0
 
 161       assert_dom "a[href='#{checked_user_traces_path}']", :text => Regexp.new(Regexp.escape(user.display_name)), :count => 1
 
 164     session_for(third_user)
 
 166     # Should still see only public ones when authenticated as another user
 
 167     get traces_path(:display_name => user.display_name)
 
 168     check_trace_index [trace_b]
 
 169     assert_dom ".nav-tabs" do
 
 170       assert_dom "a[href='#{traces_path}']", :text => "All Traces", :count => 1
 
 171       assert_dom "a[href='#{traces_mine_path}']", :text => "My Traces", :count => 1
 
 172       assert_dom "a[href='#{checked_user_traces_path}']", :text => Regexp.new(Regexp.escape(user.display_name)), :count => 1
 
 177     # Should see all traces when authenticated as the target user
 
 178     get traces_path(:display_name => user.display_name)
 
 179     check_trace_index [trace_c, trace_b]
 
 180     assert_dom ".nav-tabs" do
 
 181       assert_dom "a[href='#{traces_path}']", :text => "All Traces", :count => 1
 
 182       assert_dom "a[href='#{traces_mine_path}']", :text => "My Traces", :count => 1
 
 183       assert_dom "a[href='#{checked_user_traces_path}']", :text => Regexp.new(Regexp.escape(user.display_name)), :count => 0
 
 186     # Should only see traces with the correct tag when a tag is specified
 
 187     get traces_path(:display_name => user.display_name, :tag => "London")
 
 188     check_trace_index [trace_c]
 
 190     # Should get an error if the user does not exist
 
 191     get traces_path(:display_name => "UnknownUser")
 
 192     assert_response :not_found
 
 193     assert_template "users/no_such_user"
 
 196   # Check a multi-page index
 
 198     # Create several pages worth of traces
 
 199     create_list(:trace, 50)
 
 200     next_path = traces_path
 
 202     # Try and get the index
 
 204     assert_response :success
 
 205     assert_select "table#trace_list tbody", :count => 1 do
 
 206       assert_select "tr", :count => 20
 
 208     check_no_page_link "Newer Traces"
 
 209     next_path = check_page_link "Older Traces"
 
 211     # Try and get the second page
 
 213     assert_response :success
 
 214     assert_select "table#trace_list tbody", :count => 1 do
 
 215       assert_select "tr", :count => 20
 
 217     check_page_link "Newer Traces"
 
 218     next_path = check_page_link "Older Traces"
 
 220     # Try and get the third page
 
 222     assert_response :success
 
 223     assert_select "table#trace_list tbody", :count => 1 do
 
 224       assert_select "tr", :count => 10
 
 226     next_path = check_page_link "Newer Traces"
 
 227     check_no_page_link "Older Traces"
 
 229     # Go back to the second page
 
 231     assert_response :success
 
 232     assert_select "table#trace_list tbody", :count => 1 do
 
 233       assert_select "tr", :count => 20
 
 235     next_path = check_page_link "Newer Traces"
 
 236     check_page_link "Older Traces"
 
 238     # Go back to the first page
 
 240     assert_response :success
 
 241     assert_select "table#trace_list tbody", :count => 1 do
 
 242       assert_select "tr", :count => 20
 
 244     check_no_page_link "Newer Traces"
 
 245     check_page_link "Older Traces"
 
 248   # Check a multi-page index of tagged traces
 
 249   def test_index_tagged_paged
 
 250     # Create several pages worth of traces
 
 251     create_list(:trace, 100) do |trace, index|
 
 252       create(:tracetag, :trace => trace, :tag => "London") if index.even?
 
 254     next_path = traces_path :tag => "London"
 
 256     # Try and get the index
 
 258     assert_response :success
 
 259     assert_select "table#trace_list tbody", :count => 1 do
 
 260       assert_select "tr", :count => 20
 
 262     check_no_page_link "Newer Traces"
 
 263     next_path = check_page_link "Older Traces"
 
 265     # Try and get the second page
 
 267     assert_response :success
 
 268     assert_select "table#trace_list tbody", :count => 1 do
 
 269       assert_select "tr", :count => 20
 
 271     check_page_link "Newer Traces"
 
 272     next_path = check_page_link "Older Traces"
 
 274     # Try and get the third page
 
 276     assert_response :success
 
 277     assert_select "table#trace_list tbody", :count => 1 do
 
 278       assert_select "tr", :count => 10
 
 280     next_path = check_page_link "Newer Traces"
 
 281     check_no_page_link "Older Traces"
 
 283     # Go back to the second page
 
 285     assert_response :success
 
 286     assert_select "table#trace_list tbody", :count => 1 do
 
 287       assert_select "tr", :count => 20
 
 289     next_path = check_page_link "Newer Traces"
 
 290     check_page_link "Older Traces"
 
 292     # Go back to the first page
 
 294     assert_response :success
 
 295     assert_select "table#trace_list tbody", :count => 1 do
 
 296       assert_select "tr", :count => 20
 
 298     check_no_page_link "Newer Traces"
 
 299     check_page_link "Older Traces"
 
 302   def test_index_invalid_paged
 
 303     # Try some invalid paged accesses
 
 304     %w[-1 fred].each do |id|
 
 305       get traces_path(:before => id)
 
 306       assert_redirected_to :controller => :errors, :action => :bad_request
 
 308       get traces_path(:after => id)
 
 309       assert_redirected_to :controller => :errors, :action => :bad_request
 
 313   # Test showing a trace
 
 315     public_trace_file = create(:trace, :visibility => "public")
 
 317     # First with no auth, which should work since the trace is public
 
 318     get show_trace_path(public_trace_file.user, public_trace_file)
 
 319     check_trace_show public_trace_file
 
 321     # Now with some other user, which should work since the trace is public
 
 322     session_for(create(:user))
 
 323     get show_trace_path(public_trace_file.user, public_trace_file)
 
 324     check_trace_show public_trace_file
 
 326     # And finally we should be able to do it with the owner of the trace
 
 327     session_for(public_trace_file.user)
 
 328     get show_trace_path(public_trace_file.user, public_trace_file)
 
 329     check_trace_show public_trace_file
 
 332   # Check an anonymous trace can't be viewed by another user
 
 334     anon_trace_file = create(:trace, :visibility => "private")
 
 337     get show_trace_path(anon_trace_file.user, anon_trace_file)
 
 338     assert_redirected_to :action => :index
 
 340     # Now with some other user, which should not work since the trace is anon
 
 341     session_for(create(:user))
 
 342     get show_trace_path(anon_trace_file.user, anon_trace_file)
 
 343     assert_redirected_to :action => :index
 
 345     # And finally we should be able to do it with the owner of the trace
 
 346     session_for(anon_trace_file.user)
 
 347     get show_trace_path(anon_trace_file.user, anon_trace_file)
 
 348     check_trace_show anon_trace_file
 
 351   # Test showing a trace that doesn't exist
 
 352   def test_show_not_found
 
 353     deleted_trace_file = create(:trace, :deleted)
 
 355     # First with a trace that has never existed
 
 356     get show_trace_path(create(:user), 0)
 
 357     assert_redirected_to :action => :index
 
 359     # Now with a trace that has been deleted
 
 360     session_for(deleted_trace_file.user)
 
 361     get show_trace_path(deleted_trace_file.user, deleted_trace_file)
 
 362     assert_redirected_to :action => :index
 
 365   # Test fetching the new trace page
 
 369     assert_redirected_to login_path(:referer => new_trace_path)
 
 371     # Now authenticated as a user with gps.trace.visibility set
 
 373     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
 
 376     assert_response :success
 
 378     assert_select "select#trace_visibility option[value=identifiable][selected]", 1
 
 380     # Now authenticated as a user with gps.trace.public set
 
 381     second_user = create(:user)
 
 382     create(:user_preference, :user => second_user, :k => "gps.trace.public", :v => "default")
 
 383     session_for(second_user)
 
 385     assert_response :success
 
 387     assert_select "select#trace_visibility option[value=public][selected]", 1
 
 389     # Now authenticated as a user with no preferences
 
 390     third_user = create(:user)
 
 391     session_for(third_user)
 
 393     assert_response :success
 
 395     assert_select "select#trace_visibility option[value=private][selected]", 1
 
 398   # Test creating a trace
 
 401     fixture = Rails.root.join("test/gpx/fixtures/a.gpx")
 
 402     file = Rack::Test::UploadedFile.new(fixture, "application/gpx+xml")
 
 406     post traces_path(:trace => { :gpx_file => file, :description => "New Trace", :tagstring => "new,trace", :visibility => "trackable" })
 
 407     assert_response :forbidden
 
 413     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
 
 414     assert_not_equal "trackable", user.preferences.find_by(:k => "gps.trace.visibility").v
 
 416     post traces_path, :params => { :trace => { :gpx_file => file, :description => "New Trace", :tagstring => "new,trace", :visibility => "trackable" } }
 
 417     assert_redirected_to :action => :index, :display_name => user.display_name
 
 418     assert_match(/file has been uploaded/, flash[:notice])
 
 419     trace = Trace.order(:id => :desc).first
 
 420     assert_equal "a.gpx", trace.name
 
 421     assert_equal "New Trace", trace.description
 
 422     assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
 
 423     assert_equal "trackable", trace.visibility
 
 424     assert_not trace.inserted
 
 425     assert_equal File.new(fixture).read, trace.file.blob.download
 
 427     assert_equal "trackable", user.preferences.find_by(:k => "gps.trace.visibility").v
 
 430   # Test creating a trace with validation errors
 
 431   def test_create_post_with_validation_errors
 
 433     fixture = Rails.root.join("test/gpx/fixtures/a.gpx")
 
 434     file = Rack::Test::UploadedFile.new(fixture, "application/gpx+xml")
 
 438     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
 
 439     assert_not_equal "trackable", user.preferences.find_by(:k => "gps.trace.visibility").v
 
 441     post traces_path, :params => { :trace => { :gpx_file => file, :description => "", :tagstring => "new,trace", :visibility => "trackable" } }
 
 443     assert_match "is too short (minimum is 1 character)", response.body
 
 446   # Test fetching the edit page for a trace using GET
 
 448     public_trace_file = create(:trace, :visibility => "public")
 
 449     deleted_trace_file = create(:trace, :deleted)
 
 452     get edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 453     assert_redirected_to login_path(:referer => edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file.id))
 
 455     # Now with some other user, which should fail
 
 456     session_for(create(:user))
 
 457     get edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 458     assert_response :forbidden
 
 460     # Now with a trace which doesn't exist
 
 461     session_for(create(:user))
 
 462     get edit_trace_path(:display_name => create(:user).display_name, :id => 0)
 
 463     assert_response :not_found
 
 465     # Now with a trace which has been deleted
 
 466     session_for(deleted_trace_file.user)
 
 467     get edit_trace_path(:display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file)
 
 468     assert_response :not_found
 
 470     # Finally with a trace that we are allowed to edit
 
 471     session_for(public_trace_file.user)
 
 472     get edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 473     assert_response :success
 
 476   # Test saving edits to a trace
 
 478     public_trace_file = create(:trace, :visibility => "public")
 
 479     deleted_trace_file = create(:trace, :deleted)
 
 482     new_details = { :description => "Changed description", :tagstring => "new_tag", :visibility => "private" }
 
 485     put trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file, :trace => new_details)
 
 486     assert_response :forbidden
 
 488     # Now with some other user, which should fail
 
 489     session_for(create(:user))
 
 490     put trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file, :trace => new_details)
 
 491     assert_response :forbidden
 
 493     # Now with a trace which doesn't exist
 
 494     session_for(create(:user))
 
 495     put trace_path(:display_name => create(:user).display_name, :id => 0, :trace => new_details)
 
 496     assert_response :not_found
 
 498     # Now with a trace which has been deleted
 
 499     session_for(deleted_trace_file.user)
 
 500     put trace_path(:display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file, :trace => new_details)
 
 501     assert_response :not_found
 
 503     # Finally with a trace that we are allowed to edit
 
 504     session_for(public_trace_file.user)
 
 505     put trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file, :trace => new_details)
 
 506     assert_redirected_to :action => :show, :display_name => public_trace_file.user.display_name
 
 507     trace = Trace.find(public_trace_file.id)
 
 508     assert_equal new_details[:description], trace.description
 
 509     assert_equal new_details[:tagstring], trace.tagstring
 
 510     assert_equal new_details[:visibility], trace.visibility
 
 513   # Test invalid updates
 
 514   def test_update_invalid
 
 515     trace = create(:trace)
 
 518     session_for(trace.user)
 
 519     put trace_path(trace, :trace => { :description => "Changed description", :tagstring => "new_tag", :visibility => "wrong" })
 
 520     assert_response :success
 
 521     assert_select "title", :text => /^Editing Trace/
 
 524   # Test destroying a trace
 
 526     public_trace_file = create(:trace, :visibility => "public")
 
 527     deleted_trace_file = create(:trace, :deleted)
 
 530     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 531     assert_response :forbidden
 
 533     # Now with some other user, which should fail
 
 534     session_for(create(:user))
 
 535     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 536     assert_response :forbidden
 
 538     # Now with a trace which doesn't exist
 
 539     session_for(create(:user))
 
 540     delete trace_path(:display_name => create(:user).display_name, :id => 0)
 
 541     assert_response :not_found
 
 543     # Now with a trace has already been deleted
 
 544     session_for(deleted_trace_file.user)
 
 545     delete trace_path(:display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file)
 
 546     assert_response :not_found
 
 548     # Now with a trace that we are allowed to delete
 
 549     session_for(public_trace_file.user)
 
 550     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 551     assert_redirected_to :action => :index, :display_name => public_trace_file.user.display_name
 
 552     trace = Trace.find(public_trace_file.id)
 
 553     assert_not trace.visible
 
 555     # Finally with a trace that is destroyed by an admin
 
 556     public_trace_file = create(:trace, :visibility => "public")
 
 557     admin = create(:administrator_user)
 
 559     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 560     assert_redirected_to :action => :index, :display_name => public_trace_file.user.display_name
 
 561     trace = Trace.find(public_trace_file.id)
 
 562     assert_not trace.visible
 
 567   def check_trace_index(traces)
 
 568     assert_response :success
 
 569     assert_template "index"
 
 572       assert_select "h2", /Nothing here yet/
 
 574       assert_select "table#trace_list tbody", :count => 1 do
 
 575         assert_select "tr", :count => traces.length do |rows|
 
 576           traces.zip(rows).each do |trace, row|
 
 577             assert_select row, "a", Regexp.new(Regexp.escape(trace.name))
 
 578             assert_select row, "li", Regexp.new(Regexp.escape("#{trace.size} points")) if trace.inserted?
 
 579             assert_select row, "td", Regexp.new(Regexp.escape(trace.description))
 
 580             assert_select row, "td", Regexp.new(Regexp.escape("by #{trace.user.display_name}"))
 
 581             assert_select row, "a[href='#{user_path trace.user}']", :text => trace.user.display_name
 
 588   def check_no_page_link(name)
 
 589     assert_select "a.page-link", { :text => /#{Regexp.quote(name)}/, :count => 0 }, "unexpected #{name} page link"
 
 592   def check_page_link(name)
 
 593     assert_select "a.page-link", { :text => /#{Regexp.quote(name)}/ }, "missing #{name} page link" do |buttons|
 
 594       return buttons.first.attributes["href"].value
 
 598   def check_trace_show(trace)
 
 599     assert_response :success
 
 600     assert_template "show"
 
 602     assert_select "table", :count => 1 do
 
 603       assert_select "td", /^#{Regexp.quote(trace.name)} /
 
 604       assert_select "td a[href='#{user_path trace.user}']", :text => trace.user.display_name
 
 605       assert_select "td", trace.description