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