| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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() |
| OLD | NEW |