Merge branch 'master' into 9956-keepstore-config
[arvados.git] / apps / workbench / test / integration / work_units_test.rb
1 require 'helpers/fake_websocket_helper'
2 require 'integration_helper'
3
4 class WorkUnitsTest < ActionDispatch::IntegrationTest
5   include FakeWebsocketHelper
6
7   setup do
8     need_javascript
9   end
10
11   test "scroll all_processes page" do
12       expected_min, expected_max, expected, not_expected = [
13         25, 100,
14         ['/pipeline_instances/zzzzz-d1hrv-1yfj61234abcdk3',
15          '/pipeline_instances/zzzzz-d1hrv-jobspeccomponts',
16          '/jobs/zzzzz-8i9sb-grx15v5mjnsyxk7',
17          '/jobs/zzzzz-8i9sb-n7omg50bvt0m1nf',
18          '/container_requests/zzzzz-xvhdp-cr4completedcr2',
19          '/container_requests/zzzzz-xvhdp-cr4requestercn2'],
20         ['/pipeline_instances/zzzzz-d1hrv-scarxiyajtshq3l',
21          '/container_requests/zzzzz-xvhdp-oneof60crs00001']
22       ]
23
24       visit page_with_token('active', "/all_processes")
25
26       page_scrolls = expected_max/20 + 2
27       within('.arv-recent-all-processes') do
28         (0..page_scrolls).each do |i|
29           page.driver.scroll_to 0, 999000
30           begin
31             wait_for_ajax
32           rescue
33           end
34         end
35       end
36
37       # Verify that expected number of processes are found
38       found_items = page.all('tr[data-object-uuid]')
39       found_count = found_items.count
40       if expected_min == expected_max
41         assert_equal(true, found_count == expected_min,
42           "Not found expected number of items. Expected #{expected_min} and found #{found_count}")
43         assert page.has_no_text? 'request failed'
44       else
45         assert_equal(true, found_count>=expected_min,
46           "Found too few items. Expected at least #{expected_min} and found #{found_count}")
47         assert_equal(true, found_count<=expected_max,
48           "Found too many items. Expected at most #{expected_max} and found #{found_count}")
49       end
50
51       # verify that all expected uuid links are found
52       expected.each do |link|
53         assert_selector "a[href=\"#{link}\"]"
54       end
55
56       # verify that none of the not_expected uuid links are found
57       not_expected.each do |link|
58         assert_no_selector "a[href=\"#{link}\"]"
59       end
60   end
61
62   [
63     ['jobs', 'running_job_with_components', true],
64     ['pipeline_instances', 'components_is_jobspec', false],
65     ['containers', 'running', false],
66     ['container_requests', 'running', true],
67   ].each do |type, fixture, cancelable|
68     test "cancel button for #{type}/#{fixture}" do
69       if cancelable
70         need_selenium 'to cancel'
71       end
72
73       obj = api_fixture(type)[fixture]
74       visit page_with_token "active", "/#{type}/#{obj['uuid']}"
75
76       assert_text 'created_at'
77
78       if cancelable
79         assert_text 'priority: 1' if type.include?('container')
80         assert_selector 'button', text: 'Cancel'
81         first('a,button', text: 'Cancel').click
82         wait_for_ajax
83       end
84       assert_text 'priority: 0' if cancelable and type.include?('container')
85     end
86   end
87
88   [
89     ['jobs', 'running_job_with_components'],
90     ['pipeline_instances', 'has_component_with_completed_jobs'],
91     ['container_requests', 'running'],
92     ['container_requests', 'completed'],
93   ].each do |type, fixture|
94     test "edit description for #{type}/#{fixture}" do
95       obj = api_fixture(type)[fixture]
96       visit page_with_token "active", "/#{type}/#{obj['uuid']}"
97
98       within('.arv-description-as-subtitle') do
99         find('.fa-pencil').click
100         find('.editable-input textarea').set('*Textile description for object*')
101         find('.editable-submit').click
102       end
103       wait_for_ajax
104
105       # verify description
106       assert page.has_no_text? '*Textile description for object*'
107       assert page.has_text? 'Textile description for object'
108     end
109   end
110
111   [
112     ['Two Part Pipeline Template', 'part-one', 'Provide a value for the following'],
113     ['Workflow with input specifications', 'this workflow has inputs specified', 'Provide a value for the following'],
114   ].each do |template_name, preview_txt, process_txt|
115     test "run a process using template #{template_name} from dashboard" do
116       visit page_with_token('admin')
117       assert_text 'Recent pipelines and processes' # seeing dashboard now
118
119       within('.recent-processes-actions') do
120         assert page.has_link?('All processes')
121         find('a', text: 'Run a pipeline').click
122       end
123
124       # in the chooser, verify preview and click Next button
125       within('.modal-dialog') do
126         find('.selectable', text: template_name).click
127         assert_text preview_txt
128         find('.btn', text: 'Next: choose inputs').click
129       end
130
131       # in the process page now
132       assert_text process_txt
133       assert_selector 'a', text: template_name
134     end
135   end
136
137   test 'display container state changes in Container Request live log' do
138     use_fake_websocket_driver
139     c = api_fixture('containers')['queued']
140     cr = api_fixture('container_requests')['queued']
141     visit page_with_token('active', '/container_requests/'+cr['uuid'])
142     click_link('Log')
143
144     # The attrs of the "terminal window" text div in the log tab
145     # indicates which objects' events are worth displaying. Events
146     # that arrive too early (before that div exists) are not
147     # shown. For the user's sake, these early logs should also be
148     # retrieved and shown one way or another -- but in this particular
149     # test, we are only interested in logs that arrive by
150     # websocket. Therefore, to avoid races, we wait for the log tab to
151     # display before sending any events.
152     assert_text 'Recent logs'
153
154     [[{
155         event_type: 'dispatch',
156         properties: {
157           text: "dispatch logged a fake message\n",
158         },
159       }, "dispatch logged"],
160      [{
161         event_type: 'update',
162         properties: {
163           old_attributes: {state: 'Locked'},
164           new_attributes: {state: 'Queued'},
165         },
166       }, "Container #{c['uuid']} was returned to the queue"],
167      [{
168         event_type: 'update',
169         properties: {
170           old_attributes: {state: 'Queued'},
171           new_attributes: {state: 'Locked'},
172         },
173       }, "Container #{c['uuid']} was taken from the queue by a dispatch process"],
174      [{
175         event_type: 'crunch-run',
176         properties: {
177           text: "according to fake crunch-run,\nsome setup stuff happened on the compute node\n",
178         },
179       }, "setup stuff happened"],
180      [{
181         event_type: 'update',
182         properties: {
183           old_attributes: {state: 'Locked'},
184           new_attributes: {state: 'Running'},
185         },
186       }, "Container #{c['uuid']} started"],
187      [{
188         event_type: 'update',
189         properties: {
190           old_attributes: {state: 'Running'},
191           new_attributes: {state: 'Complete', exit_code: 1},
192         },
193       }, "Container #{c['uuid']} finished with exit code 1 (failure)"],
194      # It's unrealistic for state to change again once it's Complete,
195      # but the logging code doesn't care, so we do it to keep the test
196      # simple.
197      [{
198         event_type: 'update',
199         properties: {
200           old_attributes: {state: 'Running'},
201           new_attributes: {state: 'Cancelled'},
202         },
203       }, "Container #{c['uuid']} was cancelled"],
204     ].each do |send_event, expect_log_text|
205       assert_no_text(expect_log_text)
206       fake_websocket_event(send_event.merge(object_uuid: c['uuid']))
207       assert_text(expect_log_text)
208     end
209   end
210 end