1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
7 class PipelineInstancesControllerTest < ActionController::TestCase
8 include PipelineInstancesHelper
10 def create_instance_long_enough_to(instance_attrs={})
11 # create 'two_part' pipeline with the given instance attributes
12 pt_fixture = api_fixture('pipeline_templates')['two_part']
14 pipeline_instance: instance_attrs.merge({
15 pipeline_template_uuid: pt_fixture['uuid']
18 }, session_for(:active)
19 assert_response :success
20 pi_uuid = assigns(:object).uuid
21 assert_not_nil assigns(:object)
24 yield pi_uuid, pt_fixture
26 # delete the pipeline instance
28 PipelineInstance.where(uuid: pi_uuid).first.destroy
31 test "pipeline instance components populated after create" do
32 create_instance_long_enough_to do |new_instance_uuid, template_fixture|
33 assert_equal(template_fixture['components'].to_json,
34 assigns(:object).components.to_json)
38 test "can render pipeline instance with tagged collections" do
39 # Make sure to pass in a tagged collection to test that part of the rendering behavior.
41 {id: api_fixture("pipeline_instances")["pipeline_with_tagged_collection_input"]["uuid"]},
43 assert_response :success
46 test "update script_parameters one at a time using merge param" do
47 template_fixture = api_fixture('pipeline_templates')['two_part']
49 id: api_fixture("pipeline_instances")["pipeline_to_merge_params"]["uuid"],
66 }, session_for(:active)
67 assert_response :success
68 assert_not_nil assigns(:object)
69 orig_params = template_fixture['components']['part-two']['script_parameters']
70 new_params = assigns(:object).components[:'part-two'][:script_parameters]
71 orig_params.keys.each do |k|
72 unless %w(integer_with_value plain_string).index(k)
73 assert_equal orig_params[k].to_json, new_params[k.to_sym].to_json
78 test "component rendering copes with unexpected components format" do
80 {id: api_fixture("pipeline_instances")["components_is_jobspec"]["uuid"]},
82 assert_response :success
85 test "dates in JSON components are parsed" do
87 {id: api_fixture('pipeline_instances')['has_component_with_completed_jobs']['uuid']},
89 assert_response :success
90 assert_not_nil assigns(:object)
91 assert_not_nil assigns(:object).components[:foo][:job]
92 start_at = assigns(:object).components[:foo][:job][:started_at]
93 start_at = Time.parse(start_at) if (start_at.andand.class == String)
94 assert start_at.is_a? Time
95 finished_at = assigns(:object).components[:foo][:job][:started_at]
96 finished_at = Time.parse(finished_at) if (finished_at.andand.class == String)
97 assert finished_at.is_a? Time
100 # The next two tests ensure that a pipeline instance can be copied
101 # when the template has components that do not exist in the
102 # instance (ticket #4000).
104 test "copy pipeline instance with components=use_latest" do
107 id: api_fixture('pipeline_instances')['pipeline_with_newer_template']['uuid'],
108 components: 'use_latest',
109 script: 'use_latest',
111 state: 'RunningOnServer'
114 session_for(:active))
116 assert_not_nil assigns(:object)
118 # Component 'foo' has script parameters only in the pipeline instance.
119 # Component 'bar' is present only in the pipeline_template.
120 # Test that the copied pipeline instance includes parameters for
121 # component 'foo' from the source instance, and parameters for
122 # component 'bar' from the source template.
124 assert_not_nil assigns(:object).components[:foo]
125 foo = assigns(:object).components[:foo]
126 assert_not_nil foo[:script_parameters]
127 assert_not_nil foo[:script_parameters][:input]
128 assert_equal 'foo instance input', foo[:script_parameters][:input][:title]
130 assert_not_nil assigns(:object).components[:bar]
131 bar = assigns(:object).components[:bar]
132 assert_not_nil bar[:script_parameters]
133 assert_not_nil bar[:script_parameters][:input]
134 assert_equal 'bar template input', bar[:script_parameters][:input][:title]
137 test "copy pipeline instance on newer template works with script=use_same" do
140 id: api_fixture('pipeline_instances')['pipeline_with_newer_template']['uuid'],
141 components: 'use_latest',
144 state: 'RunningOnServer'
147 session_for(:active))
149 assert_not_nil assigns(:object)
151 # Test that relevant component parameters were copied from both
152 # the source instance and source template, respectively (see
155 assert_not_nil assigns(:object).components[:foo]
156 foo = assigns(:object).components[:foo]
157 assert_not_nil foo[:script_parameters]
158 assert_not_nil foo[:script_parameters][:input]
159 assert_equal 'foo instance input', foo[:script_parameters][:input][:title]
161 assert_not_nil assigns(:object).components[:bar]
162 bar = assigns(:object).components[:bar]
163 assert_not_nil bar[:script_parameters]
164 assert_not_nil bar[:script_parameters][:input]
165 assert_equal 'bar template input', bar[:script_parameters][:input][:title]
168 test "generate graph" do
172 pipeline_for_graph = {
174 uuid: 'zzzzz-d1hrv-9fm8l10i9z2kqc9',
179 script_version: 'master',
180 job: {uuid: 'zzzzz-8i9sb-graphstage10000'},
181 output_uuid: 'zzzzz-4zz18-bv31uwvy3neko22'
186 script_version: 'master',
188 input: 'fa7aeb5140e2848d39b416daeef4ffc5+45'
190 job: {uuid: 'zzzzz-8i9sb-graphstage20000'},
191 output_uuid: 'zzzzz-4zz18-uukreo9rbgwsujx'
196 @controller.params['tab_pane'] = "Graph"
197 provenance, pips = @controller.graph([pipeline_for_graph])
199 graph_test_collection1 = find_fixture Collection, "graph_test_collection1"
200 stage1 = find_fixture Job, "graph_stage1"
201 stage2 = find_fixture Job, "graph_stage2"
203 ['component_zzzzz-d1hrv-9fm8l10i9z2kqc9_stage1',
204 'component_zzzzz-d1hrv-9fm8l10i9z2kqc9_stage2',
209 pipeline_for_graph[:components][:stage1][:output_uuid],
210 pipeline_for_graph[:components][:stage2][:output_uuid]
213 assert_not_nil provenance[k], "Expected key #{k} in provenance set"
214 assert_equal 1, pips[k], "Expected key #{k} in pips set" if !k.start_with? "component_"
217 prov_svg = ProvenanceHelper::create_provenance_graph provenance, "provenance_svg", {
218 :request => RequestDuck,
219 :all_script_parameters => true,
220 :combine_jobs => :script_and_version,
222 :only_components => true }
224 stage1_id = "#{stage1[:script]}_#{stage1[:script_version]}_#{Digest::MD5.hexdigest(stage1[:script_parameters].to_json)}"
225 stage2_id = "#{stage2[:script]}_#{stage2[:script_version]}_#{Digest::MD5.hexdigest(stage2[:script_parameters].to_json)}"
227 stage1_out = stage1[:output].gsub('+','\\\+')
229 assert_match /#{stage1_id}->#{stage1_out}/, prov_svg
231 assert_match /#{stage1_out}->#{stage2_id}/, prov_svg
235 test "generate graph compare" do
239 pipeline_for_graph1 = {
241 uuid: 'zzzzz-d1hrv-9fm8l10i9z2kqc9',
246 script_version: 'master',
247 job: {uuid: 'zzzzz-8i9sb-graphstage10000'},
248 output_uuid: 'zzzzz-4zz18-bv31uwvy3neko22'
253 script_version: 'master',
255 input: 'fa7aeb5140e2848d39b416daeef4ffc5+45'
257 job: {uuid: 'zzzzz-8i9sb-graphstage20000'},
258 output_uuid: 'zzzzz-4zz18-uukreo9rbgwsujx'
263 pipeline_for_graph2 = {
265 uuid: 'zzzzz-d1hrv-9fm8l10i9z2kqc0',
270 script_version: 'master',
271 job: {uuid: 'zzzzz-8i9sb-graphstage10000'},
272 output_uuid: 'zzzzz-4zz18-bv31uwvy3neko22'
277 script_version: 'master',
280 job: {uuid: 'zzzzz-8i9sb-graphstage30000'},
281 output_uuid: 'zzzzz-4zz18-uukreo9rbgwsujj'
286 @controller.params['tab_pane'] = "Graph"
287 provenance, pips = @controller.graph([pipeline_for_graph1, pipeline_for_graph2])
289 collection1 = find_fixture Collection, "graph_test_collection1"
291 stage1 = find_fixture Job, "graph_stage1"
292 stage2 = find_fixture Job, "graph_stage2"
293 stage3 = find_fixture Job, "graph_stage3"
295 [['component_zzzzz-d1hrv-9fm8l10i9z2kqc9_stage1', nil],
296 ['component_zzzzz-d1hrv-9fm8l10i9z2kqc9_stage2', nil],
297 ['component_zzzzz-d1hrv-9fm8l10i9z2kqc0_stage1', nil],
298 ['component_zzzzz-d1hrv-9fm8l10i9z2kqc0_stage2', nil],
305 [pipeline_for_graph1[:components][:stage1][:output_uuid], 3],
306 [pipeline_for_graph1[:components][:stage2][:output_uuid], 1],
307 [pipeline_for_graph2[:components][:stage2][:output_uuid], 2]
309 assert_not_nil provenance[k[0]], "Expected key #{k[0]} in provenance set"
310 assert_equal k[1], pips[k[0]], "Expected key #{k} in pips" if !k[0].start_with? "component_"
313 prov_svg = ProvenanceHelper::create_provenance_graph provenance, "provenance_svg", {
314 :request => RequestDuck,
315 :all_script_parameters => true,
316 :combine_jobs => :script_and_version,
318 :only_components => true }
320 collection1_id = collection1.portable_data_hash.gsub('+','\\\+')
322 stage2_id = "#{stage2[:script]}_#{stage2[:script_version]}_#{Digest::MD5.hexdigest(stage2[:script_parameters].to_json)}"
323 stage3_id = "#{stage3[:script]}_#{stage3[:script_version]}_#{Digest::MD5.hexdigest(stage3[:script_parameters].to_json)}"
325 stage2_out = stage2[:output].gsub('+','\\\+')
326 stage3_out = stage3[:output].gsub('+','\\\+')
328 assert_match /#{collection1_id}->#{stage2_id}/, prov_svg
329 assert_match /#{collection1_id}->#{stage3_id}/, prov_svg
331 assert_match /#{stage2_id}->#{stage2_out}/, prov_svg
332 assert_match /#{stage3_id}->#{stage3_out}/, prov_svg