]> git.openstreetmap.org Git - rails.git/blob - test/controllers/api/traces_controller_test.rb
Merge pull request #3846 from SK53/osgb-date-2022
[rails.git] / test / controllers / api / traces_controller_test.rb
1 require "test_helper"
2
3 module Api
4   class TracesControllerTest < ActionDispatch::IntegrationTest
5     ##
6     # test all routes which lead to this controller
7     def test_routes
8       assert_routing(
9         { :path => "/api/0.6/gpx/create", :method => :post },
10         { :controller => "api/traces", :action => "create" }
11       )
12       assert_routing(
13         { :path => "/api/0.6/gpx/1", :method => :get },
14         { :controller => "api/traces", :action => "show", :id => "1" }
15       )
16       assert_routing(
17         { :path => "/api/0.6/gpx/1", :method => :put },
18         { :controller => "api/traces", :action => "update", :id => "1" }
19       )
20       assert_routing(
21         { :path => "/api/0.6/gpx/1", :method => :delete },
22         { :controller => "api/traces", :action => "destroy", :id => "1" }
23       )
24       assert_recognizes(
25         { :controller => "api/traces", :action => "show", :id => "1" },
26         { :path => "/api/0.6/gpx/1/details", :method => :get }
27       )
28       assert_routing(
29         { :path => "/api/0.6/gpx/1/data", :method => :get },
30         { :controller => "api/traces", :action => "data", :id => "1" }
31       )
32       assert_routing(
33         { :path => "/api/0.6/gpx/1/data.xml", :method => :get },
34         { :controller => "api/traces", :action => "data", :id => "1", :format => "xml" }
35       )
36     end
37
38     # Check getting a specific trace through the api
39     def test_show
40       public_trace_file = create(:trace, :visibility => "public")
41
42       # First with no auth
43       get api_trace_path(public_trace_file)
44       assert_response :unauthorized
45
46       # Now with some other user, which should work since the trace is public
47       auth_header = basic_authorization_header create(:user).display_name, "test"
48       get api_trace_path(public_trace_file), :headers => auth_header
49       assert_response :success
50
51       # And finally we should be able to do it with the owner of the trace
52       auth_header = basic_authorization_header public_trace_file.user.display_name, "test"
53       get api_trace_path(public_trace_file), :headers => auth_header
54       assert_response :success
55     end
56
57     # Check an anonymous trace can't be specifically fetched by another user
58     def test_show_anon
59       anon_trace_file = create(:trace, :visibility => "private")
60
61       # First with no auth
62       get api_trace_path(anon_trace_file)
63       assert_response :unauthorized
64
65       # Now try with another user, which shouldn't work since the trace is anon
66       auth_header = basic_authorization_header create(:user).display_name, "test"
67       get api_trace_path(anon_trace_file), :headers => auth_header
68       assert_response :forbidden
69
70       # And finally we should be able to get the trace details with the trace owner
71       auth_header = basic_authorization_header anon_trace_file.user.display_name, "test"
72       get api_trace_path(anon_trace_file), :headers => auth_header
73       assert_response :success
74     end
75
76     # Check the api details for a trace that doesn't exist
77     def test_show_not_found
78       deleted_trace_file = create(:trace, :deleted)
79
80       # Try first with no auth, as it should require it
81       get api_trace_path(:id => 0)
82       assert_response :unauthorized
83
84       # Login, and try again
85       auth_header = basic_authorization_header deleted_trace_file.user.display_name, "test"
86       get api_trace_path(:id => 0), :headers => auth_header
87       assert_response :not_found
88
89       # Now try a trace which did exist but has been deleted
90       auth_header = basic_authorization_header deleted_trace_file.user.display_name, "test"
91       get api_trace_path(deleted_trace_file), :headers => auth_header
92       assert_response :not_found
93     end
94
95     # Test downloading a trace through the api
96     def test_data
97       public_trace_file = create(:trace, :visibility => "public", :fixture => "a")
98
99       # First with no auth
100       get api_trace_data_path(public_trace_file)
101       assert_response :unauthorized
102
103       # Now with some other user, which should work since the trace is public
104       auth_header = basic_authorization_header create(:user).display_name, "test"
105       get api_trace_data_path(public_trace_file), :headers => auth_header
106       follow_redirect!
107       follow_redirect!
108       check_trace_data public_trace_file, "848caa72f2f456d1bd6a0fdf228aa1b9"
109
110       # And finally we should be able to do it with the owner of the trace
111       auth_header = basic_authorization_header public_trace_file.user.display_name, "test"
112       get api_trace_data_path(public_trace_file), :headers => auth_header
113       follow_redirect!
114       follow_redirect!
115       check_trace_data public_trace_file, "848caa72f2f456d1bd6a0fdf228aa1b9"
116     end
117
118     # Test downloading a compressed trace through the api
119     def test_data_compressed
120       identifiable_trace_file = create(:trace, :visibility => "identifiable", :fixture => "d")
121
122       # Authenticate as the owner of the trace we will be using
123       auth_header = basic_authorization_header identifiable_trace_file.user.display_name, "test"
124
125       # First get the data as is
126       get api_trace_data_path(identifiable_trace_file), :headers => auth_header
127       follow_redirect!
128       follow_redirect!
129       check_trace_data identifiable_trace_file, "c6422a3d8750faae49ed70e7e8a51b93", "application/gzip", "gpx.gz"
130
131       # Now ask explicitly for XML format
132       get api_trace_data_path(identifiable_trace_file, :format => "xml"), :headers => auth_header
133       check_trace_data identifiable_trace_file, "abd6675fdf3024a84fc0a1deac147c0d", "application/xml", "xml"
134
135       # Now ask explicitly for GPX format
136       get api_trace_data_path(identifiable_trace_file, :format => "gpx"), :headers => auth_header
137       check_trace_data identifiable_trace_file, "abd6675fdf3024a84fc0a1deac147c0d"
138     end
139
140     # Check an anonymous trace can't be downloaded by another user through the api
141     def test_data_anon
142       anon_trace_file = create(:trace, :visibility => "private", :fixture => "b")
143
144       # First with no auth
145       get api_trace_data_path(anon_trace_file)
146       assert_response :unauthorized
147
148       # Now with some other user, which shouldn't work since the trace is anon
149       auth_header = basic_authorization_header create(:user).display_name, "test"
150       get api_trace_data_path(anon_trace_file), :headers => auth_header
151       assert_response :forbidden
152
153       # And finally we should be able to do it with the owner of the trace
154       auth_header = basic_authorization_header anon_trace_file.user.display_name, "test"
155       get api_trace_data_path(anon_trace_file), :headers => auth_header
156       follow_redirect!
157       follow_redirect!
158       check_trace_data anon_trace_file, "db4cb5ed2d7d2b627b3b504296c4f701"
159     end
160
161     # Test downloading a trace that doesn't exist through the api
162     def test_data_not_found
163       deleted_trace_file = create(:trace, :deleted)
164
165       # Try first with no auth, as it should require it
166       get api_trace_data_path(:id => 0)
167       assert_response :unauthorized
168
169       # Login, and try again
170       auth_header = basic_authorization_header create(:user).display_name, "test"
171       get api_trace_data_path(:id => 0), :headers => auth_header
172       assert_response :not_found
173
174       # Now try a trace which did exist but has been deleted
175       auth_header = basic_authorization_header deleted_trace_file.user.display_name, "test"
176       get api_trace_data_path(deleted_trace_file), :headers => auth_header
177       assert_response :not_found
178     end
179
180     # Test creating a trace through the api
181     def test_create
182       # Get file to use
183       fixture = Rails.root.join("test/gpx/fixtures/a.gpx")
184       file = Rack::Test::UploadedFile.new(fixture, "application/gpx+xml")
185       user = create(:user)
186
187       # First with no auth
188       post gpx_create_path, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :visibility => "trackable" }
189       assert_response :unauthorized
190
191       # Rewind the file
192       file.rewind
193
194       # Now authenticated
195       create(:user_preference, :user => user, :k => "gps.trace.visibility", :v => "identifiable")
196       assert_not_equal "trackable", user.preferences.where(:k => "gps.trace.visibility").first.v
197       auth_header = basic_authorization_header user.display_name, "test"
198       post gpx_create_path, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :visibility => "trackable" }, :headers => auth_header
199       assert_response :success
200       trace = Trace.find(response.body.to_i)
201       assert_equal "a.gpx", trace.name
202       assert_equal "New Trace", trace.description
203       assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
204       assert_equal "trackable", trace.visibility
205       assert_not trace.inserted
206       assert_equal File.new(fixture).read, trace.file.blob.download
207       trace.destroy
208       assert_equal "trackable", user.preferences.where(:k => "gps.trace.visibility").first.v
209
210       # Rewind the file
211       file.rewind
212
213       # Now authenticated, with the legacy public flag
214       assert_not_equal "public", user.preferences.where(:k => "gps.trace.visibility").first.v
215       auth_header = basic_authorization_header user.display_name, "test"
216       post gpx_create_path, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :public => 1 }, :headers => auth_header
217       assert_response :success
218       trace = Trace.find(response.body.to_i)
219       assert_equal "a.gpx", trace.name
220       assert_equal "New Trace", trace.description
221       assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
222       assert_equal "public", trace.visibility
223       assert_not trace.inserted
224       assert_equal File.new(fixture).read, trace.file.blob.download
225       trace.destroy
226       assert_equal "public", user.preferences.where(:k => "gps.trace.visibility").first.v
227
228       # Rewind the file
229       file.rewind
230
231       # Now authenticated, with the legacy private flag
232       second_user = create(:user)
233       assert_nil second_user.preferences.where(:k => "gps.trace.visibility").first
234       auth_header = basic_authorization_header second_user.display_name, "test"
235       post gpx_create_path, :params => { :file => file, :description => "New Trace", :tags => "new,trace", :public => 0 }, :headers => auth_header
236       assert_response :success
237       trace = Trace.find(response.body.to_i)
238       assert_equal "a.gpx", trace.name
239       assert_equal "New Trace", trace.description
240       assert_equal %w[new trace], trace.tags.order(:tag).collect(&:tag)
241       assert_equal "private", trace.visibility
242       assert_not trace.inserted
243       assert_equal File.new(fixture).read, trace.file.blob.download
244       trace.destroy
245       assert_equal "private", second_user.preferences.where(:k => "gps.trace.visibility").first.v
246     end
247
248     # Check updating a trace through the api
249     def test_update
250       public_trace_file = create(:trace, :visibility => "public", :fixture => "a")
251       deleted_trace_file = create(:trace, :deleted)
252       anon_trace_file = create(:trace, :visibility => "private")
253
254       # First with no auth
255       put api_trace_path(public_trace_file), :params => create_trace_xml(public_trace_file)
256       assert_response :unauthorized
257
258       # Now with some other user, which should fail
259       auth_header = basic_authorization_header create(:user).display_name, "test"
260       put api_trace_path(public_trace_file), :params => create_trace_xml(public_trace_file), :headers => auth_header
261       assert_response :forbidden
262
263       # Now with a trace which doesn't exist
264       auth_header = basic_authorization_header create(:user).display_name, "test"
265       put api_trace_path(:id => 0), :params => create_trace_xml(public_trace_file), :headers => auth_header
266       assert_response :not_found
267
268       # Now with a trace which did exist but has been deleted
269       auth_header = basic_authorization_header deleted_trace_file.user.display_name, "test"
270       put api_trace_path(deleted_trace_file), :params => create_trace_xml(deleted_trace_file), :headers => auth_header
271       assert_response :not_found
272
273       # Now try an update with the wrong ID
274       auth_header = basic_authorization_header public_trace_file.user.display_name, "test"
275       put api_trace_path(public_trace_file), :params => create_trace_xml(anon_trace_file), :headers => auth_header
276       assert_response :bad_request,
277                       "should not be able to update a trace with a different ID from the XML"
278
279       # And finally try an update that should work
280       auth_header = basic_authorization_header public_trace_file.user.display_name, "test"
281       t = public_trace_file
282       t.description = "Changed description"
283       t.visibility = "private"
284       put api_trace_path(t), :params => create_trace_xml(t), :headers => auth_header
285       assert_response :success
286       nt = Trace.find(t.id)
287       assert_equal nt.description, t.description
288       assert_equal nt.visibility, t.visibility
289     end
290
291     # Test that updating a trace doesn't duplicate the tags
292     def test_update_tags
293       tracetag = create(:tracetag)
294       trace = tracetag.trace
295       auth_header = basic_authorization_header trace.user.display_name, "test"
296
297       put api_trace_path(trace), :params => create_trace_xml(trace), :headers => auth_header
298       assert_response :success
299
300       updated = Trace.find(trace.id)
301       # Ensure there's only one tag in the database after updating
302       assert_equal(1, Tracetag.count)
303       # The new tag object might have a different id, so check the string representation
304       assert_equal trace.tagstring, updated.tagstring
305     end
306
307     # Check deleting a trace through the api
308     def test_destroy
309       public_trace_file = create(:trace, :visibility => "public")
310
311       # First with no auth
312       delete api_trace_path(public_trace_file)
313       assert_response :unauthorized
314
315       # Now with some other user, which should fail
316       auth_header = basic_authorization_header create(:user).display_name, "test"
317       delete api_trace_path(public_trace_file), :headers => auth_header
318       assert_response :forbidden
319
320       # Now with a trace which doesn't exist
321       auth_header = basic_authorization_header create(:user).display_name, "test"
322       delete api_trace_path(:id => 0), :headers => auth_header
323       assert_response :not_found
324
325       # And finally we should be able to do it with the owner of the trace
326       auth_header = basic_authorization_header public_trace_file.user.display_name, "test"
327       delete api_trace_path(public_trace_file), :headers => auth_header
328       assert_response :success
329
330       # Try it a second time, which should fail
331       auth_header = basic_authorization_header public_trace_file.user.display_name, "test"
332       delete api_trace_path(public_trace_file), :headers => auth_header
333       assert_response :not_found
334     end
335
336     private
337
338     def check_trace_data(trace, digest, content_type = "application/gpx+xml", extension = "gpx")
339       assert_response :success
340       assert_equal digest, Digest::MD5.hexdigest(response.body)
341       assert_equal content_type, response.media_type
342       assert_equal "attachment; filename=\"#{trace.id}.#{extension}\"; filename*=UTF-8''#{trace.id}.#{extension}", @response.header["Content-Disposition"]
343     end
344
345     ##
346     # build XML for traces
347     # this builds a minimum viable XML for the tests in this suite
348     def create_trace_xml(trace)
349       root = XML::Document.new
350       root.root = XML::Node.new "osm"
351       trc = XML::Node.new "gpx_file"
352       trc["id"] = trace.id.to_s
353       trc["visibility"] = trace.visibility
354       trc["visible"] = trace.visible.to_s
355       desc = XML::Node.new "description"
356       desc << trace.description
357       trc << desc
358       trace.tags.each do |tag|
359         t = XML::Node.new "tag"
360         t << tag.tag
361         trc << t
362       end
363       root.root << trc
364       root.to_s
365     end
366   end
367 end