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

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

Issue 2832243002: swarming: mechanical changes to unit tests (Closed)
Patch Set: Disable tx before calling tq Created 3 years, 8 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/handlers_test.py ('k') | appengine/swarming/server/task_to_run_test.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 29 matching lines...) Expand all
40 from server import task_scheduler 40 from server import task_scheduler
41 from server import task_to_run 41 from server import task_to_run
42 from server.task_result import State 42 from server.task_result import State
43 43
44 from proto import config_pb2 44 from proto import config_pb2
45 45
46 46
47 # pylint: disable=W0212,W0612 47 # pylint: disable=W0212,W0612
48 48
49 49
50 def _gen_request(properties=None, **kwargs):
51 """Creates a TaskRequest."""
52 props = {
53 'command': [u'command1'],
54 'dimensions': {u'pool': u'default'},
55 'env': {},
56 'execution_timeout_secs': 24*60*60,
57 'io_timeout_secs': None,
58 }
59 props.update(properties or {})
60 now = utils.utcnow()
61 args = {
62 'created_ts': now,
63 'name': 'Request name',
64 'priority': 50,
65 'properties': task_request.TaskProperties(**props),
66 'expiration_ts': now + datetime.timedelta(seconds=60),
67 'tags': [u'tag:1'],
68 'user': 'Jesus',
69 }
70 args.update(kwargs)
71 ret = task_request.TaskRequest(**args)
72 task_request.init_new_request(ret, True, None)
73 return ret
74
75
76 def get_results(request_key): 50 def get_results(request_key):
77 """Fetches all task results for a specified TaskRequest ndb.Key. 51 """Fetches all task results for a specified TaskRequest ndb.Key.
78 52
79 Returns: 53 Returns:
80 tuple(TaskResultSummary, list of TaskRunResult that exist). 54 tuple(TaskResultSummary, list of TaskRunResult that exist).
81 """ 55 """
82 result_summary_key = task_pack.request_key_to_result_summary_key(request_key) 56 result_summary_key = task_pack.request_key_to_result_summary_key(request_key)
83 result_summary = result_summary_key.get() 57 result_summary = result_summary_key.get()
84 # There's two way to look at it, either use a DB query or fetch all the 58 # There's two way to look at it, either use a DB query or fetch all the
85 # entities that could exist, at most 255. In general, there will be <3 59 # entities that could exist, at most 255. In general, there will be <3
86 # entities so just fetching them by key would be faster. This function is 60 # entities so just fetching them by key would be faster. This function is
87 # exclusively used in unit tests so it's not performance critical. 61 # exclusively used in unit tests so it's not performance critical.
88 q = task_result.TaskRunResult.query(ancestor=result_summary_key) 62 q = task_result.TaskRunResult.query(ancestor=result_summary_key)
89 q = q.order(task_result.TaskRunResult.key) 63 q = q.order(task_result.TaskRunResult.key)
90 return result_summary, q.fetch() 64 return result_summary, q.fetch()
91 65
92 66
93 def _quick_schedule(dims):
94 """Schedules a task."""
95 request = _gen_request(properties={'dimensions': dims})
96 task_request.init_new_request(request, True, None)
97 return task_scheduler.schedule_request(request, None)
98
99
100 def _register_bot(bot_dimensions):
101 """Registers the bot so the task queues knows there's a worker than can run
102 the task.
103 """
104 bot_management.bot_event(
105 'bot_connected', bot_dimensions[u'id'][0], '1.2.3.4', 'joe@localhost',
106 bot_dimensions, {'state': 'real'}, '1234', False, None, None)
107 task_queues.assert_bot(bot_dimensions)
108
109
110 def _quick_reap():
111 """Reaps a task."""
112 _quick_schedule({u'os': u'Windows-3.1.1', u'pool': u'default'})
113 bot_dimensions = {
114 u'id': [u'localhost'],
115 u'os': [u'Windows-3.1.1'],
116 u'pool': [u'default'],
117 }
118 _register_bot(bot_dimensions)
119 reaped_request, _, run_result = task_scheduler.bot_reap_task(
120 bot_dimensions, 'abc', None)
121 return run_result
122
123
124 class TaskSchedulerApiTest(test_env_handlers.AppTestBase): 67 class TaskSchedulerApiTest(test_env_handlers.AppTestBase):
125 def setUp(self): 68 def setUp(self):
126 super(TaskSchedulerApiTest, self).setUp() 69 super(TaskSchedulerApiTest, self).setUp()
127 self.now = datetime.datetime(2014, 1, 2, 3, 4, 5, 6) 70 self.now = datetime.datetime(2014, 1, 2, 3, 4, 5, 6)
128 self.mock_now(self.now) 71 self.mock_now(self.now)
129 self.mock(stats_framework, 'add_entry', self._parse_line) 72 self.mock(stats_framework, 'add_entry', self._parse_line)
130 auth_testing.mock_get_current_identity(self) 73 auth_testing.mock_get_current_identity(self)
131 event_mon_metrics.initialize() 74 event_mon_metrics.initialize()
132 # Setup the backend to handle task queues for 'task-dimensions'. 75 # Setup the backend to handle task queues for 'task-dimensions'.
133 self.app = webtest.TestApp( 76 self.app = webtest.TestApp(
(...skipping 26 matching lines...) Expand all
160 self.assertFalse(self._pub_sub_mocked) 103 self.assertFalse(self._pub_sub_mocked)
161 self._pub_sub_mocked = True 104 self._pub_sub_mocked = True
162 calls = [] 105 calls = []
163 def pubsub_publish(**kwargs): 106 def pubsub_publish(**kwargs):
164 if not self.publish_successful: 107 if not self.publish_successful:
165 raise pubsub.TransientError('Fail') 108 raise pubsub.TransientError('Fail')
166 calls.append(('directly', kwargs)) 109 calls.append(('directly', kwargs))
167 self.mock(pubsub, 'publish', pubsub_publish) 110 self.mock(pubsub, 'publish', pubsub_publish)
168 return calls 111 return calls
169 112
113 def _gen_request(self, properties=None, **kwargs):
114 """Creates a TaskRequest."""
115 props = {
116 'command': [u'command1'],
117 'dimensions': {u'pool': u'default'},
118 'env': {},
119 'execution_timeout_secs': 24*60*60,
120 'io_timeout_secs': None,
121 }
122 props.update(properties or {})
123 now = utils.utcnow()
124 args = {
125 'created_ts': now,
126 'name': 'Request name',
127 'priority': 50,
128 'properties': task_request.TaskProperties(**props),
129 'expiration_ts': now + datetime.timedelta(seconds=60),
130 'tags': [u'tag:1'],
131 'user': 'Jesus',
132 }
133 args.update(kwargs)
134 ret = task_request.TaskRequest(**args)
135 task_request.init_new_request(ret, True, None)
136 return ret
137
138 def _quick_schedule(self, dims, nb_task=0):
139 """Schedules a task."""
140 request = self._gen_request(properties={'dimensions': dims})
141 result_summary = task_scheduler.schedule_request(request, None)
142 self.assertEqual(nb_task, self.execute_tasks())
143 return result_summary
144
145 def _register_bot(self, bot_dimensions, nb_task=0):
146 """Registers the bot so the task queues knows there's a worker than can run
147 the task.
148 """
149 bot_management.bot_event(
150 'bot_connected', bot_dimensions[u'id'][0], '1.2.3.4', 'joe@localhost',
151 bot_dimensions, {'state': 'real'}, '1234', False, None, None)
152 task_queues.assert_bot(bot_dimensions)
153 self.assertEqual(nb_task, self.execute_tasks())
154
155 def _quick_reap(self, nb_task=0):
156 """Reaps a task."""
157 self._quick_schedule({u'os': u'Windows-3.1.1', u'pool': u'default'})
158 bot_dimensions = {
159 u'id': [u'localhost'],
160 u'os': [u'Windows-3.1.1'],
161 u'pool': [u'default'],
162 }
163 self._register_bot(bot_dimensions, nb_task=nb_task)
164 reaped_request, _, run_result = task_scheduler.bot_reap_task(
165 bot_dimensions, 'abc', None)
166 return run_result
167
170 def test_all_apis_are_tested(self): 168 def test_all_apis_are_tested(self):
171 # Ensures there's a test for each public API. 169 # Ensures there's a test for each public API.
172 # TODO(maruel): Remove this once coverage is asserted. 170 # TODO(maruel): Remove this once coverage is asserted.
173 module = task_scheduler 171 module = task_scheduler
174 expected = set( 172 expected = set(
175 i for i in dir(module) 173 i for i in dir(module)
176 if i[0] != '_' and hasattr(getattr(module, i), 'func_name')) 174 if i[0] != '_' and hasattr(getattr(module, i), 'func_name'))
177 missing = expected - set(i[5:] for i in dir(self) if i.startswith('test_')) 175 missing = expected - set(i[5:] for i in dir(self) if i.startswith('test_'))
178 self.assertFalse(missing) 176 self.assertFalse(missing)
179 177
180 def test_bot_reap_task(self): 178 def test_bot_reap_task(self):
181 request = _gen_request( 179 request = self._gen_request(
182 properties={ 180 properties={
183 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 181 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
184 }) 182 })
185 task_request.init_new_request(request, True, None) 183 task_request.init_new_request(request, True, None)
186 _result_summary = task_scheduler.schedule_request(request, None) 184 _result_summary = task_scheduler.schedule_request(request, None)
187 bot_dimensions = { 185 bot_dimensions = {
188 u'foo': [u'bar'], 186 u'foo': [u'bar'],
189 u'id': [u'localhost'], 187 u'id': [u'localhost'],
190 u'os': [u'Windows', u'Windows-3.1.1'], 188 u'os': [u'Windows', u'Windows-3.1.1'],
191 u'pool': [u'default'], 189 u'pool': [u'default'],
192 } 190 }
193 _register_bot(bot_dimensions) 191 self._register_bot(bot_dimensions)
194 actual_request, _, run_result = task_scheduler.bot_reap_task( 192 actual_request, _, run_result = task_scheduler.bot_reap_task(
195 bot_dimensions, 'abc', None) 193 bot_dimensions, 'abc', None)
196 self.assertEqual(request, actual_request) 194 self.assertEqual(request, actual_request)
197 self.assertEqual('localhost', run_result.bot_id) 195 self.assertEqual('localhost', run_result.bot_id)
198 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number) 196 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number)
199 197
200 def test_bot_reap_task_not_enough_time(self): 198 def test_bot_reap_task_not_enough_time(self):
201 request = _gen_request( 199 request = self._gen_request(
202 properties={ 200 properties={
203 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 201 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
204 }) 202 })
205 task_request.init_new_request(request, True, None) 203 task_request.init_new_request(request, True, None)
206 _result_summary = task_scheduler.schedule_request(request, None) 204 _result_summary = task_scheduler.schedule_request(request, None)
207 bot_dimensions = { 205 bot_dimensions = {
208 u'foo': [u'bar'], 206 u'foo': [u'bar'],
209 u'id': [u'localhost'], 207 u'id': [u'localhost'],
210 u'os': [u'Windows', u'Windows-3.1.1'], 208 u'os': [u'Windows', u'Windows-3.1.1'],
211 u'pool': [u'default'], 209 u'pool': [u'default'],
212 } 210 }
213 _register_bot(bot_dimensions) 211 self._register_bot(bot_dimensions)
214 actual_request, _, run_result = task_scheduler.bot_reap_task( 212 actual_request, _, run_result = task_scheduler.bot_reap_task(
215 bot_dimensions, 'abc', datetime.datetime(1969, 1, 1)) 213 bot_dimensions, 'abc', datetime.datetime(1969, 1, 1))
216 self.failIf(actual_request) 214 self.failIf(actual_request)
217 self.failIf(run_result) 215 self.failIf(run_result)
218 self.failUnless(task_to_run.TaskToRun.query().get().queue_number) 216 self.failUnless(task_to_run.TaskToRun.query().get().queue_number)
219 217
220 def test_bot_reap_task_enough_time(self): 218 def test_bot_reap_task_enough_time(self):
221 request = _gen_request( 219 request = self._gen_request(
222 properties={ 220 properties={
223 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 221 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
224 }) 222 })
225 task_request.init_new_request(request, True, None) 223 task_request.init_new_request(request, True, None)
226 _result_summary = task_scheduler.schedule_request(request, None) 224 _result_summary = task_scheduler.schedule_request(request, None)
227 bot_dimensions = { 225 bot_dimensions = {
228 u'foo': [u'bar'], 226 u'foo': [u'bar'],
229 u'id': [u'localhost'], 227 u'id': [u'localhost'],
230 u'os': [u'Windows', u'Windows-3.1.1'], 228 u'os': [u'Windows', u'Windows-3.1.1'],
231 u'pool': [u'default'], 229 u'pool': [u'default'],
232 } 230 }
233 _register_bot(bot_dimensions) 231 self._register_bot(bot_dimensions)
234 actual_request, _, run_result = task_scheduler.bot_reap_task( 232 actual_request, _, run_result = task_scheduler.bot_reap_task(
235 bot_dimensions, 'abc', datetime.datetime(3000, 1, 1)) 233 bot_dimensions, 'abc', datetime.datetime(3000, 1, 1))
236 self.assertEqual(request, actual_request) 234 self.assertEqual(request, actual_request)
237 self.assertEqual('localhost', run_result.bot_id) 235 self.assertEqual('localhost', run_result.bot_id)
238 self.failIf(task_to_run.TaskToRun.query().get().queue_number) 236 self.failIf(task_to_run.TaskToRun.query().get().queue_number)
239 237
240 def test_exponential_backoff(self): 238 def test_exponential_backoff(self):
241 self.mock( 239 self.mock(
242 task_scheduler.random, 'random', 240 task_scheduler.random, 'random',
243 lambda: task_scheduler._PROBABILITY_OF_QUICK_COMEBACK) 241 lambda: task_scheduler._PROBABILITY_OF_QUICK_COMEBACK)
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 }) 277 })
280 self.assertEqual([ 278 self.assertEqual([
281 { 279 {
282 'attributes': {'auth_token': 'token'}, 280 'attributes': {'auth_token': 'token'},
283 'message': '{"task_id":"abcdef123","userdata":"userdata"}', 281 'message': '{"task_id":"abcdef123","userdata":"userdata"}',
284 'topic': 'projects/abc/topics/def', 282 'topic': 'projects/abc/topics/def',
285 }], calls) 283 }], calls)
286 284
287 def _task_ran_successfully(self): 285 def _task_ran_successfully(self):
288 """Runs a task successfully and returns the task_id.""" 286 """Runs a task successfully and returns the task_id."""
289 request = _gen_request( 287 request = self._gen_request(
290 properties={ 288 properties={
291 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 289 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
292 'idempotent': True, 290 'idempotent': True,
293 }) 291 })
294 task_request.init_new_request(request, True, None) 292 task_request.init_new_request(request, True, None)
295 _result_summary = task_scheduler.schedule_request(request, None) 293 _result_summary = task_scheduler.schedule_request(request, None)
296 bot_dimensions = { 294 bot_dimensions = {
297 u'foo': [u'bar'], 295 u'foo': [u'bar'],
298 u'id': [u'localhost'], 296 u'id': [u'localhost'],
299 u'os': [u'Windows', u'Windows-3.1.1'], 297 u'os': [u'Windows', u'Windows-3.1.1'],
300 u'pool': [u'default'], 298 u'pool': [u'default'],
301 } 299 }
302 _register_bot(bot_dimensions) 300 self._register_bot(bot_dimensions)
303 actual_request, _, run_result = task_scheduler.bot_reap_task( 301 actual_request, _, run_result = task_scheduler.bot_reap_task(
304 bot_dimensions, 'abc', None) 302 bot_dimensions, 'abc', None)
305 self.assertEqual(request, actual_request) 303 self.assertEqual(request, actual_request)
306 self.assertEqual('localhost', run_result.bot_id) 304 self.assertEqual('localhost', run_result.bot_id)
307 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number) 305 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number)
308 # It's important to terminate the task with success. 306 # It's important to terminate the task with success.
309 self.assertEqual( 307 self.assertEqual(
310 task_result.State.COMPLETED, 308 task_result.State.COMPLETED,
311 task_scheduler.bot_update_task( 309 task_scheduler.bot_update_task(
312 run_result_key=run_result.key, 310 run_result_key=run_result.key,
313 bot_id='localhost', 311 bot_id='localhost',
314 cipd_pins=None, 312 cipd_pins=None,
315 output='Foo1', 313 output='Foo1',
316 output_chunk_start=0, 314 output_chunk_start=0,
317 exit_code=0, 315 exit_code=0,
318 duration=0.1, 316 duration=0.1,
319 hard_timeout=False, 317 hard_timeout=False,
320 io_timeout=False, 318 io_timeout=False,
321 cost_usd=0.1, 319 cost_usd=0.1,
322 outputs_ref=None, 320 outputs_ref=None,
323 performance_stats=None)) 321 performance_stats=None))
324 return unicode(run_result.task_id) 322 return unicode(run_result.task_id)
325 323
326 def _task_deduped(self, new_ts, deduped_from, task_id, nb_queues, now=None): 324 def _task_deduped(self, new_ts, deduped_from, task_id, nb_task=0, now=None):
327 request = _gen_request( 325 request = self._gen_request(
328 name='yay', 326 name='yay',
329 user='Raoul', 327 user='Raoul',
330 properties={ 328 properties={
331 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 329 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
332 'idempotent': True, 330 'idempotent': True,
333 }) 331 })
334 task_request.init_new_request(request, True, None) 332 task_request.init_new_request(request, True, None)
335 _result_summary = task_scheduler.schedule_request(request, None) 333 _result_summary = task_scheduler.schedule_request(request, None)
336 bot_dimensions = { 334 bot_dimensions = {
337 u'foo': [u'bar'], 335 u'foo': [u'bar'],
338 u'id': [u'localhost'], 336 u'id': [u'localhost'],
339 u'os': [u'Windows', u'Windows-3.1.1'], 337 u'os': [u'Windows', u'Windows-3.1.1'],
340 u'pool': [u'default'], 338 u'pool': [u'default'],
341 } 339 }
342 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number) 340 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number)
343 _register_bot(bot_dimensions) 341 self._register_bot(bot_dimensions, nb_task=nb_task)
344 actual_request_2, _, run_result_2 = task_scheduler.bot_reap_task( 342 actual_request_2, _, run_result_2 = task_scheduler.bot_reap_task(
345 bot_dimensions, 'abc', None) 343 bot_dimensions, 'abc', None)
346 self.assertEqual(None, actual_request_2) 344 self.assertEqual(None, actual_request_2)
347 self.assertEqual(nb_queues, self.execute_tasks())
348 result_summary_duped, run_results_duped = get_results(request.key) 345 result_summary_duped, run_results_duped = get_results(request.key)
349 expected = { 346 expected = {
350 'abandoned_ts': None, 347 'abandoned_ts': None,
351 'bot_dimensions': bot_dimensions, 348 'bot_dimensions': bot_dimensions,
352 'bot_id': u'localhost', 349 'bot_id': u'localhost',
353 'bot_version': u'abc', 350 'bot_version': u'abc',
354 'cipd_pins': None, 351 'cipd_pins': None,
355 'children_task_ids': [], 352 'children_task_ids': [],
356 'completed_ts': now or self.now, 353 'completed_ts': now or self.now,
357 'costs_usd': [], 354 'costs_usd': [],
(...skipping 28 matching lines...) Expand all
386 } 383 }
387 self.assertEqual(expected, result_summary_duped.to_dict()) 384 self.assertEqual(expected, result_summary_duped.to_dict())
388 self.assertEqual([], run_results_duped) 385 self.assertEqual([], run_results_duped)
389 386
390 def test_task_idempotent(self): 387 def test_task_idempotent(self):
391 # First task is idempotent. 388 # First task is idempotent.
392 task_id = self._task_ran_successfully() 389 task_id = self._task_ran_successfully()
393 390
394 # Second task is deduped against first task. 391 # Second task is deduped against first task.
395 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs-1) 392 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs-1)
396 self._task_deduped(new_ts, task_id, '1d8dc670a0008a10', 0) 393 self._task_deduped(new_ts, task_id, '1d8dc670a0008a10')
397 394
398 def test_task_idempotent_old(self): 395 def test_task_idempotent_old(self):
399 # First task is idempotent. 396 # First task is idempotent.
400 self._task_ran_successfully() 397 self._task_ran_successfully()
401 398
402 # Second task is scheduled, first task is too old to be reused. 399 # Second task is scheduled, first task is too old to be reused.
403 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs) 400 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs)
404 request = _gen_request( 401 request = self._gen_request(
405 name='yay', 402 name='yay',
406 user='Raoul', 403 user='Raoul',
407 properties={ 404 properties={
408 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 405 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
409 'idempotent': True, 406 'idempotent': True,
410 }) 407 })
411 task_request.init_new_request(request, True, None) 408 task_request.init_new_request(request, True, None)
412 _result_summary = task_scheduler.schedule_request(request, None) 409 _result_summary = task_scheduler.schedule_request(request, None)
413 # The task was enqueued for execution. 410 # The task was enqueued for execution.
414 self.assertNotEqual(None, task_to_run.TaskToRun.query().get().queue_number) 411 self.assertNotEqual(None, task_to_run.TaskToRun.query().get().queue_number)
415 412
416 def test_task_idempotent_three(self): 413 def test_task_idempotent_three(self):
417 # First task is idempotent. 414 # First task is idempotent.
418 task_id = self._task_ran_successfully() 415 task_id = self._task_ran_successfully()
419 416
420 # Second task is deduped against first task. 417 # Second task is deduped against first task.
421 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs-1) 418 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs-1)
422 self._task_deduped(new_ts, task_id, '1d8dc670a0008a10', 0) 419 self._task_deduped(new_ts, task_id, '1d8dc670a0008a10')
423 420
424 # Third task is scheduled, second task is not dedupable, first task is too 421 # Third task is scheduled, second task is not dedupable, first task is too
425 # old. 422 # old.
426 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs) 423 new_ts = self.mock_now(self.now, config.settings().reusable_task_age_secs)
427 request = _gen_request( 424 request = self._gen_request(
428 name='yay', 425 name='yay',
429 user='Jesus', 426 user='Jesus',
430 properties={ 427 properties={
431 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 428 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
432 'idempotent': True, 429 'idempotent': True,
433 }) 430 })
434 task_request.init_new_request(request, True, None) 431 task_request.init_new_request(request, True, None)
435 _result_summary = task_scheduler.schedule_request(request, None) 432 _result_summary = task_scheduler.schedule_request(request, None)
436 # The task was enqueued for execution. 433 # The task was enqueued for execution.
437 self.assertNotEqual(None, task_to_run.TaskToRun.query().get().queue_number) 434 self.assertNotEqual(None, task_to_run.TaskToRun.query().get().queue_number)
(...skipping 12 matching lines...) Expand all
450 second_ts = self.mock_now(self.now, 10) 447 second_ts = self.mock_now(self.now, 10)
451 task_id = self._task_ran_successfully() 448 task_id = self._task_ran_successfully()
452 449
453 # Now any of the 2 tasks could be reused. Assert the right one (the most 450 # Now any of the 2 tasks could be reused. Assert the right one (the most
454 # recent) is reused. 451 # recent) is reused.
455 cfg.reusable_task_age_secs = 100 452 cfg.reusable_task_age_secs = 100
456 453
457 # Third task is deduped against second task. That ensures ordering works 454 # Third task is deduped against second task. That ensures ordering works
458 # correctly. 455 # correctly.
459 third_ts = self.mock_now(self.now, 20) 456 third_ts = self.mock_now(self.now, 20)
460 self._task_deduped(third_ts, task_id, '1d69ba3ea8008b10', 0, second_ts) 457 self._task_deduped(third_ts, task_id, '1d69ba3ea8008b10', now=second_ts)
461 458
462 def test_task_parent_children(self): 459 def test_task_parent_children(self):
463 # Parent task creates a child task. 460 # Parent task creates a child task.
464 parent_id = self._task_ran_successfully() 461 parent_id = self._task_ran_successfully()
465 request = _gen_request( 462 request = self._gen_request(
466 parent_task_id=parent_id, 463 parent_task_id=parent_id,
467 properties={ 464 properties={
468 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 465 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
469 }) 466 })
470 task_request.init_new_request(request, True, None) 467 task_request.init_new_request(request, True, None)
471 result_summary = task_scheduler.schedule_request(request, None) 468 result_summary = task_scheduler.schedule_request(request, None)
472 self.assertEqual([], result_summary.children_task_ids) 469 self.assertEqual([], result_summary.children_task_ids)
473 self.assertEqual(parent_id, request.parent_task_id) 470 self.assertEqual(parent_id, request.parent_task_id)
474 471
475 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)
476 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(
477 parent_run_result_key) 474 parent_run_result_key)
478 expected = [result_summary.task_id] 475 expected = [result_summary.task_id]
479 self.assertEqual(expected, parent_run_result_key.get().children_task_ids) 476 self.assertEqual(expected, parent_run_result_key.get().children_task_ids)
480 self.assertEqual(expected, parent_res_summary_key.get().children_task_ids) 477 self.assertEqual(expected, parent_res_summary_key.get().children_task_ids)
481 478
482 def test_task_parent_isolated(self): 479 def test_task_parent_isolated(self):
483 request = _gen_request( 480 request = self._gen_request(
484 properties={ 481 properties={
485 'command': [], 482 'command': [],
486 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 483 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
487 'inputs_ref': { 484 'inputs_ref': {
488 'isolated': '1' * 40, 485 'isolated': '1' * 40,
489 'isolatedserver': 'http://localhost:1', 486 'isolatedserver': 'http://localhost:1',
490 'namespace': 'default-gzip', 487 'namespace': 'default-gzip',
491 }, 488 },
492 }) 489 })
493 task_request.init_new_request(request, True, None) 490 task_request.init_new_request(request, True, None)
494 _result_summary = task_scheduler.schedule_request(request, None) 491 _result_summary = task_scheduler.schedule_request(request, None)
495 bot_dimensions = { 492 bot_dimensions = {
496 u'foo': [u'bar'], 493 u'foo': [u'bar'],
497 u'id': [u'localhost'], 494 u'id': [u'localhost'],
498 u'os': [u'Windows', u'Windows-3.1.1'], 495 u'os': [u'Windows', u'Windows-3.1.1'],
499 u'pool': [u'default'], 496 u'pool': [u'default'],
500 } 497 }
501 _register_bot(bot_dimensions) 498 self._register_bot(bot_dimensions)
502 actual_request, _, run_result = task_scheduler.bot_reap_task( 499 actual_request, _, run_result = task_scheduler.bot_reap_task(
503 bot_dimensions, 'abc', None) 500 bot_dimensions, 'abc', None)
504 self.assertEqual(request, actual_request) 501 self.assertEqual(request, actual_request)
505 self.assertEqual('localhost', run_result.bot_id) 502 self.assertEqual('localhost', run_result.bot_id)
506 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number) 503 self.assertEqual(None, task_to_run.TaskToRun.query().get().queue_number)
507 # It's important to terminate the task with success. 504 # It's important to terminate the task with success.
508 self.assertEqual( 505 self.assertEqual(
509 task_result.State.COMPLETED, 506 task_result.State.COMPLETED,
510 task_scheduler.bot_update_task( 507 task_scheduler.bot_update_task(
511 run_result_key=run_result.key, 508 run_result_key=run_result.key,
512 bot_id='localhost', 509 bot_id='localhost',
513 cipd_pins=None, 510 cipd_pins=None,
514 output='Foo1', 511 output='Foo1',
515 output_chunk_start=0, 512 output_chunk_start=0,
516 exit_code=0, 513 exit_code=0,
517 duration=0.1, 514 duration=0.1,
518 hard_timeout=False, 515 hard_timeout=False,
519 io_timeout=False, 516 io_timeout=False,
520 cost_usd=0.1, 517 cost_usd=0.1,
521 outputs_ref=None, 518 outputs_ref=None,
522 performance_stats=None)) 519 performance_stats=None))
523 520
524 parent_id = run_result.task_id 521 parent_id = run_result.task_id
525 request = _gen_request( 522 request = self._gen_request(
526 parent_task_id=parent_id, 523 parent_task_id=parent_id,
527 properties={ 524 properties={
528 'dimensions':{u'os': u'Windows-3.1.1', u'pool': u'default'}, 525 'dimensions':{u'os': u'Windows-3.1.1', u'pool': u'default'},
529 }) 526 })
530 task_request.init_new_request(request, True, None) 527 task_request.init_new_request(request, True, None)
531 result_summary = task_scheduler.schedule_request(request, None) 528 result_summary = task_scheduler.schedule_request(request, None)
532 self.assertEqual([], result_summary.children_task_ids) 529 self.assertEqual([], result_summary.children_task_ids)
533 self.assertEqual(parent_id, request.parent_task_id) 530 self.assertEqual(parent_id, request.parent_task_id)
534 531
535 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)
536 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(
537 parent_run_result_key) 534 parent_run_result_key)
538 expected = [result_summary.task_id] 535 expected = [result_summary.task_id]
539 self.assertEqual(expected, parent_run_result_key.get().children_task_ids) 536 self.assertEqual(expected, parent_run_result_key.get().children_task_ids)
540 self.assertEqual(expected, parent_res_summary_key.get().children_task_ids) 537 self.assertEqual(expected, parent_res_summary_key.get().children_task_ids)
541 538
542 def test_get_results(self): 539 def test_get_results(self):
543 # TODO(maruel): Split in more focused tests. 540 # TODO(maruel): Split in more focused tests.
544 created_ts = self.now 541 created_ts = self.now
545 self.mock_now(created_ts) 542 self.mock_now(created_ts)
546 request = _gen_request( 543 request = self._gen_request(
547 properties={ 544 properties={
548 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 545 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
549 }) 546 })
550 task_request.init_new_request(request, True, None) 547 task_request.init_new_request(request, True, None)
551 _result_summary = task_scheduler.schedule_request(request, None) 548 _result_summary = task_scheduler.schedule_request(request, None)
552 549
553 # The TaskRequest was enqueued, the TaskResultSummary was created but no 550 # The TaskRequest was enqueued, the TaskResultSummary was created but no
554 # 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.
555 result_summary, run_results = get_results(request.key) 552 result_summary, run_results = get_results(request.key)
556 expected = { 553 expected = {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 self.assertEqual([], run_results) 589 self.assertEqual([], run_results)
593 590
594 # A bot reaps the TaskToRun. 591 # A bot reaps the TaskToRun.
595 reaped_ts = self.now + datetime.timedelta(seconds=60) 592 reaped_ts = self.now + datetime.timedelta(seconds=60)
596 self.mock_now(reaped_ts) 593 self.mock_now(reaped_ts)
597 bot_dimensions = { 594 bot_dimensions = {
598 u'id': [u'localhost'], 595 u'id': [u'localhost'],
599 u'os': [u'Windows-3.1.1'], 596 u'os': [u'Windows-3.1.1'],
600 u'pool': [u'default'], 597 u'pool': [u'default'],
601 } 598 }
602 _register_bot(bot_dimensions) 599 self._register_bot(bot_dimensions)
603 reaped_request, _, run_result = task_scheduler.bot_reap_task( 600 reaped_request, _, run_result = task_scheduler.bot_reap_task(
604 bot_dimensions, 'abc', None) 601 bot_dimensions, 'abc', None)
605 self.assertEqual(request, reaped_request) 602 self.assertEqual(request, reaped_request)
606 self.assertTrue(run_result) 603 self.assertTrue(run_result)
607 result_summary, run_results = get_results(request.key) 604 result_summary, run_results = get_results(request.key)
608 expected = { 605 expected = {
609 'abandoned_ts': None, 606 'abandoned_ts': None,
610 'bot_dimensions': bot_dimensions, 607 'bot_dimensions': bot_dimensions,
611 'bot_id': u'localhost', 608 'bot_id': u'localhost',
612 'bot_version': u'abc', 609 'bot_version': u'abc',
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 }, 776 },
780 'server_versions': [u'v1a'], 777 'server_versions': [u'v1a'],
781 'started_ts': reaped_ts, 778 'started_ts': reaped_ts,
782 'state': State.COMPLETED, 779 'state': State.COMPLETED,
783 'try_number': 1, 780 'try_number': 1,
784 }, 781 },
785 ] 782 ]
786 self.assertEqual(expected, [t.to_dict() for t in run_results]) 783 self.assertEqual(expected, [t.to_dict() for t in run_results])
787 784
788 def test_exit_code_failure(self): 785 def test_exit_code_failure(self):
789 request = _gen_request( 786 request = self._gen_request(
790 properties={ 787 properties={
791 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 788 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
792 }) 789 })
793 task_request.init_new_request(request, True, None) 790 task_request.init_new_request(request, True, None)
794 _result_summary = task_scheduler.schedule_request(request, None) 791 _result_summary = task_scheduler.schedule_request(request, None)
795 bot_dimensions = { 792 bot_dimensions = {
796 u'id': [u'localhost'], 793 u'id': [u'localhost'],
797 u'os': [u'Windows-3.1.1'], 794 u'os': [u'Windows-3.1.1'],
798 u'pool': [u'default'], 795 u'pool': [u'default'],
799 } 796 }
800 _register_bot(bot_dimensions) 797 self._register_bot(bot_dimensions)
801 reaped_request, _, run_result = task_scheduler.bot_reap_task( 798 reaped_request, _, run_result = task_scheduler.bot_reap_task(
802 bot_dimensions, 'abc', None) 799 bot_dimensions, 'abc', None)
803 self.assertEqual(request, reaped_request) 800 self.assertEqual(request, reaped_request)
804 self.assertEqual( 801 self.assertEqual(
805 task_result.State.COMPLETED, 802 task_result.State.COMPLETED,
806 task_scheduler.bot_update_task( 803 task_scheduler.bot_update_task(
807 run_result_key=run_result.key, 804 run_result_key=run_result.key,
808 bot_id='localhost', 805 bot_id='localhost',
809 cipd_pins=None, 806 cipd_pins=None,
810 output='Foo1', 807 output='Foo1',
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
876 'started_ts': self.now, 873 'started_ts': self.now,
877 'state': State.COMPLETED, 874 'state': State.COMPLETED,
878 'try_number': 1, 875 'try_number': 1,
879 }, 876 },
880 ] 877 ]
881 self.assertEqual(expected, [t.to_dict() for t in run_results]) 878 self.assertEqual(expected, [t.to_dict() for t in run_results])
882 879
883 def test_schedule_request(self): 880 def test_schedule_request(self):
884 # It is tested indirectly in the other functions. 881 # It is tested indirectly in the other functions.
885 self.assertTrue( 882 self.assertTrue(
886 _quick_schedule({u'os': u'Windows-3.1.1', u'pool': u'default'})) 883 self._quick_schedule({u'os': u'Windows-3.1.1', u'pool': u'default'}))
887 884
888 def mock_dim_acls(self, mapping): 885 def mock_dim_acls(self, mapping):
889 self.mock(config, 'settings', lambda: config_pb2.SettingsCfg( 886 self.mock(config, 'settings', lambda: config_pb2.SettingsCfg(
890 dimension_acls=config_pb2.DimensionACLs(entry=[ 887 dimension_acls=config_pb2.DimensionACLs(entry=[
891 config_pb2.DimensionACLs.Entry(dimension=[d], usable_by=g) 888 config_pb2.DimensionACLs.Entry(dimension=[d], usable_by=g)
892 for d, g in sorted(mapping.iteritems()) 889 for d, g in sorted(mapping.iteritems())
893 ]), 890 ]),
894 )) 891 ))
895 892
896 def test_schedule_request_forbidden_dim(self): 893 def test_schedule_request_forbidden_dim(self):
897 self.mock_dim_acls({u'pool:bad': u'noone'}) 894 self.mock_dim_acls({u'pool:bad': u'noone'})
898 _quick_schedule({u'pool': u'good'}) 895 self._quick_schedule({u'pool': u'good'})
899 with self.assertRaises(auth.AuthorizationError): 896 with self.assertRaises(auth.AuthorizationError):
900 _quick_schedule({u'pool': u'bad'}) 897 self._quick_schedule({u'pool': u'bad'})
901 898
902 def test_schedule_request_forbidden_dim_via_star(self): 899 def test_schedule_request_forbidden_dim_via_star(self):
903 self.mock_dim_acls({u'abc:*': u'noone'}) 900 self.mock_dim_acls({u'abc:*': u'noone'})
904 _quick_schedule({u'pool': u'default'}) 901 self._quick_schedule({u'pool': u'default'})
905 with self.assertRaises(auth.AuthorizationError): 902 with self.assertRaises(auth.AuthorizationError):
906 _quick_schedule({u'pool': u'default', u'abc': u'blah'}) 903 self._quick_schedule({u'pool': u'default', u'abc': u'blah'})
907 904
908 def test_schedule_request_id_without_pool(self): 905 def test_schedule_request_id_without_pool(self):
909 self.mock_dim_acls({u'pool:good': u'mocked'}) 906 self.mock_dim_acls({u'pool:good': u'mocked'})
910 with self.assertRaises(auth.AuthorizationError): 907 with self.assertRaises(auth.AuthorizationError):
911 _quick_schedule({u'id': u'abc'}) 908 self._quick_schedule({u'id': u'abc'})
912 auth_testing.mock_is_admin(self) 909 auth_testing.mock_is_admin(self)
913 _quick_schedule({u'id': u'abc'}) 910 self._quick_schedule({u'id': u'abc'})
914 911
915 def test_schedule_request_id_and_pool(self): 912 def test_schedule_request_id_and_pool(self):
916 self.mock_dim_acls({u'pool:good': u'mocked'}) 913 self.mock_dim_acls({u'pool:good': u'mocked'})
917 self.mock_dim_acls({u'pool:bad': u'unknown'}) 914 self.mock_dim_acls({u'pool:bad': u'unknown'})
918 915
919 def mocked_is_group_member(group, ident): 916 def mocked_is_group_member(group, ident):
920 if group == 'mocked' and ident == auth_testing.DEFAULT_MOCKED_IDENTITY: 917 if group == 'mocked' and ident == auth_testing.DEFAULT_MOCKED_IDENTITY:
921 return True 918 return True
922 return False 919 return False
923 self.mock(auth, 'is_group_member', mocked_is_group_member) 920 self.mock(auth, 'is_group_member', mocked_is_group_member)
924 921
925 _quick_schedule({u'id': u'abc', u'pool': u'unknown'}) 922 self._quick_schedule({u'id': u'abc', u'pool': u'unknown'})
926 _quick_schedule({u'id': u'abc', u'pool': u'good'}) 923 self._quick_schedule({u'id': u'abc', u'pool': u'good'})
927 with self.assertRaises(auth.AuthorizationError): 924 with self.assertRaises(auth.AuthorizationError):
928 _quick_schedule({u'id': u'abc', u'pool': u'bad'}) 925 self._quick_schedule({u'id': u'abc', u'pool': u'bad'})
929 926
930 def test_bot_update_task(self): 927 def test_bot_update_task(self):
931 run_result = _quick_reap() 928 run_result = self._quick_reap()
932 self.assertEqual( 929 self.assertEqual(
933 task_result.State.RUNNING, 930 task_result.State.RUNNING,
934 task_scheduler.bot_update_task( 931 task_scheduler.bot_update_task(
935 run_result_key=run_result.key, 932 run_result_key=run_result.key,
936 bot_id='localhost', 933 bot_id='localhost',
937 cipd_pins=None, 934 cipd_pins=None,
938 output='hi', 935 output='hi',
939 output_chunk_start=0, 936 output_chunk_start=0,
940 exit_code=None, 937 exit_code=None,
941 duration=None, 938 duration=None,
(...skipping 13 matching lines...) Expand all
955 exit_code=0, 952 exit_code=0,
956 duration=0.1, 953 duration=0.1,
957 hard_timeout=False, 954 hard_timeout=False,
958 io_timeout=False, 955 io_timeout=False,
959 cost_usd=0.1, 956 cost_usd=0.1,
960 outputs_ref=None, 957 outputs_ref=None,
961 performance_stats=None)) 958 performance_stats=None))
962 self.assertEqual('hihey', run_result.key.get().get_output()) 959 self.assertEqual('hihey', run_result.key.get().get_output())
963 960
964 def test_bot_update_task_new_overwrite(self): 961 def test_bot_update_task_new_overwrite(self):
965 run_result = _quick_reap() 962 run_result = self._quick_reap()
966 self.assertEqual( 963 self.assertEqual(
967 task_result.State.RUNNING, 964 task_result.State.RUNNING,
968 task_scheduler.bot_update_task( 965 task_scheduler.bot_update_task(
969 run_result_key=run_result.key, 966 run_result_key=run_result.key,
970 bot_id='localhost', 967 bot_id='localhost',
971 cipd_pins=None, 968 cipd_pins=None,
972 output='hi', 969 output='hi',
973 output_chunk_start=0, 970 output_chunk_start=0,
974 exit_code=None, 971 exit_code=None,
975 duration=None, 972 duration=None,
(...skipping 13 matching lines...) Expand all
989 exit_code=None, 986 exit_code=None,
990 duration=None, 987 duration=None,
991 hard_timeout=False, 988 hard_timeout=False,
992 io_timeout=False, 989 io_timeout=False,
993 cost_usd=0.1, 990 cost_usd=0.1,
994 outputs_ref=None, 991 outputs_ref=None,
995 performance_stats=None)) 992 performance_stats=None))
996 self.assertEqual('hhey', run_result.key.get().get_output()) 993 self.assertEqual('hhey', run_result.key.get().get_output())
997 994
998 def test_bot_update_exception(self): 995 def test_bot_update_exception(self):
999 run_result = _quick_reap() 996 run_result = self._quick_reap()
1000 def r(*_): 997 def r(*_):
1001 raise datastore_utils.CommitError('Sorry!') 998 raise datastore_utils.CommitError('Sorry!')
1002 999
1003 self.mock(ndb, 'put_multi', r) 1000 self.mock(ndb, 'put_multi', r)
1004 self.assertEqual( 1001 self.assertEqual(
1005 None, 1002 None,
1006 task_scheduler.bot_update_task( 1003 task_scheduler.bot_update_task(
1007 run_result_key=run_result.key, 1004 run_result_key=run_result.key,
1008 bot_id='localhost', 1005 bot_id='localhost',
1009 cipd_pins=None, 1006 cipd_pins=None,
1010 output='hi', 1007 output='hi',
1011 output_chunk_start=0, 1008 output_chunk_start=0,
1012 exit_code=0, 1009 exit_code=0,
1013 duration=0.1, 1010 duration=0.1,
1014 hard_timeout=False, 1011 hard_timeout=False,
1015 io_timeout=False, 1012 io_timeout=False,
1016 cost_usd=0.1, 1013 cost_usd=0.1,
1017 outputs_ref=None, 1014 outputs_ref=None,
1018 performance_stats=None)) 1015 performance_stats=None))
1019 1016
1020 def test_bot_update_pubsub_error(self): 1017 def test_bot_update_pubsub_error(self):
1021 pub_sub_calls = self.mock_pub_sub() 1018 pub_sub_calls = self.mock_pub_sub()
1022 request = _gen_request( 1019 request = self._gen_request(
1023 properties={ 1020 properties={
1024 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1021 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1025 }, 1022 },
1026 pubsub_topic='projects/abc/topics/def') 1023 pubsub_topic='projects/abc/topics/def')
1027 task_request.init_new_request(request, True, None) 1024 task_request.init_new_request(request, True, None)
1028 task_scheduler.schedule_request(request, None) 1025 task_scheduler.schedule_request(request, None)
1029 bot_dimensions = { 1026 bot_dimensions = {
1030 u'foo': [u'bar'], 1027 u'foo': [u'bar'],
1031 u'id': [u'localhost'], 1028 u'id': [u'localhost'],
1032 u'os': [u'Windows', u'Windows-3.1.1'], 1029 u'os': [u'Windows', u'Windows-3.1.1'],
1033 u'pool': [u'default'], 1030 u'pool': [u'default'],
1034 } 1031 }
1035 _register_bot(bot_dimensions) 1032 self._register_bot(bot_dimensions)
1036 _, _, run_result = task_scheduler.bot_reap_task( 1033 _, _, run_result = task_scheduler.bot_reap_task(
1037 bot_dimensions, 'abc', None) 1034 bot_dimensions, 'abc', None)
1038 self.assertEqual('localhost', run_result.bot_id) 1035 self.assertEqual('localhost', run_result.bot_id)
1039 self.assertEqual(1, self.execute_tasks())
1040 1036
1041 # Attempt to terminate the task with success, but make PubSub call fail. 1037 # Attempt to terminate the task with success, but make PubSub call fail.
1042 self.publish_successful = False 1038 self.publish_successful = False
1043 self.assertEqual( 1039 self.assertEqual(
1044 None, 1040 None,
1045 task_scheduler.bot_update_task( 1041 task_scheduler.bot_update_task(
1046 run_result_key=run_result.key, 1042 run_result_key=run_result.key,
1047 bot_id='localhost', 1043 bot_id='localhost',
1048 cipd_pins=None, 1044 cipd_pins=None,
1049 output='Foo1', 1045 output='Foo1',
1050 output_chunk_start=0, 1046 output_chunk_start=0,
1051 exit_code=0, 1047 exit_code=0,
1052 duration=0.1, 1048 duration=0.1,
1053 hard_timeout=False, 1049 hard_timeout=False,
1054 io_timeout=False, 1050 io_timeout=False,
1055 cost_usd=0.1, 1051 cost_usd=0.1,
1056 outputs_ref=None, 1052 outputs_ref=None,
1057 performance_stats=None)) 1053 performance_stats=None))
1058 self.assertEqual(0, self.execute_tasks()) 1054 self.assertEqual(1, self.execute_tasks(status=500))
1059 1055
1060 # Bot retries bot_update, now PubSub works and notification is sent. 1056 # Bot retries bot_update, now PubSub works and notification is sent.
1061 self.publish_successful = True 1057 self.publish_successful = True
1062 self.assertEqual( 1058 self.assertEqual(
1063 task_result.State.COMPLETED, 1059 task_result.State.COMPLETED,
1064 task_scheduler.bot_update_task( 1060 task_scheduler.bot_update_task(
1065 run_result_key=run_result.key, 1061 run_result_key=run_result.key,
1066 bot_id='localhost', 1062 bot_id='localhost',
1067 cipd_pins=None, 1063 cipd_pins=None,
1068 output='Foo1', 1064 output='Foo1',
1069 output_chunk_start=0, 1065 output_chunk_start=0,
1070 exit_code=0, 1066 exit_code=0,
1071 duration=0.1, 1067 duration=0.1,
1072 hard_timeout=False, 1068 hard_timeout=False,
1073 io_timeout=False, 1069 io_timeout=False,
1074 cost_usd=0.1, 1070 cost_usd=0.1,
1075 outputs_ref=None, 1071 outputs_ref=None,
1076 performance_stats=None)) 1072 performance_stats=None))
1077 self.assertEqual(0, self.execute_tasks()) 1073 self.assertEqual(0, self.execute_tasks())
1078 self.assertEqual(2, len(pub_sub_calls)) # notification is sent 1074 self.assertEqual(1, len(pub_sub_calls)) # notification is sent
1079 1075
1080 def _bot_update_timeouts(self, hard, io): 1076 def _bot_update_timeouts(self, hard, io):
1081 request = _gen_request( 1077 request = self._gen_request(
1082 properties={ 1078 properties={
1083 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1079 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1084 }) 1080 })
1085 task_request.init_new_request(request, True, None) 1081 task_request.init_new_request(request, True, None)
1086 result_summary = task_scheduler.schedule_request(request, None) 1082 result_summary = task_scheduler.schedule_request(request, None)
1087 bot_dimensions = { 1083 bot_dimensions = {
1088 u'id': [u'localhost'], 1084 u'id': [u'localhost'],
1089 u'os': [u'Windows-3.1.1'], 1085 u'os': [u'Windows-3.1.1'],
1090 u'pool': [u'default'], 1086 u'pool': [u'default'],
1091 } 1087 }
1092 _register_bot(bot_dimensions) 1088 self._register_bot(bot_dimensions)
1093 reaped_request, _, run_result = task_scheduler.bot_reap_task( 1089 reaped_request, _, run_result = task_scheduler.bot_reap_task(
1094 bot_dimensions, 'abc', None) 1090 bot_dimensions, 'abc', None)
1095 self.assertEqual( 1091 self.assertEqual(
1096 task_result.State.TIMED_OUT, 1092 task_result.State.TIMED_OUT,
1097 task_scheduler.bot_update_task( 1093 task_scheduler.bot_update_task(
1098 run_result_key=run_result.key, 1094 run_result_key=run_result.key,
1099 bot_id='localhost', 1095 bot_id='localhost',
1100 cipd_pins=None, 1096 cipd_pins=None,
1101 output='hi', 1097 output='hi',
1102 output_chunk_start=0, 1098 output_chunk_start=0,
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1169 1165
1170 def test_bot_update_hard_timeout(self): 1166 def test_bot_update_hard_timeout(self):
1171 self._bot_update_timeouts(True, False) 1167 self._bot_update_timeouts(True, False)
1172 1168
1173 def test_bot_update_io_timeout(self): 1169 def test_bot_update_io_timeout(self):
1174 self._bot_update_timeouts(False, True) 1170 self._bot_update_timeouts(False, True)
1175 1171
1176 def test_bot_kill_task(self): 1172 def test_bot_kill_task(self):
1177 pub_sub_calls = self.mock_pub_sub() 1173 pub_sub_calls = self.mock_pub_sub()
1178 dimensions = {u'os': u'Windows-3.1.1', u'pool': u'default'} 1174 dimensions = {u'os': u'Windows-3.1.1', u'pool': u'default'}
1179 request = _gen_request( 1175 request = self._gen_request(
1180 properties={'dimensions': dimensions}, 1176 properties={'dimensions': dimensions},
1181 pubsub_topic='projects/abc/topics/def') 1177 pubsub_topic='projects/abc/topics/def')
1182 task_request.init_new_request(request, True, None) 1178 task_request.init_new_request(request, True, None)
1183 result_summary = task_scheduler.schedule_request(request, None) 1179 result_summary = task_scheduler.schedule_request(request, None)
1184 bot_dimensions = { 1180 bot_dimensions = {
1185 u'id': [u'localhost'], 1181 u'id': [u'localhost'],
1186 u'os': [u'Windows-3.1.1'], 1182 u'os': [u'Windows-3.1.1'],
1187 u'pool': [u'default'], 1183 u'pool': [u'default'],
1188 } 1184 }
1189 _register_bot(bot_dimensions) 1185 self._register_bot(bot_dimensions)
1190 reaped_request, _, run_result = task_scheduler.bot_reap_task( 1186 reaped_request, _, run_result = task_scheduler.bot_reap_task(
1191 bot_dimensions, 'abc', None) 1187 bot_dimensions, 'abc', None)
1192 self.assertEqual(1, self.execute_tasks()) 1188 self.assertEqual(1, self.execute_tasks())
1193 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING 1189 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING
1194 1190
1195 self.assertEqual( 1191 self.assertEqual(
1196 None, task_scheduler.bot_kill_task(run_result.key, 'localhost')) 1192 None, task_scheduler.bot_kill_task(run_result.key, 'localhost'))
1197 expected = { 1193 expected = {
1198 'abandoned_ts': self.now, 1194 'abandoned_ts': self.now,
1199 'bot_dimensions': bot_dimensions, 1195 'bot_dimensions': bot_dimensions,
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1249 'server_versions': [u'v1a'], 1245 'server_versions': [u'v1a'],
1250 'started_ts': self.now, 1246 'started_ts': self.now,
1251 'state': State.BOT_DIED, 1247 'state': State.BOT_DIED,
1252 'try_number': 1, 1248 'try_number': 1,
1253 } 1249 }
1254 self.assertEqual(expected, run_result.key.get().to_dict()) 1250 self.assertEqual(expected, run_result.key.get().to_dict())
1255 self.assertEqual(1, self.execute_tasks()) 1251 self.assertEqual(1, self.execute_tasks())
1256 self.assertEqual(2, len(pub_sub_calls)) # RUNNING -> BOT_DIED 1252 self.assertEqual(2, len(pub_sub_calls)) # RUNNING -> BOT_DIED
1257 1253
1258 def test_bot_kill_task_wrong_bot(self): 1254 def test_bot_kill_task_wrong_bot(self):
1259 request = _gen_request( 1255 request = self._gen_request(
1260 properties={ 1256 properties={
1261 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1257 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1262 }) 1258 })
1263 task_request.init_new_request(request, True, None) 1259 task_request.init_new_request(request, True, None)
1264 result_summary = task_scheduler.schedule_request(request, None) 1260 result_summary = task_scheduler.schedule_request(request, None)
1265 bot_dimensions = { 1261 bot_dimensions = {
1266 u'id': [u'localhost'], 1262 u'id': [u'localhost'],
1267 u'os': [u'Windows-3.1.1'], 1263 u'os': [u'Windows-3.1.1'],
1268 u'pool': [u'default'], 1264 u'pool': [u'default'],
1269 } 1265 }
1270 _register_bot(bot_dimensions) 1266 self._register_bot(bot_dimensions)
1271 reaped_request, _, run_result = task_scheduler.bot_reap_task( 1267 reaped_request, _, run_result = task_scheduler.bot_reap_task(
1272 bot_dimensions, 'abc', None) 1268 bot_dimensions, 'abc', None)
1273 expected = ( 1269 expected = (
1274 'Bot bot1 sent task kill for task 1d69b9f088008911 owned by bot ' 1270 'Bot bot1 sent task kill for task 1d69b9f088008911 owned by bot '
1275 'localhost') 1271 'localhost')
1276 self.assertEqual( 1272 self.assertEqual(
1277 expected, task_scheduler.bot_kill_task(run_result.key, 'bot1')) 1273 expected, task_scheduler.bot_kill_task(run_result.key, 'bot1'))
1278 1274
1279 def test_cancel_task(self): 1275 def test_cancel_task(self):
1280 request = _gen_request( 1276 request = self._gen_request(
1281 properties={ 1277 properties={
1282 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1278 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1283 }, 1279 },
1284 pubsub_topic='projects/abc/topics/def') 1280 pubsub_topic='projects/abc/topics/def')
1285 pub_sub_calls = self.mock_pub_sub() 1281 pub_sub_calls = self.mock_pub_sub()
1286 task_request.init_new_request(request, True, None) 1282 task_request.init_new_request(request, True, None)
1287 result_summary = task_scheduler.schedule_request(request, None) 1283 result_summary = task_scheduler.schedule_request(request, None)
1288 ok, was_running = task_scheduler.cancel_task(request, result_summary.key) 1284 ok, was_running = task_scheduler.cancel_task(request, result_summary.key)
1289 self.assertEqual(True, ok) 1285 self.assertEqual(True, ok)
1290 self.assertEqual(False, was_running) 1286 self.assertEqual(False, was_running)
1291 result_summary = result_summary.key.get() 1287 result_summary = result_summary.key.get()
1292 self.assertEqual(task_result.State.CANCELED, result_summary.state) 1288 self.assertEqual(task_result.State.CANCELED, result_summary.state)
1293 self.assertEqual(1, self.execute_tasks()) 1289 self.assertEqual(1, self.execute_tasks())
1294 self.assertEqual(1, len(pub_sub_calls)) # sent completion notification 1290 self.assertEqual(1, len(pub_sub_calls)) # sent completion notification
1295 1291
1296 def test_cancel_task_running(self): 1292 def test_cancel_task_running(self):
1297 request = _gen_request( 1293 request = self._gen_request(
1298 properties={ 1294 properties={
1299 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1295 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1300 }, 1296 },
1301 pubsub_topic='projects/abc/topics/def') 1297 pubsub_topic='projects/abc/topics/def')
1302 pub_sub_calls = self.mock_pub_sub() 1298 pub_sub_calls = self.mock_pub_sub()
1303 task_request.init_new_request(request, True, None) 1299 task_request.init_new_request(request, True, None)
1304 result_summary = task_scheduler.schedule_request(request, None) 1300 result_summary = task_scheduler.schedule_request(request, None)
1305 bot_dimensions = { 1301 bot_dimensions = {
1306 u'id': [u'localhost'], 1302 u'id': [u'localhost'],
1307 u'os': [u'Windows-3.1.1'], 1303 u'os': [u'Windows-3.1.1'],
1308 u'pool': [u'default'], 1304 u'pool': [u'default'],
1309 } 1305 }
1310 _register_bot(bot_dimensions) 1306 self._register_bot(bot_dimensions)
1311 reaped_request, _, run_result = task_scheduler.bot_reap_task( 1307 reaped_request, _, run_result = task_scheduler.bot_reap_task(
1312 bot_dimensions, 'abc', None) 1308 bot_dimensions, 'abc', None)
1313 ok, was_running = task_scheduler.cancel_task(request, result_summary.key) 1309 ok, was_running = task_scheduler.cancel_task(request, result_summary.key)
1314 self.assertEqual(False, ok) 1310 self.assertEqual(False, ok)
1315 self.assertEqual(True, was_running) 1311 self.assertEqual(True, was_running)
1316 result_summary = result_summary.key.get() 1312 result_summary = result_summary.key.get()
1317 self.assertEqual(task_result.State.RUNNING, result_summary.state) 1313 self.assertEqual(task_result.State.RUNNING, result_summary.state)
1318 self.assertEqual(1, self.execute_tasks()) 1314 self.assertEqual(1, self.execute_tasks())
1319 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING 1315 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING
1320 1316
1321 def test_cron_abort_expired_task_to_run(self): 1317 def test_cron_abort_expired_task_to_run(self):
1322 request = _gen_request( 1318 request = self._gen_request(
1323 properties={ 1319 properties={
1324 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1320 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1325 }, 1321 },
1326 pubsub_topic='projects/abc/topics/def') 1322 pubsub_topic='projects/abc/topics/def')
1327 task_request.init_new_request(request, True, None) 1323 task_request.init_new_request(request, True, None)
1328 pub_sub_calls = self.mock_pub_sub() 1324 pub_sub_calls = self.mock_pub_sub()
1329 result_summary = task_scheduler.schedule_request(request, None) 1325 result_summary = task_scheduler.schedule_request(request, None)
1330 abandoned_ts = self.mock_now(self.now, request.expiration_secs+1) 1326 abandoned_ts = self.mock_now(self.now, request.expiration_secs+1)
1331 self.assertEqual( 1327 self.assertEqual(
1332 ['1d69b9f088008910'], 1328 ['1d69b9f088008910'],
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1367 'try_number': None, 1363 'try_number': None,
1368 'user': u'Jesus', 1364 'user': u'Jesus',
1369 } 1365 }
1370 self.assertEqual(expected, result_summary.key.get().to_dict()) 1366 self.assertEqual(expected, result_summary.key.get().to_dict())
1371 self.assertEqual(1, self.execute_tasks()) 1367 self.assertEqual(1, self.execute_tasks())
1372 self.assertEqual(1, len(pub_sub_calls)) # pubsub completion notification 1368 self.assertEqual(1, len(pub_sub_calls)) # pubsub completion notification
1373 1369
1374 def test_cron_abort_expired_task_to_run_retry(self): 1370 def test_cron_abort_expired_task_to_run_retry(self):
1375 pub_sub_calls = self.mock_pub_sub() 1371 pub_sub_calls = self.mock_pub_sub()
1376 now = utils.utcnow() 1372 now = utils.utcnow()
1377 request = _gen_request( 1373 request = self._gen_request(
1378 properties={ 1374 properties={
1379 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1375 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1380 'idempotent': True, 1376 'idempotent': True,
1381 }, 1377 },
1382 created_ts=now, 1378 created_ts=now,
1383 expiration_ts=now+datetime.timedelta(seconds=600), 1379 expiration_ts=now+datetime.timedelta(seconds=600),
1384 pubsub_topic='projects/abc/topics/def') 1380 pubsub_topic='projects/abc/topics/def')
1385 task_request.init_new_request(request, True, None) 1381 task_request.init_new_request(request, True, None)
1386 result_summary = task_scheduler.schedule_request(request, None) 1382 result_summary = task_scheduler.schedule_request(request, None)
1387 1383
1388 # Fake first try bot died. 1384 # Fake first try bot died.
1389 bot_dimensions = { 1385 bot_dimensions = {
1390 u'foo': [u'bar'], 1386 u'foo': [u'bar'],
1391 u'id': [u'localhost'], 1387 u'id': [u'localhost'],
1392 u'os': [u'Windows', u'Windows-3.1.1'], 1388 u'os': [u'Windows', u'Windows-3.1.1'],
1393 u'pool': [u'default'], 1389 u'pool': [u'default'],
1394 } 1390 }
1395 _register_bot(bot_dimensions) 1391 self._register_bot(bot_dimensions)
1396 _request, _, run_result = task_scheduler.bot_reap_task( 1392 _request, _, run_result = task_scheduler.bot_reap_task(
1397 bot_dimensions, 'abc', None) 1393 bot_dimensions, 'abc', None)
1398 self.assertEqual(1, self.execute_tasks()) 1394 self.assertEqual(1, self.execute_tasks())
1399 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING 1395 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING
1400 now_1 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 1) 1396 now_1 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 1)
1401 self.assertEqual(([], 1, 0), task_scheduler.cron_handle_bot_died('f.local')) 1397 self.assertEqual(([], 1, 0), task_scheduler.cron_handle_bot_died('f.local'))
1402 self.assertEqual(task_result.State.BOT_DIED, run_result.key.get().state) 1398 self.assertEqual(task_result.State.BOT_DIED, run_result.key.get().state)
1403 self.assertEqual( 1399 self.assertEqual(
1404 task_result.State.PENDING, run_result.result_summary_key.get().state) 1400 task_result.State.PENDING, run_result.result_summary_key.get().state)
1405 self.assertEqual(1, self.execute_tasks()) 1401 self.assertEqual(1, self.execute_tasks())
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1449 self.assertEqual(expected, result_summary.key.get().to_dict()) 1445 self.assertEqual(expected, result_summary.key.get().to_dict())
1450 1446
1451 self.assertEqual(1, self.execute_tasks()) 1447 self.assertEqual(1, self.execute_tasks())
1452 self.assertEqual(3, len(pub_sub_calls)) # PENDING -> BOT_DIED 1448 self.assertEqual(3, len(pub_sub_calls)) # PENDING -> BOT_DIED
1453 1449
1454 def test_cron_handle_bot_died(self): 1450 def test_cron_handle_bot_died(self):
1455 pub_sub_calls = self.mock_pub_sub() 1451 pub_sub_calls = self.mock_pub_sub()
1456 1452
1457 # Test first retry, then success. 1453 # Test first retry, then success.
1458 now = utils.utcnow() 1454 now = utils.utcnow()
1459 request = _gen_request( 1455 request = self._gen_request(
1460 properties={ 1456 properties={
1461 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1457 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1462 'idempotent': True, 1458 'idempotent': True,
1463 }, 1459 },
1464 created_ts=now, 1460 created_ts=now,
1465 expiration_ts=now+datetime.timedelta(seconds=600), 1461 expiration_ts=now+datetime.timedelta(seconds=600),
1466 pubsub_topic='projects/abc/topics/def') 1462 pubsub_topic='projects/abc/topics/def')
1467 task_request.init_new_request(request, True, None) 1463 task_request.init_new_request(request, True, None)
1468 _result_summary = task_scheduler.schedule_request(request, None) 1464 _result_summary = task_scheduler.schedule_request(request, None)
1469 self.assertEqual(0, len(pub_sub_calls)) 1465 self.assertEqual(0, len(pub_sub_calls))
1470 bot_dimensions = { 1466 bot_dimensions = {
1471 u'foo': [u'bar'], 1467 u'foo': [u'bar'],
1472 u'id': [u'localhost'], 1468 u'id': [u'localhost'],
1473 u'os': [u'Windows', u'Windows-3.1.1'], 1469 u'os': [u'Windows', u'Windows-3.1.1'],
1474 u'pool': [u'default'], 1470 u'pool': [u'default'],
1475 } 1471 }
1476 _register_bot(bot_dimensions) 1472 self._register_bot(bot_dimensions)
1477 request, _, run_result = task_scheduler.bot_reap_task( 1473 request, _, run_result = task_scheduler.bot_reap_task(
1478 bot_dimensions, 'abc', None) 1474 bot_dimensions, 'abc', None)
1479 self.assertEqual( 1475 self.assertEqual(
1480 task_result.State.RUNNING, run_result.result_summary_key.get().state) 1476 task_result.State.RUNNING, run_result.result_summary_key.get().state)
1481 self.assertEqual(1, self.execute_tasks()) 1477 self.assertEqual(1, self.execute_tasks())
1482 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING 1478 self.assertEqual(1, len(pub_sub_calls)) # PENDING -> RUNNING
1483 self.assertEqual(1, run_result.try_number) 1479 self.assertEqual(1, run_result.try_number)
1484 self.assertEqual(task_result.State.RUNNING, run_result.state) 1480 self.assertEqual(task_result.State.RUNNING, run_result.state)
1485 now_1 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 1) 1481 now_1 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 1)
1486 self.assertEqual(([], 1, 0), task_scheduler.cron_handle_bot_died('f.local')) 1482 self.assertEqual(([], 1, 0), task_scheduler.cron_handle_bot_died('f.local'))
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1544 ], 1540 ],
1545 'try_number': 1, 1541 'try_number': 1,
1546 'user': u'Jesus', 1542 'user': u'Jesus',
1547 } 1543 }
1548 self.assertEqual(expected, run_result.result_summary_key.get().to_dict()) 1544 self.assertEqual(expected, run_result.result_summary_key.get().to_dict())
1549 1545
1550 # Task was retried. 1546 # Task was retried.
1551 now_2 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 2) 1547 now_2 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 2)
1552 bot_dimensions_second = bot_dimensions.copy() 1548 bot_dimensions_second = bot_dimensions.copy()
1553 bot_dimensions_second[u'id'] = [u'localhost-second'] 1549 bot_dimensions_second[u'id'] = [u'localhost-second']
1554 _register_bot(bot_dimensions_second) 1550 self._register_bot(bot_dimensions_second)
1555 _request, _, run_result = task_scheduler.bot_reap_task( 1551 _request, _, run_result = task_scheduler.bot_reap_task(
1556 bot_dimensions_second, 'abc', None) 1552 bot_dimensions_second, 'abc', None)
1557 self.assertEqual(1, self.execute_tasks()) 1553 self.assertEqual(1, self.execute_tasks())
1558 self.assertEqual(3, len(pub_sub_calls)) # PENDING -> RUNNING 1554 self.assertEqual(3, len(pub_sub_calls)) # PENDING -> RUNNING
1559 logging.info('%s', [t.to_dict() for t in task_to_run.TaskToRun.query()]) 1555 logging.info('%s', [t.to_dict() for t in task_to_run.TaskToRun.query()])
1560 self.assertEqual(2, run_result.try_number) 1556 self.assertEqual(2, run_result.try_number)
1561 self.assertEqual( 1557 self.assertEqual(
1562 task_result.State.COMPLETED, 1558 task_result.State.COMPLETED,
1563 task_scheduler.bot_update_task( 1559 task_scheduler.bot_update_task(
1564 run_result_key=run_result.key, 1560 run_result_key=run_result.key,
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1610 } 1606 }
1611 self.assertEqual(expected, run_result.result_summary_key.get().to_dict()) 1607 self.assertEqual(expected, run_result.result_summary_key.get().to_dict())
1612 self.assertEqual(0.1, run_result.key.get().cost_usd) 1608 self.assertEqual(0.1, run_result.key.get().cost_usd)
1613 1609
1614 self.assertEqual(0, self.execute_tasks()) 1610 self.assertEqual(0, self.execute_tasks())
1615 self.assertEqual(4, len(pub_sub_calls)) # RUNNING -> COMPLETED 1611 self.assertEqual(4, len(pub_sub_calls)) # RUNNING -> COMPLETED
1616 1612
1617 def test_cron_handle_bot_died_same_bot_denied(self): 1613 def test_cron_handle_bot_died_same_bot_denied(self):
1618 # Test first retry, then success. 1614 # Test first retry, then success.
1619 now = utils.utcnow() 1615 now = utils.utcnow()
1620 request = _gen_request( 1616 request = self._gen_request(
1621 properties={ 1617 properties={
1622 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1618 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1623 'idempotent': True, 1619 'idempotent': True,
1624 }, 1620 },
1625 created_ts=now, 1621 created_ts=now,
1626 expiration_ts=now+datetime.timedelta(seconds=600)) 1622 expiration_ts=now+datetime.timedelta(seconds=600))
1627 task_request.init_new_request(request, True, None) 1623 task_request.init_new_request(request, True, None)
1628 _result_summary = task_scheduler.schedule_request(request, None) 1624 _result_summary = task_scheduler.schedule_request(request, None)
1629 bot_dimensions = { 1625 bot_dimensions = {
1630 u'foo': [u'bar'], 1626 u'foo': [u'bar'],
1631 u'id': [u'localhost'], 1627 u'id': [u'localhost'],
1632 u'os': [u'Windows', u'Windows-3.1.1'], 1628 u'os': [u'Windows', u'Windows-3.1.1'],
1633 u'pool': [u'default'], 1629 u'pool': [u'default'],
1634 } 1630 }
1635 _register_bot(bot_dimensions) 1631 self._register_bot(bot_dimensions)
1636 _request, _, run_result = task_scheduler.bot_reap_task( 1632 _request, _, run_result = task_scheduler.bot_reap_task(
1637 bot_dimensions, 'abc', None) 1633 bot_dimensions, 'abc', None)
1638 self.assertEqual(1, run_result.try_number) 1634 self.assertEqual(1, run_result.try_number)
1639 self.assertEqual(task_result.State.RUNNING, run_result.state) 1635 self.assertEqual(task_result.State.RUNNING, run_result.state)
1640 now_1 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 1) 1636 now_1 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 1)
1641 self.assertEqual(([], 1, 0), task_scheduler.cron_handle_bot_died('f.local')) 1637 self.assertEqual(([], 1, 0), task_scheduler.cron_handle_bot_died('f.local'))
1642 1638
1643 # Refresh and compare: 1639 # Refresh and compare:
1644 expected = { 1640 expected = {
1645 'abandoned_ts': now_1, 1641 'abandoned_ts': now_1,
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1704 now_2 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 2) 1700 now_2 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 2)
1705 request, _, run_result = task_scheduler.bot_reap_task( 1701 request, _, run_result = task_scheduler.bot_reap_task(
1706 bot_dimensions, 'abc', None) 1702 bot_dimensions, 'abc', None)
1707 self.assertEqual(None, request) 1703 self.assertEqual(None, request)
1708 self.assertEqual(None, run_result) 1704 self.assertEqual(None, run_result)
1709 logging.info('%s', [t.to_dict() for t in task_to_run.TaskToRun.query()]) 1705 logging.info('%s', [t.to_dict() for t in task_to_run.TaskToRun.query()])
1710 1706
1711 def test_cron_handle_bot_died_second(self): 1707 def test_cron_handle_bot_died_second(self):
1712 # Test two tries internal_failure's leading to a BOT_DIED status. 1708 # Test two tries internal_failure's leading to a BOT_DIED status.
1713 now = utils.utcnow() 1709 now = utils.utcnow()
1714 request = _gen_request( 1710 request = self._gen_request(
1715 properties={ 1711 properties={
1716 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1712 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1717 'idempotent': True, 1713 'idempotent': True,
1718 }, 1714 },
1719 created_ts=now, 1715 created_ts=now,
1720 expiration_ts=now+datetime.timedelta(seconds=600)) 1716 expiration_ts=now+datetime.timedelta(seconds=600))
1721 task_request.init_new_request(request, True, None) 1717 task_request.init_new_request(request, True, None)
1722 _result_summary = task_scheduler.schedule_request(request, None) 1718 _result_summary = task_scheduler.schedule_request(request, None)
1723 bot_dimensions = { 1719 bot_dimensions = {
1724 u'foo': [u'bar'], 1720 u'foo': [u'bar'],
1725 u'id': [u'localhost'], 1721 u'id': [u'localhost'],
1726 u'os': [u'Windows', u'Windows-3.1.1'], 1722 u'os': [u'Windows', u'Windows-3.1.1'],
1727 u'pool': [u'default'], 1723 u'pool': [u'default'],
1728 } 1724 }
1729 _register_bot(bot_dimensions) 1725 self._register_bot(bot_dimensions)
1730 _request, _, run_result = task_scheduler.bot_reap_task( 1726 _request, _, run_result = task_scheduler.bot_reap_task(
1731 bot_dimensions, 'abc', None) 1727 bot_dimensions, 'abc', None)
1732 self.assertEqual(1, run_result.try_number) 1728 self.assertEqual(1, run_result.try_number)
1733 self.assertEqual(task_result.State.RUNNING, run_result.state) 1729 self.assertEqual(task_result.State.RUNNING, run_result.state)
1734 self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 1) 1730 self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 1)
1735 self.assertEqual(([], 1, 0), task_scheduler.cron_handle_bot_died('f.local')) 1731 self.assertEqual(([], 1, 0), task_scheduler.cron_handle_bot_died('f.local'))
1736 now_1 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 2) 1732 now_1 = self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 2)
1737 # It must be a different bot. 1733 # It must be a different bot.
1738 bot_dimensions_second = bot_dimensions.copy() 1734 bot_dimensions_second = bot_dimensions.copy()
1739 bot_dimensions_second[u'id'] = [u'localhost-second'] 1735 bot_dimensions_second[u'id'] = [u'localhost-second']
1740 _register_bot(bot_dimensions_second) 1736 self._register_bot(bot_dimensions_second)
1737 # No task to run because the task dimensions were already seen.
1741 _request, _, run_result = task_scheduler.bot_reap_task( 1738 _request, _, run_result = task_scheduler.bot_reap_task(
1742 bot_dimensions_second, 'abc', None) 1739 bot_dimensions_second, 'abc', None)
1743 now_2 = self.mock_now(self.now + 2 * task_result.BOT_PING_TOLERANCE, 3) 1740 now_2 = self.mock_now(self.now + 2 * task_result.BOT_PING_TOLERANCE, 3)
1744 self.assertEqual( 1741 self.assertEqual(
1745 (['1d69b9f088008912'], 0, 0), 1742 (['1d69b9f088008912'], 0, 0),
1746 task_scheduler.cron_handle_bot_died('f.local')) 1743 task_scheduler.cron_handle_bot_died('f.local'))
1747 self.assertEqual(([], 0, 0), task_scheduler.cron_handle_bot_died('f.local')) 1744 self.assertEqual(([], 0, 0), task_scheduler.cron_handle_bot_died('f.local'))
1748 expected = { 1745 expected = {
1749 'abandoned_ts': now_2, 1746 'abandoned_ts': now_2,
1750 'bot_dimensions': bot_dimensions_second, 1747 'bot_dimensions': bot_dimensions_second,
(...skipping 26 matching lines...) Expand all
1777 u'tag:1', 1774 u'tag:1',
1778 u'user:Jesus', 1775 u'user:Jesus',
1779 ], 1776 ],
1780 'try_number': 2, 1777 'try_number': 2,
1781 'user': u'Jesus', 1778 'user': u'Jesus',
1782 } 1779 }
1783 self.assertEqual(expected, run_result.result_summary_key.get().to_dict()) 1780 self.assertEqual(expected, run_result.result_summary_key.get().to_dict())
1784 1781
1785 def test_cron_handle_bot_died_ignored_expired(self): 1782 def test_cron_handle_bot_died_ignored_expired(self):
1786 now = utils.utcnow() 1783 now = utils.utcnow()
1787 request = _gen_request( 1784 request = self._gen_request(
1788 properties={ 1785 properties={
1789 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'}, 1786 'dimensions': {u'os': u'Windows-3.1.1', u'pool': u'default'},
1790 }, 1787 },
1791 created_ts=now, 1788 created_ts=now,
1792 expiration_ts=now+datetime.timedelta(seconds=600)) 1789 expiration_ts=now+datetime.timedelta(seconds=600))
1793 task_request.init_new_request(request, True, None) 1790 task_request.init_new_request(request, True, None)
1794 _result_summary = task_scheduler.schedule_request(request, None) 1791 _result_summary = task_scheduler.schedule_request(request, None)
1795 bot_dimensions = { 1792 bot_dimensions = {
1796 u'foo': [u'bar'], 1793 u'foo': [u'bar'],
1797 u'id': [u'localhost'], 1794 u'id': [u'localhost'],
1798 u'os': [u'Windows', u'Windows-3.1.1'], 1795 u'os': [u'Windows', u'Windows-3.1.1'],
1799 u'pool': [u'default'], 1796 u'pool': [u'default'],
1800 } 1797 }
1801 _register_bot(bot_dimensions) 1798 self._register_bot(bot_dimensions)
1802 _request, _, run_result = task_scheduler.bot_reap_task( 1799 _request, _, run_result = task_scheduler.bot_reap_task(
1803 bot_dimensions, 'abc', None) 1800 bot_dimensions, 'abc', None)
1804 self.assertEqual(1, run_result.try_number) 1801 self.assertEqual(1, run_result.try_number)
1805 self.assertEqual(task_result.State.RUNNING, run_result.state) 1802 self.assertEqual(task_result.State.RUNNING, run_result.state)
1806 self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 601) 1803 self.mock_now(self.now + task_result.BOT_PING_TOLERANCE, 601)
1807 self.assertEqual( 1804 self.assertEqual(
1808 (['1d69b9f088008911'], 0, 0), 1805 (['1d69b9f088008911'], 0, 0),
1809 task_scheduler.cron_handle_bot_died('f.local')) 1806 task_scheduler.cron_handle_bot_died('f.local'))
1810 1807
1811 1808
1812 if __name__ == '__main__': 1809 if __name__ == '__main__':
1813 if '-v' in sys.argv: 1810 if '-v' in sys.argv:
1814 unittest.TestCase.maxDiff = None 1811 unittest.TestCase.maxDiff = None
1815 logging.basicConfig( 1812 logging.basicConfig(
1816 level=logging.DEBUG if '-v' in sys.argv else logging.CRITICAL) 1813 level=logging.DEBUG if '-v' in sys.argv else logging.CRITICAL)
1817 unittest.main() 1814 unittest.main()
OLDNEW
« no previous file with comments | « appengine/swarming/handlers_test.py ('k') | appengine/swarming/server/task_to_run_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698