a23b5947359506b2f659ef211663066f86572739
[rails.git] / test / controllers / trace_controller_test.rb
1 require "test_helper"
2 require "minitest/mock"
3
4 class TraceControllerTest < ActionController::TestCase
5   def setup
6     @gpx_trace_dir = Object.send("remove_const", "GPX_TRACE_DIR")
7     Object.const_set("GPX_TRACE_DIR", Rails.root.join("test", "gpx", "traces"))
8
9     @gpx_image_dir = Object.send("remove_const", "GPX_IMAGE_DIR")
10     Object.const_set("GPX_IMAGE_DIR", Rails.root.join("test", "gpx", "images"))
11   end
12
13   def teardown
14     File.unlink(*Dir.glob(File.join(GPX_TRACE_DIR, "*.gpx")))
15     File.unlink(*Dir.glob(File.join(GPX_IMAGE_DIR, "*.gif")))
16
17     Object.send("remove_const", "GPX_TRACE_DIR")
18     Object.const_set("GPX_TRACE_DIR", @gpx_trace_dir)
19
20     Object.send("remove_const", "GPX_IMAGE_DIR")
21     Object.const_set("GPX_IMAGE_DIR", @gpx_image_dir)
22   end
23
24   ##
25   # test all routes which lead to this controller
26   def test_routes
27     assert_routing(
28       { :path => "/api/0.6/gpx/create", :method => :post },
29       { :controller => "trace", :action => "api_create" }
30     )
31     assert_routing(
32       { :path => "/api/0.6/gpx/1", :method => :get },
33       { :controller => "trace", :action => "api_read", :id => "1" }
34     )
35     assert_routing(
36       { :path => "/api/0.6/gpx/1", :method => :put },
37       { :controller => "trace", :action => "api_update", :id => "1" }
38     )
39     assert_routing(
40       { :path => "/api/0.6/gpx/1", :method => :delete },
41       { :controller => "trace", :action => "api_delete", :id => "1" }
42     )
43     assert_recognizes(
44       { :controller => "trace", :action => "api_read", :id => "1" },
45       { :path => "/api/0.6/gpx/1/details", :method => :get }
46     )
47     assert_routing(
48       { :path => "/api/0.6/gpx/1/data", :method => :get },
49       { :controller => "trace", :action => "api_data", :id => "1" }
50     )
51     assert_routing(
52       { :path => "/api/0.6/gpx/1/data.xml", :method => :get },
53       { :controller => "trace", :action => "api_data", :id => "1", :format => "xml" }
54     )
55
56     assert_routing(
57       { :path => "/traces", :method => :get },
58       { :controller => "trace", :action => "list" }
59     )
60     assert_routing(
61       { :path => "/traces/page/1", :method => :get },
62       { :controller => "trace", :action => "list", :page => "1" }
63     )
64     assert_routing(
65       { :path => "/traces/tag/tagname", :method => :get },
66       { :controller => "trace", :action => "list", :tag => "tagname" }
67     )
68     assert_routing(
69       { :path => "/traces/tag/tagname/page/1", :method => :get },
70       { :controller => "trace", :action => "list", :tag => "tagname", :page => "1" }
71     )
72     assert_routing(
73       { :path => "/user/username/traces", :method => :get },
74       { :controller => "trace", :action => "list", :display_name => "username" }
75     )
76     assert_routing(
77       { :path => "/user/username/traces/page/1", :method => :get },
78       { :controller => "trace", :action => "list", :display_name => "username", :page => "1" }
79     )
80     assert_routing(
81       { :path => "/user/username/traces/tag/tagname", :method => :get },
82       { :controller => "trace", :action => "list", :display_name => "username", :tag => "tagname" }
83     )
84     assert_routing(
85       { :path => "/user/username/traces/tag/tagname/page/1", :method => :get },
86       { :controller => "trace", :action => "list", :display_name => "username", :tag => "tagname", :page => "1" }
87     )
88
89     assert_routing(
90       { :path => "/traces/mine", :method => :get },
91       { :controller => "trace", :action => "mine" }
92     )
93     assert_routing(
94       { :path => "/traces/mine/page/1", :method => :get },
95       { :controller => "trace", :action => "mine", :page => "1" }
96     )
97     assert_routing(
98       { :path => "/traces/mine/tag/tagname", :method => :get },
99       { :controller => "trace", :action => "mine", :tag => "tagname" }
100     )
101     assert_routing(
102       { :path => "/traces/mine/tag/tagname/page/1", :method => :get },
103       { :controller => "trace", :action => "mine", :tag => "tagname", :page => "1" }
104     )
105
106     assert_routing(
107       { :path => "/traces/rss", :method => :get },
108       { :controller => "trace", :action => "georss", :format => :rss }
109     )
110     assert_routing(
111       { :path => "/traces/tag/tagname/rss", :method => :get },
112       { :controller => "trace", :action => "georss", :tag => "tagname", :format => :rss }
113     )
114     assert_routing(
115       { :path => "/user/username/traces/rss", :method => :get },
116       { :controller => "trace", :action => "georss", :display_name => "username", :format => :rss }
117     )
118     assert_routing(
119       { :path => "/user/username/traces/tag/tagname/rss", :method => :get },
120       { :controller => "trace", :action => "georss", :display_name => "username", :tag => "tagname", :format => :rss }
121     )
122
123     assert_routing(
124       { :path => "/user/username/traces/1", :method => :get },
125       { :controller => "trace", :action => "view", :display_name => "username", :id => "1" }
126     )
127     assert_routing(
128       { :path => "/user/username/traces/1/picture", :method => :get },
129       { :controller => "trace", :action => "picture", :display_name => "username", :id => "1" }
130     )
131     assert_routing(
132       { :path => "/user/username/traces/1/icon", :method => :get },
133       { :controller => "trace", :action => "icon", :display_name => "username", :id => "1" }
134     )
135
136     assert_routing(
137       { :path => "/trace/create", :method => :get },
138       { :controller => "trace", :action => "create" }
139     )
140     assert_routing(
141       { :path => "/trace/create", :method => :post },
142       { :controller => "trace", :action => "create" }
143     )
144     assert_routing(
145       { :path => "/trace/1/data", :method => :get },
146       { :controller => "trace", :action => "data", :id => "1" }
147     )
148     assert_routing(
149       { :path => "/trace/1/data.xml", :method => :get },
150       { :controller => "trace", :action => "data", :id => "1", :format => "xml" }
151     )
152     assert_routing(
153       { :path => "/trace/1/edit", :method => :get },
154       { :controller => "trace", :action => "edit", :id => "1" }
155     )
156     assert_routing(
157       { :path => "/trace/1/edit", :method => :post },
158       { :controller => "trace", :action => "edit", :id => "1" }
159     )
160     assert_routing(
161       { :path => "/trace/1/delete", :method => :post },
162       { :controller => "trace", :action => "delete", :id => "1" }
163     )
164   end
165
166   # Check that the list of traces is displayed
167   def test_list
168     user = create(:user)
169     # The fourth test below is surpisingly sensitive to timestamp ordering when the timestamps are equal.
170     trace_a = create(:trace, :visibility => "public", :timestamp => 4.seconds.ago) do |trace|
171       create(:tracetag, :trace => trace, :tag => "London")
172     end
173     trace_b = create(:trace, :visibility => "public", :timestamp => 3.seconds.ago) do |trace|
174       create(:tracetag, :trace => trace, :tag => "Birmingham")
175     end
176     trace_c = create(:trace, :visibility => "private", :user => user, :timestamp => 2.seconds.ago) do |trace|
177       create(:tracetag, :trace => trace, :tag => "London")
178     end
179     trace_d = create(:trace, :visibility => "private", :user => user, :timestamp => 1.second.ago) do |trace|
180       create(:tracetag, :trace => trace, :tag => "Birmingham")
181     end
182
183     # First with the public list
184     get :list
185     check_trace_list [trace_b, trace_a]
186
187     # Restrict traces to those with a given tag
188     get :list, :params => { :tag => "London" }
189     check_trace_list [trace_a]
190
191     # Should see more when we are logged in
192     get :list, :session => { :user => user }
193     check_trace_list [trace_d, trace_c, trace_b, trace_a]
194
195     # Again, we should see more when we are logged in
196     get :list, :params => { :tag => "London" }, :session => { :user => user }
197     check_trace_list [trace_c, trace_a]
198   end
199
200   # Check that I can get mine
201   def test_list_mine
202     user = create(:user)
203     create(:trace, :visibility => "public") do |trace|
204       create(:tracetag, :trace => trace, :tag => "Birmingham")
205     end
206     trace_b = create(:trace, :visibility => "private", :user => user) do |trace|
207       create(:tracetag, :trace => trace, :tag => "London")
208     end
209
210     # First try to get it when not logged in
211     get :mine
212     assert_redirected_to :controller => "user", :action => "login", :referer => "/traces/mine"
213
214     # Now try when logged in
215     get :mine, :session => { :user => user }
216     assert_redirected_to :controller => "trace", :action => "list", :display_name => user.display_name
217
218     # Fetch the actual list
219     get :list, :params => { :display_name => user.display_name }, :session => { :user => user }
220     check_trace_list [trace_b]
221   end
222
223   # Check the list of traces for a specific user
224   def test_list_user
225     user = create(:user)
226     second_user = create(:user)
227     third_user = create(:user)
228     create(:trace)
229     trace_b = create(:trace, :visibility => "public", :user => user)
230     trace_c = create(:trace, :visibility => "private", :user => user) do |trace|
231       create(:tracetag, :trace => trace, :tag => "London")
232     end
233
234     # Test a user with no traces
235     get :list, :params => { :display_name => second_user.display_name }
236     check_trace_list []
237
238     # Test the user with the traces - should see only public ones
239     get :list, :params => { :display_name => user.display_name }
240     check_trace_list [trace_b]
241
242     # Should still see only public ones when authenticated as another user
243     get :list, :params => { :display_name => user.display_name }, :session => { :user => third_user }
244     check_trace_list [trace_b]
245
246     # Should see all traces when authenticated as the target user
247     get :list, :params => { :display_name => user.display_name }, :session => { :user => user }
248     check_trace_list [trace_c, trace_b]
249
250     # Should only see traces with the correct tag when a tag is specified
251     get :list, :params => { :display_name => user.display_name, :tag => "London" }, :session => { :user => user }
252     check_trace_list [trace_c]
253
254     # Should get an error if the user does not exist
255     get :list, :params => { :display_name => "UnknownUser" }
256     assert_response :not_found
257     assert_template "user/no_such_user"
258   end
259
260   # Check a multi-page list
261   def test_list_paged
262     # Create several pages worth of traces
263     create_list(:trace, 50)
264
265     # Try and get the list
266     get :list
267     assert_response :success
268     assert_select "table#trace_list tbody", :count => 1 do
269       assert_select "tr", :count => 20
270     end
271
272     # Try and get the second page
273     get :list, :params => { :page => 2 }
274     assert_response :success
275     assert_select "table#trace_list tbody", :count => 1 do
276       assert_select "tr", :count => 20
277     end
278   end
279
280   # Check that the rss loads
281   def test_rss
282     user = create(:user)
283
284     # First with the public feed
285     get :georss, :params => { :format => :rss }
286     check_trace_feed Trace.visible_to_all
287
288     # Restrict traces to those with a given tag
289     get :georss, :params => { :tag => "London", :format => :rss }
290     check_trace_feed Trace.tagged("London").visible_to_all
291
292     # Restrict traces to those for a given user
293     get :georss, :params => { :display_name => user.display_name, :format => :rss }
294     check_trace_feed user.traces.visible_to_all
295
296     # Restrict traces to those for a given user with a tiven tag
297     get :georss, :params => { :display_name => user.display_name, :tag => "Birmingham", :format => :rss }
298     check_trace_feed user.traces.tagged("Birmingham").visible_to_all
299   end
300
301   # Test viewing a trace
302   def test_view
303     public_trace_file = create(:trace, :visibility => "public")
304
305     # First with no auth, which should work since the trace is public
306     get :view, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }
307     check_trace_view public_trace_file
308
309     # Now with some other user, which should work since the trace is public
310     get :view, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => create(:user) }
311     check_trace_view public_trace_file
312
313     # And finally we should be able to do it with the owner of the trace
314     get :view, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => public_trace_file.user }
315     check_trace_view public_trace_file
316   end
317
318   # Check an anonymous trace can't be viewed by another user
319   def test_view_anon
320     anon_trace_file = create(:trace, :visibility => "private")
321
322     # First with no auth
323     get :view, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }
324     assert_response :redirect
325     assert_redirected_to :action => :list
326
327     # Now with some other user, which should not work since the trace is anon
328     get :view, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }, :session => { :user => create(:user) }
329     assert_response :redirect
330     assert_redirected_to :action => :list
331
332     # And finally we should be able to do it with the owner of the trace
333     get :view, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }, :session => { :user => anon_trace_file.user }
334     check_trace_view anon_trace_file
335   end
336
337   # Test viewing a trace that doesn't exist
338   def test_view_not_found
339     deleted_trace_file = create(:trace, :deleted)
340
341     # First with a trace that has never existed
342     get :view, :params => { :display_name => create(:user).display_name, :id => 0 }
343     assert_response :redirect
344     assert_redirected_to :action => :list
345
346     # Now with a trace that has been deleted
347     get :view, :params => { :display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file.id }, :session => { :user => deleted_trace_file.user }
348     assert_response :redirect
349     assert_redirected_to :action => :list
350   end
351
352   # Test downloading a trace
353   def test_data
354     public_trace_file = create(:trace, :visibility => "public", :fixture => "a")
355
356     # First with no auth, which should work since the trace is public
357     get :data, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }
358     check_trace_data public_trace_file
359
360     # Now with some other user, which should work since the trace is public
361     get :data, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => create(:user) }
362     check_trace_data public_trace_file
363
364     # And finally we should be able to do it with the owner of the trace
365     get :data, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => public_trace_file.user }
366     check_trace_data public_trace_file
367   end
368
369   # Test downloading a compressed trace
370   def test_data_compressed
371     identifiable_trace_file = create(:trace, :visibility => "identifiable", :fixture => "d")
372
373     # First get the data as is
374     get :data, :params => { :display_name => identifiable_trace_file.user.display_name, :id => identifiable_trace_file.id }
375     check_trace_data identifiable_trace_file, "application/x-gzip", "gpx.gz"
376
377     # Now ask explicitly for XML format
378     get :data, :params => { :display_name => identifiable_trace_file.user.display_name, :id => identifiable_trace_file.id, :format => "xml" }
379     check_trace_data identifiable_trace_file, "application/xml", "xml"
380
381     # Now ask explicitly for GPX format
382     get :data, :params => { :display_name => identifiable_trace_file.user.display_name, :id => identifiable_trace_file.id, :format => "gpx" }
383     check_trace_data identifiable_trace_file
384   end
385
386   # Check an anonymous trace can't be downloaded by another user
387   def test_data_anon
388     anon_trace_file = create(:trace, :visibility => "private", :fixture => "b")
389
390     # First with no auth
391     get :data, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }
392     assert_response :not_found
393
394     # Now with some other user, which shouldn't work since the trace is anon
395     get :data, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }, :session => { :user => create(:user) }
396     assert_response :not_found
397
398     # And finally we should be able to do it with the owner of the trace
399     get :data, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }, :session => { :user => anon_trace_file.user }
400     check_trace_data anon_trace_file
401   end
402
403   # Test downloading a trace that doesn't exist
404   def test_data_not_found
405     deleted_trace_file = create(:trace, :deleted)
406
407     # First with a trace that has never existed
408     get :data, :params => { :display_name => create(:user).display_name, :id => 0 }
409     assert_response :not_found
410
411     # Now with a trace that has been deleted
412     get :data, :params => { :display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file.id }, :session => { :user => deleted_trace_file.user }
413     assert_response :not_found
414   end
415
416   # Test downloading the picture for a trace
417   def test_picture
418     public_trace_file = create(:trace, :visibility => "public", :fixture => "a")
419
420     # First with no auth, which should work since the trace is public
421     get :picture, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }
422     check_trace_picture public_trace_file
423
424     # Now with some other user, which should work since the trace is public
425     get :picture, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => create(:user) }
426     check_trace_picture public_trace_file
427
428     # And finally we should be able to do it with the owner of the trace
429     get :picture, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => public_trace_file.user }
430     check_trace_picture public_trace_file
431   end
432
433   # Check the picture for an anonymous trace can't be downloaded by another user
434   def test_picture_anon
435     anon_trace_file = create(:trace, :visibility => "private", :fixture => "b")
436
437     # First with no auth
438     get :picture, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }
439     assert_response :forbidden
440
441     # Now with some other user, which shouldn't work since the trace is anon
442     get :picture, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }, :session => { :user => create(:user) }
443     assert_response :forbidden
444
445     # And finally we should be able to do it with the owner of the trace
446     get :picture, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }, :session => { :user => anon_trace_file.user }
447     check_trace_picture anon_trace_file
448   end
449
450   # Test downloading the picture for a trace that doesn't exist
451   def test_picture_not_found
452     deleted_trace_file = create(:trace, :deleted)
453
454     # First with a trace that has never existed
455     get :picture, :params => { :display_name => create(:user).display_name, :id => 0 }
456     assert_response :not_found
457
458     # Now with a trace that has been deleted
459     get :picture, :params => { :display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file.id }, :session => { :user => deleted_trace_file.user }
460     assert_response :not_found
461   end
462
463   # Test downloading the icon for a trace
464   def test_icon
465     public_trace_file = create(:trace, :visibility => "public", :fixture => "a")
466
467     # First with no auth, which should work since the trace is public
468     get :icon, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }
469     check_trace_icon public_trace_file
470
471     # Now with some other user, which should work since the trace is public
472     get :icon, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => create(:user) }
473     check_trace_icon public_trace_file
474
475     # And finally we should be able to do it with the owner of the trace
476     get :icon, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => public_trace_file.user }
477     check_trace_icon public_trace_file
478   end
479
480   # Check the icon for an anonymous trace can't be downloaded by another user
481   def test_icon_anon
482     anon_trace_file = create(:trace, :visibility => "private", :fixture => "b")
483
484     # First with no auth
485     get :icon, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }
486     assert_response :forbidden
487
488     # Now with some other user, which shouldn't work since the trace is anon
489     get :icon, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }, :session => { :user => create(:user) }
490     assert_response :forbidden
491
492     # And finally we should be able to do it with the owner of the trace
493     get :icon, :params => { :display_name => anon_trace_file.user.display_name, :id => anon_trace_file.id }, :session => { :user => anon_trace_file.user }
494     check_trace_icon anon_trace_file
495   end
496
497   # Test downloading the icon for a trace that doesn't exist
498   def test_icon_not_found
499     deleted_trace_file = create(:trace, :deleted)
500
501     # First with a trace that has never existed
502     get :icon, :params => { :display_name => create(:user).display_name, :id => 0 }
503     assert_response :not_found
504
505     # Now with a trace that has been deleted
506     get :icon, :params => { :display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file.id }, :session => { :user => deleted_trace_file.user }
507     assert_response :not_found
508   end
509
510   # Test fetching the create page
511   def test_create_get
512     # First with no auth
513     get :create
514     assert_response :redirect
515     assert_redirected_to :controller => :user, :action => :login, :referer => trace_create_path
516
517     # Now authenticated as a user with gps.trace.visibility set
518     user = create(:user)
519     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
520     get :create, :session => { :user => user }
521     assert_response :success
522     assert_template :create
523     assert_select "select#trace_visibility option[value=identifiable][selected]", 1
524
525     # Now authenticated as a user with gps.trace.public set
526     second_user = create(:user)
527     create(:user_preference, :user => second_user, :k => "gps.trace.public", :v => "default")
528     get :create, :session => { :user => second_user }
529     assert_response :success
530     assert_template :create
531     assert_select "select#trace_visibility option[value=public][selected]", 1
532
533     # Now authenticated as a user with no preferences
534     third_user = create(:user)
535     get :create, :session => { :user => third_user }
536     assert_response :success
537     assert_template :create
538     assert_select "select#trace_visibility option[value=private][selected]", 1
539   end
540
541   # Test creating a trace
542   def test_create_post
543     # Get file to use
544     fixture = Rails.root.join("test", "gpx", "fixtures", "a.gpx")
545     file = Rack::Test::UploadedFile.new(fixture, "application/gpx+xml")
546     user = create(:user)
547
548     # First with no auth
549     post :create, :params => { :trace => { :gpx_file => file, :description => "New Trace", :tagstring => "new,trace", :visibility => "trackable" } }
550     assert_response :forbidden
551
552     # Now authenticated
553     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
554     assert_not_equal "trackable", user.preferences.where(:k => "gps.trace.visibility").first.v
555     post :create, :params => { :trace => { :gpx_file => file, :description => "New Trace", :tagstring => "new,trace", :visibility => "trackable" } }, :session => { :user => user }
556     assert_response :redirect
557     assert_redirected_to :action => :list, :display_name => user.display_name
558     assert_match /file has been uploaded/, flash[:notice]
559     trace = Trace.order(:id => :desc).first
560     assert_equal "a.gpx", trace.name
561     assert_equal "New Trace", trace.description
562     assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
563     assert_equal "trackable", trace.visibility
564     assert_equal false, trace.inserted
565     assert_equal File.new(fixture).read, File.new(trace.trace_name).read
566     trace.destroy
567     assert_equal "trackable", user.preferences.where(:k => "gps.trace.visibility").first.v
568   end
569
570   # Test fetching the edit page for a trace using GET
571   def test_edit_get
572     public_trace_file = create(:trace, :visibility => "public")
573     deleted_trace_file = create(:trace, :deleted)
574
575     # First with no auth
576     get :edit, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }
577     assert_response :redirect
578     assert_redirected_to :controller => :user, :action => :login, :referer => trace_edit_path(:display_name => public_trace_file.user.display_name, :id => public_trace_file.id)
579
580     # Now with some other user, which should fail
581     get :edit, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => create(:user) }
582     assert_response :forbidden
583
584     # Now with a trace which doesn't exist
585     get :edit, :params => { :display_name => create(:user).display_name, :id => 0 }, :session => { :user => create(:user) }
586     assert_response :not_found
587
588     # Now with a trace which has been deleted
589     get :edit, :params => { :display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file.id }, :session => { :user => deleted_trace_file.user }
590     assert_response :not_found
591
592     # Finally with a trace that we are allowed to edit
593     get :edit, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => public_trace_file.user }
594     assert_response :success
595   end
596
597   # Test fetching the edit page for a trace using POST
598   def test_edit_post_no_details
599     public_trace_file = create(:trace, :visibility => "public")
600     deleted_trace_file = create(:trace, :deleted)
601
602     # First with no auth
603     post :edit, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }
604     assert_response :forbidden
605
606     # Now with some other user, which should fail
607     post :edit, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => create(:user) }
608     assert_response :forbidden
609
610     # Now with a trace which doesn't exist
611     post :edit, :params => { :display_name => create(:user).display_name, :id => 0 }, :session => { :user => create(:user) }
612     assert_response :not_found
613
614     # Now with a trace which has been deleted
615     post :edit, :params => { :display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file.id }, :session => { :user => deleted_trace_file.user }
616     assert_response :not_found
617
618     # Finally with a trace that we are allowed to edit
619     post :edit, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => public_trace_file.user }
620     assert_response :success
621   end
622
623   # Test saving edits to a trace
624   def test_edit_post_with_details
625     public_trace_file = create(:trace, :visibility => "public")
626     deleted_trace_file = create(:trace, :deleted)
627
628     # New details
629     new_details = { :description => "Changed description", :tagstring => "new_tag", :visibility => "private" }
630
631     # First with no auth
632     post :edit, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id, :trace => new_details }
633     assert_response :forbidden
634
635     # Now with some other user, which should fail
636     post :edit, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id, :trace => new_details }, :session => { :user => create(:user) }
637     assert_response :forbidden
638
639     # Now with a trace which doesn't exist
640     post :edit, :params => { :display_name => create(:user).display_name, :id => 0 }, :session => { :user => create(:user), :trace => new_details }
641     assert_response :not_found
642
643     # Now with a trace which has been deleted
644     post :edit, :params => { :display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file.id, :trace => new_details }, :session => { :user => deleted_trace_file.user }
645     assert_response :not_found
646
647     # Finally with a trace that we are allowed to edit
648     post :edit, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id, :trace => new_details }, :session => { :user => public_trace_file.user }
649     assert_response :redirect
650     assert_redirected_to :action => :view, :display_name => public_trace_file.user.display_name
651     trace = Trace.find(public_trace_file.id)
652     assert_equal new_details[:description], trace.description
653     assert_equal new_details[:tagstring], trace.tagstring
654     assert_equal new_details[:visibility], trace.visibility
655   end
656
657   # Test deleting a trace
658   def test_delete
659     public_trace_file = create(:trace, :visibility => "public")
660     deleted_trace_file = create(:trace, :deleted)
661
662     # First with no auth
663     post :delete, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }
664     assert_response :forbidden
665
666     # Now with some other user, which should fail
667     post :delete, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => create(:user) }
668     assert_response :forbidden
669
670     # Now with a trace which doesn't exist
671     post :delete, :params => { :display_name => create(:user).display_name, :id => 0 }, :session => { :user => create(:user) }
672     assert_response :not_found
673
674     # Now with a trace has already been deleted
675     post :delete, :params => { :display_name => deleted_trace_file.user.display_name, :id => deleted_trace_file.id }, :session => { :user => deleted_trace_file.user }
676     assert_response :not_found
677
678     # Finally with a trace that we are allowed to delete
679     post :delete, :params => { :display_name => public_trace_file.user.display_name, :id => public_trace_file.id }, :session => { :user => public_trace_file.user }
680     assert_response :redirect
681     assert_redirected_to :action => :list, :display_name => public_trace_file.user.display_name
682     trace = Trace.find(public_trace_file.id)
683     assert_equal false, trace.visible
684   end
685
686   # Check getting a specific trace through the api
687   def test_api_read
688     public_trace_file = create(:trace, :visibility => "public")
689
690     # First with no auth
691     get :api_read, :params => { :id => public_trace_file.id }
692     assert_response :unauthorized
693
694     # Now with some other user, which should work since the trace is public
695     basic_authorization create(:user).display_name, "test"
696     get :api_read, :params => { :id => public_trace_file.id }
697     assert_response :success
698
699     # And finally we should be able to do it with the owner of the trace
700     basic_authorization public_trace_file.user.display_name, "test"
701     get :api_read, :params => { :id => public_trace_file.id }
702     assert_response :success
703   end
704
705   # Check an anoymous trace can't be specifically fetched by another user
706   def test_api_read_anon
707     anon_trace_file = create(:trace, :visibility => "private")
708
709     # First with no auth
710     get :api_read, :params => { :id => anon_trace_file.id }
711     assert_response :unauthorized
712
713     # Now try with another user, which shouldn't work since the trace is anon
714     basic_authorization create(:user).display_name, "test"
715     get :api_read, :params => { :id => anon_trace_file.id }
716     assert_response :forbidden
717
718     # And finally we should be able to get the trace details with the trace owner
719     basic_authorization anon_trace_file.user.display_name, "test"
720     get :api_read, :params => { :id => anon_trace_file.id }
721     assert_response :success
722   end
723
724   # Check the api details for a trace that doesn't exist
725   def test_api_read_not_found
726     deleted_trace_file = create(:trace, :deleted)
727
728     # Try first with no auth, as it should require it
729     get :api_read, :params => { :id => 0 }
730     assert_response :unauthorized
731
732     # Login, and try again
733     basic_authorization deleted_trace_file.user.display_name, "test"
734     get :api_read, :params => { :id => 0 }
735     assert_response :not_found
736
737     # Now try a trace which did exist but has been deleted
738     basic_authorization deleted_trace_file.user.display_name, "test"
739     get :api_read, :params => { :id => deleted_trace_file.id }
740     assert_response :not_found
741   end
742
743   # Test downloading a trace through the api
744   def test_api_data
745     public_trace_file = create(:trace, :visibility => "public", :fixture => "a")
746
747     # First with no auth
748     get :api_data, :params => { :id => public_trace_file.id }
749     assert_response :unauthorized
750
751     # Now with some other user, which should work since the trace is public
752     basic_authorization create(:user).display_name, "test"
753     get :api_data, :params => { :id => public_trace_file.id }
754     check_trace_data public_trace_file
755
756     # And finally we should be able to do it with the owner of the trace
757     basic_authorization public_trace_file.user.display_name, "test"
758     get :api_data, :params => { :id => public_trace_file.id }
759     check_trace_data public_trace_file
760   end
761
762   # Test downloading a compressed trace through the api
763   def test_api_data_compressed
764     identifiable_trace_file = create(:trace, :visibility => "identifiable", :fixture => "d")
765
766     # Authenticate as the owner of the trace we will be using
767     basic_authorization identifiable_trace_file.user.display_name, "test"
768
769     # First get the data as is
770     get :api_data, :params => { :id => identifiable_trace_file.id }
771     check_trace_data identifiable_trace_file, "application/x-gzip", "gpx.gz"
772
773     # Now ask explicitly for XML format
774     get :api_data, :params => { :id => identifiable_trace_file.id, :format => "xml" }
775     check_trace_data identifiable_trace_file, "application/xml", "xml"
776
777     # Now ask explicitly for GPX format
778     get :api_data, :params => { :id => identifiable_trace_file.id, :format => "gpx" }
779     check_trace_data identifiable_trace_file
780   end
781
782   # Check an anonymous trace can't be downloaded by another user through the api
783   def test_api_data_anon
784     anon_trace_file = create(:trace, :visibility => "private", :fixture => "b")
785
786     # First with no auth
787     get :api_data, :params => { :id => anon_trace_file.id }
788     assert_response :unauthorized
789
790     # Now with some other user, which shouldn't work since the trace is anon
791     basic_authorization create(:user).display_name, "test"
792     get :api_data, :params => { :id => anon_trace_file.id }
793     assert_response :forbidden
794
795     # And finally we should be able to do it with the owner of the trace
796     basic_authorization anon_trace_file.user.display_name, "test"
797     get :api_data, :params => { :id => anon_trace_file.id }
798     check_trace_data anon_trace_file
799   end
800
801   # Test downloading a trace that doesn't exist through the api
802   def test_api_data_not_found
803     deleted_trace_file = create(:trace, :deleted)
804
805     # Try first with no auth, as it should require it
806     get :api_data, :params => { :id => 0 }
807     assert_response :unauthorized
808
809     # Login, and try again
810     basic_authorization create(:user).display_name, "test"
811     get :api_data, :params => { :id => 0 }
812     assert_response :not_found
813
814     # Now try a trace which did exist but has been deleted
815     basic_authorization deleted_trace_file.user.display_name, "test"
816     get :api_data, :params => { :id => deleted_trace_file.id }
817     assert_response :not_found
818   end
819
820   # Test creating a trace through the api
821   def test_api_create
822     # Get file to use
823     fixture = Rails.root.join("test", "gpx", "fixtures", "a.gpx")
824     file = Rack::Test::UploadedFile.new(fixture, "application/gpx+xml")
825     user = create(:user)
826
827     # First with no auth
828     post :api_create, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :visibility => "trackable" }
829     assert_response :unauthorized
830
831     # Now authenticated
832     create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
833     assert_not_equal "trackable", user.preferences.where(:k => "gps.trace.visibility").first.v
834     basic_authorization user.display_name, "test"
835     post :api_create, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :visibility => "trackable" }
836     assert_response :success
837     trace = Trace.find(response.body.to_i)
838     assert_equal "a.gpx", trace.name
839     assert_equal "New Trace", trace.description
840     assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
841     assert_equal "trackable", trace.visibility
842     assert_equal false, trace.inserted
843     assert_equal File.new(fixture).read, File.new(trace.trace_name).read
844     trace.destroy
845     assert_equal "trackable", user.preferences.where(:k => "gps.trace.visibility").first.v
846
847     # Rewind the file
848     file.rewind
849
850     # Now authenticated, with the legacy public flag
851     assert_not_equal "public", user.preferences.where(:k => "gps.trace.visibility").first.v
852     basic_authorization user.display_name, "test"
853     post :api_create, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :public => 1 }
854     assert_response :success
855     trace = Trace.find(response.body.to_i)
856     assert_equal "a.gpx", trace.name
857     assert_equal "New Trace", trace.description
858     assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
859     assert_equal "public", trace.visibility
860     assert_equal false, trace.inserted
861     assert_equal File.new(fixture).read, File.new(trace.trace_name).read
862     trace.destroy
863     assert_equal "public", user.preferences.where(:k => "gps.trace.visibility").first.v
864
865     # Rewind the file
866     file.rewind
867
868     # Now authenticated, with the legacy private flag
869     second_user = create(:user)
870     assert_nil second_user.preferences.where(:k => "gps.trace.visibility").first
871     basic_authorization second_user.display_name, "test"
872     post :api_create, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :public => 0 }
873     assert_response :success
874     trace = Trace.find(response.body.to_i)
875     assert_equal "a.gpx", trace.name
876     assert_equal "New Trace", trace.description
877     assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
878     assert_equal "private", trace.visibility
879     assert_equal false, trace.inserted
880     assert_equal File.new(fixture).read, File.new(trace.trace_name).read
881     trace.destroy
882     assert_equal "private", second_user.preferences.where(:k => "gps.trace.visibility").first.v
883   end
884
885   # Check updating a trace through the api
886   def test_api_update
887     public_trace_file = create(:trace, :visibility => "public", :fixture => "a")
888     deleted_trace_file = create(:trace, :deleted)
889     anon_trace_file = create(:trace, :visibility => "private")
890
891     # First with no auth
892     content public_trace_file.to_xml
893     put :api_update, :params => { :id => public_trace_file.id }
894     assert_response :unauthorized
895
896     # Now with some other user, which should fail
897     basic_authorization create(:user).display_name, "test"
898     content public_trace_file.to_xml
899     put :api_update, :params => { :id => public_trace_file.id }
900     assert_response :forbidden
901
902     # Now with a trace which doesn't exist
903     basic_authorization create(:user).display_name, "test"
904     content public_trace_file.to_xml
905     put :api_update, :params => { :id => 0 }
906     assert_response :not_found
907
908     # Now with a trace which did exist but has been deleted
909     basic_authorization deleted_trace_file.user.display_name, "test"
910     content deleted_trace_file.to_xml
911     put :api_update, :params => { :id => deleted_trace_file.id }
912     assert_response :not_found
913
914     # Now try an update with the wrong ID
915     basic_authorization public_trace_file.user.display_name, "test"
916     content anon_trace_file.to_xml
917     put :api_update, :params => { :id => public_trace_file.id }
918     assert_response :bad_request,
919                     "should not be able to update a trace with a different ID from the XML"
920
921     # And finally try an update that should work
922     basic_authorization public_trace_file.user.display_name, "test"
923     t = public_trace_file
924     t.description = "Changed description"
925     t.visibility = "private"
926     content t.to_xml
927     put :api_update, :params => { :id => t.id }
928     assert_response :success
929     nt = Trace.find(t.id)
930     assert_equal nt.description, t.description
931     assert_equal nt.visibility, t.visibility
932   end
933
934   # Test that updating a trace doesn't duplicate the tags
935   def test_api_update_tags
936     tracetag = create(:tracetag)
937     trace = tracetag.trace
938     basic_authorization trace.user.display_name, "test"
939
940     content trace.to_xml
941     put :api_update, :params => { :id => trace.id }
942     assert_response :success
943
944     updated = Trace.find(trace.id)
945     # Ensure there's only one tag in the database after updating
946     assert_equal Tracetag.count, 1
947     # The new tag object might have a different id, so check the string representation
948     assert_equal trace.tagstring, updated.tagstring
949   end
950
951   # Check deleting a trace through the api
952   def test_api_delete
953     public_trace_file = create(:trace, :visibility => "public")
954
955     # First with no auth
956     delete :api_delete, :params => { :id => public_trace_file.id }
957     assert_response :unauthorized
958
959     # Now with some other user, which should fail
960     basic_authorization create(:user).display_name, "test"
961     delete :api_delete, :params => { :id => public_trace_file.id }
962     assert_response :forbidden
963
964     # Now with a trace which doesn't exist
965     basic_authorization create(:user).display_name, "test"
966     delete :api_delete, :params => { :id => 0 }
967     assert_response :not_found
968
969     # And finally we should be able to do it with the owner of the trace
970     basic_authorization public_trace_file.user.display_name, "test"
971     delete :api_delete, :params => { :id => public_trace_file.id }
972     assert_response :success
973
974     # Try it a second time, which should fail
975     basic_authorization public_trace_file.user.display_name, "test"
976     delete :api_delete, :params => { :id => public_trace_file.id }
977     assert_response :not_found
978   end
979
980   private
981
982   def check_trace_feed(traces)
983     assert_response :success
984     assert_template "georss"
985     assert_equal "application/rss+xml", @response.content_type
986     assert_select "rss", :count => 1 do
987       assert_select "channel", :count => 1 do
988         assert_select "title"
989         assert_select "description"
990         assert_select "link"
991         assert_select "image"
992         assert_select "item", :count => traces.visible.count do |items|
993           traces.visible.order("timestamp DESC").zip(items).each do |trace, item|
994             assert_select item, "title", trace.name
995             assert_select item, "link", "http://test.host/user/#{trace.user.display_name}/traces/#{trace.id}"
996             assert_select item, "guid", "http://test.host/user/#{trace.user.display_name}/traces/#{trace.id}"
997             assert_select item, "description"
998             # assert_select item, "dc:creator", trace.user.display_name
999             assert_select item, "pubDate", trace.timestamp.rfc822
1000           end
1001         end
1002       end
1003     end
1004   end
1005
1006   def check_trace_list(traces)
1007     assert_response :success
1008     assert_template "list"
1009
1010     if !traces.empty?
1011       assert_select "table#trace_list tbody", :count => 1 do
1012         assert_select "tr", :count => traces.length do |rows|
1013           traces.zip(rows).each do |trace, row|
1014             assert_select row, "a", Regexp.new(Regexp.escape(trace.name))
1015             assert_select row, "span.trace_summary", Regexp.new(Regexp.escape("(#{trace.size} points)")) if trace.inserted?
1016             assert_select row, "td", Regexp.new(Regexp.escape(trace.description))
1017             assert_select row, "td", Regexp.new(Regexp.escape("by #{trace.user.display_name}"))
1018           end
1019         end
1020       end
1021     else
1022       assert_select "h4", /Nothing here yet/
1023     end
1024   end
1025
1026   def check_trace_view(trace)
1027     assert_response :success
1028     assert_template "view"
1029
1030     assert_select "table", :count => 1 do
1031       assert_select "td", /^#{Regexp.quote(trace.name)} /
1032       assert_select "td", trace.user.display_name
1033       assert_select "td", trace.description
1034     end
1035   end
1036
1037   def check_trace_data(trace, content_type = "application/gpx+xml", extension = "gpx")
1038     assert_response :success
1039     assert_equal content_type, response.content_type
1040     assert_equal "attachment; filename=\"#{trace.id}.#{extension}\"", @response.header["Content-Disposition"]
1041   end
1042
1043   def check_trace_picture(trace)
1044     assert_response :success
1045     assert_equal "image/gif", response.content_type
1046     assert_equal trace.large_picture, response.body
1047   end
1048
1049   def check_trace_icon(trace)
1050     assert_response :success
1051     assert_equal "image/gif", response.content_type
1052     assert_equal trace.icon_picture, response.body
1053   end
1054 end