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