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