1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 require 'helpers/fake_websocket_helper'
6 require 'integration_helper'
8 class WorkUnitsTest < ActionDispatch::IntegrationTest
9 include FakeWebsocketHelper
16 ['/pipeline_instances/zzzzz-d1hrv-1yfj61234abcdk3',
17 '/pipeline_instances/zzzzz-d1hrv-1yfj61234abcdk4',
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']],
25 ['/pipeline_instances/zzzzz-d1hrv-1yfj61234abcdk3',
26 '/pipeline_instances/zzzzz-d1hrv-1yfj61234abcdk4',
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'
34 ].each do |show_children, expected_min, expected_max, expected, not_expected|
35 test "scroll all_processes page with show_children=#{show_children}" do
36 visit page_with_token('active', "/all_processes")
39 find('#IncludeChildProcs').click
43 page_scrolls = expected_max/20 + 2
44 within('.arv-recent-all-processes') do
45 (0..page_scrolls).each do |i|
46 page.driver.scroll_to 0, 999000
54 # Verify that expected number of processes are found
55 found_items = page.all('tr[data-object-uuid]')
56 found_count = found_items.count
57 if expected_min == expected_max
58 assert_equal(true, found_count == expected_min,
59 "Not found expected number of items. Expected #{expected_min} and found #{found_count}")
60 assert page.has_no_text? 'request failed'
62 assert_equal(true, found_count>=expected_min,
63 "Found too few items. Expected at least #{expected_min} and found #{found_count}")
64 assert_equal(true, found_count<=expected_max,
65 "Found too many items. Expected at most #{expected_max} and found #{found_count}")
68 # verify that all expected uuid links are found
69 expected.each do |link|
70 assert_selector "a[href=\"#{link}\"]"
73 # verify that none of the not_expected uuid links are found
74 not_expected.each do |link|
75 assert_no_selector "a[href=\"#{link}\"]"
81 ['containers', 'running', false],
82 ['container_requests', 'running', true],
83 ].each do |type, fixture, cancelable, confirm_cancellation|
84 test "cancel button for #{type}/#{fixture}" do
86 need_selenium 'to cancel'
89 obj = api_fixture(type)[fixture]
90 visit page_with_token "active", "/#{type}/#{obj['uuid']}"
92 assert_text 'created_at'
94 assert_text 'priority: 501' if type.include?('container')
95 if type.include?('pipeline')
96 assert_selector 'a', text: 'Pause'
97 first('a,link', text: 'Pause').click
99 assert_selector 'button', text: 'Cancel'
100 first('a,button', text: 'Cancel').click
102 if confirm_cancellation
103 alert = page.driver.browser.switch_to.alert
109 if type.include?('pipeline')
110 assert_selector 'a', text: 'Resume'
111 assert_no_selector 'a', text: 'Pause'
112 elsif type.include?('job')
113 assert_text 'Cancelled'
114 assert_text 'Paused' # this job has a pipeline child which was also cancelled
115 assert_no_selector 'button', text: 'Cancel'
117 assert_text 'priority: 0'
123 ['container_requests', 'running'],
124 ['container_requests', 'completed'],
125 ].each do |type, fixture|
126 test "edit description for #{type}/#{fixture}" do
127 obj = api_fixture(type)[fixture]
128 visit page_with_token "active", "/#{type}/#{obj['uuid']}"
130 within('.arv-description-as-subtitle') do
131 find('.fa-pencil').click
132 find('.editable-input textarea').set('*Textile description for object*')
133 find('.editable-submit').click
138 assert page.has_no_text? '*Textile description for object*'
139 assert page.has_text? 'Textile description for object'
144 ['Workflow with default input specifications', 'this workflow has inputs specified', 'Provide a value for the following'],
145 ].each do |template_name, preview_txt, process_txt|
146 test "run a process using template #{template_name} from dashboard" do
147 visit page_with_token('admin')
148 assert_text 'Recent processes' # seeing dashboard now
150 within('.recent-processes-actions') do
151 assert page.has_link?('All processes')
152 find('a', text: 'Run a process').click
155 # in the chooser, verify preview and click Next button
156 within('.modal-dialog') do
157 find('.selectable', text: template_name).click
158 assert_text preview_txt
159 find('.btn', text: 'Next: choose inputs').click
162 # in the process page now
163 assert_text process_txt
164 assert_selector 'a', text: template_name
166 assert_equal "true", find('span[data-name="reuse_steps"]').text
168 assert_equal "Set value for ex_string_def", find('div.form-group > div.form-control-static > a', text: "hello-testing-123")[:"data-title"]
170 page.assert_selector 'a.disabled,button.disabled', text: 'Run'
174 test 'display container state changes in Container Request live log' do
175 use_fake_websocket_driver
176 c = api_fixture('containers')['queued']
177 cr = api_fixture('container_requests')['queued']
178 visit page_with_token('active', '/container_requests/'+cr['uuid'])
181 # The attrs of the "terminal window" text div in the log tab
182 # indicates which objects' events are worth displaying. Events
183 # that arrive too early (before that div exists) are not
184 # shown. For the user's sake, these early logs should also be
185 # retrieved and shown one way or another -- but in this particular
186 # test, we are only interested in logs that arrive by
187 # websocket. Therefore, to avoid races, we wait for the log tab to
188 # display before sending any events.
189 assert_text 'Recent logs'
192 event_type: 'dispatch',
194 text: "dispatch logged a fake message\n",
196 }, "dispatch logged"],
198 event_type: 'update',
200 old_attributes: {state: 'Locked'},
201 new_attributes: {state: 'Queued'},
203 }, "Container #{c['uuid']} was returned to the queue"],
205 event_type: 'update',
207 old_attributes: {state: 'Queued'},
208 new_attributes: {state: 'Locked'},
210 }, "Container #{c['uuid']} was taken from the queue by a dispatch process"],
212 event_type: 'crunch-run',
214 text: "according to fake crunch-run,\nsome setup stuff happened on the compute node\n",
216 }, "setup stuff happened"],
218 event_type: 'update',
220 old_attributes: {state: 'Locked'},
221 new_attributes: {state: 'Running'},
223 }, "Container #{c['uuid']} started"],
225 event_type: 'update',
227 old_attributes: {state: 'Running'},
228 new_attributes: {state: 'Complete', exit_code: 1},
230 }, "Container #{c['uuid']} finished"],
231 # It's unrealistic for state to change again once it's Complete,
232 # but the logging code doesn't care, so we do it to keep the test
235 event_type: 'update',
237 old_attributes: {state: 'Running'},
238 new_attributes: {state: 'Cancelled'},
240 }, "Container #{c['uuid']} was cancelled"],
241 ].each do |send_event, expect_log_text|
242 assert_no_text(expect_log_text)
243 fake_websocket_event(send_event.merge(object_uuid: c['uuid']))
244 assert_text(expect_log_text)
248 test 'Run from workflows index page' do
249 visit page_with_token('active', '/workflows')
251 wf_count = page.all('a[data-original-title="show workflow"]').count
252 assert_equal true, wf_count>0
254 # Run one of the workflows
255 wf_name = 'Workflow with input specifications'
256 within('tr', text: wf_name) do
257 find('a,button', text: 'Run').click
260 # Choose project for the container_request being created
261 within('.modal-dialog') do
262 find('.selectable', text: 'A Project').click
263 find('button', text: 'Choose').click
266 # In newly created container_request page now
267 assert_text 'A Project' # CR created in "A Project"
268 assert_text "This container request was created from the workflow #{wf_name}"
269 assert_match /Provide a value for .* then click the \"Run\" button to start the workflow/, page.text
272 test 'Run workflow from show page' do
273 visit page_with_token('active', '/workflows/zzzzz-7fd4e-validwithinputs')
275 find('a,button', text: 'Run this workflow').click
277 # Choose project for the container_request being created
278 within('.modal-dialog') do
279 find('.selectable', text: 'A Project').click
280 find('button', text: 'Choose').click
283 # In newly created container_request page now
284 assert_text 'A Project' # CR created in "A Project"
285 assert_text "This container request was created from the workflow"
286 assert_match /Provide a value for .* then click the \"Run\" button to start the workflow/, page.text
289 test "create workflow with WorkflowRunnerResources" do
290 visit page_with_token('active', '/workflows/zzzzz-7fd4e-validwithinput3')
292 find('a,button', text: 'Run this workflow').click
294 # Choose project for the container_request being created
295 within('.modal-dialog') do
296 find('.selectable', text: 'A Project').click
297 find('button', text: 'Choose').click
299 click_link 'Advanced'
300 click_link("API response")
301 assert_text('"container_image": "arvados/jobs:2.0.4"')
302 assert_text('"vcpus": 2')
303 assert_text('"ram": 1293942784')
304 assert_text('"--collection-cache-size=678"')