Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(638)

Side by Side Diff: appengine/swarming/server/task_scheduler_test.py

Issue 2926713004: Add support for repeated keys in TaskRequest. (Closed)
Patch Set: rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/swarming/server/task_scheduler.py ('k') | appengine/swarming/server/task_to_run.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2014 The LUCI Authors. All rights reserved. 2 # Copyright 2014 The LUCI Authors. All rights reserved.
3 # Use of this source code is governed under the Apache License, Version 2.0 3 # Use of this source code is governed under the Apache License, Version 2.0
4 # that can be found in the LICENSE file. 4 # that can be found in the LICENSE file.
5 5
6 import datetime 6 import datetime
7 import logging 7 import logging
8 import os 8 import os
9 import random 9 import random
10 import sys 10 import sys
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 if not self.publish_successful: 99 if not self.publish_successful:
100 raise pubsub.TransientError('Fail') 100 raise pubsub.TransientError('Fail')
101 calls.append(('directly', kwargs)) 101 calls.append(('directly', kwargs))
102 self.mock(pubsub, 'publish', pubsub_publish) 102 self.mock(pubsub, 'publish', pubsub_publish)
103 return calls 103 return calls
104 104
105 def _gen_request(self, properties=None, **kwargs): 105 def _gen_request(self, properties=None, **kwargs):
106 """Creates a TaskRequest.""" 106 """Creates a TaskRequest."""
107 props = { 107 props = {
108 'command': [u'command1'], 108 'command': [u'command1'],
109 'dimensions': {u'pool': u'default'}, 109 'dimensions_flat': [u'pool:default'],
110 'env': {}, 110 'env': {},
111 'execution_timeout_secs': 24*60*60, 111 'execution_timeout_secs': 24*60*60,
112 'io_timeout_secs': None, 112 'io_timeout_secs': None,
113 } 113 }
114 props.update(properties or {}) 114 props.update(properties or {})
115 props['dimensions_dict'] = props.pop('dimensions')
116 now = utils.utcnow() 115 now = utils.utcnow()
117 args = { 116 args = {
118 'created_ts': now, 117 'created_ts': now,
119 'name': 'Request name', 118 'name': 'Request name',
120 'priority': 50, 119 'priority': 50,
121 'properties': task_request.TaskProperties(**props), 120 'properties': task_request.TaskProperties(**props),
122 'expiration_ts': now + datetime.timedelta(seconds=60), 121 'expiration_ts': now + datetime.timedelta(seconds=60),
123 'tags': [u'tag:1'], 122 'tags': [u'tag:1'],
124 'user': 'Jesus', 123 'user': 'Jesus',
125 } 124 }
126 args.update(kwargs) 125 args.update(kwargs)
127 ret = task_request.TaskRequest(**args) 126 ret = task_request.TaskRequest(**args)
128 task_request.init_new_request(ret, True, None) 127 task_request.init_new_request(ret, True, None)
129 return ret 128 return ret
130 129
131 def _quick_schedule(self, dims, nb_task=1): 130 def _quick_schedule(self, dims, nb_task=1):
132 """Schedules a task. 131 """Schedules a task.
133 132
134 nb_task is 1 if a GAE task queue rebuild-task-cache was enqueued. 133 nb_task is 1 if a GAE task queue rebuild-task-cache was enqueued.
135 """ 134 """
136 request = self._gen_request(properties={'dimensions': dims}) 135 self.assertIsInstance(dims, list)
136 request = self._gen_request(properties={'dimensions_flat': dims})
137 result_summary = task_scheduler.schedule_request(request, None) 137 result_summary = task_scheduler.schedule_request(request, None)
138 self.assertEqual(nb_task, self.execute_tasks()) 138 self.assertEqual(nb_task, self.execute_tasks())
139 return result_summary 139 return result_summary
140 140
141 def _register_bot(self, bot_dimensions, nb_task=1): 141 def _register_bot(self, bot_dimensions, nb_task=1):
142 """Registers the bot so the task queues knows there's a worker than can run 142 """Registers the bot so the task queues knows there's a worker than can run
143 the task. 143 the task.
144 """ 144 """
145 bot_management.bot_event( 145 bot_management.bot_event(
146 'bot_connected', bot_dimensions[u'id'][0], '1.2.3.4', 'joe@localhost', 146 'bot_connected', bot_dimensions[u'id'][0], '1.2.3.4', 'joe@localhost',
147 bot_dimensions, {'state': 'real'}, '1234', False, None, None) 147 bot_dimensions, {'state': 'real'}, '1234', False, None, None)
148 task_queues.assert_bot(bot_dimensions) 148 task_queues.assert_bot(bot_dimensions)
149 self.assertEqual(nb_task, self.execute_tasks()) 149 self.assertEqual(nb_task, self.execute_tasks())
150 150
151 def _quick_reap(self, nb_task=1): 151 def _quick_reap(self, nb_task=1):
152 """Reaps a task.""" 152 """Reaps a task."""
153 self._quick_schedule({u'os': u'Windows-3.1.1', u'pool': u'default'}) 153 self._quick_schedule([u'os:Windows-3.1.1', u'pool:default'])
154 bot_dimensions = { 154 bot_dimensions = {
155 u'id': [u'localhost'], 155 u'id': [u'localhost'],
156 u'os': [u'Windows-3.1.1'], 156 u'os': [u'Windows-3.1.1'],
157 u'pool': [u'default'], 157 u'pool': [u'default'],
158 } 158 }
159 self._register_bot(bot_dimensions, nb_task=nb_task) 159 self._register_bot(bot_dimensions, nb_task=nb_task)
160 reaped_request, _, run_result = task_scheduler.bot_reap_task( 160 reaped_request, _, run_result = task_scheduler.bot_reap_task(
161 bot_dimensions, 'abc', None) 161 bot_dimensions, 'abc', None)
162 return run_result 162 return run_result
163 163
164 def test_all_apis_are_tested(self): 164 def test_all_apis_are_tested(self):
165 # Ensures there's a test for each public API. 165 # Ensures there's a test for each public API.
166 # TODO(maruel): Remove this once coverage is asserted. 166 # TODO(maruel): Remove this once coverage is asserted.
167 module = task_scheduler 167 module = task_scheduler
168 expected = set( 168 expected = set(
169 i for i in dir(module) 169 i for i in dir(module)
170 if i[0] != '_' and hasattr(getattr(module, i), 'func_name')) 170 if i[0] != '_' and hasattr(getattr(module, i), 'func_name'))
171 missing = expected - set(i[5:] for i in dir(self) if i.startswith('test_')) 171 missing = expected - set(i[5:] for i in dir(self) if i.startswith('test_'))
172 self.assertFalse(missing) 172 self.assertFalse(missing)
173 173
174 def test_bot_reap_task(self): 174 def test_bot_reap_task(self):
175 request = self._gen_request( 175 request = self._gen_request(
176 properties={ 176 properties={
177 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 177 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
178 }) 178 })
179 task_request.init_new_request(request, True, None) 179 task_request.init_new_request(request, True, None)
180 _result_summary = task_scheduler.schedule_request(request, None) 180 _result_summary = task_scheduler.schedule_request(request, None)
181 bot_dimensions = { 181 bot_dimensions = {
182 u'foo': [u'bar'], 182 u'foo': [u'bar'],
183 u'id': [u'localhost'], 183 u'id': [u'localhost'],
184 u'os': [u'Windows', u'Windows-3.1.1'], 184 u'os': [u'Windows', u'Windows-3.1.1'],
185 u'pool': [u'default'], 185 u'pool': [u'default'],
186 } 186 }
187 self._register_bot(bot_dimensions) 187 self._register_bot(bot_dimensions)
188 actual_request, _, run_result = task_scheduler.bot_reap_task( 188 actual_request, _, run_result = task_scheduler.bot_reap_task(
189 bot_dimensions, 'abc', None) 189 bot_dimensions, 'abc', None)
190 self.assertEqual(request, actual_request) 190 self.assertEqual(request, actual_request)
191 self.assertEqual('localhost', run_result.bot_id) 191 self.assertEqual('localhost', run_result.bot_id)
192 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number) 192 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number)
193 193
194 def test_bot_reap_task_not_enough_time(self): 194 def test_bot_reap_task_not_enough_time(self):
195 request = self._gen_request( 195 request = self._gen_request(
196 properties={ 196 properties={
197 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 197 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
198 }) 198 })
199 task_request.init_new_request(request, True, None) 199 task_request.init_new_request(request, True, None)
200 _result_summary = task_scheduler.schedule_request(request, None) 200 _result_summary = task_scheduler.schedule_request(request, None)
201 bot_dimensions = { 201 bot_dimensions = {
202 u'foo': [u'bar'], 202 u'foo': [u'bar'],
203 u'id': [u'localhost'], 203 u'id': [u'localhost'],
204 u'os': [u'Windows', u'Windows-3.1.1'], 204 u'os': [u'Windows', u'Windows-3.1.1'],
205 u'pool': [u'default'], 205 u'pool': [u'default'],
206 } 206 }
207 self._register_bot(bot_dimensions) 207 self._register_bot(bot_dimensions)
208 actual_request, _, run_result = task_scheduler.bot_reap_task( 208 actual_request, _, run_result = task_scheduler.bot_reap_task(
209 bot_dimensions, 'abc', datetime.datetime(1969, 1, 1)) 209 bot_dimensions, 'abc', datetime.datetime(1969, 1, 1))
210 self.failIf(actual_request) 210 self.failIf(actual_request)
211 self.failIf(run_result) 211 self.failIf(run_result)
212 self.failUnless(task_to_run.TaskToRun.query().get().queue_number) 212 self.failUnless(task_to_run.TaskToRun.query().get().queue_number)
213 213
214 def test_bot_reap_task_enough_time(self): 214 def test_bot_reap_task_enough_time(self):
215 request = self._gen_request( 215 request = self._gen_request(
216 properties={ 216 properties={
217 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 217 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
218 }) 218 })
219 task_request.init_new_request(request, True, None) 219 task_request.init_new_request(request, True, None)
220 _result_summary = task_scheduler.schedule_request(request, None) 220 _result_summary = task_scheduler.schedule_request(request, None)
221 bot_dimensions = { 221 bot_dimensions = {
222 u'foo': [u'bar'], 222 u'foo': [u'bar'],
223 u'id': [u'localhost'], 223 u'id': [u'localhost'],
224 u'os': [u'Windows', u'Windows-3.1.1'], 224 u'os': [u'Windows', u'Windows-3.1.1'],
225 u'pool': [u'default'], 225 u'pool': [u'default'],
226 } 226 }
227 self._register_bot(bot_dimensions) 227 self._register_bot(bot_dimensions)
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 'auth_token': 'token', 271 'auth_token': 'token',
272 'userdata': 'userdata', 272 'userdata': 'userdata',
273 }) 273 })
274 self.assertEqual([ 274 self.assertEqual([
275 { 275 {
276 'attributes': {'auth_token': 'token'}, 276 'attributes': {'auth_token': 'token'},
277 'message': '{"task_id":"abcdef123","userdata":"userdata"}', 277 'message': '{"task_id":"abcdef123","userdata":"userdata"}',
278 'topic': 'projects/abc/topics/def', 278 'topic': 'projects/abc/topics/def',
279 }], calls) 279 }], calls)
280 280
281 def _task_ran_successfully(self, nb_task=1): 281 def _task_ran_successfully(self, dimensions_flat=None, nb_task=1):
282 """Runs a task successfully and returns the task_id.""" 282 """Runs a task successfully and returns the task_id."""
283 dimensions_flat = dimensions_flat or [u'os:Windows-3.1.1', u'pool:default']
283 request = self._gen_request( 284 request = self._gen_request(
284 properties={ 285 properties={'dimensions_flat': dimensions_flat, 'idempotent': True})
285 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
286 'idempotent': True,
287 })
288 task_request.init_new_request(request, True, None) 286 task_request.init_new_request(request, True, None)
289 _result_summary = task_scheduler.schedule_request(request, None) 287 _result_summary = task_scheduler.schedule_request(request, None)
290 bot_dimensions = { 288 bot_dimensions = {
291 u'foo': [u'bar'], 289 u'foo': [u'bar'],
292 u'id': [u'localhost'], 290 u'id': [u'localhost'],
293 u'os': [u'Windows', u'Windows-3.1.1'], 291 u'os': [u'Windows', u'Windows-3.1.1'],
294 u'pool': [u'default'], 292 u'pool': [u'default', u'testing'],
295 } 293 }
296 self._register_bot(bot_dimensions, nb_task=nb_task) 294 self._register_bot(bot_dimensions, nb_task=nb_task)
297 actual_request, _, run_result = task_scheduler.bot_reap_task( 295 actual_request, _, run_result = task_scheduler.bot_reap_task(
298 bot_dimensions, 'abc', None) 296 bot_dimensions, 'abc', None)
299 self.assertEqual(request, actual_request) 297 self.assertEqual(request, actual_request)
300 self.assertEqual('localhost', run_result.bot_id) 298 self.assertEqual('localhost', run_result.bot_id)
301 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number) 299 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number)
302 # It's important to terminate the task with success. 300 # It's important to terminate the task with success.
303 self.assertEqual( 301 self.assertEqual(
304 task_result.State.COMPLETED, 302 task_result.State.COMPLETED,
(...skipping 10 matching lines...) Expand all
315 cost_usd=0.1, 313 cost_usd=0.1,
316 outputs_ref=None, 314 outputs_ref=None,
317 performance_stats=None)) 315 performance_stats=None))
318 return unicode(run_result.task_id) 316 return unicode(run_result.task_id)
319 317
320 def _task_deduped(self, new_ts, deduped_from, task_id, nb_task=1, now=None): 318 def _task_deduped(self, new_ts, deduped_from, task_id, nb_task=1, now=None):
321 request = self._gen_request( 319 request = self._gen_request(
322 name='yay', 320 name='yay',
323 user='Raoul', 321 user='Raoul',
324 properties={ 322 properties={
325 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 323 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
326 'idempotent': True, 324 'idempotent': True,
327 }) 325 })
328 task_request.init_new_request(request, True, None) 326 task_request.init_new_request(request, True, None)
329 _result_summary = task_scheduler.schedule_request(request, None) 327 _result_summary = task_scheduler.schedule_request(request, None)
330 bot_dimensions = { 328 bot_dimensions = {
331 u'foo': [u'bar'], 329 u'foo': [u'bar'],
332 u'id': [u'localhost'], 330 u'id': [u'localhost'],
333 u'os': [u'Windows', u'Windows-3.1.1'], 331 u'os': [u'Windows', u'Windows-3.1.1'],
334 u'pool': [u'default'], 332 u'pool': [u'default', u'testing'],
335 } 333 }
336 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number) 334 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number)
337 self._register_bot(bot_dimensions, nb_task=nb_task) 335 self._register_bot(bot_dimensions, nb_task=nb_task)
338 actual_request_2, _, run_result_2 = task_scheduler.bot_reap_task( 336 actual_request_2, _, run_result_2 = task_scheduler.bot_reap_task(
339 bot_dimensions, 'abc', None) 337 bot_dimensions, 'abc', None)
340 self.assertEqual(None, actual_request_2) 338 self.assertEqual(None, actual_request_2)
341 result_summary_duped, run_results_duped = get_results(request.key) 339 result_summary_duped, run_results_duped = get_results(request.key)
342 expected = { 340 expected = {
343 'abandoned_ts': None, 341 'abandoned_ts': None,
344 'bot_dimensions': bot_dimensions, 342 'bot_dimensions': bot_dimensions,
(...skipping 28 matching lines...) Expand all
373 u'service_account:none', 371 u'service_account:none',
374 u'tag:1', 372 u'tag:1',
375 u'user:Raoul', 373 u'user:Raoul',
376 ], 374 ],
377 'try_number': 0, 375 'try_number': 0,
378 'user': u'Raoul', 376 'user': u'Raoul',
379 } 377 }
380 self.assertEqual(expected, result_summary_duped.to_dict()) 378 self.assertEqual(expected, result_summary_duped.to_dict())
381 self.assertEqual([], run_results_duped) 379 self.assertEqual([], run_results_duped)
382 380
381 def test_task_two_pools(self):
382 self._task_ran_successfully(
383 dimensions_flat=[u'pool:default', u'pool:testing'])
384
383 def test_task_idempotent(self): 385 def test_task_idempotent(self):
384 # First task is idempotent. 386 # First task is idempotent.
385 task_id = self._task_ran_successfully() 387 task_id = self._task_ran_successfully()
386 388
387 # Second task is deduped against first task. 389 # Second task is deduped against first task.
388 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs-1) 390 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs-1)
389 self._task_deduped(new_ts, task_id, '1d8dc670a0008a10') 391 self._task_deduped(new_ts, task_id, '1d8dc670a0008a10')
390 392
391 def test_task_idempotent_old(self): 393 def test_task_idempotent_old(self):
392 # First task is idempotent. 394 # First task is idempotent.
393 self._task_ran_successfully() 395 self._task_ran_successfully()
394 396
395 # Second task is scheduled, first task is too old to be reused. 397 # Second task is scheduled, first task is too old to be reused.
396 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs) 398 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs)
397 request = self._gen_request( 399 request = self._gen_request(
398 name='yay', 400 name='yay',
399 user='Raoul', 401 user='Raoul',
400 properties={ 402 properties={
401 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 403 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
402 'idempotent': True, 404 'idempotent': True,
403 }) 405 })
404 task_request.init_new_request(request, True, None) 406 task_request.init_new_request(request, True, None)
405 _result_summary = task_scheduler.schedule_request(request, None) 407 _result_summary = task_scheduler.schedule_request(request, None)
406 self.assertEqual(1, self.execute_tasks()) 408 self.assertEqual(1, self.execute_tasks())
407 # The task was enqueued for execution. 409 # The task was enqueued for execution.
408 self.assertNotEqual(None, task_to_run.TaskToRun.query().get().queue_number) 410 self.assertNotEqual(None, task_to_run.TaskToRun.query().get().queue_number)
409 411
410 def test_task_idempotent_three(self): 412 def test_task_idempotent_three(self):
411 # First task is idempotent. 413 # First task is idempotent.
412 task_id = self._task_ran_successfully() 414 task_id = self._task_ran_successfully()
413 415
414 # Second task is deduped against first task. 416 # Second task is deduped against first task.
415 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs-1) 417 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs-1)
416 self._task_deduped(new_ts, task_id, '1d8dc670a0008a10') 418 self._task_deduped(new_ts, task_id, '1d8dc670a0008a10')
417 419
418 # Third task is scheduled, second task is not dedupable, first task is too 420 # Third task is scheduled, second task is not dedupable, first task is too
419 # old. 421 # old.
420 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs) 422 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs)
421 request = self._gen_request( 423 request = self._gen_request(
422 name='yay', 424 name='yay',
423 user='Jesus', 425 user='Jesus',
424 properties={ 426 properties={
425 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 427 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
426 'idempotent': True, 428 'idempotent': True,
427 }) 429 })
428 task_request.init_new_request(request, True, None) 430 task_request.init_new_request(request, True, None)
429 _result_summary = task_scheduler.schedule_request(request, None) 431 _result_summary = task_scheduler.schedule_request(request, None)
430 # The task was enqueued for execution. 432 # The task was enqueued for execution.
431 self.assertNotEqual(None, task_to_run.TaskToRun.query().get().queue_number) 433 self.assertNotEqual(None, task_to_run.TaskToRun.query().get().queue_number)
432 434
433 def test_task_idempotent_variable(self): 435 def test_task_idempotent_variable(self):
434 # Test the edge case where config.settings().reusable_task_age_secs is being 436 # Test the edge case where config.settings().reusable_task_age_secs is being
435 # modified. This ensure TaskResultSummary.order(TRS.key) works. 437 # modified. This ensure TaskResultSummary.order(TRS.key) works.
(...skipping 17 matching lines...) Expand all
453 third_ts = self.mock_now(self.now, 20) 455 third_ts = self.mock_now(self.now, 20)
454 self._task_deduped( 456 self._task_deduped(
455 third_ts, task_id, '1d69ba3ea8008b10', nb_task=0, now=second_ts) 457 third_ts, task_id, '1d69ba3ea8008b10', nb_task=0, now=second_ts)
456 458
457 def test_task_parent_children(self): 459 def test_task_parent_children(self):
458 # Parent task creates a child task. 460 # Parent task creates a child task.
459 parent_id = self._task_ran_successfully() 461 parent_id = self._task_ran_successfully()
460 request = self._gen_request( 462 request = self._gen_request(
461 parent_task_id=parent_id, 463 parent_task_id=parent_id,
462 properties={ 464 properties={
463 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 465 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
464 }) 466 })
465 task_request.init_new_request(request, True, None) 467 task_request.init_new_request(request, True, None)
466 result_summary = task_scheduler.schedule_request(request, None) 468 result_summary = task_scheduler.schedule_request(request, None)
467 self.assertEqual([], result_summary.children_task_ids) 469 self.assertEqual([], result_summary.children_task_ids)
468 self.assertEqual(parent_id, request.parent_task_id) 470 self.assertEqual(parent_id, request.parent_task_id)
469 471
470 parent_run_result_key = task_pack.unpack_run_result_key(parent_id) 472 parent_run_result_key = task_pack.unpack_run_result_key(parent_id)
471 parent_res_summary_key = task_pack.run_result_key_to_result_summary_key( 473 parent_res_summary_key = task_pack.run_result_key_to_result_summary_key(
472 parent_run_result_key) 474 parent_run_result_key)
473 expected = [result_summary.task_id] 475 expected = [result_summary.task_id]
474 self.assertEqual(expected, parent_run_result_key.get().children_task_ids) 476 self.assertEqual(expected, parent_run_result_key.get().children_task_ids)
475 self.assertEqual(expected, parent_res_summary_key.get().children_task_ids) 477 self.assertEqual(expected, parent_res_summary_key.get().children_task_ids)
476 478
477 def test_task_parent_isolated(self): 479 def test_task_parent_isolated(self):
478 request = self._gen_request( 480 request = self._gen_request(
479 properties={ 481 properties={
480 'command': [], 482 'command': [],
481 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 483 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
482 'inputs_ref': { 484 'inputs_ref': {
483 'isolated': '1' * 40, 485 'isolated': '1' * 40,
484 'isolatedserver': 'http://localhost:1', 486 'isolatedserver': 'http://localhost:1',
485 'namespace': 'default-gzip', 487 'namespace': 'default-gzip',
486 }, 488 },
487 }) 489 })
488 task_request.init_new_request(request, True, None) 490 task_request.init_new_request(request, True, None)
489 _result_summary = task_scheduler.schedule_request(request, None) 491 _result_summary = task_scheduler.schedule_request(request, None)
490 bot_dimensions = { 492 bot_dimensions = {
491 u'foo': [u'bar'], 493 u'foo': [u'bar'],
(...skipping 21 matching lines...) Expand all
513 hard_timeout=False, 515 hard_timeout=False,
514 io_timeout=False, 516 io_timeout=False,
515 cost_usd=0.1, 517 cost_usd=0.1,
516 outputs_ref=None, 518 outputs_ref=None,
517 performance_stats=None)) 519 performance_stats=None))
518 520
519 parent_id = run_result.task_id 521 parent_id = run_result.task_id
520 request = self._gen_request( 522 request = self._gen_request(
521 parent_task_id=parent_id, 523 parent_task_id=parent_id,
522 properties={ 524 properties={
523 'dimensions':{u'os': u'Windows-3.1.1', u'pool': u'default'}, 525 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
524 }) 526 })
525 task_request.init_new_request(request, True, None) 527 task_request.init_new_request(request, True, None)
526 result_summary = task_scheduler.schedule_request(request, None) 528 result_summary = task_scheduler.schedule_request(request, None)
527 self.assertEqual([], result_summary.children_task_ids) 529 self.assertEqual([], result_summary.children_task_ids)
528 self.assertEqual(parent_id, request.parent_task_id) 530 self.assertEqual(parent_id, request.parent_task_id)
529 531
530 parent_run_result_key = task_pack.unpack_run_result_key(parent_id) 532 parent_run_result_key = task_pack.unpack_run_result_key(parent_id)
531 parent_res_summary_key = task_pack.run_result_key_to_result_summary_key( 533 parent_res_summary_key = task_pack.run_result_key_to_result_summary_key(
532 parent_run_result_key) 534 parent_run_result_key)
533 expected = [result_summary.task_id] 535 expected = [result_summary.task_id]
534 self.assertEqual(expected, parent_run_result_key.get().children_task_ids) 536 self.assertEqual(expected, parent_run_result_key.get().children_task_ids)
535 self.assertEqual(expected, parent_res_summary_key.get().children_task_ids) 537 self.assertEqual(expected, parent_res_summary_key.get().children_task_ids)
536 538
537 def test_get_results(self): 539 def test_get_results(self):
538 # TODO(maruel): Split in more focused tests. 540 # TODO(maruel): Split in more focused tests.
539 created_ts = self.now 541 created_ts = self.now
540 self.mock_now(created_ts) 542 self.mock_now(created_ts)
541 request = self._gen_request( 543 request = self._gen_request(
542 properties={ 544 properties={
543 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 545 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
544 }) 546 })
545 task_request.init_new_request(request, True, None) 547 task_request.init_new_request(request, True, None)
546 _result_summary = task_scheduler.schedule_request(request, None) 548 _result_summary = task_scheduler.schedule_request(request, None)
547 549
548 # The TaskRequest was enqueued, the TaskResultSummary was created but no 550 # The TaskRequest was enqueued, the TaskResultSummary was created but no
549 # TaskRunResult exist yet since the task was not scheduled on any bot. 551 # TaskRunResult exist yet since the task was not scheduled on any bot.
550 result_summary, run_results = get_results(request.key) 552 result_summary, run_results = get_results(request.key)
551 expected = { 553 expected = {
552 'abandoned_ts': None, 554 'abandoned_ts': None,
553 'bot_dimensions': None, 555 'bot_dimensions': None,
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
776 'started_ts': reaped_ts, 778 'started_ts': reaped_ts,
777 'state': State.COMPLETED, 779 'state': State.COMPLETED,
778 'try_number': 1, 780 'try_number': 1,
779 }, 781 },
780 ] 782 ]
781 self.assertEqual(expected, [t.to_dict() for t in run_results]) 783 self.assertEqual(expected, [t.to_dict() for t in run_results])
782 784
783 def test_exit_code_failure(self): 785 def test_exit_code_failure(self):
784 request = self._gen_request( 786 request = self._gen_request(
785 properties={ 787 properties={
786 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 788 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
787 }) 789 })
788 task_request.init_new_request(request, True, None) 790 task_request.init_new_request(request, True, None)
789 _result_summary = task_scheduler.schedule_request(request, None) 791 _result_summary = task_scheduler.schedule_request(request, None)
790 bot_dimensions = { 792 bot_dimensions = {
791 u'id': [u'localhost'], 793 u'id': [u'localhost'],
792 u'os': [u'Windows-3.1.1'], 794 u'os': [u'Windows-3.1.1'],
793 u'pool': [u'default'], 795 u'pool': [u'default'],
794 } 796 }
795 self._register_bot(bot_dimensions) 797 self._register_bot(bot_dimensions)
796 reaped_request, _, run_result = task_scheduler.bot_reap_task( 798 reaped_request, _, run_result = task_scheduler.bot_reap_task(
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
871 'started_ts': self.now, 873 'started_ts': self.now,
872 'state': State.COMPLETED, 874 'state': State.COMPLETED,
873 'try_number': 1, 875 'try_number': 1,
874 }, 876 },
875 ] 877 ]
876 self.assertEqual(expected, [t.to_dict() for t in run_results]) 878 self.assertEqual(expected, [t.to_dict() for t in run_results])
877 879
878 def test_schedule_request(self): 880 def test_schedule_request(self):
879 # It is tested indirectly in the other functions. 881 # It is tested indirectly in the other functions.
880 self.assertTrue( 882 self.assertTrue(
881 self._quick_schedule({u'os': u'Windows-3.1.1', u'pool': u'default'})) 883 self._quick_schedule([u'os:Windows-3.1.1', u'pool:default']))
882 884
883 def mock_dim_acls(self, mapping): 885 def mock_dim_acls(self, mapping):
884 self.mock(config, 'settings', lambda: config_pb2.SettingsCfg( 886 self.mock(config, 'settings', lambda: config_pb2.SettingsCfg(
885 dimension_acls=config_pb2.DimensionACLs(entry=[ 887 dimension_acls=config_pb2.DimensionACLs(entry=[
886 config_pb2.DimensionACLs.Entry(dimension=[d], usable_by=g) 888 config_pb2.DimensionACLs.Entry(dimension=[d], usable_by=g)
887 for d, g in sorted(mapping.iteritems()) 889 for d, g in sorted(mapping.iteritems())
888 ]), 890 ]),
889 )) 891 ))
890 892
891 def test_schedule_request_forbidden_dim(self): 893 def test_schedule_request_forbidden_dim(self):
892 self.mock_dim_acls({u'pool:bad': u'noone'}) 894 self.mock_dim_acls({u'pool:bad': u'noone'})
893 self._quick_schedule({u'pool': u'good'}) 895 self._quick_schedule([u'pool:good'])
894 with self.assertRaises(auth.AuthorizationError): 896 with self.assertRaises(auth.AuthorizationError):
895 self._quick_schedule({u'pool': u'bad'}) 897 self._quick_schedule([u'pool:bad'])
896 898
897 def test_schedule_request_forbidden_dim_via_star(self): 899 def test_schedule_request_forbidden_dim_via_star(self):
898 self.mock_dim_acls({u'abc:*': u'noone'}) 900 self.mock_dim_acls({u'abc:*': u'noone'})
899 self._quick_schedule({u'pool': u'default'}) 901 self._quick_schedule([u'pool:default'])
900 with self.assertRaises(auth.AuthorizationError): 902 with self.assertRaises(auth.AuthorizationError):
901 self._quick_schedule({u'pool': u'default', u'abc': u'blah'}) 903 self._quick_schedule([u'abc:blah', u'pool:default'])
902 904
903 def test_schedule_request_id_without_pool(self): 905 def test_schedule_request_id_without_pool(self):
904 self.mock_dim_acls({u'pool:good': u'mocked'}) 906 self.mock_dim_acls({u'pool:good': u'mocked'})
905 with self.assertRaises(auth.AuthorizationError): 907 with self.assertRaises(auth.AuthorizationError):
906 self._quick_schedule({u'id': u'abc'}) 908 self._quick_schedule([u'id:abc'])
907 auth_testing.mock_is_admin(self) 909 auth_testing.mock_is_admin(self)
908 self._quick_schedule({u'id': u'abc'}, nb_task=0) 910 self._quick_schedule([u'id:abc'], nb_task=0)
909 911
910 def test_schedule_request_id_and_pool(self): 912 def test_schedule_request_id_and_pool(self):
911 self.mock_dim_acls({u'pool:good': u'mocked'}) 913 self.mock_dim_acls({u'pool:good': u'mocked'})
912 self.mock_dim_acls({u'pool:bad': u'unknown'}) 914 self.mock_dim_acls({u'pool:bad': u'unknown'})
913 915
914 def mocked_is_group_member(group, ident): 916 def mocked_is_group_member(group, ident):
915 if group == 'mocked' and ident == auth_testing.DEFAULT_MOCKED_IDENTITY: 917 if group == 'mocked' and ident == auth_testing.DEFAULT_MOCKED_IDENTITY:
916 return True 918 return True
917 return False 919 return False
918 self.mock(auth, 'is_group_member', mocked_is_group_member) 920 self.mock(auth, 'is_group_member', mocked_is_group_member)
919 921
920 self._quick_schedule({u'id': u'abc', u'pool': u'unknown'}, nb_task=0) 922 self._quick_schedule([u'id:abc', u'pool:unknown'], nb_task=0)
921 self._quick_schedule({u'id': u'abc', u'pool': u'good'}, nb_task=0) 923 self._quick_schedule([u'id:abc', u'pool:good'], nb_task=0)
922 with self.assertRaises(auth.AuthorizationError): 924 with self.assertRaises(auth.AuthorizationError):
923 self._quick_schedule({u'id': u'abc', u'pool': u'bad'}) 925 self._quick_schedule([u'id:abc', u'pool:bad'])
924 926
925 def test_bot_update_task(self): 927 def test_bot_update_task(self):
926 run_result = self._quick_reap(nb_task=0) 928 run_result = self._quick_reap(nb_task=0)
927 self.assertEqual( 929 self.assertEqual(
928 task_result.State.RUNNING, 930 task_result.State.RUNNING,
929 task_scheduler.bot_update_task( 931 task_scheduler.bot_update_task(
930 run_result_key=run_result.key, 932 run_result_key=run_result.key,
931 bot_id='localhost', 933 bot_id='localhost',
932 cipd_pins=None, 934 cipd_pins=None,
933 output='hi', 935 output='hi',
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1009 hard_timeout=False, 1011 hard_timeout=False,
1010 io_timeout=False, 1012 io_timeout=False,
1011 cost_usd=0.1, 1013 cost_usd=0.1,
1012 outputs_ref=None, 1014 outputs_ref=None,
1013 performance_stats=None)) 1015 performance_stats=None))
1014 1016
1015 def test_bot_update_pubsub_error(self): 1017 def test_bot_update_pubsub_error(self):
1016 pub_sub_calls = self.mock_pub_sub() 1018 pub_sub_calls = self.mock_pub_sub()
1017 request = self._gen_request( 1019 request = self._gen_request(
1018 properties={ 1020 properties={
1019 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1021 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
1020 }, 1022 },
1021 pubsub_topic='projects/abc/topics/def') 1023 pubsub_topic='projects/abc/topics/def')
1022 task_request.init_new_request(request, True, None) 1024 task_request.init_new_request(request, True, None)
1023 task_scheduler.schedule_request(request, None) 1025 task_scheduler.schedule_request(request, None)
1024 bot_dimensions = { 1026 bot_dimensions = {
1025 u'foo': [u'bar'], 1027 u'foo': [u'bar'],
1026 u'id': [u'localhost'], 1028 u'id': [u'localhost'],
1027 u'os': [u'Windows', u'Windows-3.1.1'], 1029 u'os': [u'Windows', u'Windows-3.1.1'],
1028 u'pool': [u'default'], 1030 u'pool': [u'default'],
1029 } 1031 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1067 io_timeout=False, 1069 io_timeout=False,
1068 cost_usd=0.1, 1070 cost_usd=0.1,
1069 outputs_ref=None, 1071 outputs_ref=None,
1070 performance_stats=None)) 1072 performance_stats=None))
1071 self.assertEqual(0, self.execute_tasks()) 1073 self.assertEqual(0, self.execute_tasks())
1072 self.assertEqual(1, len(pub_sub_calls)) # notification is sent 1074 self.assertEqual(1, len(pub_sub_calls)) # notification is sent
1073 1075
1074 def _bot_update_timeouts(self, hard, io): 1076 def _bot_update_timeouts(self, hard, io):
1075 request = self._gen_request( 1077 request = self._gen_request(
1076 properties={ 1078 properties={
1077 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1079 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
1078 }) 1080 })
1079 task_request.init_new_request(request, True, None) 1081 task_request.init_new_request(request, True, None)
1080 result_summary = task_scheduler.schedule_request(request, None) 1082 result_summary = task_scheduler.schedule_request(request, None)
1081 bot_dimensions = { 1083 bot_dimensions = {
1082 u'id': [u'localhost'], 1084 u'id': [u'localhost'],
1083 u'os': [u'Windows-3.1.1'], 1085 u'os': [u'Windows-3.1.1'],
1084 u'pool': [u'default'], 1086 u'pool': [u'default'],
1085 } 1087 }
1086 self._register_bot(bot_dimensions) 1088 self._register_bot(bot_dimensions)
1087 reaped_request, _, run_result = task_scheduler.bot_reap_task( 1089 reaped_request, _, run_result = task_scheduler.bot_reap_task(
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1162 self.assertEqual(expected, run_result.key.get().to_dict()) 1164 self.assertEqual(expected, run_result.key.get().to_dict())
1163 1165
1164 def test_bot_update_hard_timeout(self): 1166 def test_bot_update_hard_timeout(self):
1165 self._bot_update_timeouts(True, False) 1167 self._bot_update_timeouts(True, False)
1166 1168
1167 def test_bot_update_io_timeout(self): 1169 def test_bot_update_io_timeout(self):
1168 self._bot_update_timeouts(False, True) 1170 self._bot_update_timeouts(False, True)
1169 1171
1170 def test_bot_kill_task(self): 1172 def test_bot_kill_task(self):
1171 pub_sub_calls = self.mock_pub_sub() 1173 pub_sub_calls = self.mock_pub_sub()
1172 dimensions = {u'os': u'Windows-3.1.1', u'pool': u'default'}
1173 request = self._gen_request( 1174 request = self._gen_request(
1174 properties={'dimensions': dimensions}, 1175 properties={'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default']},
1175 pubsub_topic='projects/abc/topics/def') 1176 pubsub_topic='projects/abc/topics/def')
1176 task_request.init_new_request(request, True, None) 1177 task_request.init_new_request(request, True, None)
1177 result_summary = task_scheduler.schedule_request(request, None) 1178 result_summary = task_scheduler.schedule_request(request, None)
1178 bot_dimensions = { 1179 bot_dimensions = {
1179 u'id': [u'localhost'], 1180 u'id': [u'localhost'],
1180 u'os': [u'Windows-3.1.1'], 1181 u'os': [u'Windows-3.1.1'],
1181 u'pool': [u'default'], 1182 u'pool': [u'default'],
1182 } 1183 }
1183 self._register_bot(bot_dimensions) 1184 self._register_bot(bot_dimensions)
1184 reaped_request, _, run_result = task_scheduler.bot_reap_task( 1185 reaped_request, _, run_result = task_scheduler.bot_reap_task(
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1244 'started_ts': self.now, 1245 'started_ts': self.now,
1245 'state': State.BOT_DIED, 1246 'state': State.BOT_DIED,
1246 'try_number': 1, 1247 'try_number': 1,
1247 } 1248 }
1248 self.assertEqual(expected, run_result.key.get().to_dict()) 1249 self.assertEqual(expected, run_result.key.get().to_dict())
1249 self.assertEqual(1, self.execute_tasks()) 1250 self.assertEqual(1, self.execute_tasks())
1250 self.assertEqual(2, len(pub_sub_calls)) # RUNNING -> BOT_DIED 1251 self.assertEqual(2, len(pub_sub_calls)) # RUNNING -> BOT_DIED
1251 1252
1252 def test_bot_kill_task_wrong_bot(self): 1253 def test_bot_kill_task_wrong_bot(self):
1253 request = self._gen_request( 1254 request = self._gen_request(
1254 properties={ 1255 properties={'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default']})
1255 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1256 })
1257 task_request.init_new_request(request, True, None) 1256 task_request.init_new_request(request, True, None)
1258 result_summary = task_scheduler.schedule_request(request, None) 1257 result_summary = task_scheduler.schedule_request(request, None)
1259 bot_dimensions = { 1258 bot_dimensions = {
1260 u'id': [u'localhost'], 1259 u'id': [u'localhost'],
1261 u'os': [u'Windows-3.1.1'], 1260 u'os': [u'Windows-3.1.1'],
1262 u'pool': [u'default'], 1261 u'pool': [u'default'],
1263 } 1262 }
1264 self._register_bot(bot_dimensions) 1263 self._register_bot(bot_dimensions)
1265 reaped_request, _, run_result = task_scheduler.bot_reap_task( 1264 reaped_request, _, run_result = task_scheduler.bot_reap_task(
1266 bot_dimensions, 'abc', None) 1265 bot_dimensions, 'abc', None)
1267 expected = ( 1266 expected = (
1268 'Bot bot1 sent task kill for task 1d69b9f088008911 owned by bot ' 1267 'Bot bot1 sent task kill for task 1d69b9f088008911 owned by bot '
1269 'localhost') 1268 'localhost')
1270 self.assertEqual( 1269 self.assertEqual(
1271 expected, task_scheduler.bot_kill_task(run_result.key, 'bot1')) 1270 expected, task_scheduler.bot_kill_task(run_result.key, 'bot1'))
1272 1271
1273 def test_cancel_task(self): 1272 def test_cancel_task(self):
1274 request = self._gen_request( 1273 request = self._gen_request(
1275 properties={ 1274 properties={'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default']},
1276 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1277 },
1278 pubsub_topic='projects/abc/topics/def') 1275 pubsub_topic='projects/abc/topics/def')
1279 pub_sub_calls = self.mock_pub_sub() 1276 pub_sub_calls = self.mock_pub_sub()
1280 task_request.init_new_request(request, True, None) 1277 task_request.init_new_request(request, True, None)
1281 result_summary = task_scheduler.schedule_request(request, None) 1278 result_summary = task_scheduler.schedule_request(request, None)
1282 ok, was_running = task_scheduler.cancel_task(request, result_summary.key) 1279 ok, was_running = task_scheduler.cancel_task(request, result_summary.key)
1283 self.assertEqual(True, ok) 1280 self.assertEqual(True, ok)
1284 self.assertEqual(False, was_running) 1281 self.assertEqual(False, was_running)
1285 result_summary = result_summary.key.get() 1282 result_summary = result_summary.key.get()
1286 self.assertEqual(task_result.State.CANCELED, result_summary.state) 1283 self.assertEqual(task_result.State.CANCELED, result_summary.state)
1287 self.assertEqual(2, self.execute_tasks()) 1284 self.assertEqual(2, self.execute_tasks())
1288 self.assertEqual(1, len(pub_sub_calls)) # sent completion notification 1285 self.assertEqual(1, len(pub_sub_calls)) # sent completion notification
1289 1286
1290 def test_cancel_task_running(self): 1287 def test_cancel_task_running(self):
1291 request = self._gen_request( 1288 request = self._gen_request(
1292 properties={ 1289 properties={'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default']},
1293 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1294 },
1295 pubsub_topic='projects/abc/topics/def') 1290 pubsub_topic='projects/abc/topics/def')
1296 pub_sub_calls = self.mock_pub_sub() 1291 pub_sub_calls = self.mock_pub_sub()
1297 task_request.init_new_request(request, True, None) 1292 task_request.init_new_request(request, True, None)
1298 result_summary = task_scheduler.schedule_request(request, None) 1293 result_summary = task_scheduler.schedule_request(request, None)
1299 bot_dimensions = { 1294 bot_dimensions = {
1300 u'id': [u'localhost'], 1295 u'id': [u'localhost'],
1301 u'os': [u'Windows-3.1.1'], 1296 u'os': [u'Windows-3.1.1'],
1302 u'pool': [u'default'], 1297 u'pool': [u'default'],
1303 } 1298 }
1304 self._register_bot(bot_dimensions) 1299 self._register_bot(bot_dimensions)
1305 reaped_request, _, run_result = task_scheduler.bot_reap_task( 1300 reaped_request, _, run_result = task_scheduler.bot_reap_task(
1306 bot_dimensions, 'abc', None) 1301 bot_dimensions, 'abc', None)
1307 ok, was_running = task_scheduler.cancel_task(request, result_summary.key) 1302 ok, was_running = task_scheduler.cancel_task(request, result_summary.key)
1308 self.assertEqual(False, ok) 1303 self.assertEqual(False, ok)
1309 self.assertEqual(True, was_running) 1304 self.assertEqual(True, was_running)
1310 result_summary = result_summary.key.get() 1305 result_summary = result_summary.key.get()
1311 self.assertEqual(task_result.State.RUNNING, result_summary.state) 1306 self.assertEqual(task_result.State.RUNNING, result_summary.state)
1312 self.assertEqual(1, self.execute_tasks()) 1307 self.assertEqual(1, self.execute_tasks())
1313 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING 1308 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING
1314 1309
1315 def test_cron_abort_expired_task_to_run(self): 1310 def test_cron_abort_expired_task_to_run(self):
1316 request = self._gen_request( 1311 request = self._gen_request(
1317 properties={ 1312 properties={'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default']},
1318 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1313 pubsub_topic='projects/abc/topics/def')
1319 },
1320 pubsub_topic='projects/abc/topics/def')
1321 task_request.init_new_request(request, True, None) 1314 task_request.init_new_request(request, True, None)
1322 pub_sub_calls = self.mock_pub_sub() 1315 pub_sub_calls = self.mock_pub_sub()
1323 result_summary = task_scheduler.schedule_request(request, None) 1316 result_summary = task_scheduler.schedule_request(request, None)
1324 abandoned_ts = self.mock_now(self.now, request.expiration_secs+1) 1317 abandoned_ts = self.mock_now(self.now, request.expiration_secs+1)
1325 self.assertEqual( 1318 self.assertEqual(
1326 ['1d69b9f088008910'], 1319 ['1d69b9f088008910'],
1327 task_scheduler.cron_abort_expired_task_to_run('f.local')) 1320 task_scheduler.cron_abort_expired_task_to_run('f.local'))
1328 self.assertEqual([], task_result.TaskRunResult.query().fetch()) 1321 self.assertEqual([], task_result.TaskRunResult.query().fetch())
1329 expected = { 1322 expected = {
1330 'abandoned_ts': abandoned_ts, 1323 'abandoned_ts': abandoned_ts,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1363 } 1356 }
1364 self.assertEqual(expected, result_summary.key.get().to_dict()) 1357 self.assertEqual(expected, result_summary.key.get().to_dict())
1365 self.assertEqual(2, self.execute_tasks()) 1358 self.assertEqual(2, self.execute_tasks())
1366 self.assertEqual(1, len(pub_sub_calls)) # pubsub completion notification 1359 self.assertEqual(1, len(pub_sub_calls)) # pubsub completion notification
1367 1360
1368 def test_cron_abort_expired_task_to_run_retry(self): 1361 def test_cron_abort_expired_task_to_run_retry(self):
1369 pub_sub_calls = self.mock_pub_sub() 1362 pub_sub_calls = self.mock_pub_sub()
1370 now = utils.utcnow() 1363 now = utils.utcnow()
1371 request = self._gen_request( 1364 request = self._gen_request(
1372 properties={ 1365 properties={
1373 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1366 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
1374 'idempotent': True, 1367 'idempotent': True,
1375 }, 1368 },
1376 created_ts=now, 1369 created_ts=now,
1377 expiration_ts=now+datetime.timedelta(seconds=600), 1370 expiration_ts=now+datetime.timedelta(seconds=600),
1378 pubsub_topic='projects/abc/topics/def') 1371 pubsub_topic='projects/abc/topics/def')
1379 task_request.init_new_request(request, True, None) 1372 task_request.init_new_request(request, True, None)
1380 result_summary = task_scheduler.schedule_request(request, None) 1373 result_summary = task_scheduler.schedule_request(request, None)
1381 1374
1382 # Fake first try bot died. 1375 # Fake first try bot died.
1383 bot_dimensions = { 1376 bot_dimensions = {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
1445 self.assertEqual(1, self.execute_tasks()) 1438 self.assertEqual(1, self.execute_tasks())
1446 self.assertEqual(3, len(pub_sub_calls)) # PENDING -> BOT_DIED 1439 self.assertEqual(3, len(pub_sub_calls)) # PENDING -> BOT_DIED
1447 1440
1448 def test_cron_handle_bot_died(self): 1441 def test_cron_handle_bot_died(self):
1449 pub_sub_calls = self.mock_pub_sub() 1442 pub_sub_calls = self.mock_pub_sub()
1450 1443
1451 # Test first retry, then success. 1444 # Test first retry, then success.
1452 now = utils.utcnow() 1445 now = utils.utcnow()
1453 request = self._gen_request( 1446 request = self._gen_request(
1454 properties={ 1447 properties={
1455 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1448 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
1456 'idempotent': True, 1449 'idempotent': True,
1457 }, 1450 },
1458 created_ts=now, 1451 created_ts=now,
1459 expiration_ts=now+datetime.timedelta(seconds=600), 1452 expiration_ts=now+datetime.timedelta(seconds=600),
1460 pubsub_topic='projects/abc/topics/def') 1453 pubsub_topic='projects/abc/topics/def')
1461 task_request.init_new_request(request, True, None) 1454 task_request.init_new_request(request, True, None)
1462 _result_summary = task_scheduler.schedule_request(request, None) 1455 _result_summary = task_scheduler.schedule_request(request, None)
1463 self.assertEqual(1, self.execute_tasks()) 1456 self.assertEqual(1, self.execute_tasks())
1464 self.assertEqual(0, len(pub_sub_calls)) 1457 self.assertEqual(0, len(pub_sub_calls))
1465 bot_dimensions = { 1458 bot_dimensions = {
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1607 self.assertEqual(0.1, run_result.key.get().cost_usd) 1600 self.assertEqual(0.1, run_result.key.get().cost_usd)
1608 1601
1609 self.assertEqual(0, self.execute_tasks()) 1602 self.assertEqual(0, self.execute_tasks())
1610 self.assertEqual(4, len(pub_sub_calls)) # RUNNING -> COMPLETED 1603 self.assertEqual(4, len(pub_sub_calls)) # RUNNING -> COMPLETED
1611 1604
1612 def test_cron_handle_bot_died_same_bot_denied(self): 1605 def test_cron_handle_bot_died_same_bot_denied(self):
1613 # Test first retry, then success. 1606 # Test first retry, then success.
1614 now = utils.utcnow() 1607 now = utils.utcnow()
1615 request = self._gen_request( 1608 request = self._gen_request(
1616 properties={ 1609 properties={
1617 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1610 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
1618 'idempotent': True, 1611 'idempotent': True,
1619 }, 1612 },
1620 created_ts=now, 1613 created_ts=now,
1621 expiration_ts=now+datetime.timedelta(seconds=600)) 1614 expiration_ts=now+datetime.timedelta(seconds=600))
1622 task_request.init_new_request(request, True, None) 1615 task_request.init_new_request(request, True, None)
1623 _result_summary = task_scheduler.schedule_request(request, None) 1616 _result_summary = task_scheduler.schedule_request(request, None)
1624 bot_dimensions = { 1617 bot_dimensions = {
1625 u'foo': [u'bar'], 1618 u'foo': [u'bar'],
1626 u'id': [u'localhost'], 1619 u'id': [u'localhost'],
1627 u'os': [u'Windows', u'Windows-3.1.1'], 1620 u'os': [u'Windows', u'Windows-3.1.1'],
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1701 bot_dimensions, 'abc', None) 1694 bot_dimensions, 'abc', None)
1702 self.assertEqual(None, request) 1695 self.assertEqual(None, request)
1703 self.assertEqual(None, run_result) 1696 self.assertEqual(None, run_result)
1704 logging.info('%s', [t.to_dict() for t in task_to_run.TaskToRun.query()]) 1697 logging.info('%s', [t.to_dict() for t in task_to_run.TaskToRun.query()])
1705 1698
1706 def test_cron_handle_bot_died_second(self): 1699 def test_cron_handle_bot_died_second(self):
1707 # Test two tries internal_failure's leading to a BOT_DIED status. 1700 # Test two tries internal_failure's leading to a BOT_DIED status.
1708 now = utils.utcnow() 1701 now = utils.utcnow()
1709 request = self._gen_request( 1702 request = self._gen_request(
1710 properties={ 1703 properties={
1711 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1704 'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default'],
1712 'idempotent': True, 1705 'idempotent': True,
1713 }, 1706 },
1714 created_ts=now, 1707 created_ts=now,
1715 expiration_ts=now+datetime.timedelta(seconds=600)) 1708 expiration_ts=now+datetime.timedelta(seconds=600))
1716 task_request.init_new_request(request, True, None) 1709 task_request.init_new_request(request, True, None)
1717 _result_summary = task_scheduler.schedule_request(request, None) 1710 _result_summary = task_scheduler.schedule_request(request, None)
1718 bot_dimensions = { 1711 bot_dimensions = {
1719 u'foo': [u'bar'], 1712 u'foo': [u'bar'],
1720 u'id': [u'localhost'], 1713 u'id': [u'localhost'],
1721 u'os': [u'Windows', u'Windows-3.1.1'], 1714 u'os': [u'Windows', u'Windows-3.1.1'],
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1774 u'user:Jesus', 1767 u'user:Jesus',
1775 ], 1768 ],
1776 'try_number': 2, 1769 'try_number': 2,
1777 'user': u'Jesus', 1770 'user': u'Jesus',
1778 } 1771 }
1779 self.assertEqual(expected, run_result.result_summary_key.get().to_dict()) 1772 self.assertEqual(expected, run_result.result_summary_key.get().to_dict())
1780 1773
1781 def test_cron_handle_bot_died_ignored_expired(self): 1774 def test_cron_handle_bot_died_ignored_expired(self):
1782 now = utils.utcnow() 1775 now = utils.utcnow()
1783 request = self._gen_request( 1776 request = self._gen_request(
1784 properties={ 1777 properties={'dimensions_flat': [u'os:Windows-3.1.1', u'pool:default']},
1785 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1786 },
1787 created_ts=now, 1778 created_ts=now,
1788 expiration_ts=now+datetime.timedelta(seconds=600)) 1779 expiration_ts=now+datetime.timedelta(seconds=600))
1789 task_request.init_new_request(request, True, None) 1780 task_request.init_new_request(request, True, None)
1790 _result_summary = task_scheduler.schedule_request(request, None) 1781 _result_summary = task_scheduler.schedule_request(request, None)
1791 bot_dimensions = { 1782 bot_dimensions = {
1792 u'foo': [u'bar'], 1783 u'foo': [u'bar'],
1793 u'id': [u'localhost'], 1784 u'id': [u'localhost'],
1794 u'os': [u'Windows', u'Windows-3.1.1'], 1785 u'os': [u'Windows', u'Windows-3.1.1'],
1795 u'pool': [u'default'], 1786 u'pool': [u'default'],
1796 } 1787 }
1797 self._register_bot(bot_dimensions) 1788 self._register_bot(bot_dimensions)
1798 _request, _, run_result = task_scheduler.bot_reap_task( 1789 _request, _, run_result = task_scheduler.bot_reap_task(
1799 bot_dimensions, 'abc', None) 1790 bot_dimensions, 'abc', None)
1800 self.assertEqual(1, run_result.try_number) 1791 self.assertEqual(1, run_result.try_number)
1801 self.assertEqual(task_result.State.RUNNING, run_result.state) 1792 self.assertEqual(task_result.State.RUNNING, run_result.state)
1802 self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 601) 1793 self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 601)
1803 self.assertEqual( 1794 self.assertEqual(
1804 (['1d69b9f088008911'], 0, 0), 1795 (['1d69b9f088008911'], 0, 0),
1805 task_scheduler.cron_handle_bot_died('f.local')) 1796 task_scheduler.cron_handle_bot_died('f.local'))
1806 1797
1807 1798
1808 if __name__ == '__main__': 1799 if __name__ == '__main__':
1809 if '-v' in sys.argv: 1800 if '-v' in sys.argv:
1810 unittest.TestCase.maxDiff = None 1801 unittest.TestCase.maxDiff = None
1811 logging.basicConfig( 1802 logging.basicConfig(
1812 level=logging.DEBUG if '-v' in sys.argv else logging.CRITICAL) 1803 level=logging.DEBUG if '-v' in sys.argv else logging.CRITICAL)
1813 unittest.main() 1804 unittest.main()
OLDNEW
« no previous file with comments | « appengine/swarming/server/task_scheduler.py ('k') | appengine/swarming/server/task_to_run.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698