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