Merge branch 'master' into 4186-install-doc-improvements
[arvados.git] / apps / workbench / test / integration / pipeline_instances_test.rb
1 require 'integration_helper'
2 require 'selenium-webdriver'
3 require 'headless'
4
5 class PipelineInstancesTest < ActionDispatch::IntegrationTest
6   setup do
7     # Selecting collections requiresLocalStorage
8     headless = Headless.new
9     headless.start
10     Capybara.current_driver = :selenium
11   end
12
13   test 'Create and run a pipeline' do
14     visit page_with_token('active_trustedclient')
15
16     visit '/pipeline_templates'
17     within('tr', text: 'Two Part Pipeline Template') do
18       find('a,button', text: 'Run').click
19     end
20
21     # project chooser
22     within('.modal-dialog') do
23       find('.selectable', text: 'A Project').click
24       find('button', text: 'Choose').click
25     end
26
27     # This pipeline needs input. So, Run should be disabled
28     page.assert_selector 'a.disabled,button.disabled', text: 'Run'
29
30     instance_page = current_path
31
32     # Go over to the collections page and select something
33     visit '/collections'
34     within('tr', text: 'GNU_General_Public_License') do
35       find('input[type=checkbox]').click
36     end
37     find('#persistent-selection-count').click
38
39     # Add this collection to the project
40     visit '/projects'
41     find("#projects-menu").click
42     find('.dropdown-menu a,button', text: 'A Project').click
43     find('.btn', text: 'Add data').click
44     within('.modal-dialog') do
45       wait_for_ajax
46       first('span', text: 'foo_tag').click
47       find('.btn', text: 'Add').click
48     end
49     using_wait_time(Capybara.default_wait_time * 3) do
50       wait_for_ajax
51     end
52
53     click_link 'Jobs and pipelines'
54     find('tr[data-kind="arvados#pipelineInstance"]', text: '(none)').
55       find('a', text: 'Show').
56       click
57
58     assert find('p', text: 'Provide a value')
59
60     find('div.form-group', text: 'Foo/bar pair').
61       find('.btn', text: 'Choose').
62       click
63
64     within('.modal-dialog') do
65       assert(has_text?("Foo/bar pair"),
66              "pipeline input picker missing name of input")
67       wait_for_ajax
68       first('span', text: 'foo_tag').click
69       find('button', text: 'OK').click
70     end
71     wait_for_ajax
72
73     # "Run" button is now enabled
74     page.assert_no_selector 'a.disabled,button.disabled', text: 'Run'
75
76     first('a,button', text: 'Run').click
77
78     # Pipeline is running. We have a "Pause" button instead now.
79     page.assert_selector 'a,button', text: 'Pause'
80     find('a,button', text: 'Pause').click
81
82     # Pipeline is stopped. It should now be in paused state and Runnable again.
83     assert page.has_text? 'Paused'
84     page.assert_no_selector 'a.disabled,button.disabled', text: 'Resume'
85     page.assert_selector 'a,button', text: 'Re-run with latest'
86     page.assert_selector 'a,button', text: 'Re-run options'
87
88     # Since it is test env, no jobs are created to run. So, graph not visible
89     assert_not page.has_text? 'Graph'
90   end
91
92   # Create a pipeline instance from within a project and run
93   test 'Create pipeline inside a project and run' do
94     visit page_with_token('active_trustedclient')
95
96     # Go over to the collections page and select something
97     visit '/collections'
98     within('tr', text: 'GNU_General_Public_License') do
99       find('input[type=checkbox]').click
100     end
101     find('#persistent-selection-count').click
102
103     # Add this collection to the project using collections menu from top nav
104     visit '/projects'
105     find("#projects-menu").click
106     find('.dropdown-menu a,button', text: 'A Project').click
107     find('.btn', text: 'Add data').click
108     within('.modal-dialog') do
109       wait_for_ajax
110       first('span', text: 'foo_tag').click
111       find('.btn', text: 'Add').click
112     end
113     using_wait_time(Capybara.default_wait_time * 3) do
114       wait_for_ajax
115     end
116
117     create_and_run_pipeline_in_aproject true
118   end
119
120   # Create a pipeline instance from within a project and run
121   test 'Run a pipeline from dashboard' do
122     visit page_with_token('active_trustedclient')
123     create_and_run_pipeline_in_aproject false
124   end
125
126   test 'view pipeline with job and see graph' do
127     visit page_with_token('active_trustedclient')
128
129     visit '/pipeline_instances'
130     assert page.has_text? 'pipeline_with_job'
131
132     find('a', text: 'pipeline_with_job').click
133
134     # since the pipeline component has a job, expect to see the graph
135     assert page.has_text? 'Graph'
136     click_link 'Graph'
137     assert page.has_text? 'script_version'
138   end
139
140   test 'pipeline description' do
141     visit page_with_token('active_trustedclient')
142
143     visit '/pipeline_instances'
144     assert page.has_text? 'pipeline_with_job'
145
146     find('a', text: 'pipeline_with_job').click
147
148     within('.arv-description-as-subtitle') do
149       find('.fa-pencil').click
150       find('.editable-input textarea').set('*Textile description for pipeline instance*')
151       find('.editable-submit').click
152     end
153     wait_for_ajax
154
155     # verify description
156     assert page.has_no_text? '*Textile description for pipeline instance*'
157     assert page.has_text? 'Textile description for pipeline instance'
158   end
159
160   test "JSON popup available for strange components" do
161     uuid = api_fixture("pipeline_instances")["components_is_jobspec"]["uuid"]
162     visit page_with_token("active", "/pipeline_instances/#{uuid}")
163     click_on "Components"
164     assert(page.has_no_text?("script_parameters"),
165            "components JSON visible without popup")
166     click_on "Show components JSON"
167     assert(page.has_text?("script_parameters"),
168            "components JSON not found")
169   end
170
171   PROJECT_WITH_SEARCH_COLLECTION = "A Subproject"
172   def check_parameter_search(proj_name)
173     template = api_fixture("pipeline_templates")["parameter_with_search"]
174     search_text = template["components"]["with-search"]["script_parameters"]["input"]["search_for"]
175     visit page_with_token("active", "/pipeline_templates/#{template['uuid']}")
176     click_on "Run this pipeline"
177     within(".modal-dialog") do  # Set project for the new pipeline instance
178       find(".selectable", text: proj_name).click
179       click_on "Choose"
180     end
181     assert(has_text?("This pipeline was created from the template"), "did not land on pipeline instance page")
182     first("a.btn,button", text: "Choose").click
183     within(".modal-body") do
184       if (proj_name != PROJECT_WITH_SEARCH_COLLECTION)
185         # Switch finder modal to Subproject to find the Collection.
186         click_on proj_name
187         click_on PROJECT_WITH_SEARCH_COLLECTION
188       end
189       assert_equal(search_text, first("input").value,
190                    "parameter search not preseeded")
191       assert(has_text?(api_fixture("collections")["baz_collection_name_in_asubproject"]["name"]),
192              "baz Collection not in preseeded search results")
193     end
194   end
195
196   test "Workbench respects search_for parameter in templates" do
197     check_parameter_search(PROJECT_WITH_SEARCH_COLLECTION)
198   end
199
200   test "Workbench preserves search_for parameter after project switch" do
201     check_parameter_search("A Project")
202   end
203
204   [
205     ['active', false, false, false],
206     ['active', false, false, true],
207     ['active', true, false, false],
208     ['active', true, true, false],
209     ['active', true, false, true],
210     ['active', true, true, true],
211     ['project_viewer', false, false, true],
212     ['project_viewer', true, false, true],
213     ['project_viewer', true, true, true],
214   ].each do |user, with_options, choose_options, in_aproject|
215     test "Rerun pipeline instance as #{user} using options #{with_options} #{choose_options} in #{in_aproject}" do
216       visit page_with_token('active')
217
218       if in_aproject
219         find("#projects-menu").click
220         find('.dropdown-menu a,button', text: 'A Project').click
221       end
222
223       create_and_run_pipeline_in_aproject in_aproject
224       instance_path = current_path
225
226       # Pause the pipeline
227       find('a,button', text: 'Pause').click
228       assert page.has_text? 'Paused'
229       page.assert_no_selector 'a.disabled,button.disabled', text: 'Resume'
230       page.assert_selector 'a,button', text: 'Re-run with latest'
231       page.assert_selector 'a,button', text: 'Re-run options'
232
233       # Pipeline can be re-run now. Access it as the specified user, and re-run
234       if user == 'project_viewer'
235         visit page_with_token(user, instance_path)
236         assert page.has_text? 'A Project'
237         page.assert_no_selector 'a.disabled,button.disabled', text: 'Resume'
238         page.assert_selector 'a,button', text: 'Re-run with latest'
239         page.assert_selector 'a,button', text: 'Re-run options'
240       end
241
242       # Now re-run the pipeline
243       if with_options
244         find('a,button', text: 'Re-run options').click
245         within('.modal-dialog') do
246           page.assert_selector 'a,button', text: 'Copy and edit inputs'
247           page.assert_selector 'a,button', text: 'Run now'
248           if choose_options
249             find('button', text: 'Copy and edit inputs').click
250           else
251             find('button', text: 'Run now').click
252           end
253         end
254       else
255         find('a,button', text: 'Re-run with latest').click
256       end
257
258       # Verify that the newly created instance is created in the right project.
259       # In case of project_viewer user, since the use cannot write to the project,
260       # the pipeline should have been created in the user's Home project.
261       rerun_instance_path = current_path
262       assert_not_equal instance_path, rerun_instance_path, 'Rerun instance path expected to be different'
263       assert page.has_text? 'Home'
264       if in_aproject && (user != 'project_viewer')
265         assert page.has_text? 'A Project'
266       else
267         assert page.has_no_text? 'A Project'
268       end
269     end
270   end
271
272   # Create and run a pipeline for 'Two Part Pipeline Template' in 'A Project'
273   def create_and_run_pipeline_in_aproject in_aproject
274     # create a pipeline instance
275     find('.btn', text: 'Run a pipeline').click
276     within('.modal-dialog') do
277       find('.selectable', text: 'Two Part Pipeline Template').click
278       find('.btn', text: 'Next: choose inputs').click
279     end
280
281     assert find('p', text: 'Provide a value')
282
283     find('div.form-group', text: 'Foo/bar pair').
284       find('.btn', text: 'Choose').
285       click
286
287     within('.modal-dialog') do
288       if in_aproject
289         assert_selector 'button.dropdown-toggle', text: 'A Project'
290         wait_for_ajax
291       else
292         assert_selector 'button.dropdown-toggle', text: 'Home'
293         wait_for_ajax
294         click_button "Home"
295         click_link "A Project"
296         wait_for_ajax
297       end
298       first('span', text: 'foo_tag').click
299       find('button', text: 'OK').click
300     end
301     wait_for_ajax
302
303     # "Run" button present and enabled
304     page.assert_no_selector 'a.disabled,button.disabled', text: 'Run'
305     first('a,button', text: 'Run').click
306
307     # Pipeline is running. We have a "Pause" button instead now.
308     page.assert_no_selector 'a,button', text: 'Run'
309     page.assert_no_selector 'a.disabled,button.disabled', text: 'Resume'
310     page.assert_selector 'a,button', text: 'Pause'
311
312     # Since it is test env, no jobs are created to run. So, graph not visible
313     assert_not page.has_text? 'Graph'
314   end
315
316   [
317     [0, 0], # run time 0 minutes
318     [9, 17*60*60 + 51*60], # run time 17 hours and 51 minutes
319   ].each do |index, run_time|
320     test "pipeline start and finish time display #{index}" do
321       visit page_with_token("user1_with_load", "/pipeline_instances/zzzzz-d1hrv-10pipelines0#{index.to_s.rjust(3, '0')}")
322
323       assert page.has_text? 'This pipeline started at'
324       page_text = page.text
325
326       match = /This pipeline started at (.*)\. It failed after (.*) seconds at (.*)\. Check the Log/.match page_text
327       assert_not_nil(match, 'Did not find text - This pipeline started at . . . ')
328
329       start_at = match[1]
330       finished_at = match[3]
331       assert_not_nil(start_at, 'Did not find start_at time')
332       assert_not_nil(finished_at, 'Did not find finished_at time')
333
334       # start and finished time display is of the format '2:20 PM 10/20/2014'
335       start_time = DateTime.strptime(start_at, '%H:%M %p %m/%d/%Y').to_time
336       finished_time = DateTime.strptime(finished_at, '%H:%M %p %m/%d/%Y').to_time
337       assert_equal(run_time, finished_time-start_time,
338         "Time difference did not match for start_at #{start_at}, finished_at #{finished_at}, ran_for #{match[2]}")
339     end
340   end
341 end