Merge branch '8784-dir-listings'
[arvados.git] / sdk / cli / test / test_crunch-job.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: Apache-2.0
4
5 require 'minitest/autorun'
6
7 class TestCrunchJob < Minitest::Test
8   SPECIAL_EXIT = {
9     EX_RETRY_UNLOCKED: 93,
10     EX_TEMPFAIL: 75,
11   }
12
13   JOBSPEC = {
14     grep_local: {
15       owner_uuid: 'zzzzz-j7d0g-it30l961gq3t0oi',
16       script: 'grep',
17       script_version: 'master',
18       repository: File.absolute_path('../../../..', __FILE__),
19       script_parameters: {foo: 'bar'},
20     },
21   }
22
23   def setup
24   end
25
26   def crunchjob
27     File.absolute_path '../../bin/crunch-job', __FILE__
28   end
29
30   # Return environment suitable for running crunch-job.
31   def crunchenv opts={}
32     env = ENV.to_h
33     env['CRUNCH_REFRESH_TRIGGER'] =
34       File.absolute_path('../../../../tmp/crunch-refresh-trigger', __FILE__)
35     env
36   end
37
38   def jobspec label
39     JOBSPEC[label].dup
40   end
41
42   # Encode job record to json and run it with crunch-job.
43   #
44   # opts[:binstubs] is an array of X where ./binstub_X is added to
45   # PATH in order to mock system programs.
46   def tryjobrecord jobrecord, opts={}
47     env = crunchenv
48     (opts[:binstubs] || []).each do |binstub|
49       env['PATH'] = File.absolute_path('../binstub_'+binstub, __FILE__) + ':' + env['PATH']
50     end
51     system env, crunchjob, '--job', jobrecord.to_json
52   end
53
54   def test_bogus_json
55     out, err = capture_subprocess_io do
56       system crunchenv, crunchjob, '--job', '"}{"'
57     end
58     assert_equal false, $?.success?
59     # Must not conflict with our special exit statuses
60     assert_jobfail $?
61     assert_match /JSON/, err
62   end
63
64   def test_fail_sanity_check
65     out, err = capture_subprocess_io do
66       j = {}
67       tryjobrecord j, binstubs: ['sanity_check']
68     end
69     assert_equal 75, $?.exitstatus
70     assert_match /Sanity check failed: 7/, err
71   end
72
73   def test_fail_docker_sanity_check
74     out, err = capture_subprocess_io do
75       j = {}
76       j[:docker_image_locator] = '4d449b9d34f2e2222747ef79c53fa3ff+1234'
77       tryjobrecord j, binstubs: ['sanity_check']
78     end
79     assert_equal 75, $?.exitstatus
80     assert_match /Sanity check failed: 8/, err
81   end
82
83   def test_no_script_specified
84     out, err = capture_subprocess_io do
85       j = jobspec :grep_local
86       j.delete :script
87       tryjobrecord j
88     end
89     assert_match /No script specified/, err
90     assert_jobfail $?
91   end
92
93   def test_fail_clean_tmp
94     out, err = capture_subprocess_io do
95       j = jobspec :grep_local
96       tryjobrecord j, binstubs: ['clean_fail']
97     end
98     assert_match /Failing mount stub was called/, err
99     assert_match /clean work dirs: exit 44\n$/, err
100     assert_equal SPECIAL_EXIT[:EX_RETRY_UNLOCKED], $?.exitstatus
101   end
102
103   def test_output_collection_owner_uuid
104     j = jobspec :grep_local
105     out, err = capture_subprocess_io do
106       tryjobrecord j, binstubs: ['arv-mount', 'output_coll_owner']
107     end
108     assert_match /owner_uuid: #{j['owner_uuid']}/, err
109   end
110
111   def test_docker_image_missing
112     skip 'API bug: it refuses to create this job in Running state'
113     out, err = capture_subprocess_io do
114       j = jobspec :grep_local
115       j[:docker_image_locator] = '4d449b9d34f2e2222747ef79c53fa3ff+1234'
116       tryjobrecord j, binstubs: ['docker_noop']
117     end
118     assert_match /No Docker image hash found from locator/, err
119     assert_jobfail $?
120   end
121
122   def test_script_version_not_found_in_repository
123     bogus_version = 'f8b72707c1f5f740dbf1ed56eb429a36e0dee770'
124     out, err = capture_subprocess_io do
125       j = jobspec :grep_local
126       j[:script_version] = bogus_version
127       tryjobrecord j, binstubs: ['arv-mount']
128     end
129     assert_match /'#{bogus_version}' not found, giving up/, err
130     assert_jobfail $?
131   end
132
133   # Ensure procstatus is not interpreted as a temporary infrastructure
134   # problem. Would be assert_http_4xx if this were http.
135   def assert_jobfail procstatus
136     refute_includes SPECIAL_EXIT.values, procstatus.exitstatus
137     assert_equal false, procstatus.success?
138   end
139 end