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