3185: Fix job validation failure with no errors given.
[arvados.git] / services / api / test / functional / arvados / v1 / jobs_controller_test.rb
1 require 'test_helper'
2 require 'helpers/git_test_helper'
3
4 class Arvados::V1::JobsControllerTest < ActionController::TestCase
5
6   include GitTestHelper
7
8   test "submit a job" do
9     authorize_with :active
10     post :create, job: {
11       script: "hash",
12       script_version: "master",
13       repository: "foo",
14       script_parameters: {}
15     }
16     assert_response :success
17     assert_not_nil assigns(:object)
18     new_job = JSON.parse(@response.body)
19     assert_not_nil new_job['uuid']
20     assert_not_nil new_job['script_version'].match(/^[0-9a-f]{40}$/)
21     # Default: not persistent
22     assert_equal false, new_job['output_is_persistent']
23   end
24
25   test "normalize output and log uuids when creating job" do
26     authorize_with :active
27     post :create, job: {
28       script: "hash",
29       script_version: "master",
30       script_parameters: {},
31       repository: "foo",
32       started_at: Time.now,
33       finished_at: Time.now,
34       running: false,
35       success: true,
36       output: 'd41d8cd98f00b204e9800998ecf8427e+0+K@xyzzy',
37       log: 'd41d8cd98f00b204e9800998ecf8427e+0+K@xyzzy'
38     }
39     assert_response :success
40     assert_not_nil assigns(:object)
41     new_job = JSON.parse(@response.body)
42     assert_equal 'd41d8cd98f00b204e9800998ecf8427e+0', new_job['log']
43     assert_equal 'd41d8cd98f00b204e9800998ecf8427e+0', new_job['output']
44     version = new_job['script_version']
45
46     # Make sure version doesn't get mangled by normalize
47     assert_not_nil version.match(/^[0-9a-f]{40}$/)
48     put :update, {
49       id: new_job['uuid'],
50       job: {
51         log: new_job['log']
52       }
53     }
54     assert_equal version, JSON.parse(@response.body)['script_version']
55   end
56
57   test "cancel a running job" do
58     # We need to verify that "cancel" creates a trigger file, so first
59     # let's make sure there is no stale trigger file.
60     begin
61       File.unlink(Rails.configuration.crunch_refresh_trigger)
62     rescue Errno::ENOENT
63     end
64
65     authorize_with :active
66     put :update, {
67       id: jobs(:running).uuid,
68       job: {
69         cancelled_at: 4.day.ago
70       }
71     }
72     assert_response :success
73     assert_not_nil assigns(:object)
74     job = JSON.parse(@response.body)
75     assert_not_nil job['uuid']
76     assert_not_nil job['cancelled_at']
77     assert_not_nil job['cancelled_by_user_uuid']
78     assert_not_nil job['cancelled_by_client_uuid']
79     assert_equal(true, Time.parse(job['cancelled_at']) > 1.minute.ago,
80                  'server should correct bogus cancelled_at ' +
81                  job['cancelled_at'])
82     assert_equal(true,
83                  File.exists?(Rails.configuration.crunch_refresh_trigger),
84                  'trigger file should be created when job is cancelled')
85
86     put :update, {
87       id: jobs(:running).uuid,
88       job: {
89         cancelled_at: nil
90       }
91     }
92     job = JSON.parse(@response.body)
93     assert_not_nil job['cancelled_at'], 'un-cancelled job stays cancelled'
94   end
95
96   test "update a job without failing script_version check" do
97     authorize_with :admin
98     put :update, {
99       id: jobs(:uses_nonexistent_script_version).uuid,
100       job: {
101         owner_uuid: users(:admin).uuid
102       }
103     }
104     assert_response :success
105     put :update, {
106       id: jobs(:uses_nonexistent_script_version).uuid,
107       job: {
108         owner_uuid: users(:active).uuid
109       }
110     }
111     assert_response :success
112   end
113
114   test "search jobs by uuid with >= query" do
115     authorize_with :active
116     get :index, {
117       filters: [['uuid', '>=', 'zzzzz-8i9sb-pshmckwoma9plh7']]
118     }
119     assert_response :success
120     found = assigns(:objects).collect(&:uuid)
121     assert_equal true, !!found.index('zzzzz-8i9sb-pshmckwoma9plh7')
122     assert_equal false, !!found.index('zzzzz-8i9sb-4cf0nhn6xte809j')
123   end
124
125   test "search jobs by uuid with <= query" do
126     authorize_with :active
127     get :index, {
128       filters: [['uuid', '<=', 'zzzzz-8i9sb-pshmckwoma9plh7']]
129     }
130     assert_response :success
131     found = assigns(:objects).collect(&:uuid)
132     assert_equal true, !!found.index('zzzzz-8i9sb-pshmckwoma9plh7')
133     assert_equal true, !!found.index('zzzzz-8i9sb-4cf0nhn6xte809j')
134   end
135
136   test "search jobs by uuid with >= and <= query" do
137     authorize_with :active
138     get :index, {
139       filters: [['uuid', '>=', 'zzzzz-8i9sb-pshmckwoma9plh7'],
140               ['uuid', '<=', 'zzzzz-8i9sb-pshmckwoma9plh7']]
141     }
142     assert_response :success
143     found = assigns(:objects).collect(&:uuid)
144     assert_equal found, ['zzzzz-8i9sb-pshmckwoma9plh7']
145   end
146
147   test "search jobs by uuid with < query" do
148     authorize_with :active
149     get :index, {
150       filters: [['uuid', '<', 'zzzzz-8i9sb-pshmckwoma9plh7']]
151     }
152     assert_response :success
153     found = assigns(:objects).collect(&:uuid)
154     assert_equal false, !!found.index('zzzzz-8i9sb-pshmckwoma9plh7')
155     assert_equal true, !!found.index('zzzzz-8i9sb-4cf0nhn6xte809j')
156   end
157
158   test "search jobs by uuid with like query" do
159     authorize_with :active
160     get :index, {
161       filters: [['uuid', 'like', '%hmckwoma9pl%']]
162     }
163     assert_response :success
164     found = assigns(:objects).collect(&:uuid)
165     assert_equal found, ['zzzzz-8i9sb-pshmckwoma9plh7']
166   end
167
168   test "search jobs by uuid with 'in' query" do
169     authorize_with :active
170     get :index, {
171       filters: [['uuid', 'in', ['zzzzz-8i9sb-4cf0nhn6xte809j',
172                                 'zzzzz-8i9sb-pshmckwoma9plh7']]]
173     }
174     assert_response :success
175     found = assigns(:objects).collect(&:uuid)
176     assert_equal found.sort, ['zzzzz-8i9sb-4cf0nhn6xte809j',
177                               'zzzzz-8i9sb-pshmckwoma9plh7']
178   end
179
180   test "search jobs by uuid with 'not in' query" do
181     exclude_uuids = [jobs(:running).uuid,
182                      jobs(:running_cancelled).uuid]
183     authorize_with :active
184     get :index, {
185       filters: [['uuid', 'not in', exclude_uuids]]
186     }
187     assert_response :success
188     found = assigns(:objects).collect(&:uuid)
189     assert_not_empty found, "'not in' query returned nothing"
190     assert_empty(found & exclude_uuids,
191                  "'not in' query returned uuids I asked not to get")
192   end
193
194   ['=', '!='].each do |operator|
195     [['uuid', 'zzzzz-8i9sb-pshmckwoma9plh7'],
196      ['output', nil]].each do |attr, operand|
197       test "search jobs with #{attr} #{operator} #{operand.inspect} query" do
198         authorize_with :active
199         get :index, {
200           filters: [[attr, operator, operand]]
201         }
202         assert_response :success
203         values = assigns(:objects).collect { |x| x.send(attr) }
204         assert_not_empty values, "query should return non-empty result"
205         if operator == '='
206           assert_empty values - [operand], "query results do not satisfy query"
207         else
208           assert_empty values & [operand], "query results do not satisfy query"
209         end
210       end
211     end
212   end
213
214   test "search jobs by started_at with < query" do
215     authorize_with :active
216     get :index, {
217       filters: [['started_at', '<', Time.now.to_s]]
218     }
219     assert_response :success
220     found = assigns(:objects).collect(&:uuid)
221     assert_equal true, !!found.index('zzzzz-8i9sb-pshmckwoma9plh7')
222   end
223
224   test "search jobs by started_at with > query" do
225     authorize_with :active
226     get :index, {
227       filters: [['started_at', '>', Time.now.to_s]]
228     }
229     assert_response :success
230     assert_equal 0, assigns(:objects).count
231   end
232
233   test "search jobs by started_at with >= query on metric date" do
234     authorize_with :active
235     get :index, {
236       filters: [['started_at', '>=', '2014-01-01']]
237     }
238     assert_response :success
239     found = assigns(:objects).collect(&:uuid)
240     assert_equal true, !!found.index('zzzzz-8i9sb-pshmckwoma9plh7')
241   end
242
243   test "search jobs by started_at with >= query on metric date and time" do
244     authorize_with :active
245     get :index, {
246       filters: [['started_at', '>=', '2014-01-01 01:23:45']]
247     }
248     assert_response :success
249     found = assigns(:objects).collect(&:uuid)
250     assert_equal true, !!found.index('zzzzz-8i9sb-pshmckwoma9plh7')
251   end
252
253   test "search jobs with 'any' operator" do
254     authorize_with :active
255     get :index, {
256       where: { any: ['contains', 'pshmckw'] }
257     }
258     assert_response :success
259     found = assigns(:objects).collect(&:uuid)
260     assert_equal 0, found.index('zzzzz-8i9sb-pshmckwoma9plh7')
261     assert_equal 1, found.count
262   end
263
264   test "search jobs by nonexistent column with < query" do
265     authorize_with :active
266     get :index, {
267       filters: [['is_borked', '<', 'fizzbuzz']]
268     }
269     assert_response 422
270   end
271
272   test "finish a job" do
273     authorize_with :active
274     put :update, {
275       id: jobs(:nearly_finished_job).uuid,
276       job: {
277         output: '551392cc37a317abf865b95f66f4ef94+101',
278         log: '9215de2a951a721f5f156bc08cf63ad7+93',
279         tasks_summary: {done: 1, running: 0, todo: 0, failed: 0},
280         success: true,
281         running: false,
282         finished_at: Time.now.to_s
283       }
284     }
285     assert_response :success
286   end
287
288   [:active, :admin].each do |which_token|
289     test "get job queue as #{which_token} user" do
290       authorize_with which_token
291       get :queue
292       assert_response :success
293       assert_operator 1, :<=, assigns(:objects).count
294     end
295     test "get job queue as #{which_token} user, with a filter" do
296       authorize_with which_token
297       get :queue, { filters: [['script','=','foo']] }
298       assert_response :success
299       assert_equal ['foo'], assigns(:objects).collect(&:script).uniq
300     end
301   end
302
303 end