12315: Propagate show_children to infinite scroll pages. Fix & add tests.
[arvados.git] / apps / workbench / test / integration / work_units_test.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'helpers/fake_websocket_helper'
6 require 'integration_helper'
7
8 class WorkUnitsTest < ActionDispatch::IntegrationTest
9   include FakeWebsocketHelper
10
11   setup do
12     need_javascript
13   end
14
15   [[true, 25, 100,
16     ['/pipeline_instances/zzzzz-d1hrv-1yfj61234abcdk3',
17      '/pipeline_instances/zzzzz-d1hrv-jobspeccomponts',
18      '/jobs/zzzzz-8i9sb-grx15v5mjnsyxk7',
19      '/jobs/zzzzz-8i9sb-n7omg50bvt0m1nf',
20      '/container_requests/zzzzz-xvhdp-cr4completedcr2',
21      '/container_requests/zzzzz-xvhdp-cr4requestercn2'],
22     ['/pipeline_instances/zzzzz-d1hrv-scarxiyajtshq3l',
23      '/container_requests/zzzzz-xvhdp-oneof60crs00001']],
24    [false, 25, 100,
25     ['/pipeline_instances/zzzzz-d1hrv-1yfj61234abcdk3',
26      '/pipeline_instances/zzzzz-d1hrv-jobspeccomponts',
27      '/container_requests/zzzzz-xvhdp-cr4completedcr2'],
28     ['/pipeline_instances/zzzzz-d1hrv-scarxiyajtshq3l',
29      '/container_requests/zzzzz-xvhdp-oneof60crs00001',
30      '/jobs/zzzzz-8i9sb-grx15v5mjnsyxk7',
31      '/jobs/zzzzz-8i9sb-n7omg50bvt0m1nf',
32      '/container_requests/zzzzz-xvhdp-cr4requestercn2'
33     ]]
34   ].each do |expects|
35     test "scroll all_processes page with show_children #{expects[0]}" do
36       show_children, expected_min, expected_max, expected, not_expected = expects
37       visit page_with_token('active', "/all_processes")
38
39       if show_children
40         find('#IncludeChildProcs').click
41         wait_for_ajax
42       end
43
44       page_scrolls = expected_max/20 + 2
45       within('.arv-recent-all-processes') do
46         (0..page_scrolls).each do |i|
47           page.driver.scroll_to 0, 999000
48           begin
49             wait_for_ajax
50           rescue
51           end
52         end
53       end
54
55       # Verify that expected number of processes are found
56       found_items = page.all('tr[data-object-uuid]')
57       found_count = found_items.count
58       if expected_min == expected_max
59         assert_equal(true, found_count == expected_min,
60                      "Not found expected number of items. Expected #{expected_min} and found #{found_count}")
61         assert page.has_no_text? 'request failed'
62       else
63         assert_equal(true, found_count>=expected_min,
64                      "Found too few items. Expected at least #{expected_min} and found #{found_count}")
65         assert_equal(true, found_count<=expected_max,
66                      "Found too many items. Expected at most #{expected_max} and found #{found_count}")
67       end
68
69       # verify that all expected uuid links are found
70       expected.each do |link|
71         assert_selector "a[href=\"#{link}\"]"
72       end
73
74       # verify that none of the not_expected uuid links are found
75       not_expected.each do |link|
76         assert_no_selector "a[href=\"#{link}\"]"
77       end
78     end
79   end
80
81   [
82     ['jobs', 'running_job_with_components', true, true],
83     ['pipeline_instances', 'components_is_jobspec', true, true],
84     ['containers', 'running', false],
85     ['container_requests', 'running', true],
86   ].each do |type, fixture, cancelable, confirm_cancellation|
87     test "cancel button for #{type}/#{fixture}" do
88       if cancelable
89         need_selenium 'to cancel'
90       end
91
92       obj = api_fixture(type)[fixture]
93       visit page_with_token "active", "/#{type}/#{obj['uuid']}"
94
95       assert_text 'created_at'
96       if cancelable
97         assert_text 'priority: 1' if type.include?('container')
98         if type.include?('pipeline')
99           assert_selector 'a', text: 'Pause'
100           first('a,link', text: 'Pause').click
101         else
102           assert_selector 'button', text: 'Cancel'
103           first('a,button', text: 'Cancel').click
104         end
105         if confirm_cancellation
106           alert = page.driver.browser.switch_to.alert
107           alert.accept
108         end
109         wait_for_ajax
110       end
111
112       if type.include?('pipeline')
113         assert_selector 'a', text: 'Resume'
114         assert_no_selector 'a', text: 'Pause'
115       elsif type.include?('job')
116         assert_text 'Cancelled'
117         assert_text 'Paused'  # this job has a pipeline child which was also cancelled
118         assert_no_selector 'button', text: 'Cancel'
119       elsif cancelable
120         assert_text 'priority: 0'
121       end
122     end
123   end
124
125   [
126     ['jobs', 'running_job_with_components'],
127     ['pipeline_instances', 'has_component_with_completed_jobs'],
128     ['container_requests', 'running'],
129     ['container_requests', 'completed'],
130   ].each do |type, fixture|
131     test "edit description for #{type}/#{fixture}" do
132       obj = api_fixture(type)[fixture]
133       visit page_with_token "active", "/#{type}/#{obj['uuid']}"
134
135       within('.arv-description-as-subtitle') do
136         find('.fa-pencil').click
137         find('.editable-input textarea').set('*Textile description for object*')
138         find('.editable-submit').click
139       end
140       wait_for_ajax
141
142       # verify description
143       assert page.has_no_text? '*Textile description for object*'
144       assert page.has_text? 'Textile description for object'
145     end
146   end
147
148   [
149     ['Pipeline with default input specifications', 'part-one', 'Provide values for the following'],
150     ['Workflow with default input specifications', 'this workflow has inputs specified', 'Provide a value for the following'],
151   ].each do |template_name, preview_txt, process_txt|
152     test "run a process using template #{template_name} from dashboard" do
153       visit page_with_token('admin')
154       assert_text 'Recent pipelines and processes' # seeing dashboard now
155
156       within('.recent-processes-actions') do
157         assert page.has_link?('All processes')
158         find('a', text: 'Run a process').click
159       end
160
161       # in the chooser, verify preview and click Next button
162       within('.modal-dialog') do
163         find('.selectable', text: template_name).click
164         assert_text preview_txt
165         find('.btn', text: 'Next: choose inputs').click
166       end
167
168       # in the process page now
169       assert_text process_txt
170       assert_selector 'a', text: template_name
171
172       assert_equal "Set value for ex_string_def", find('div.form-group > div > p.form-control-static > a', text: "hello-testing-123")[:"data-title"]
173
174       page.assert_selector 'a.disabled,button.disabled', text: 'Run'
175     end
176   end
177
178   test 'display container state changes in Container Request live log' do
179     use_fake_websocket_driver
180     c = api_fixture('containers')['queued']
181     cr = api_fixture('container_requests')['queued']
182     visit page_with_token('active', '/container_requests/'+cr['uuid'])
183     click_link('Log')
184
185     # The attrs of the "terminal window" text div in the log tab
186     # indicates which objects' events are worth displaying. Events
187     # that arrive too early (before that div exists) are not
188     # shown. For the user's sake, these early logs should also be
189     # retrieved and shown one way or another -- but in this particular
190     # test, we are only interested in logs that arrive by
191     # websocket. Therefore, to avoid races, we wait for the log tab to
192     # display before sending any events.
193     assert_text 'Recent logs'
194
195     [[{
196         event_type: 'dispatch',
197         properties: {
198           text: "dispatch logged a fake message\n",
199         },
200       }, "dispatch logged"],
201      [{
202         event_type: 'update',
203         properties: {
204           old_attributes: {state: 'Locked'},
205           new_attributes: {state: 'Queued'},
206         },
207       }, "Container #{c['uuid']} was returned to the queue"],
208      [{
209         event_type: 'update',
210         properties: {
211           old_attributes: {state: 'Queued'},
212           new_attributes: {state: 'Locked'},
213         },
214       }, "Container #{c['uuid']} was taken from the queue by a dispatch process"],
215      [{
216         event_type: 'crunch-run',
217         properties: {
218           text: "according to fake crunch-run,\nsome setup stuff happened on the compute node\n",
219         },
220       }, "setup stuff happened"],
221      [{
222         event_type: 'update',
223         properties: {
224           old_attributes: {state: 'Locked'},
225           new_attributes: {state: 'Running'},
226         },
227       }, "Container #{c['uuid']} started"],
228      [{
229         event_type: 'update',
230         properties: {
231           old_attributes: {state: 'Running'},
232           new_attributes: {state: 'Complete', exit_code: 1},
233         },
234       }, "Container #{c['uuid']} finished"],
235      # It's unrealistic for state to change again once it's Complete,
236      # but the logging code doesn't care, so we do it to keep the test
237      # simple.
238      [{
239         event_type: 'update',
240         properties: {
241           old_attributes: {state: 'Running'},
242           new_attributes: {state: 'Cancelled'},
243         },
244       }, "Container #{c['uuid']} was cancelled"],
245     ].each do |send_event, expect_log_text|
246       assert_no_text(expect_log_text)
247       fake_websocket_event(send_event.merge(object_uuid: c['uuid']))
248       assert_text(expect_log_text)
249     end
250   end
251
252   [
253     ['jobs', 'active', 'running_job_with_components', 'component1', '/jobs/zzzzz-8i9sb-jyq01m7in1jlofj#Log'],
254     ['pipeline_instances', 'active', 'pipeline_in_running_state', 'foo', '/jobs/zzzzz-8i9sb-pshmckwoma9plh7#Log'],
255     ['pipeline_instances', nil, 'pipeline_in_publicly_accessible_project_but_other_objects_elsewhere', 'foo', 'Log unavailable'],
256   ].each do |type, token, fixture, child, log_link|
257     test "link_to_log for #{fixture} for #{token}" do
258       obj = api_fixture(type)[fixture]
259       if token
260         visit page_with_token token, "/#{type}/#{obj['uuid']}"
261       else
262         Rails.configuration.anonymous_user_token =
263           api_fixture("api_client_authorizations", "anonymous", "api_token")
264         visit "/#{type}/#{obj['uuid']}"
265       end
266
267       click_link(child)
268
269       if token
270         assert_selector "a[href=\"#{log_link}\"]"
271       else
272         assert_text log_link
273       end
274     end
275   end
276
277   test 'Run from workflows index page' do
278     visit page_with_token('active', '/workflows')
279
280     wf_count = page.all('a[data-original-title="show workflow"]').count
281     assert_equal true, wf_count>0
282
283     # Run one of the workflows
284     wf_name = 'Workflow with input specifications'
285     within('tr', text: wf_name) do
286       find('a,button', text: 'Run').click
287     end
288
289     # Choose project for the container_request being created
290     within('.modal-dialog') do
291       find('.selectable', text: 'A Project').click
292       find('button', text: 'Choose').click
293     end
294
295     # In newly created container_request page now
296     assert_text 'A Project' # CR created in "A Project"
297     assert_text "This container request was created from the workflow #{wf_name}"
298     assert_match /Provide a value for .* then click the \"Run\" button to start the workflow/, page.text
299   end
300
301   test 'Run workflow from show page' do
302     visit page_with_token('active', '/workflows/zzzzz-7fd4e-validwithinputs')
303
304     find('a,button', text: 'Run this workflow').click
305
306     # Choose project for the container_request being created
307     within('.modal-dialog') do
308       find('.selectable', text: 'A Project').click
309       find('button', text: 'Choose').click
310     end
311
312     # In newly created container_request page now
313     assert_text 'A Project' # CR created in "A Project"
314     assert_text "This container request was created from the workflow"
315     assert_match /Provide a value for .* then click the \"Run\" button to start the workflow/, page.text
316   end
317 end