1 # frozen_string_literal: true
 
   5 class TracesControllerTest < ActionDispatch::IntegrationTest
 
   7   # test all routes which lead to this controller
 
  10       { :path => "/traces", :method => :get },
 
  11       { :controller => "traces", :action => "index" }
 
  14       { :path => "/traces/tag/tagname", :method => :get },
 
  15       { :controller => "traces", :action => "index", :tag => "tagname" }
 
  18       { :path => "/user/username/traces", :method => :get },
 
  19       { :controller => "traces", :action => "index", :display_name => "username" }
 
  22       { :path => "/user/username/traces/tag/tagname", :method => :get },
 
  23       { :controller => "traces", :action => "index", :display_name => "username", :tag => "tagname" }
 
  27       { :path => "/traces/mine", :method => :get },
 
  28       { :controller => "traces", :action => "mine" }
 
  31       { :path => "/traces/mine/tag/tagname", :method => :get },
 
  32       { :controller => "traces", :action => "mine", :tag => "tagname" }
 
  36       { :path => "/user/username/traces/1", :method => :get },
 
  37       { :controller => "traces", :action => "show", :display_name => "username", :id => "1" }
 
  41       { :path => "/traces/new", :method => :get },
 
  42       { :controller => "traces", :action => "new" }
 
  45       { :path => "/traces", :method => :post },
 
  46       { :controller => "traces", :action => "create" }
 
  49       { :path => "/traces/1/edit", :method => :get },
 
  50       { :controller => "traces", :action => "edit", :id => "1" }
 
  53       { :path => "/traces/1", :method => :put },
 
  54       { :controller => "traces", :action => "update", :id => "1" }
 
  57       { :path => "/traces/1", :method => :delete },
 
  58       { :controller => "traces", :action => "destroy", :id => "1" }
 
  62     assert_redirected_to "/traces"
 
  64     get "/traces/tag/tagname/page/1"
 
  65     assert_redirected_to "/traces/tag/tagname"
 
  67     get "/user/username/traces/page/1"
 
  68     assert_redirected_to "/user/username/traces"
 
  70     get "/user/username/traces/tag/tagname/page/1"
 
  71     assert_redirected_to "/user/username/traces/tag/tagname"
 
  73     get "/traces/mine/page/1"
 
  74     assert_redirected_to "/traces/mine"
 
  76     get "/traces/mine/tag/tagname/page/1"
 
  77     assert_redirected_to "/traces/mine/tag/tagname"
 
  80   # Check that the index of traces is displayed
 
  83     # The fourth test below is surprisingly sensitive to timestamp ordering when the timestamps are equal.
 
  84     trace_a = create(:trace, :visibility => "public", :timestamp => 4.seconds.ago) do |trace|
 
  85       create(:tracetag, :trace => trace, :tag => "London")
 
  87     trace_b = create(:trace, :visibility => "public", :timestamp => 3.seconds.ago) do |trace|
 
  88       create(:tracetag, :trace => trace, :tag => "Birmingham")
 
  90     trace_c = create(:trace, :visibility => "private", :user => user, :timestamp => 2.seconds.ago) do |trace|
 
  91       create(:tracetag, :trace => trace, :tag => "London")
 
  93     trace_d = create(:trace, :visibility => "private", :user => user, :timestamp => 1.second.ago) do |trace|
 
  94       create(:tracetag, :trace => trace, :tag => "Birmingham")
 
  97     # First with the public index
 
  99     check_trace_index [trace_b, trace_a]
 
 101     # Restrict traces to those with a given tag
 
 102     get traces_path(:tag => "London")
 
 103     check_trace_index [trace_a]
 
 107     # Should see more when we are logged in
 
 109     check_trace_index [trace_d, trace_c, trace_b, trace_a]
 
 111     # Again, we should see more when we are logged in
 
 112     get traces_path(:tag => "London")
 
 113     check_trace_index [trace_c, trace_a]
 
 116   # Check that I can get mine
 
 119     create(:trace, :visibility => "public") do |trace|
 
 120       create(:tracetag, :trace => trace, :tag => "Birmingham")
 
 122     trace_b = create(:trace, :visibility => "private", :user => user) do |trace|
 
 123       create(:tracetag, :trace => trace, :tag => "London")
 
 126     # First try to get it when not logged in
 
 128     assert_redirected_to login_path(:referer => "/traces/mine")
 
 132     # Now try when logged in
 
 134     assert_redirected_to :action => "index", :display_name => user.display_name
 
 136     # Fetch the actual index
 
 137     get traces_path(:display_name => user.display_name)
 
 138     check_trace_index [trace_b]
 
 141   # Check the index of traces for a specific user
 
 144     checked_user_traces_path = url_for :only_path => true, :controller => "traces", :action => "index", :display_name => user.display_name
 
 145     second_user = create(:user)
 
 146     third_user = create(:user)
 
 148     trace_b = create(:trace, :visibility => "public", :user => user)
 
 149     trace_c = create(:trace, :visibility => "private", :user => user) do |trace|
 
 150       create(:tracetag, :trace => trace, :tag => "London")
 
 153     # Test a user with no traces
 
 154     get traces_path(:display_name => second_user.display_name)
 
 157     # Test the user with the traces - should see only public ones
 
 158     get traces_path(:display_name => user.display_name)
 
 159     check_trace_index [trace_b]
 
 160     assert_dom ".nav-tabs" do
 
 161       assert_dom "a[href='#{traces_path}']", :text => "All Traces", :count => 1
 
 162       assert_dom "a[href='#{traces_mine_path}']", :text => "My Traces", :count => 0
 
 163       assert_dom "a[href='#{checked_user_traces_path}']", :text => Regexp.new(Regexp.escape(user.display_name)), :count => 1
 
 166     session_for(third_user)
 
 168     # Should still see only public ones when authenticated as another user
 
 169     get traces_path(:display_name => user.display_name)
 
 170     check_trace_index [trace_b]
 
 171     assert_dom ".nav-tabs" do
 
 172       assert_dom "a[href='#{traces_path}']", :text => "All Traces", :count => 1
 
 173       assert_dom "a[href='#{traces_mine_path}']", :text => "My Traces", :count => 1
 
 174       assert_dom "a[href='#{checked_user_traces_path}']", :text => Regexp.new(Regexp.escape(user.display_name)), :count => 1
 
 179     # Should see all traces when authenticated as the target user
 
 180     get traces_path(:display_name => user.display_name)
 
 181     check_trace_index [trace_c, trace_b]
 
 182     assert_dom ".nav-tabs" do
 
 183       assert_dom "a[href='#{traces_path}']", :text => "All Traces", :count => 1
 
 184       assert_dom "a[href='#{traces_mine_path}']", :text => "My Traces", :count => 1
 
 185       assert_dom "a[href='#{checked_user_traces_path}']", :text => Regexp.new(Regexp.escape(user.display_name)), :count => 0
 
 188     # Should only see traces with the correct tag when a tag is specified
 
 189     get traces_path(:display_name => user.display_name, :tag => "London")
 
 190     check_trace_index [trace_c]
 
 192     # Should get an error if the user does not exist
 
 193     get traces_path(:display_name => "UnknownUser")
 
 194     assert_response :not_found
 
 195     assert_template "users/no_such_user"
 
 198   # Check a multi-page index
 
 200     # Create several pages worth of traces
 
 201     create_list(:trace, 50)
 
 202     next_path = traces_path
 
 204     # Try and get the index
 
 206     assert_response :success
 
 207     assert_select "table#trace_list tbody", :count => 1 do
 
 208       assert_select "tr", :count => 20
 
 210     check_no_page_link "Newer Traces"
 
 211     next_path = check_page_link "Older Traces"
 
 213     # Try and get the second page
 
 215     assert_response :success
 
 216     assert_select "table#trace_list tbody", :count => 1 do
 
 217       assert_select "tr", :count => 20
 
 219     check_page_link "Newer Traces"
 
 220     next_path = check_page_link "Older Traces"
 
 222     # Try and get the third page
 
 224     assert_response :success
 
 225     assert_select "table#trace_list tbody", :count => 1 do
 
 226       assert_select "tr", :count => 10
 
 228     next_path = check_page_link "Newer Traces"
 
 229     check_no_page_link "Older Traces"
 
 231     # Go back to the second page
 
 233     assert_response :success
 
 234     assert_select "table#trace_list tbody", :count => 1 do
 
 235       assert_select "tr", :count => 20
 
 237     next_path = check_page_link "Newer Traces"
 
 238     check_page_link "Older Traces"
 
 240     # Go back to the first page
 
 242     assert_response :success
 
 243     assert_select "table#trace_list tbody", :count => 1 do
 
 244       assert_select "tr", :count => 20
 
 246     check_no_page_link "Newer Traces"
 
 247     check_page_link "Older Traces"
 
 250   # Check a multi-page index of tagged traces
 
 251   def test_index_tagged_paged
 
 252     # Create several pages worth of traces
 
 253     create_list(:trace, 100) do |trace, index|
 
 254       create(:tracetag, :trace => trace, :tag => "London") if index.even?
 
 256     next_path = traces_path :tag => "London"
 
 258     # Try and get the index
 
 260     assert_response :success
 
 261     assert_select "table#trace_list tbody", :count => 1 do
 
 262       assert_select "tr", :count => 20
 
 264     check_no_page_link "Newer Traces"
 
 265     next_path = check_page_link "Older Traces"
 
 267     # Try and get the second page
 
 269     assert_response :success
 
 270     assert_select "table#trace_list tbody", :count => 1 do
 
 271       assert_select "tr", :count => 20
 
 273     check_page_link "Newer Traces"
 
 274     next_path = check_page_link "Older Traces"
 
 276     # Try and get the third page
 
 278     assert_response :success
 
 279     assert_select "table#trace_list tbody", :count => 1 do
 
 280       assert_select "tr", :count => 10
 
 282     next_path = check_page_link "Newer Traces"
 
 283     check_no_page_link "Older Traces"
 
 285     # Go back to the second page
 
 287     assert_response :success
 
 288     assert_select "table#trace_list tbody", :count => 1 do
 
 289       assert_select "tr", :count => 20
 
 291     next_path = check_page_link "Newer Traces"
 
 292     check_page_link "Older Traces"
 
 294     # Go back to the first page
 
 296     assert_response :success
 
 297     assert_select "table#trace_list tbody", :count => 1 do
 
 298       assert_select "tr", :count => 20
 
 300     check_no_page_link "Newer Traces"
 
 301     check_page_link "Older Traces"
 
 304   def test_index_invalid_paged
 
 305     # Try some invalid paged accesses
 
 306     %w[-1 fred].each do |id|
 
 307       get traces_path(:before => id)
 
 308       assert_redirected_to :controller => :errors, :action => :bad_request
 
 310       get traces_path(:after => id)
 
 311       assert_redirected_to :controller => :errors, :action => :bad_request
 
 315   # Test showing a trace
 
 317     public_trace_file = create(:trace, :visibility => "public")
 
 319     # First with no auth, which should work since the trace is public
 
 320     get show_trace_path(public_trace_file.user, public_trace_file)
 
 321     check_trace_show public_trace_file
 
 323     # Now with some other user, which should work since the trace is public
 
 324     session_for(create(:user))
 
 325     get show_trace_path(public_trace_file.user, public_trace_file)
 
 326     check_trace_show public_trace_file
 
 328     # And finally we should be able to do it with the owner of the trace
 
 329     session_for(public_trace_file.user)
 
 330     get show_trace_path(public_trace_file.user, public_trace_file)
 
 331     check_trace_show public_trace_file
 
 334   # Check an anonymous trace can't be viewed by another user
 
 336     anon_trace_file = create(:trace, :visibility => "private")
 
 339     get show_trace_path(anon_trace_file.user, anon_trace_file)
 
 340     assert_redirected_to :action => :index
 
 342     # Now with some other user, which should not work since the trace is anon
 
 343     session_for(create(:user))
 
 344     get show_trace_path(anon_trace_file.user, anon_trace_file)
 
 345     assert_redirected_to :action => :index
 
 347     # And finally we should be able to do it with the owner of the trace
 
 348     session_for(anon_trace_file.user)
 
 349     get show_trace_path(anon_trace_file.user, anon_trace_file)
 
 350     check_trace_show anon_trace_file
 
 353   # Test showing a trace that doesn't exist
 
 354   def test_show_not_found
 
 355     deleted_trace_file = create(:trace, :deleted)
 
 357     # First with a trace that has never existed
 
 358     get show_trace_path(create(:user), 0)
 
 359     assert_redirected_to :action => :index
 
 361     # Now with a trace that has been deleted
 
 362     session_for(deleted_trace_file.user)
 
 363     get show_trace_path(deleted_trace_file.user, deleted_trace_file)
 
 364     assert_redirected_to :action => :index
 
 367   # Test fetching the new trace page
 
 371     assert_redirected_to login_path(:referer => new_trace_path)
 
 373     # Now authenticated as a user with gps.trace.visibility set
 
 375     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
 
 378     assert_response :success
 
 380     assert_select "select#trace_visibility option[value=identifiable][selected]", 1
 
 382     # Now authenticated as a user with gps.trace.public set
 
 383     second_user = create(:user)
 
 384     create(:user_preference, :user => second_user, :k => "gps.trace.public", :v => "default")
 
 385     session_for(second_user)
 
 387     assert_response :success
 
 389     assert_select "select#trace_visibility option[value=public][selected]", 1
 
 391     # Now authenticated as a user with no preferences
 
 392     third_user = create(:user)
 
 393     session_for(third_user)
 
 395     assert_response :success
 
 397     assert_select "select#trace_visibility option[value=private][selected]", 1
 
 400   # Test creating a trace
 
 403     fixture = Rails.root.join("test/gpx/fixtures/a.gpx")
 
 404     file = Rack::Test::UploadedFile.new(fixture, "application/gpx+xml")
 
 408     post traces_path(:trace => { :gpx_file => file, :description => "New Trace", :tagstring => "new,trace", :visibility => "trackable" })
 
 409     assert_response :forbidden
 
 415     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
 
 416     assert_not_equal "trackable", user.preferences.find_by(:k => "gps.trace.visibility").v
 
 418     post traces_path, :params => { :trace => { :gpx_file => file, :description => "New Trace", :tagstring => "new,trace", :visibility => "trackable" } }
 
 419     assert_redirected_to :action => :index, :display_name => user.display_name
 
 420     assert_match(/file has been uploaded/, flash[:notice])
 
 421     trace = Trace.order(:id => :desc).first
 
 422     assert_equal "a.gpx", trace.name
 
 423     assert_equal "New Trace", trace.description
 
 424     assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
 
 425     assert_equal "trackable", trace.visibility
 
 426     assert_not trace.inserted
 
 427     assert_equal File.new(fixture).read, trace.file.blob.download
 
 429     assert_equal "trackable", user.preferences.find_by(:k => "gps.trace.visibility").v
 
 432   # Test creating a trace with validation errors
 
 433   def test_create_post_with_validation_errors
 
 435     fixture = Rails.root.join("test/gpx/fixtures/a.gpx")
 
 436     file = Rack::Test::UploadedFile.new(fixture, "application/gpx+xml")
 
 440     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
 
 441     assert_not_equal "trackable", user.preferences.find_by(:k => "gps.trace.visibility").v
 
 443     post traces_path, :params => { :trace => { :gpx_file => file, :description => "", :tagstring => "new,trace", :visibility => "trackable" } }
 
 445     assert_match "is too short (minimum is 1 character)", response.body
 
 448   # Test fetching the edit page for a trace using GET
 
 450     public_trace_file = create(:trace, :visibility => "public")
 
 451     deleted_trace_file = create(:trace, :deleted)
 
 454     get edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 455     assert_redirected_to login_path(:referer => edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file.id))
 
 457     # Now with some other user, which should fail
 
 458     session_for(create(:user))
 
 459     get edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 460     assert_response :forbidden
 
 462     # Now with a trace which doesn't exist
 
 463     session_for(create(:user))
 
 464     get edit_trace_path(:display_name => create(:user).display_name, :id => 0)
 
 465     assert_response :not_found
 
 467     # Now with a trace which has been deleted
 
 468     session_for(deleted_trace_file.user)
 
 469     get edit_trace_path(:display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file)
 
 470     assert_response :not_found
 
 472     # Finally with a trace that we are allowed to edit
 
 473     session_for(public_trace_file.user)
 
 474     get edit_trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 475     assert_response :success
 
 478   # Test saving edits to a trace
 
 480     public_trace_file = create(:trace, :visibility => "public")
 
 481     deleted_trace_file = create(:trace, :deleted)
 
 484     new_details = { :description => "Changed description", :tagstring => "new_tag", :visibility => "private" }
 
 487     put trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file, :trace => new_details)
 
 488     assert_response :forbidden
 
 490     # Now with some other user, which should fail
 
 491     session_for(create(:user))
 
 492     put trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file, :trace => new_details)
 
 493     assert_response :forbidden
 
 495     # Now with a trace which doesn't exist
 
 496     session_for(create(:user))
 
 497     put trace_path(:display_name => create(:user).display_name, :id => 0, :trace => new_details)
 
 498     assert_response :not_found
 
 500     # Now with a trace which has been deleted
 
 501     session_for(deleted_trace_file.user)
 
 502     put trace_path(:display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file, :trace => new_details)
 
 503     assert_response :not_found
 
 505     # Finally with a trace that we are allowed to edit
 
 506     session_for(public_trace_file.user)
 
 507     put trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file, :trace => new_details)
 
 508     assert_redirected_to :action => :show, :display_name => public_trace_file.user.display_name
 
 509     trace = Trace.find(public_trace_file.id)
 
 510     assert_equal new_details[:description], trace.description
 
 511     assert_equal new_details[:tagstring], trace.tagstring
 
 512     assert_equal new_details[:visibility], trace.visibility
 
 515   # Test invalid updates
 
 516   def test_update_invalid
 
 517     trace = create(:trace)
 
 520     session_for(trace.user)
 
 521     put trace_path(trace, :trace => { :description => "Changed description", :tagstring => "new_tag", :visibility => "wrong" })
 
 522     assert_response :success
 
 523     assert_select "title", :text => /^Editing Trace/
 
 526   # Test destroying a trace
 
 528     public_trace_file = create(:trace, :visibility => "public")
 
 529     deleted_trace_file = create(:trace, :deleted)
 
 532     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 533     assert_response :forbidden
 
 535     # Now with some other user, which should fail
 
 536     session_for(create(:user))
 
 537     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 538     assert_response :forbidden
 
 540     # Now with a trace which doesn't exist
 
 541     session_for(create(:user))
 
 542     delete trace_path(:display_name => create(:user).display_name, :id => 0)
 
 543     assert_response :not_found
 
 545     # Now with a trace has already been deleted
 
 546     session_for(deleted_trace_file.user)
 
 547     delete trace_path(:display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file)
 
 548     assert_response :not_found
 
 550     # Now with a trace that we are allowed to delete
 
 551     session_for(public_trace_file.user)
 
 552     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 553     assert_redirected_to :action => :index, :display_name => public_trace_file.user.display_name
 
 554     trace = Trace.find(public_trace_file.id)
 
 555     assert_not trace.visible
 
 557     # Finally with a trace that is destroyed by an admin
 
 558     public_trace_file = create(:trace, :visibility => "public")
 
 559     admin = create(:administrator_user)
 
 561     delete trace_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file)
 
 562     assert_redirected_to :action => :index, :display_name => public_trace_file.user.display_name
 
 563     trace = Trace.find(public_trace_file.id)
 
 564     assert_not trace.visible
 
 569   def check_trace_index(traces)
 
 570     assert_response :success
 
 571     assert_template "index"
 
 574       assert_select "h2", /Nothing here yet/
 
 576       assert_select "table#trace_list tbody", :count => 1 do
 
 577         assert_select "tr", :count => traces.length do |rows|
 
 578           traces.zip(rows).each do |trace, row|
 
 579             assert_select row, "a", Regexp.new(Regexp.escape(trace.name))
 
 580             assert_select row, "li", Regexp.new(Regexp.escape("#{trace.size} points")) if trace.inserted?
 
 581             assert_select row, "td", Regexp.new(Regexp.escape(trace.description))
 
 582             assert_select row, "td", Regexp.new(Regexp.escape("by #{trace.user.display_name}"))
 
 583             assert_select row, "a[href='#{user_path trace.user}']", :text => trace.user.display_name
 
 590   def check_no_page_link(name)
 
 591     assert_select "a.page-link", { :text => /#{Regexp.quote(name)}/, :count => 0 }, "unexpected #{name} page link"
 
 594   def check_page_link(name)
 
 595     assert_select "a.page-link", { :text => /#{Regexp.quote(name)}/ }, "missing #{name} page link" do |buttons|
 
 596       return buttons.first.attributes["href"].value
 
 600   def check_trace_show(trace)
 
 601     assert_response :success
 
 602     assert_template "show"
 
 604     assert_select "table", :count => 1 do
 
 605       assert_select "td", /^#{Regexp.quote(trace.name)} /
 
 606       assert_select "td a[href='#{user_path trace.user}']", :text => trace.user.display_name
 
 607       assert_select "td", trace.description