closes #6476
[arvados.git] / apps / workbench / test / controllers / application_controller_test.rb
1 require 'test_helper'
2
3 class ApplicationControllerTest < ActionController::TestCase
4   # These tests don't do state-changing API calls. Save some time by
5   # skipping the database reset.
6   reset_api_fixtures :after_each_test, false
7   reset_api_fixtures :after_suite, true
8
9   setup do
10     @user_dataclass = ArvadosBase.resource_class_for_uuid(api_fixture('users')['active']['uuid'])
11   end
12
13   test "links for object" do
14     use_token :active
15
16     ac = ApplicationController.new
17
18     link_head_uuid = api_fixture('links')['foo_file_readable_by_active']['head_uuid']
19
20     links = ac.send :links_for_object, link_head_uuid
21
22     assert links, 'Expected links'
23     assert links.is_a?(Array), 'Expected an array'
24     assert links.size > 0, 'Expected at least one link'
25     assert links[0][:uuid], 'Expected uuid for the head_link'
26   end
27
28   test "preload links for objects and uuids" do
29     use_token :active
30
31     ac = ApplicationController.new
32
33     link1_head_uuid = api_fixture('links')['foo_file_readable_by_active']['head_uuid']
34     link2_uuid = api_fixture('links')['bar_file_readable_by_active']['uuid']
35     link3_head_uuid = api_fixture('links')['bar_file_readable_by_active']['head_uuid']
36
37     link2_object = User.find(api_fixture('users')['active']['uuid'])
38     link2_object_uuid = link2_object['uuid']
39
40     uuids = [link1_head_uuid, link2_object, link3_head_uuid]
41     links = ac.send :preload_links_for_objects, uuids
42
43     assert links, 'Expected links'
44     assert links.is_a?(Hash), 'Expected a hash'
45     assert links.size == 3, 'Expected two objects in the preloaded links hash'
46     assert links[link1_head_uuid], 'Expected links for the passed in link head_uuid'
47     assert links[link2_object_uuid], 'Expected links for the passed in object uuid'
48     assert links[link3_head_uuid], 'Expected links for the passed in link head_uuid'
49
50     # invoke again for this same input. this time, the preloaded data will be returned
51     links = ac.send :preload_links_for_objects, uuids
52     assert links, 'Expected links'
53     assert links.is_a?(Hash), 'Expected a hash'
54     assert links.size == 3, 'Expected two objects in the preloaded links hash'
55     assert links[link1_head_uuid], 'Expected links for the passed in link head_uuid'
56   end
57
58   [ [:preload_links_for_objects, [] ],
59     [:preload_collections_for_objects, [] ],
60     [:preload_log_collections_for_objects, [] ],
61     [:preload_objects_for_dataclass, [] ],
62     [:preload_for_pdhs, [] ],
63   ].each do |input|
64     test "preload data for empty array input #{input}" do
65       use_token :active
66
67       ac = ApplicationController.new
68
69       if input[0] == :preload_objects_for_dataclass
70         objects = ac.send input[0], @user_dataclass, input[1]
71       else
72         objects = ac.send input[0], input[1]
73       end
74
75       assert objects, 'Expected objects'
76       assert objects.is_a?(Hash), 'Expected a hash'
77       assert objects.size == 0, 'Expected no objects in the preloaded hash'
78     end
79   end
80
81   [ [:preload_links_for_objects, 'input not an array'],
82     [:preload_links_for_objects, nil],
83     [:links_for_object, nil],
84     [:preload_collections_for_objects, 'input not an array'],
85     [:preload_collections_for_objects, nil],
86     [:collections_for_object, nil],
87     [:preload_log_collections_for_objects, 'input not an array'],
88     [:preload_log_collections_for_objects, nil],
89     [:log_collections_for_object, nil],
90     [:preload_objects_for_dataclass, 'input not an array'],
91     [:preload_objects_for_dataclass, nil],
92     [:object_for_dataclass, 'some_dataclass', nil],
93     [:object_for_dataclass, nil, 'some_uuid'],
94     [:preload_for_pdhs, 'input not an array'],
95     [:preload_for_pdhs, nil],
96   ].each do |input|
97     test "preload data for wrong type input #{input}" do
98       use_token :active
99
100       ac = ApplicationController.new
101
102       if input[0] == :object_for_dataclass
103         assert_raise ArgumentError do
104           ac.send input[0], input[1], input[2]
105         end
106       else
107         assert_raise ArgumentError do
108           ac.send input[0], input[1]
109         end
110       end
111     end
112   end
113
114   [ [:links_for_object, 'no-such-uuid' ],
115     [:collections_for_object, 'no-such-uuid' ],
116     [:log_collections_for_object, 'no-such-uuid' ],
117     [:object_for_dataclass, 'no-such-uuid' ],
118     [:collection_for_pdh, 'no-such-pdh' ],
119   ].each do |input|
120     test "get data for no such uuid #{input}" do
121       use_token :active
122
123       ac = ApplicationController.new
124
125       if input[0] == :object_for_dataclass
126         object = ac.send input[0], @user_dataclass, input[1]
127         assert_not object, 'Expected no object'
128       else
129         objects = ac.send input[0], input[1]
130         assert objects, 'Expected objects'
131         assert objects.is_a?(Array), 'Expected a array'
132         assert_empty objects
133       end
134     end
135   end
136
137   test "get 10 objects of data class user" do
138     use_token :active
139
140     ac = ApplicationController.new
141
142     objects = ac.send :get_n_objects_of_class, @user_dataclass, 10
143
144     assert objects, 'Expected objects'
145     assert objects.is_a?(ArvadosResourceList), 'Expected an ArvadosResourceList'
146
147     first_object = objects.first
148     assert first_object, 'Expected at least one object'
149     assert_equal 'User', first_object.class.name, 'Expected user object'
150
151     # invoke it again. this time, the preloaded info will be returned
152     objects = ac.send :get_n_objects_of_class, @user_dataclass, 10
153     assert objects, 'Expected objects'
154     assert_equal 'User', objects.first.class.name, 'Expected user object'
155   end
156
157   [ ['User', 10],
158     [nil, 10],
159     [@user_dataclass, 0],
160     [@user_dataclass, -1],
161     [@user_dataclass, nil] ].each do |input|
162     test "get_n_objects for incorrect input #{input}" do
163       use_token :active
164
165       ac = ApplicationController.new
166
167       assert_raise ArgumentError do
168         ac.send :get_n_objects_of_class, input[0], input[1]
169       end
170     end
171   end
172
173   test "collections for object" do
174     use_token :active
175
176     ac = ApplicationController.new
177
178     uuid = api_fixture('collections')['foo_file']['uuid']
179
180     collections = ac.send :collections_for_object, uuid
181
182     assert collections, 'Expected collections'
183     assert collections.is_a?(Array), 'Expected an array'
184     assert collections.size == 1, 'Expected one collection object'
185     assert_equal collections[0][:uuid], uuid, 'Expected uuid not found in collections'
186   end
187
188   test "preload collections for given uuids" do
189     use_token :active
190
191     ac = ApplicationController.new
192
193     uuid1 = api_fixture('collections')['foo_file']['uuid']
194     uuid2 = api_fixture('collections')['bar_file']['uuid']
195
196     uuids = [uuid1, uuid2]
197     collections = ac.send :preload_collections_for_objects, uuids
198
199     assert collections, 'Expected collection'
200     assert collections.is_a?(Hash), 'Expected a hash'
201     assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
202     assert collections[uuid1], 'Expected collections for the passed in uuid'
203     assert_equal collections[uuid1].size, 1, 'Expected one collection for the passed in uuid'
204     assert collections[uuid2], 'Expected collections for the passed in uuid'
205     assert_equal collections[uuid2].size, 1, 'Expected one collection for the passed in uuid'
206
207     # invoke again for this same input. this time, the preloaded data will be returned
208     collections = ac.send :preload_collections_for_objects, uuids
209     assert collections, 'Expected collection'
210     assert collections.is_a?(Hash), 'Expected a hash'
211     assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
212     assert collections[uuid1], 'Expected collections for the passed in uuid'
213   end
214
215   test "log collections for object" do
216     use_token :active
217
218     ac = ApplicationController.new
219
220     uuid = api_fixture('logs')['system_adds_foo_file']['object_uuid']
221
222     collections = ac.send :log_collections_for_object, uuid
223
224     assert collections, 'Expected collections'
225     assert collections.is_a?(Array), 'Expected an array'
226     assert collections.size == 1, 'Expected one collection object'
227     assert_equal collections[0][:uuid], uuid, 'Expected uuid not found in collections'
228   end
229
230   test "preload log collections for given uuids" do
231     use_token :active
232
233     ac = ApplicationController.new
234
235     uuid1 = api_fixture('logs')['system_adds_foo_file']['object_uuid']
236     uuid2 = api_fixture('collections')['bar_file']['uuid']
237
238     uuids = [uuid1, uuid2]
239     collections = ac.send :preload_log_collections_for_objects, uuids
240
241     assert collections, 'Expected collection'
242     assert collections.is_a?(Hash), 'Expected a hash'
243     assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
244     assert collections[uuid1], 'Expected collections for the passed in uuid'
245     assert_equal collections[uuid1].size, 1, 'Expected one collection for the passed in uuid'
246     assert collections[uuid2], 'Expected collections for the passed in uuid'
247     assert_equal collections[uuid2].size, 1, 'Expected one collection for the passed in uuid'
248
249     # invoke again for this same input. this time, the preloaded data will be returned
250     collections = ac.send :preload_log_collections_for_objects, uuids
251     assert collections, 'Expected collection'
252     assert collections.is_a?(Hash), 'Expected a hash'
253     assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
254     assert collections[uuid1], 'Expected collections for the passed in uuid'
255   end
256
257   test "object for dataclass" do
258     use_token :active
259
260     ac = ApplicationController.new
261
262     dataclass = ArvadosBase.resource_class_for_uuid(api_fixture('jobs')['running']['uuid'])
263     uuid = api_fixture('jobs')['running']['uuid']
264
265     obj = ac.send :object_for_dataclass, dataclass, uuid
266
267     assert obj, 'Expected object'
268     assert 'Job', obj.class
269     assert_equal uuid, obj['uuid'], 'Expected uuid not found'
270     assert_equal api_fixture('jobs')['running']['script_version'], obj['script_version'],
271       'Expected script_version not found'
272   end
273
274   test "preload objects for dataclass" do
275     use_token :active
276
277     ac = ApplicationController.new
278
279     dataclass = ArvadosBase.resource_class_for_uuid(api_fixture('jobs')['running']['uuid'])
280
281     uuid1 = api_fixture('jobs')['running']['uuid']
282     uuid2 = api_fixture('jobs')['running_cancelled']['uuid']
283
284     uuids = [uuid1, uuid2]
285     users = ac.send :preload_objects_for_dataclass, dataclass, uuids
286
287     assert users, 'Expected objects'
288     assert users.is_a?(Hash), 'Expected a hash'
289
290     assert users.size == 2, 'Expected two objects in the preloaded hash'
291     assert users[uuid1], 'Expected user object for the passed in uuid'
292     assert users[uuid2], 'Expected user object for the passed in uuid'
293
294     # invoke again for this same input. this time, the preloaded data will be returned
295     users = ac.send :preload_objects_for_dataclass, dataclass, uuids
296     assert users, 'Expected objects'
297     assert users.is_a?(Hash), 'Expected a hash'
298     assert users.size == 2, 'Expected two objects in the preloaded hash'
299
300     # invoke again for this with one more uuid
301     uuids << api_fixture('jobs')['foobar']['uuid']
302     users = ac.send :preload_objects_for_dataclass, dataclass, uuids
303     assert users, 'Expected objects'
304     assert users.is_a?(Hash), 'Expected a hash'
305     assert users.size == 3, 'Expected two objects in the preloaded hash'
306   end
307
308   test "preload one collection each for given portable_data_hash list" do
309     use_token :active
310
311     ac = ApplicationController.new
312
313     pdh1 = api_fixture('collections')['foo_file']['portable_data_hash']
314     pdh2 = api_fixture('collections')['bar_file']['portable_data_hash']
315
316     pdhs = [pdh1, pdh2]
317     collections = ac.send :preload_for_pdhs, pdhs
318
319     assert collections, 'Expected collections map'
320     assert collections.is_a?(Hash), 'Expected a hash'
321     # Each pdh has more than one collection; however, we should get only one for each
322     assert collections.size == 2, 'Expected two objects in the preloaded collection hash'
323     assert collections[pdh1], 'Expected collections for the passed in pdh #{pdh1}'
324     assert_equal collections[pdh1].size, 1, 'Expected one collection for the passed in pdh #{pdh1}'
325     assert collections[pdh2], 'Expected collections for the passed in pdh #{pdh2}'
326     assert_equal collections[pdh2].size, 1, 'Expected one collection for the passed in pdh #{pdh2}'
327   end
328
329   test "requesting a nonexistent object returns 404" do
330     # We're really testing ApplicationController's find_object_by_uuid.
331     # It's easiest to do that by instantiating a concrete controller.
332     @controller = NodesController.new
333     get(:show, {id: "zzzzz-zzzzz-zzzzzzzzzzzzzzz"}, session_for(:admin))
334     assert_response 404
335   end
336
337   test "Workbench returns 4xx when API server is unreachable" do
338     # We're really testing ApplicationController's render_exception.
339     # Our primary concern is that it doesn't raise an error and
340     # return 500.
341     orig_api_server = Rails.configuration.arvados_v1_base
342     begin
343       # The URL should look valid in all respects, and avoid talking over a
344       # network.  100::/64 is the IPv6 discard prefix, so it's perfect.
345       Rails.configuration.arvados_v1_base = "https://[100::f]:1/"
346       @controller = NodesController.new
347       get(:index, {}, session_for(:active))
348       assert_includes(405..422, @response.code.to_i,
349                       "bad response code when API server is unreachable")
350     ensure
351       Rails.configuration.arvados_v1_base = orig_api_server
352     end
353   end
354
355   [
356     [CollectionsController.new, api_fixture('collections')['user_agreement_in_anonymously_accessible_project']],
357     [CollectionsController.new, api_fixture('collections')['user_agreement_in_anonymously_accessible_project'], false],
358     [JobsController.new, api_fixture('jobs')['running_job_in_publicly_accessible_project']],
359     [JobsController.new, api_fixture('jobs')['running_job_in_publicly_accessible_project'], false],
360     [PipelineInstancesController.new, api_fixture('pipeline_instances')['pipeline_in_publicly_accessible_project']],
361     [PipelineInstancesController.new, api_fixture('pipeline_instances')['pipeline_in_publicly_accessible_project'], false],
362     [PipelineTemplatesController.new, api_fixture('pipeline_templates')['pipeline_template_in_publicly_accessible_project']],
363     [PipelineTemplatesController.new, api_fixture('pipeline_templates')['pipeline_template_in_publicly_accessible_project'], false],
364     [ProjectsController.new, api_fixture('groups')['anonymously_accessible_project']],
365     [ProjectsController.new, api_fixture('groups')['anonymously_accessible_project'], false],
366   ].each do |controller, fixture, anon_config=true|
367     test "#{controller} show method with anonymous config enabled" do
368       if anon_config
369         Rails.configuration.anonymous_user_token = api_fixture('api_client_authorizations')['anonymous']['api_token']
370       else
371         Rails.configuration.anonymous_user_token = false
372       end
373
374       @controller = controller
375
376       get(:show, {id: fixture['uuid']})
377
378       if anon_config
379         assert_response 200
380         if controller.class == JobsController
381           assert_includes @response.inspect, fixture['script']
382         else
383           assert_includes @response.inspect, fixture['name']
384         end
385       else
386         assert_response :redirect
387         assert_match /\/users\/welcome/, @response.redirect_url
388       end
389     end
390   end
391
392   [
393     true,
394     false,
395   ].each do |config|
396     test "invoke show with include_accept_encoding_header config #{config}" do
397       Rails.configuration.include_accept_encoding_header_in_api_requests = config
398
399       @controller = CollectionsController.new
400       get(:show, {id: api_fixture('collections')['foo_file']['uuid']}, session_for(:admin))
401
402       assert_equal([['.', 'foo', 3]], assigns(:object).files)
403     end
404   end
405
406   test 'Edit name and verify that a duplicate is not created' do
407     @controller = ProjectsController.new
408     project = api_fixture("groups")["aproject"]
409     post :update, {
410       id: project["uuid"],
411       project: {
412         name: 'test name'
413       },
414       format: :json
415     }, session_for(:active)
416     assert_includes @response.body, 'test name'
417     updated = assigns(:object)
418     assert_equal updated.uuid, project["uuid"]
419     assert_equal 'test name', updated.name
420   end
421 end