12216: Allow Content-Type header via CORS.
[arvados.git] / apps / workbench / test / integration / anonymous_access_test.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'integration_helper'
6
7 class AnonymousAccessTest < ActionDispatch::IntegrationTest
8   include KeepWebConfig
9
10   # These tests don't do state-changing API calls. Save some time by
11   # skipping the database reset.
12   reset_api_fixtures :after_each_test, false
13   reset_api_fixtures :after_suite, true
14
15   setup do
16     need_javascript
17     Rails.configuration.anonymous_user_token = api_fixture('api_client_authorizations')['anonymous']['api_token']
18   end
19
20   PUBLIC_PROJECT = "/projects/#{api_fixture('groups')['anonymously_accessible_project']['uuid']}"
21
22   def verify_site_navigation_anonymous_enabled user, is_active
23     if user
24       if user['is_active']
25         assert_text 'Unrestricted public data'
26         assert_selector 'a', text: 'Projects'
27         page.find("#projects-menu").click
28         within('.dropdown-menu') do
29           assert_selector 'a', text: 'Search all projects'
30           assert_selector "a[href=\"/projects/public\"]", text: 'Browse public projects'
31           assert_selector 'a', text: 'Add a new project'
32           assert_selector 'li[class="dropdown-header"]', text: 'My projects'
33         end
34       else
35         assert_text 'indicate that you have read and accepted the user agreement'
36       end
37       within('.navbar-fixed-top') do
38         assert_selector 'a', text: Rails.configuration.site_name.downcase
39         assert(page.has_link?("notifications-menu"), 'no user menu')
40         page.find("#notifications-menu").click
41         within('.dropdown-menu') do
42           assert_selector 'a', text: 'Log out'
43         end
44       end
45     else  # anonymous
46       assert_text 'Unrestricted public data'
47       within('.navbar-fixed-top') do
48         assert_text Rails.configuration.site_name.downcase
49         assert_no_selector 'a', text: Rails.configuration.site_name.downcase
50         assert_selector 'a', text: 'Log in'
51         assert_selector 'a', text: 'Browse public projects'
52       end
53     end
54   end
55
56   [
57     [nil, nil, false, false],
58     ['inactive', api_fixture('users')['inactive'], false, false],
59     ['active', api_fixture('users')['active'], true, true],
60   ].each do |token, user, is_active|
61     test "visit public project as user #{token.inspect} when anonymous browsing is enabled" do
62       if !token
63         visit PUBLIC_PROJECT
64       else
65         visit page_with_token(token, PUBLIC_PROJECT)
66       end
67
68       verify_site_navigation_anonymous_enabled user, is_active
69     end
70   end
71
72   test "selection actions when anonymous user accesses shared project" do
73     visit PUBLIC_PROJECT
74
75     assert_selector 'a', text: 'Description'
76     assert_selector 'a', text: 'Data collections'
77     assert_selector 'a', text: 'Pipelines and processes'
78     assert_selector 'a', text: 'Pipeline templates'
79     assert_selector 'a', text: 'Subprojects'
80     assert_selector 'a', text: 'Advanced'
81     assert_no_selector 'a', text: 'Other objects'
82     assert_no_selector 'button', text: 'Add data'
83
84     click_link 'Data collections'
85     click_button 'Selection'
86     within('.selection-action-container') do
87       assert_selector 'li', text: 'Compare selected'
88       assert_no_selector 'li', text: 'Create new collection with selected collections'
89       assert_no_selector 'li', text: 'Copy selected'
90       assert_no_selector 'li', text: 'Move selected'
91       assert_no_selector 'li', text: 'Remove selected'
92     end
93   end
94
95   test "anonymous user accesses data collections tab in shared project" do
96     visit PUBLIC_PROJECT
97     click_link 'Data collections'
98     collection = api_fixture('collections')['user_agreement_in_anonymously_accessible_project']
99     assert_text 'GNU General Public License'
100
101     assert_selector 'a', text: 'Data collections'
102
103     # click on show collection
104     within "tr[data-object-uuid=\"#{collection['uuid']}\"]" do
105       click_link 'Show'
106     end
107
108     # in collection page
109     assert_no_selector 'input', text: 'Create sharing link'
110     assert_no_text 'Sharing and permissions'
111     assert_no_selector 'a', text: 'Upload'
112     assert_no_selector 'button', 'Selection'
113
114     within '#collection_files tr,li', text: 'GNU_General_Public_License,_version_3.pdf' do
115       assert page.has_no_selector?('[value*="GNU_General_Public_License"]')
116       find 'a[title~=View]'
117       find 'a[title~=Download]'
118     end
119   end
120
121   test 'view file' do
122     use_keep_web_config
123
124     magic = rand(2**512).to_s 36
125     owner = api_fixture('groups')['anonymously_accessible_project']['uuid']
126     col = upload_data_and_get_collection(magic, 'admin', "Hello\\040world.txt", owner)
127     visit '/collections/' + col.uuid
128     find('tr,li', text: 'Hello world.txt').
129       find('a[title~=View]').click
130     assert_text magic
131   end
132
133   [
134     'running anonymously accessible cr',
135     'pipelineInstance'
136   ].each do |proc|
137     test "anonymous user accesses pipelines and processes tab in shared project and clicks on '#{proc}'" do
138       visit PUBLIC_PROJECT
139       click_link 'Data collections'
140       assert_text 'GNU General Public License'
141
142       click_link 'Pipelines and processes'
143       assert_text 'Pipeline in publicly accessible project'
144
145       if proc.include? 'pipeline'
146         verify_pipeline_instance_row
147       else
148         verify_container_request_row proc
149       end
150     end
151   end
152
153   def verify_container_request_row look_for
154     within first('tr', text: look_for) do
155       click_link 'Show'
156     end
157     assert_text 'Public Projects Unrestricted public data'
158     assert_text 'command'
159
160     assert_text 'zzzzz-tpzed-xurymjxw79nv3jz' # modified by user
161     assert_no_selector 'a', text: 'zzzzz-tpzed-xurymjxw79nv3jz'
162     assert_no_selector 'button', text: 'Cancel'
163   end
164
165   def verify_pipeline_instance_row
166     within first('tr[data-kind="arvados#pipelineInstance"]') do
167       assert_text 'Pipeline in publicly accessible project'
168       click_link 'Show'
169     end
170
171     # in pipeline instance page
172     assert_text 'Public Projects Unrestricted public data'
173     assert_text 'This pipeline is complete'
174     assert_no_selector 'a', text: 'Re-run with latest'
175     assert_no_selector 'a', text: 'Re-run options'
176   end
177
178   [
179     'pipelineTemplate',
180     'workflow'
181   ].each do |type|
182     test "anonymous user accesses pipeline templates tab in shared project and click on #{type}" do
183       visit PUBLIC_PROJECT
184       click_link 'Data collections'
185       assert_text 'GNU General Public License'
186
187       assert_selector 'a', text: 'Pipeline templates'
188
189       click_link 'Pipeline templates'
190       assert_text 'Pipeline template in publicly accessible project'
191       assert_text 'Workflow with input specifications'
192
193       if type == 'pipelineTemplate'
194         within first('tr[data-kind="arvados#pipelineTemplate"]') do
195           click_link 'Show'
196         end
197
198         # in template page
199         assert_text 'Public Projects Unrestricted public data'
200         assert_text 'script version'
201         assert_no_selector 'a', text: 'Run this pipeline'
202       else
203         within first('tr[data-kind="arvados#workflow"]') do
204           click_link 'Show'
205         end
206
207         # in workflow page
208         assert_text 'Public Projects Unrestricted public data'
209         assert_text 'this workflow has inputs specified'
210       end
211     end
212   end
213
214   test "anonymous user accesses subprojects tab in shared project" do
215     visit PUBLIC_PROJECT + '#Subprojects'
216
217     assert_text 'Subproject in anonymous accessible project'
218
219     within first('tr[data-kind="arvados#group"]') do
220       click_link 'Show'
221     end
222
223     # in subproject
224     assert_text 'Description for subproject in anonymous accessible project'
225   end
226
227   [
228     ['pipeline_in_publicly_accessible_project', true],
229     ['pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', false],
230     ['pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', false, 'spectator'],
231     ['pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', true, 'admin'],
232
233     ['completed_job_in_publicly_accessible_project', true],
234     ['running_job_in_publicly_accessible_project', true],
235     ['job_in_publicly_accessible_project_but_other_objects_elsewhere', false],
236   ].each do |fixture, objects_readable, user=nil|
237     test "access #{fixture} in public project with objects readable=#{objects_readable} with user #{user}" do
238       pipeline_page = true if fixture.include?('pipeline')
239
240       if pipeline_page
241         object = api_fixture('pipeline_instances')[fixture]
242         page_link = "/pipeline_instances/#{object['uuid']}"
243         expect_log_text = "Log for foo"
244       else      # job
245         object = api_fixture('jobs')[fixture]
246         page_link = "/jobs/#{object['uuid']}"
247         expect_log_text = "stderr crunchstat"
248       end
249
250       if user
251         visit page_with_token user, page_link
252       else
253         visit page_link
254       end
255
256       # click job link, if in pipeline page
257       click_link 'foo' if pipeline_page
258
259       if objects_readable
260         assert_selector 'a[href="#Log"]', text: 'Log'
261         assert_no_selector 'a[data-toggle="disabled"]', text: 'Log'
262         assert_no_text 'Output data not available'
263         if pipeline_page
264           assert_text 'This pipeline was created from'
265           job_id = object['components']['foo']['job']['uuid']
266           assert_selector 'a', text: job_id
267           assert_selector "a[href=\"/jobs/#{job_id}#Log\"]", text: 'Log'
268
269           # We'd like to test the Log tab on job pages too, but we can't right
270           # now because Poltergeist 1.x doesn't support JavaScript's
271           # Function.prototype.bind, which is used by job_log_graph.js.
272           find(:xpath, "//a[@href='#Log']").click
273           assert_text expect_log_text
274         end
275       else
276         assert_selector 'a[data-toggle="disabled"]', text: 'Log'
277         assert_text 'Output data not available'
278         assert_text object['job']
279         if pipeline_page
280           assert_no_text 'This pipeline was created from'  # template is not readable
281           assert_no_selector 'a', text: object['components']['foo']['job']['uuid']
282           assert_text 'Log unavailable'
283         end
284         find(:xpath, "//a[@href='#Log']").click
285         assert_text 'Output data not available'
286         assert_no_text expect_log_text
287       end
288     end
289   end
290
291   [
292     ['new_pipeline_in_publicly_accessible_project', true],
293     ['new_pipeline_in_publicly_accessible_project', true, 'spectator'],
294     ['new_pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', false],
295     ['new_pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', false, 'spectator'],
296     ['new_pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', true, 'admin'],
297     ['new_pipeline_in_publicly_accessible_project_with_dataclass_file_and_other_objects_elsewhere', false],
298     ['new_pipeline_in_publicly_accessible_project_with_dataclass_file_and_other_objects_elsewhere', false, 'spectator'],
299     ['new_pipeline_in_publicly_accessible_project_with_dataclass_file_and_other_objects_elsewhere', true, 'admin'],
300   ].each do |fixture, objects_readable, user=nil|
301     test "access #{fixture} in public project with objects readable=#{objects_readable} with user #{user}" do
302       object = api_fixture('pipeline_instances')[fixture]
303       page = "/pipeline_instances/#{object['uuid']}"
304       if user
305         visit page_with_token user, page
306       else
307         visit page
308       end
309
310       # click Components tab
311       click_link 'Components'
312
313       if objects_readable
314         assert_text 'This pipeline was created from'
315         if user == 'admin'
316           assert_text 'input'
317           assert_selector 'a', text: 'Choose'
318           assert_selector 'a', text: 'Run'
319           assert_no_selector 'a.disabled', text: 'Run'
320         else
321           assert_selector 'a', text: object['components']['foo']['script_parameters']['input']['value']
322           user ? (assert_selector 'a', text: 'Run') : (assert_no_selector 'a', text: 'Run')
323         end
324       else
325         assert_no_text 'This pipeline was created from'  # template is not readable
326         input = object['components']['foo']['script_parameters']['input']['value']
327         assert_no_selector 'a', text: input
328         if user
329           input = input.gsub('/', '\\/')
330           assert_text "One or more inputs provided are not readable"
331           assert_selector "input[type=text][value=#{input}]"
332           assert_selector 'a.disabled', text: 'Run'
333         else
334           assert_no_text "One or more inputs provided are not readable"
335           assert_text input
336           assert_no_selector 'a', text: 'Run'
337         end
338       end
339     end
340   end
341 end