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

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

Issue 1946253003: swarming: refactor cipd input (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@default-isolate-server
Patch Set: rebased Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/swarming/server/task_request.py ('k') | appengine/swarming/swarming_rpcs.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 by the Apache v2.0 license that can be 3 # Use of this source code is governed by the Apache v2.0 license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import datetime 6 import datetime
7 import logging 7 import logging
8 import os
9 import random 8 import random
10 import sys 9 import sys
11 import unittest 10 import unittest
12 11
13 import test_env 12 import test_env
14 test_env.setup_test_env() 13 test_env.setup_test_env()
15 14
16 from google.appengine.api import datastore_errors 15 from google.appengine.api import datastore_errors
17 from google.appengine.ext import ndb 16 from google.appengine.ext import ndb
18 17
19 from components import auth_testing 18 from components import auth_testing
20 from components import utils 19 from components import utils
21 from test_support import test_case 20 from test_support import test_case
22 21
23 from server import task_pack 22 from server import task_pack
24 from server import task_request 23 from server import task_request
25 24
26 25
27 # pylint: disable=W0212 26 # pylint: disable=W0212
28 27
29 28
30 PINNED_PACKAGE_VERSION = 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef'
31
32
33 def mkreq(req): 29 def mkreq(req):
34 return task_request.make_request(req, True) 30 return task_request.make_request(req, True)
35 31
36 32
37 def _gen_request(properties=None, **kwargs): 33 def _gen_request(properties=None, **kwargs):
38 """Creates a TaskRequest.""" 34 """Creates a TaskRequest."""
39 properties = properties or {} 35 properties = properties or {}
40 packages = properties.pop('packages', [{ 36
41 'package_name': 'rm', 37 def merge(override, defaults):
42 'version': PINNED_PACKAGE_VERSION, 38 if override is None:
43 }]) 39 return None
40 result = defaults.copy()
41 result.update(override)
42 return result
43
44 cipd_input = properties.pop('cipd_input', {})
45 cipd_input = merge(cipd_input, {
46 'client_package': merge(cipd_input.pop('client_package', {}), {
47 'package_name': 'infra/tools/cipd/${platform}',
48 'version': 'git_revision:deadbeef',
49 }),
50 'packages': [{
51 'package_name': 'rm',
52 'version': 'git_revision:deadbeef',
53 }],
54 'server': 'https://chrome-infra-packages.appspot.com'
55 })
56
44 inputs_ref = properties.pop('inputs_ref', { 57 inputs_ref = properties.pop('inputs_ref', {
45 'isolatedserver': 'https://isolateserver.appspot.com', 58 'isolatedserver': 'https://isolateserver.appspot.com',
46 'namespace': 'default-gzip', 59 'namespace': 'default-gzip',
47 }) 60 })
48 props = { 61
62 properties = merge(properties, {
63 'cipd_input': cipd_input,
49 'command': [u'command1', u'arg1'], 64 'command': [u'command1', u'arg1'],
50 'packages': [task_request.CipdPackage(**p) for p in packages],
51 'dimensions': { 65 'dimensions': {
52 u'OS': u'Windows-3.1.1', 66 u'OS': u'Windows-3.1.1',
53 u'hostname': u'localhost', 67 u'hostname': u'localhost',
54 u'pool': u'default', 68 u'pool': u'default',
55 }, 69 },
56 'env': {u'foo': u'bar', u'joe': u'2'}, 70 'env': {u'foo': u'bar', u'joe': u'2'},
57 'execution_timeout_secs': 30, 71 'execution_timeout_secs': 30,
58 'grace_period_secs': 30, 72 'grace_period_secs': 30,
59 'idempotent': False, 73 'idempotent': False,
60 'inputs_ref': inputs_ref, 74 'inputs_ref': inputs_ref,
61 'io_timeout_secs': None, 75 'io_timeout_secs': None,
62 } 76 })
63 props.update(properties)
64 now = utils.utcnow() 77 now = utils.utcnow()
65 args = { 78 args = {
66 'created_ts': now, 79 'created_ts': now,
67 'name': 'Request name', 80 'name': 'Request name',
68 'priority': 50, 81 'priority': 50,
69 'properties': task_request.TaskProperties(**props), 82 'properties': properties,
70 'expiration_ts': now + datetime.timedelta(seconds=30), 83 'expiration_ts': now + datetime.timedelta(seconds=30),
71 'tags': [u'tag:1'], 84 'tags': [u'tag:1'],
72 'user': 'Jesus', 85 'user': 'Jesus',
73 } 86 }
74 args.update(kwargs) 87 args.update(kwargs)
88 # Note that ndb model constructor accepts dicts for structured properties.
75 return task_request.TaskRequest(**args) 89 return task_request.TaskRequest(**args)
76 90
77 91
78 class Prop(object): 92 class Prop(object):
79 _name = 'foo' 93 _name = 'foo'
80 94
81 95
82 class TestCase(test_case.TestCase): 96 class TestCase(test_case.TestCase):
83 def setUp(self): 97 def setUp(self):
84 super(TestCase, self).setUp() 98 super(TestCase, self).setUp()
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 task_request.validate_request_key(key) 207 task_request.validate_request_key(key)
194 208
195 def test_make_request(self): 209 def test_make_request(self):
196 # Compare with test_make_request_clone(). 210 # Compare with test_make_request_clone().
197 parent = mkreq(_gen_request()) 211 parent = mkreq(_gen_request())
198 # Hack: Would need to know about TaskResultSummary. 212 # Hack: Would need to know about TaskResultSummary.
199 parent_id = task_pack.pack_request_key(parent.key) + '1' 213 parent_id = task_pack.pack_request_key(parent.key) + '1'
200 r = _gen_request(properties=dict(idempotent=True), parent_task_id=parent_id) 214 r = _gen_request(properties=dict(idempotent=True), parent_task_id=parent_id)
201 request = mkreq(r) 215 request = mkreq(r)
202 expected_properties = { 216 expected_properties = {
217 'cipd_input': {
218 'client_package': {
219 'package_name': 'infra/tools/cipd/${platform}',
220 'version': 'git_revision:deadbeef',
221 },
222 'packages': [{
223 'package_name': 'rm',
224 'version': 'git_revision:deadbeef',
225 }],
226 'server': 'https://chrome-infra-packages.appspot.com'
227 },
203 'command': [u'command1', u'arg1'], 228 'command': [u'command1', u'arg1'],
204 'dimensions': { 229 'dimensions': {
205 u'OS': u'Windows-3.1.1', 230 u'OS': u'Windows-3.1.1',
206 u'hostname': u'localhost', 231 u'hostname': u'localhost',
207 u'pool': u'default', 232 u'pool': u'default',
208 }, 233 },
209 'env': {u'foo': u'bar', u'joe': u'2'}, 234 'env': {u'foo': u'bar', u'joe': u'2'},
210 'extra_args': [], 235 'extra_args': [],
211 'execution_timeout_secs': 30, 236 'execution_timeout_secs': 30,
212 'grace_period_secs': 30, 237 'grace_period_secs': 30,
213 'idempotent': True, 238 'idempotent': True,
214 'inputs_ref': { 239 'inputs_ref': {
215 'isolated': None, 240 'isolated': None,
216 'isolatedserver': 'https://isolateserver.appspot.com', 241 'isolatedserver': 'https://isolateserver.appspot.com',
217 'namespace': 'default-gzip', 242 'namespace': 'default-gzip',
218 }, 243 },
219 'io_timeout_secs': None, 244 'io_timeout_secs': None,
220 'packages': [{'package_name': 'rm', 'version': PINNED_PACKAGE_VERSION}],
221 } 245 }
222 expected_request = { 246 expected_request = {
223 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, 247 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY,
224 'name': u'Request name', 248 'name': u'Request name',
225 'parent_task_id': unicode(parent_id), 249 'parent_task_id': unicode(parent_id),
226 'priority': 49, 250 'priority': 49,
227 'properties': expected_properties, 251 'properties': expected_properties,
228 # Intentionally hard code the hash value since it has to be deterministic. 252 # Intentionally hard code the hash value since it has to be deterministic.
229 # Other unit tests should use the calculated value. 253 # Other unit tests should use the calculated value.
230 'properties_hash': 'c3e067b4e232be5478e7147bb1f0506477444014', 254 'properties_hash': 'c07adb3b577d51169036f29e44764a5ddf132228',
231 'pubsub_topic': None, 255 'pubsub_topic': None,
232 'pubsub_userdata': None, 256 'pubsub_userdata': None,
233 'tags': [ 257 'tags': [
234 u'OS:Windows-3.1.1', 258 u'OS:Windows-3.1.1',
235 u'hostname:localhost', 259 u'hostname:localhost',
236 u'pool:default', 260 u'pool:default',
237 u'priority:49', 261 u'priority:49',
238 u'tag:1', 262 u'tag:1',
239 u'user:Jesus', 263 u'user:Jesus',
240 ], 264 ],
(...skipping 12 matching lines...) Expand all
253 'isolated': '0123456789012345678901234567890123456789', 277 'isolated': '0123456789012345678901234567890123456789',
254 'isolatedserver': 'http://localhost:1', 278 'isolatedserver': 'http://localhost:1',
255 'namespace': 'default-gzip', 279 'namespace': 'default-gzip',
256 }, 280 },
257 })) 281 }))
258 # Hack: Would need to know about TaskResultSummary. 282 # Hack: Would need to know about TaskResultSummary.
259 parent_id = task_pack.pack_request_key(parent.key) + '1' 283 parent_id = task_pack.pack_request_key(parent.key) + '1'
260 request = mkreq(_gen_request( 284 request = mkreq(_gen_request(
261 properties={'idempotent':True}, parent_task_id=parent_id)) 285 properties={'idempotent':True}, parent_task_id=parent_id))
262 expected_properties = { 286 expected_properties = {
287 'cipd_input': {
288 'client_package': {
289 'package_name': 'infra/tools/cipd/${platform}',
290 'version': 'git_revision:deadbeef',
291 },
292 'packages': [{
293 'package_name': 'rm',
294 'version': 'git_revision:deadbeef',
295 }],
296 'server': 'https://chrome-infra-packages.appspot.com'
297 },
263 'command': [u'command1', u'arg1'], 298 'command': [u'command1', u'arg1'],
264 'dimensions': { 299 'dimensions': {
265 u'OS': u'Windows-3.1.1', 300 u'OS': u'Windows-3.1.1',
266 u'hostname': u'localhost', 301 u'hostname': u'localhost',
267 u'pool': u'default', 302 u'pool': u'default',
268 }, 303 },
269 'env': {u'foo': u'bar', u'joe': u'2'}, 304 'env': {u'foo': u'bar', u'joe': u'2'},
270 'extra_args': [], 305 'extra_args': [],
271 'execution_timeout_secs': 30, 306 'execution_timeout_secs': 30,
272 'grace_period_secs': 30, 307 'grace_period_secs': 30,
273 'idempotent': True, 308 'idempotent': True,
274 'inputs_ref': { 309 'inputs_ref': {
275 'isolated': None, 310 'isolated': None,
276 'isolatedserver': 'https://isolateserver.appspot.com', 311 'isolatedserver': 'https://isolateserver.appspot.com',
277 'namespace': 'default-gzip', 312 'namespace': 'default-gzip',
278 }, 313 },
279 'io_timeout_secs': None, 314 'io_timeout_secs': None,
280 'packages': [{'package_name': 'rm', 'version': PINNED_PACKAGE_VERSION}],
281 } 315 }
282 expected_request = { 316 expected_request = {
283 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, 317 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY,
284 'name': u'Request name', 318 'name': u'Request name',
285 'parent_task_id': unicode(parent_id), 319 'parent_task_id': unicode(parent_id),
286 'priority': 49, 320 'priority': 49,
287 'properties': expected_properties, 321 'properties': expected_properties,
288 # Intentionally hard code the hash value since it has to be deterministic. 322 # Intentionally hard code the hash value since it has to be deterministic.
289 # Other unit tests should use the calculated value. 323 # Other unit tests should use the calculated value.
290 'properties_hash': 'c3e067b4e232be5478e7147bb1f0506477444014', 324 'properties_hash': 'c07adb3b577d51169036f29e44764a5ddf132228',
291 'pubsub_topic': None, 325 'pubsub_topic': None,
292 'pubsub_userdata': None, 326 'pubsub_userdata': None,
293 'tags': [ 327 'tags': [
294 u'OS:Windows-3.1.1', 328 u'OS:Windows-3.1.1',
295 u'hostname:localhost', 329 u'hostname:localhost',
296 u'pool:default', 330 u'pool:default',
297 u'priority:49', 331 u'priority:49',
298 u'tag:1', 332 u'tag:1',
299 u'user:Jesus', 333 u'user:Jesus',
300 ], 334 ],
(...skipping 19 matching lines...) Expand all
320 _gen_request(parent_task_id='1d69b9f088008810') 354 _gen_request(parent_task_id='1d69b9f088008810')
321 355
322 def test_make_request_idempotent(self): 356 def test_make_request_idempotent(self):
323 request = mkreq(_gen_request(properties=dict(idempotent=True))) 357 request = mkreq(_gen_request(properties=dict(idempotent=True)))
324 as_dict = request.to_dict() 358 as_dict = request.to_dict()
325 self.assertEqual(True, as_dict['properties']['idempotent']) 359 self.assertEqual(True, as_dict['properties']['idempotent'])
326 # Intentionally hard code the hash value since it has to be deterministic. 360 # Intentionally hard code the hash value since it has to be deterministic.
327 # Other unit tests should use the calculated value. 361 # Other unit tests should use the calculated value.
328 # Ensure the algorithm is deterministic. 362 # Ensure the algorithm is deterministic.
329 self.assertEqual( 363 self.assertEqual(
330 'c3e067b4e232be5478e7147bb1f0506477444014', as_dict['properties_hash']) 364 'c07adb3b577d51169036f29e44764a5ddf132228', as_dict['properties_hash'])
331 365
332 def test_duped(self): 366 def test_duped(self):
333 # Two TestRequest with the same properties. 367 # Two TestRequest with the same properties.
334 request_1 = mkreq(_gen_request(properties=dict(idempotent=True))) 368 request_1 = mkreq(_gen_request(properties=dict(idempotent=True)))
335 now = utils.utcnow() 369 now = utils.utcnow()
336 request_2 = mkreq(_gen_request( 370 request_2 = mkreq(_gen_request(
337 name='Other', 371 name='Other',
338 user='Other', 372 user='Other',
339 priority=201, 373 priority=201,
340 created_ts=now, 374 created_ts=now,
(...skipping 26 matching lines...) Expand all
367 401
368 with self.assertRaises(datastore_errors.BadValueError): 402 with self.assertRaises(datastore_errors.BadValueError):
369 mkreq(_gen_request(properties=dict(command=[]))) 403 mkreq(_gen_request(properties=dict(command=[])))
370 with self.assertRaises(datastore_errors.BadValueError): 404 with self.assertRaises(datastore_errors.BadValueError):
371 mkreq(_gen_request(properties=dict(command={'a': 'b'}))) 405 mkreq(_gen_request(properties=dict(command={'a': 'b'})))
372 with self.assertRaises(datastore_errors.BadValueError): 406 with self.assertRaises(datastore_errors.BadValueError):
373 mkreq(_gen_request(properties=dict(command='python'))) 407 mkreq(_gen_request(properties=dict(command='python')))
374 mkreq(_gen_request(properties=dict(command=['python']))) 408 mkreq(_gen_request(properties=dict(command=['python'])))
375 mkreq(_gen_request(properties=dict(command=[u'python']))) 409 mkreq(_gen_request(properties=dict(command=[u'python'])))
376 410
411 def mkcipdreq(idempotent=False, **cipd_input):
412 mkreq(_gen_request(
413 properties=dict(idempotent=idempotent, cipd_input=cipd_input)))
414
377 with self.assertRaises(datastore_errors.BadValueError): 415 with self.assertRaises(datastore_errors.BadValueError):
378 mkreq(_gen_request(properties=dict(packages=[{}]))) 416 mkcipdreq(packages=[{}])
379 with self.assertRaises(datastore_errors.BadValueError): 417 with self.assertRaises(datastore_errors.BadValueError):
380 mkreq(_gen_request(properties=dict(packages=[dict(package_name='rm')]))) 418 mkcipdreq(packages=[dict(package_name='rm')])
381 with self.assertRaises(datastore_errors.BadValueError): 419 with self.assertRaises(datastore_errors.BadValueError):
382 mkreq(_gen_request(properties=dict( 420 mkcipdreq(packages=[{'package_name': 'infra|rm', 'version': 'latest'}])
383 packages=[{'package_name': 'infra|rm', 'version': 'latest'}])))
384 with self.assertRaises(datastore_errors.BadValueError): 421 with self.assertRaises(datastore_errors.BadValueError):
385 mkreq(_gen_request(properties=dict( 422 mkcipdreq(packages=[
386 packages=[ 423 dict(package_name='rm', version='latest'),
387 {'package_name': 'rm', 'version': 'latest'}, 424 dict(package_name='rm', version='canary'),
388 {'package_name': 'rm', 'version': 'canary'}, 425 ])
389 ])))
390 with self.assertRaises(datastore_errors.BadValueError): 426 with self.assertRaises(datastore_errors.BadValueError):
391 mkreq(_gen_request(properties=dict( 427 mkcipdreq(
392 idempotent=True, 428 idempotent=True,
393 packages=[{'package_name': 'rm', 'version': 'latest'}]))) 429 packages=[dict(package_name='rm', version='latest')])
394 mkreq(_gen_request(properties=dict( 430 with self.assertRaises(datastore_errors.BadValueError):
395 packages=[{'package_name': 'rm', 'version': 'latest'}]))) 431 mkcipdreq(server='abc')
432 with self.assertRaises(datastore_errors.BadValueError):
433 mkcipdreq(client_package=dict(package_name='--bad package--'))
434 mkcipdreq()
435 mkcipdreq(packages=[dict(package_name='rm', version='latest')])
436 mkcipdreq(
437 client_package=dict(
438 package_name='infra/tools/cipd/${platform}',
439 version='git_revision:daedbeef',
440 ),
441 packages=[dict(package_name='rm', version='latest')],
442 server='https://chrome-infra-packages.appspot.com',
443 )
396 444
397 with self.assertRaises(TypeError): 445 with self.assertRaises(TypeError):
398 mkreq(_gen_request(properties=dict(dimensions=[]))) 446 mkreq(_gen_request(properties=dict(dimensions=[])))
399 with self.assertRaises(datastore_errors.BadValueError): 447 with self.assertRaises(datastore_errors.BadValueError):
400 mkreq(_gen_request(properties=dict(dimensions={}))) 448 mkreq(_gen_request(properties=dict(dimensions={})))
401 with self.assertRaises(datastore_errors.BadValueError): 449 with self.assertRaises(datastore_errors.BadValueError):
402 mkreq(_gen_request( 450 mkreq(_gen_request(
403 properties=dict(dimensions={u'id': u'b', u'a:': u'b'}))) 451 properties=dict(dimensions={u'id': u'b', u'a:': u'b'})))
404 mkreq(_gen_request( 452 mkreq(_gen_request(
405 properties=dict(dimensions={u'id': u'b', u'a.': u'b'}))) 453 properties=dict(dimensions={u'id': u'b', u'a.': u'b'})))
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
471 parent = mkreq(_gen_request()) 519 parent = mkreq(_gen_request())
472 # Hack: Would need to know about TaskResultSummary. 520 # Hack: Would need to know about TaskResultSummary.
473 parent_id = task_pack.pack_request_key(parent.key) + '1' 521 parent_id = task_pack.pack_request_key(parent.key) + '1'
474 data = _gen_request( 522 data = _gen_request(
475 properties=dict(idempotent=True), parent_task_id=parent_id) 523 properties=dict(idempotent=True), parent_task_id=parent_id)
476 request = task_request.make_request_clone(mkreq(data)) 524 request = task_request.make_request_clone(mkreq(data))
477 # Differences from make_request() are: 525 # Differences from make_request() are:
478 # - idempotent was reset to False. 526 # - idempotent was reset to False.
479 # - parent_task_id was reset to None. 527 # - parent_task_id was reset to None.
480 expected_properties = { 528 expected_properties = {
529 'cipd_input': {
530 'client_package': {
531 'package_name': 'infra/tools/cipd/${platform}',
532 'version': 'git_revision:deadbeef',
533 },
534 'packages': [{
535 'package_name': 'rm',
536 'version': 'git_revision:deadbeef',
537 }],
538 'server': 'https://chrome-infra-packages.appspot.com'
539 },
481 'command': [u'command1', u'arg1'], 540 'command': [u'command1', u'arg1'],
482 'dimensions': { 541 'dimensions': {
483 u'OS': u'Windows-3.1.1', 542 u'OS': u'Windows-3.1.1',
484 u'hostname': u'localhost', 543 u'hostname': u'localhost',
485 u'pool': u'default', 544 u'pool': u'default',
486 }, 545 },
487 'env': {u'foo': u'bar', u'joe': u'2'}, 546 'env': {u'foo': u'bar', u'joe': u'2'},
488 'execution_timeout_secs': 30, 547 'execution_timeout_secs': 30,
489 'extra_args': [], 548 'extra_args': [],
490 'grace_period_secs': 30, 549 'grace_period_secs': 30,
491 'idempotent': False, 550 'idempotent': False,
492 'inputs_ref': { 551 'inputs_ref': {
493 'isolated': None, 552 'isolated': None,
494 'isolatedserver': 'https://isolateserver.appspot.com', 553 'isolatedserver': 'https://isolateserver.appspot.com',
495 'namespace': 'default-gzip', 554 'namespace': 'default-gzip',
496 }, 555 },
497 'io_timeout_secs': None, 556 'io_timeout_secs': None,
498 'packages': [{'package_name': 'rm', 'version': PINNED_PACKAGE_VERSION}],
499 } 557 }
500 # Differences from make_request() are: 558 # Differences from make_request() are:
501 # - parent_task_id was reset to None. 559 # - parent_task_id was reset to None.
502 # - tag 'user:' was replaced 560 # - tag 'user:' was replaced
503 # - user was replaced. 561 # - user was replaced.
504 expected_request = { 562 expected_request = {
505 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, 563 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY,
506 'name': u'Request name (Retry #1)', 564 'name': u'Request name (Retry #1)',
507 'parent_task_id': None, 565 'parent_task_id': None,
508 'priority': 49, 566 'priority': 49,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 ndb.Key(task_request.TaskRequest, 0x7f14acec2fcfffff), 621 ndb.Key(task_request.TaskRequest, 0x7f14acec2fcfffff),
564 task_request.request_id_to_key(0xeb5313d0300000)) 622 task_request.request_id_to_key(0xeb5313d0300000))
565 623
566 624
567 if __name__ == '__main__': 625 if __name__ == '__main__':
568 if '-v' in sys.argv: 626 if '-v' in sys.argv:
569 unittest.TestCase.maxDiff = None 627 unittest.TestCase.maxDiff = None
570 logging.basicConfig( 628 logging.basicConfig(
571 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR) 629 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)
572 unittest.main() 630 unittest.main()
OLDNEW
« no previous file with comments | « appengine/swarming/server/task_request.py ('k') | appengine/swarming/swarming_rpcs.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698