+
+ test 'update job uuid tag in internal.git when version changes' do
+ authorize_with :active
+ j = jobs :queued
+ j.update_attributes repository: 'active/foo', script_version: 'b1'
+ assert_equal('1de84a854e2b440dc53bf42f8548afa4c17da332',
+ internal_tag(j.uuid))
+ j.update_attributes repository: 'active/foo', script_version: 'master'
+ assert_equal('077ba2ad3ea24a929091a9e6ce545c93199b8e57',
+ internal_tag(j.uuid))
+ end
+
+ test 'script_parameters_digest is independent of key order' do
+ j1 = Job.new(job_attrs(script_parameters: {'a' => 'a', 'ddee' => {'d' => 'd', 'e' => 'e'}}))
+ j2 = Job.new(job_attrs(script_parameters: {'ddee' => {'e' => 'e', 'd' => 'd'}, 'a' => 'a'}))
+ assert j1.valid?
+ assert j2.valid?
+ assert_equal(j1.script_parameters_digest, j2.script_parameters_digest)
+ end
+
+ test 'job fixtures have correct script_parameters_digest' do
+ Job.all.each do |j|
+ d = j.script_parameters_digest
+ assert_equal(j.update_script_parameters_digest, d,
+ "wrong script_parameters_digest for #{j.uuid}")
+ end
+ end
+
+ test 'deep_sort_hash on array of hashes' do
+ a = {'z' => [[{'a' => 'a', 'b' => 'b'}]]}
+ b = {'z' => [[{'b' => 'b', 'a' => 'a'}]]}
+ assert_equal Job.deep_sort_hash(a).to_json, Job.deep_sort_hash(b).to_json
+ end
+
+ test 'find_reusable without logging' do
+ Rails.logger.expects(:info).never
+ try_find_reusable
+ end
+
+ test 'find_reusable with logging' do
+ Rails.configuration.log_reuse_decisions = true
+ Rails.logger.expects(:info).at_least(3)
+ try_find_reusable
+ end
+
+ def try_find_reusable
+ foobar = jobs(:foobar)
+ example_attrs = {
+ script_version: foobar.script_version,
+ script: foobar.script,
+ script_parameters: foobar.script_parameters,
+ repository: foobar.repository,
+ }
+
+ # Two matching jobs exist with identical outputs. The older one
+ # should be reused.
+ j = Job.find_reusable(example_attrs, {}, [], [users(:active)])
+ assert j
+ assert_equal foobar.uuid, j.uuid
+
+ # Two matching jobs exist with different outputs. Neither should
+ # be reused.
+ Job.where(uuid: jobs(:job_with_latest_version).uuid).
+ update_all(output: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+1')
+ assert_nil Job.find_reusable(example_attrs, {}, [], [users(:active)])
+
+ # ...unless config says to reuse the earlier job in such cases.
+ Rails.configuration.reuse_job_if_outputs_differ = true
+ j = Job.find_reusable(example_attrs, {}, [], [users(:active)])
+ assert_equal foobar.uuid, j.uuid
+ end
+
+ [
+ true,
+ false,
+ ].each do |cascade|
+ test "cancel job with cascade #{cascade}" do
+ job = Job.find_by_uuid jobs(:running_job_with_components_at_level_1).uuid
+ job.cancel cascade: cascade
+ assert_equal Job::Cancelled, job.state
+
+ descendents = ['zzzzz-8i9sb-jobcomponentsl2',
+ 'zzzzz-d1hrv-picomponentsl02',
+ 'zzzzz-8i9sb-job1atlevel3noc',
+ 'zzzzz-8i9sb-job2atlevel3noc']
+
+ jobs = Job.where(uuid: descendents)
+ jobs.each do |j|
+ assert_equal ('Cancelled' == j.state), cascade
+ end
+
+ pipelines = PipelineInstance.where(uuid: descendents)
+ pipelines.each do |pi|
+ assert_equal ('Paused' == pi.state), cascade
+ end
+ end
+ end
+
+ test 'cancelling a completed job raises error' do
+ job = Job.find_by_uuid jobs(:job_with_latest_version).uuid
+ assert job
+ assert_equal 'Complete', job.state
+
+ assert_raises(ArvadosModel::InvalidStateTransitionError) do
+ job.cancel
+ end
+ end
+
+ test 'cancelling a job with circular relationship with another does not result in an infinite loop' do
+ job = Job.find_by_uuid jobs(:running_job_2_with_circular_component_relationship).uuid
+
+ job.cancel cascade: true
+
+ assert_equal Job::Cancelled, job.state
+
+ child = Job.find_by_uuid job.components.collect{|_, uuid| uuid}[0]
+ assert_equal Job::Cancelled, child.state
+ end