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)
 
 201     # Try and get the index
 
 203     assert_response :success
 
 204     assert_select "table#trace_list tbody", :count => 1 do
 
 205       assert_select "tr", :count => 20
 
 207     assert_select "li.page-item.disabled span.page-link", :text => "Newer Traces", :count => 2
 
 208     assert_select "li.page-item a.page-link", :text => "Older Traces", :count => 2
 
 210     # Try and get the second page
 
 211     get css_select("li.page-item a.page-link").last["href"]
 
 212     assert_response :success
 
 213     assert_select "table#trace_list tbody", :count => 1 do
 
 214       assert_select "tr", :count => 20
 
 216     assert_select "li.page-item a.page-link", :text => "Newer Traces", :count => 2
 
 217     assert_select "li.page-item a.page-link", :text => "Older Traces", :count => 2
 
 219     # Try and get the third page
 
 220     get css_select("li.page-item a.page-link").last["href"]
 
 221     assert_response :success
 
 222     assert_select "table#trace_list tbody", :count => 1 do
 
 223       assert_select "tr", :count => 10
 
 225     assert_select "li.page-item a.page-link", :text => "Newer Traces", :count => 2
 
 226     assert_select "li.page-item.disabled span.page-link", :text => "Older Traces", :count => 2
 
 228     # Go back to the second page
 
 229     get css_select("li.page-item a.page-link").first["href"]
 
 230     assert_response :success
 
 231     assert_select "table#trace_list tbody", :count => 1 do
 
 232       assert_select "tr", :count => 20
 
 234     assert_select "li.page-item a.page-link", :text => "Newer Traces", :count => 2
 
 235     assert_select "li.page-item a.page-link", :text => "Older Traces", :count => 2
 
 237     # Go back to the first page
 
 238     get css_select("li.page-item a.page-link").first["href"]
 
 239     assert_response :success
 
 240     assert_select "table#trace_list tbody", :count => 1 do
 
 241       assert_select "tr", :count => 20
 
 243     assert_select "li.page-item.disabled span.page-link", :text => "Newer Traces", :count => 2
 
 244     assert_select "li.page-item a.page-link", :text => "Older Traces", :count => 2
 
 247   # Check a multi-page index of tagged traces
 
 248   def test_index_tagged_paged
 
 249     # Create several pages worth of traces
 
 250     create_list(:trace, 100) do |trace, index|
 
 251       create(:tracetag, :trace => trace, :tag => "London") if index.even?
 
 254     # Try and get the index
 
 255     get traces_path(:tag => "London")
 
 256     assert_response :success
 
 257     assert_select "table#trace_list tbody", :count => 1 do
 
 258       assert_select "tr", :count => 20
 
 260     assert_select "li.page-item.disabled span.page-link", :text => "Newer Traces", :count => 2
 
 261     assert_select "li.page-item a.page-link", :text => "Older Traces", :count => 2
 
 263     # Try and get the second page
 
 264     get css_select("li.page-item a.page-link").last["href"]
 
 265     assert_response :success
 
 266     assert_select "table#trace_list tbody", :count => 1 do
 
 267       assert_select "tr", :count => 20
 
 269     assert_select "li.page-item a.page-link", :text => "Newer Traces", :count => 2
 
 270     assert_select "li.page-item a.page-link", :text => "Older Traces", :count => 2
 
 272     # Try and get the third page
 
 273     get css_select("li.page-item a.page-link").last["href"]
 
 274     assert_response :success
 
 275     assert_select "table#trace_list tbody", :count => 1 do
 
 276       assert_select "tr", :count => 10
 
 278     assert_select "li.page-item a.page-link", :text => "Newer Traces", :count => 2
 
 279     assert_select "li.page-item.disabled span.page-link", :text => "Older Traces", :count => 2
 
 281     # Go back to the second page
 
 282     get css_select("li.page-item a.page-link").first["href"]
 
 283     assert_response :success
 
 284     assert_select "table#trace_list tbody", :count => 1 do
 
 285       assert_select "tr", :count => 20
 
 287     assert_select "li.page-item a.page-link", :text => "Newer Traces", :count => 2
 
 288     assert_select "li.page-item a.page-link", :text => "Older Traces", :count => 2
 
 290     # Go back to the first page
 
 291     get css_select("li.page-item a.page-link").first["href"]
 
 292     assert_response :success
 
 293     assert_select "table#trace_list tbody", :count => 1 do
 
 294       assert_select "tr", :count => 20
 
 296     assert_select "li.page-item.disabled span.page-link", :text => "Newer Traces", :count => 2
 
 297     assert_select "li.page-item a.page-link", :text => "Older Traces", :count => 2
 
 300   def test_index_invalid_paged
 
 301     # Try some invalid paged accesses
 
 302     %w[-1 0 fred].each do |id|
 
 303       get traces_path(:before => id)
 
 304       assert_redirected_to :controller => :errors, :action => :bad_request
 
 306       get traces_path(:after => id)
 
 307       assert_redirected_to :controller => :errors, :action => :bad_request
 
 311   # Test showing a trace
 
 313     public_trace_file = create(:trace, :visibility => "public")
 
 315     # First with no auth, which should work since the trace is public
 
 316     get show_trace_path(public_trace_file.user, public_trace_file)
 
 317     check_trace_show public_trace_file
 
 319     # Now with some other user, which should work since the trace is public
 
 320     session_for(create(:user))
 
 321     get show_trace_path(public_trace_file.user, public_trace_file)
 
 322     check_trace_show public_trace_file
 
 324     # And finally we should be able to do it with the owner of the trace
 
 325     session_for(public_trace_file.user)
 
 326     get show_trace_path(public_trace_file.user, public_trace_file)
 
 327     check_trace_show public_trace_file
 
 330   # Check an anonymous trace can't be viewed by another user
 
 332     anon_trace_file = create(:trace, :visibility => "private")
 
 335     get show_trace_path(anon_trace_file.user, anon_trace_file)
 
 336     assert_redirected_to :action => :index
 
 338     # Now with some other user, which should not work since the trace is anon
 
 339     session_for(create(:user))
 
 340     get show_trace_path(anon_trace_file.user, anon_trace_file)
 
 341     assert_redirected_to :action => :index
 
 343     # And finally we should be able to do it with the owner of the trace
 
 344     session_for(anon_trace_file.user)
 
 345     get show_trace_path(anon_trace_file.user, anon_trace_file)
 
 346     check_trace_show anon_trace_file
 
 349   # Test showing a trace that doesn't exist
 
 350   def test_show_not_found
 
 351     deleted_trace_file = create(:trace, :deleted)
 
 353     # First with a trace that has never existed
 
 354     get show_trace_path(create(:user), 0)
 
 355     assert_redirected_to :action => :index
 
 357     # Now with a trace that has been deleted
 
 358     session_for(deleted_trace_file.user)
 
 359     get show_trace_path(deleted_trace_file.user, deleted_trace_file)
 
 360     assert_redirected_to :action => :index
 
 363   # Test fetching the new trace page
 
 367     assert_redirected_to login_path(:referer => new_trace_path)
 
 369     # Now authenticated as a user with gps.trace.visibility set
 
 371     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
 
 374     assert_response :success
 
 376     assert_select "select#trace_visibility option[value=identifiable][selected]", 1
 
 378     # Now authenticated as a user with gps.trace.public set
 
 379     second_user = create(:user)
 
 380     create(:user_preference, :user => second_user, :k => "gps.trace.public", :v => "default")
 
 381     session_for(second_user)
 
 383     assert_response :success
 
 385     assert_select "select#trace_visibility option[value=public][selected]", 1
 
 387     # Now authenticated as a user with no preferences
 
 388     third_user = create(:user)
 
 389     session_for(third_user)
 
 391     assert_response :success
 
 393     assert_select "select#trace_visibility option[value=private][selected]", 1
 
 396   # Test creating a trace
 
 399     fixture = Rails.root.join("test/gpx/fixtures/a.gpx")
 
 400     file = Rack::Test::UploadedFile.new(fixture, "application/gpx+xml")
 
 404     post traces_path(:trace => { :gpx_file => file, :description => "New Trace", :tagstring => "new,trace", :visibility => "trackable" })
 
 405     assert_response :forbidden
 
 411     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
 
 412     assert_not_equal "trackable", user.preferences.find_by(:k => "gps.trace.visibility").v
 
 414     post traces_path, :params => { :trace => { :gpx_file => file, :description => "New Trace", :tagstring => "new,trace", :visibility => "trackable" } }
 
 415     assert_redirected_to :action => :index, :display_name => user.display_name
 
 416     assert_match(/file has been uploaded/, flash[:notice])
 
 417     trace = Trace.order(:id => :desc).first
 
 418     assert_equal "a.gpx", trace.name
 
 419     assert_equal "New Trace", trace.description
 
 420     assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
 
 421     assert_equal "trackable", trace.visibility
 
 422     assert_not trace.inserted
 
 423     assert_equal File.new(fixture).read, trace.file.blob.download
 
 425     assert_equal "trackable", user.preferences.find_by(:k => "gps.trace.visibility").v
 
 428   # Test creating a trace with validation errors
 
 429   def test_create_post_with_validation_errors
 
 431     fixture = Rails.root.join("test/gpx/fixtures/a.gpx")
 
 432     file = Rack::Test::UploadedFile.new(fixture, "application/gpx+xml")
 
 436     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
 
 437     assert_not_equal "trackable", user.preferences.find_by(:k => "gps.trace.visibility").v
 
 439     post traces_path, :params => { :trace => { :gpx_file => file, :description => "", :tagstring => "new,trace", :visibility => "trackable" } }
 
 441     assert_match "is too short (minimum is 1 character)", response.body
 
 444   # Test fetching the edit page for a trace using GET
 
 446     public_trace_file = create(:trace, :visibility => "public")
 
 447     deleted_trace_file = create(:trace, :deleted)
 
 450     get edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 451     assert_redirected_to login_path(:referer => edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file.id))
 
 453     # Now with some other user, which should fail
 
 454     session_for(create(:user))
 
 455     get edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 456     assert_response :forbidden
 
 458     # Now with a trace which doesn't exist
 
 459     session_for(create(:user))
 
 460     get edit_trace_path(:display_name => create(:user).display_name, :id => 0)
 
 461     assert_response :not_found
 
 463     # Now with a trace which has been deleted
 
 464     session_for(deleted_trace_file.user)
 
 465     get edit_trace_path(:display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file)
 
 466     assert_response :not_found
 
 468     # Finally with a trace that we are allowed to edit
 
 469     session_for(public_trace_file.user)
 
 470     get edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 471     assert_response :success
 
 474   # Test saving edits to a trace
 
 476     public_trace_file = create(:trace, :visibility => "public")
 
 477     deleted_trace_file = create(:trace, :deleted)
 
 480     new_details = { :description => "Changed description", :tagstring => "new_tag", :visibility => "private" }
 
 483     put trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file, :trace => new_details)
 
 484     assert_response :forbidden
 
 486     # Now with some other user, which should fail
 
 487     session_for(create(:user))
 
 488     put trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file, :trace => new_details)
 
 489     assert_response :forbidden
 
 491     # Now with a trace which doesn't exist
 
 492     session_for(create(:user))
 
 493     put trace_path(:display_name => create(:user).display_name, :id => 0, :trace => new_details)
 
 494     assert_response :not_found
 
 496     # Now with a trace which has been deleted
 
 497     session_for(deleted_trace_file.user)
 
 498     put trace_path(:display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file, :trace => new_details)
 
 499     assert_response :not_found
 
 501     # Finally with a trace that we are allowed to edit
 
 502     session_for(public_trace_file.user)
 
 503     put trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file, :trace => new_details)
 
 504     assert_redirected_to :action => :show, :display_name => public_trace_file.user.display_name
 
 505     trace = Trace.find(public_trace_file.id)
 
 506     assert_equal new_details[:description], trace.description
 
 507     assert_equal new_details[:tagstring], trace.tagstring
 
 508     assert_equal new_details[:visibility], trace.visibility
 
 511   # Test invalid updates
 
 512   def test_update_invalid
 
 513     trace = create(:trace)
 
 516     session_for(trace.user)
 
 517     put trace_path(trace, :trace => { :description => "Changed description", :tagstring => "new_tag", :visibility => "wrong" })
 
 518     assert_response :success
 
 519     assert_select "title", :text => /^Editing Trace/
 
 522   # Test destroying a trace
 
 524     public_trace_file = create(:trace, :visibility => "public")
 
 525     deleted_trace_file = create(:trace, :deleted)
 
 528     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 529     assert_response :forbidden
 
 531     # Now with some other user, which should fail
 
 532     session_for(create(:user))
 
 533     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 534     assert_response :forbidden
 
 536     # Now with a trace which doesn't exist
 
 537     session_for(create(:user))
 
 538     delete trace_path(:display_name => create(:user).display_name, :id => 0)
 
 539     assert_response :not_found
 
 541     # Now with a trace has already been deleted
 
 542     session_for(deleted_trace_file.user)
 
 543     delete trace_path(:display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file)
 
 544     assert_response :not_found
 
 546     # Now with a trace that we are allowed to delete
 
 547     session_for(public_trace_file.user)
 
 548     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 549     assert_redirected_to :action => :index, :display_name => public_trace_file.user.display_name
 
 550     trace = Trace.find(public_trace_file.id)
 
 551     assert_not trace.visible
 
 553     # Finally with a trace that is destroyed by an admin
 
 554     public_trace_file = create(:trace, :visibility => "public")
 
 555     admin = create(:administrator_user)
 
 557     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 558     assert_redirected_to :action => :index, :display_name => public_trace_file.user.display_name
 
 559     trace = Trace.find(public_trace_file.id)
 
 560     assert_not trace.visible
 
 565   def check_trace_index(traces)
 
 566     assert_response :success
 
 567     assert_template "index"
 
 570       assert_select "h2", /Nothing here yet/
 
 572       assert_select "table#trace_list tbody", :count => 1 do
 
 573         assert_select "tr", :count => traces.length do |rows|
 
 574           traces.zip(rows).each do |trace, row|
 
 575             assert_select row, "a", Regexp.new(Regexp.escape(trace.name))
 
 576             assert_select row, "li", Regexp.new(Regexp.escape("#{trace.size} points")) if trace.inserted?
 
 577             assert_select row, "td", Regexp.new(Regexp.escape(trace.description))
 
 578             assert_select row, "td", Regexp.new(Regexp.escape("by #{trace.user.display_name}"))
 
 579             assert_select row, "a[href='#{user_path trace.user}']", :text => trace.user.display_name
 
 586   def check_trace_show(trace)
 
 587     assert_response :success
 
 588     assert_template "show"
 
 590     assert_select "table", :count => 1 do
 
 591       assert_select "td", /^#{Regexp.quote(trace.name)} /
 
 592       assert_select "td a[href='#{user_path trace.user}']", :text => trace.user.display_name
 
 593       assert_select "td", trace.description