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

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: fix import google.protobuf 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
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
20 from proto import config_pb2
21 from test_support import test_case 21 from test_support import test_case
22 22
23 from server import task_pack 23 from server import task_pack
24 from server import task_request 24 from server import task_request
25 25
26 26
27 # pylint: disable=W0212 27 # pylint: disable=W0212
28 28
29 29
30 PINNED_PACKAGE_VERSION = 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' 30 CIPD_SETTINGS = config_pb2.CipdSettings(
31 server_host='chrome-infra-packages.appspot.com',
32 client_package_name='infra/tools/cipd/${platform}',
33 client_package_version='git_revision:deadbeef')
34 PINNED_PACKAGE_VERSION = 'git_revision:deadbeef'
31 35
32 36
33 def mkreq(req): 37 def mkreq(req):
34 return task_request.make_request(req, True) 38 return task_request.make_request(req, True)
35 39
36 40
37 def _gen_request(properties=None, **kwargs): 41 def _gen_request(properties=None, **kwargs):
38 """Creates a TaskRequest.""" 42 """Creates a TaskRequest."""
39 properties = properties or {} 43 properties = properties or {}
40 packages = properties.pop('packages', [{ 44
41 'package_name': 'rm', 45 def merge(override, defaults):
42 'version': PINNED_PACKAGE_VERSION, 46 if override is None:
43 }]) 47 return None
48 result = defaults.copy()
49 result.update(override)
50 return result
51
52 cipd_input = merge(properties.pop('cipd_input', {}), {
53 'settings': CIPD_SETTINGS.SerializeToString(),
54 'packages': [{
55 'package_name': 'rm',
56 'version': PINNED_PACKAGE_VERSION,
57 }]
58 })
59
44 inputs_ref = properties.pop('inputs_ref', { 60 inputs_ref = properties.pop('inputs_ref', {
45 'isolatedserver': 'https://isolateserver.appspot.com', 61 'isolatedserver': 'https://isolateserver.appspot.com',
46 'namespace': 'default-gzip', 62 'namespace': 'default-gzip',
47 }) 63 })
48 props = { 64
65 properties = merge(properties, {
66 'cipd_input': cipd_input,
49 'command': [u'command1', u'arg1'], 67 'command': [u'command1', u'arg1'],
50 'packages': [task_request.CipdPackage(**p) for p in packages],
51 'dimensions': { 68 'dimensions': {
52 u'OS': u'Windows-3.1.1', 69 u'OS': u'Windows-3.1.1',
53 u'hostname': u'localhost', 70 u'hostname': u'localhost',
54 u'pool': u'default', 71 u'pool': u'default',
55 }, 72 },
56 'env': {u'foo': u'bar', u'joe': u'2'}, 73 'env': {u'foo': u'bar', u'joe': u'2'},
57 'execution_timeout_secs': 30, 74 'execution_timeout_secs': 30,
58 'grace_period_secs': 30, 75 'grace_period_secs': 30,
59 'idempotent': False, 76 'idempotent': False,
60 'inputs_ref': inputs_ref, 77 'inputs_ref': inputs_ref,
61 'io_timeout_secs': None, 78 'io_timeout_secs': None,
62 } 79 })
63 props.update(properties)
64 now = utils.utcnow() 80 now = utils.utcnow()
65 args = { 81 args = {
66 'created_ts': now, 82 'created_ts': now,
67 'name': 'Request name', 83 'name': 'Request name',
68 'priority': 50, 84 'priority': 50,
69 'properties': task_request.TaskProperties(**props), 85 'properties': properties,
70 'expiration_ts': now + datetime.timedelta(seconds=30), 86 'expiration_ts': now + datetime.timedelta(seconds=30),
71 'tags': [u'tag:1'], 87 'tags': [u'tag:1'],
72 'user': 'Jesus', 88 'user': 'Jesus',
73 } 89 }
74 args.update(kwargs) 90 args.update(kwargs)
91 # Note that ndb model constructor accepts dicts for structured properties.
75 return task_request.TaskRequest(**args) 92 return task_request.TaskRequest(**args)
76 93
77 94
78 class Prop(object): 95 class Prop(object):
79 _name = 'foo' 96 _name = 'foo'
80 97
81 98
82 class TestCase(test_case.TestCase): 99 class TestCase(test_case.TestCase):
83 def setUp(self): 100 def setUp(self):
84 super(TestCase, self).setUp() 101 super(TestCase, self).setUp()
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 task_request.validate_request_key(key) 210 task_request.validate_request_key(key)
194 211
195 def test_make_request(self): 212 def test_make_request(self):
196 # Compare with test_make_request_clone(). 213 # Compare with test_make_request_clone().
197 parent = mkreq(_gen_request()) 214 parent = mkreq(_gen_request())
198 # Hack: Would need to know about TaskResultSummary. 215 # Hack: Would need to know about TaskResultSummary.
199 parent_id = task_pack.pack_request_key(parent.key) + '1' 216 parent_id = task_pack.pack_request_key(parent.key) + '1'
200 r = _gen_request(properties=dict(idempotent=True), parent_task_id=parent_id) 217 r = _gen_request(properties=dict(idempotent=True), parent_task_id=parent_id)
201 request = mkreq(r) 218 request = mkreq(r)
202 expected_properties = { 219 expected_properties = {
220 'cipd_input': {
221 'settings': CIPD_SETTINGS.SerializeToString(),
222 'packages': [{'package_name': 'rm', 'version': PINNED_PACKAGE_VERSION}],
223 },
203 'command': [u'command1', u'arg1'], 224 'command': [u'command1', u'arg1'],
204 'dimensions': { 225 'dimensions': {
205 u'OS': u'Windows-3.1.1', 226 u'OS': u'Windows-3.1.1',
206 u'hostname': u'localhost', 227 u'hostname': u'localhost',
207 u'pool': u'default', 228 u'pool': u'default',
208 }, 229 },
209 'env': {u'foo': u'bar', u'joe': u'2'}, 230 'env': {u'foo': u'bar', u'joe': u'2'},
210 'extra_args': [], 231 'extra_args': [],
211 'execution_timeout_secs': 30, 232 'execution_timeout_secs': 30,
212 'grace_period_secs': 30, 233 'grace_period_secs': 30,
213 'idempotent': True, 234 'idempotent': True,
214 'inputs_ref': { 235 'inputs_ref': {
215 'isolated': None, 236 'isolated': None,
216 'isolatedserver': 'https://isolateserver.appspot.com', 237 'isolatedserver': 'https://isolateserver.appspot.com',
217 'namespace': 'default-gzip', 238 'namespace': 'default-gzip',
218 }, 239 },
219 'io_timeout_secs': None, 240 'io_timeout_secs': None,
220 'packages': [{'package_name': 'rm', 'version': PINNED_PACKAGE_VERSION}],
221 } 241 }
222 expected_request = { 242 expected_request = {
223 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, 243 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY,
224 'name': u'Request name', 244 'name': u'Request name',
225 'parent_task_id': unicode(parent_id), 245 'parent_task_id': unicode(parent_id),
226 'priority': 49, 246 'priority': 49,
227 'properties': expected_properties, 247 'properties': expected_properties,
228 # Intentionally hard code the hash value since it has to be deterministic. 248 # Intentionally hard code the hash value since it has to be deterministic.
229 # Other unit tests should use the calculated value. 249 # Other unit tests should use the calculated value.
230 'properties_hash': 'c3e067b4e232be5478e7147bb1f0506477444014', 250 'properties_hash': '2559848c0be0921d34b2f2085a6fb599efc9a8c9',
231 'pubsub_topic': None, 251 'pubsub_topic': None,
232 'pubsub_userdata': None, 252 'pubsub_userdata': None,
233 'tags': [ 253 'tags': [
234 u'OS:Windows-3.1.1', 254 u'OS:Windows-3.1.1',
235 u'hostname:localhost', 255 u'hostname:localhost',
236 u'pool:default', 256 u'pool:default',
237 u'priority:49', 257 u'priority:49',
238 u'tag:1', 258 u'tag:1',
239 u'user:Jesus', 259 u'user:Jesus',
240 ], 260 ],
(...skipping 12 matching lines...) Expand all
253 'isolated': '0123456789012345678901234567890123456789', 273 'isolated': '0123456789012345678901234567890123456789',
254 'isolatedserver': 'http://localhost:1', 274 'isolatedserver': 'http://localhost:1',
255 'namespace': 'default-gzip', 275 'namespace': 'default-gzip',
256 }, 276 },
257 })) 277 }))
258 # Hack: Would need to know about TaskResultSummary. 278 # Hack: Would need to know about TaskResultSummary.
259 parent_id = task_pack.pack_request_key(parent.key) + '1' 279 parent_id = task_pack.pack_request_key(parent.key) + '1'
260 request = mkreq(_gen_request( 280 request = mkreq(_gen_request(
261 properties={'idempotent':True}, parent_task_id=parent_id)) 281 properties={'idempotent':True}, parent_task_id=parent_id))
262 expected_properties = { 282 expected_properties = {
283 'cipd_input': {
284 'packages': [{'package_name': 'rm', 'version': PINNED_PACKAGE_VERSION}],
285 'settings': CIPD_SETTINGS.SerializeToString(),
286 },
263 'command': [u'command1', u'arg1'], 287 'command': [u'command1', u'arg1'],
264 'dimensions': { 288 'dimensions': {
265 u'OS': u'Windows-3.1.1', 289 u'OS': u'Windows-3.1.1',
266 u'hostname': u'localhost', 290 u'hostname': u'localhost',
267 u'pool': u'default', 291 u'pool': u'default',
268 }, 292 },
269 'env': {u'foo': u'bar', u'joe': u'2'}, 293 'env': {u'foo': u'bar', u'joe': u'2'},
270 'extra_args': [], 294 'extra_args': [],
271 'execution_timeout_secs': 30, 295 'execution_timeout_secs': 30,
272 'grace_period_secs': 30, 296 'grace_period_secs': 30,
273 'idempotent': True, 297 'idempotent': True,
274 'inputs_ref': { 298 'inputs_ref': {
275 'isolated': None, 299 'isolated': None,
276 'isolatedserver': 'https://isolateserver.appspot.com', 300 'isolatedserver': 'https://isolateserver.appspot.com',
277 'namespace': 'default-gzip', 301 'namespace': 'default-gzip',
278 }, 302 },
279 'io_timeout_secs': None, 303 'io_timeout_secs': None,
280 'packages': [{'package_name': 'rm', 'version': PINNED_PACKAGE_VERSION}],
281 } 304 }
282 expected_request = { 305 expected_request = {
283 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, 306 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY,
284 'name': u'Request name', 307 'name': u'Request name',
285 'parent_task_id': unicode(parent_id), 308 'parent_task_id': unicode(parent_id),
286 'priority': 49, 309 'priority': 49,
287 'properties': expected_properties, 310 'properties': expected_properties,
288 # Intentionally hard code the hash value since it has to be deterministic. 311 # Intentionally hard code the hash value since it has to be deterministic.
289 # Other unit tests should use the calculated value. 312 # Other unit tests should use the calculated value.
290 'properties_hash': 'c3e067b4e232be5478e7147bb1f0506477444014', 313 'properties_hash': '2559848c0be0921d34b2f2085a6fb599efc9a8c9',
291 'pubsub_topic': None, 314 'pubsub_topic': None,
292 'pubsub_userdata': None, 315 'pubsub_userdata': None,
293 'tags': [ 316 'tags': [
294 u'OS:Windows-3.1.1', 317 u'OS:Windows-3.1.1',
295 u'hostname:localhost', 318 u'hostname:localhost',
296 u'pool:default', 319 u'pool:default',
297 u'priority:49', 320 u'priority:49',
298 u'tag:1', 321 u'tag:1',
299 u'user:Jesus', 322 u'user:Jesus',
300 ], 323 ],
(...skipping 19 matching lines...) Expand all
320 _gen_request(parent_task_id='1d69b9f088008810') 343 _gen_request(parent_task_id='1d69b9f088008810')
321 344
322 def test_make_request_idempotent(self): 345 def test_make_request_idempotent(self):
323 request = mkreq(_gen_request(properties=dict(idempotent=True))) 346 request = mkreq(_gen_request(properties=dict(idempotent=True)))
324 as_dict = request.to_dict() 347 as_dict = request.to_dict()
325 self.assertEqual(True, as_dict['properties']['idempotent']) 348 self.assertEqual(True, as_dict['properties']['idempotent'])
326 # Intentionally hard code the hash value since it has to be deterministic. 349 # Intentionally hard code the hash value since it has to be deterministic.
327 # Other unit tests should use the calculated value. 350 # Other unit tests should use the calculated value.
328 # Ensure the algorithm is deterministic. 351 # Ensure the algorithm is deterministic.
329 self.assertEqual( 352 self.assertEqual(
330 'c3e067b4e232be5478e7147bb1f0506477444014', as_dict['properties_hash']) 353 '2559848c0be0921d34b2f2085a6fb599efc9a8c9', as_dict['properties_hash'])
331 354
332 def test_duped(self): 355 def test_duped(self):
333 # Two TestRequest with the same properties. 356 # Two TestRequest with the same properties.
334 request_1 = mkreq(_gen_request(properties=dict(idempotent=True))) 357 request_1 = mkreq(_gen_request(properties=dict(idempotent=True)))
335 now = utils.utcnow() 358 now = utils.utcnow()
336 request_2 = mkreq(_gen_request( 359 request_2 = mkreq(_gen_request(
337 name='Other', 360 name='Other',
338 user='Other', 361 user='Other',
339 priority=201, 362 priority=201,
340 created_ts=now, 363 created_ts=now,
(...skipping 26 matching lines...) Expand all
367 390
368 with self.assertRaises(datastore_errors.BadValueError): 391 with self.assertRaises(datastore_errors.BadValueError):
369 mkreq(_gen_request(properties=dict(command=[]))) 392 mkreq(_gen_request(properties=dict(command=[])))
370 with self.assertRaises(datastore_errors.BadValueError): 393 with self.assertRaises(datastore_errors.BadValueError):
371 mkreq(_gen_request(properties=dict(command={'a': 'b'}))) 394 mkreq(_gen_request(properties=dict(command={'a': 'b'})))
372 with self.assertRaises(datastore_errors.BadValueError): 395 with self.assertRaises(datastore_errors.BadValueError):
373 mkreq(_gen_request(properties=dict(command='python'))) 396 mkreq(_gen_request(properties=dict(command='python')))
374 mkreq(_gen_request(properties=dict(command=['python']))) 397 mkreq(_gen_request(properties=dict(command=['python'])))
375 mkreq(_gen_request(properties=dict(command=[u'python']))) 398 mkreq(_gen_request(properties=dict(command=[u'python'])))
376 399
400 def mkcipdreq(idempotent=False, **cipd_input):
401 mkreq(_gen_request(
402 properties=dict(idempotent=idempotent, cipd_input=cipd_input)))
403
377 with self.assertRaises(datastore_errors.BadValueError): 404 with self.assertRaises(datastore_errors.BadValueError):
378 mkreq(_gen_request(properties=dict(packages=[{}]))) 405 mkcipdreq(packages=[{}])
379 with self.assertRaises(datastore_errors.BadValueError): 406 with self.assertRaises(datastore_errors.BadValueError):
380 mkreq(_gen_request(properties=dict(packages=[dict(package_name='rm')]))) 407 mkcipdreq(packages=[dict(package_name='rm')])
381 with self.assertRaises(datastore_errors.BadValueError): 408 with self.assertRaises(datastore_errors.BadValueError):
382 mkreq(_gen_request(properties=dict( 409 mkcipdreq(packages=[{'package_name': 'infra|rm', 'version': 'latest'}])
383 packages=[{'package_name': 'infra|rm', 'version': 'latest'}])))
384 with self.assertRaises(datastore_errors.BadValueError): 410 with self.assertRaises(datastore_errors.BadValueError):
385 mkreq(_gen_request(properties=dict( 411 mkcipdreq(packages=[
386 packages=[ 412 {'package_name': 'rm', 'version': 'latest'},
387 {'package_name': 'rm', 'version': 'latest'}, 413 {'package_name': 'rm', 'version': 'canary'},
388 {'package_name': 'rm', 'version': 'canary'}, 414 ])
389 ])))
390 with self.assertRaises(datastore_errors.BadValueError): 415 with self.assertRaises(datastore_errors.BadValueError):
391 mkreq(_gen_request(properties=dict( 416 mkcipdreq(
392 idempotent=True, 417 idempotent=True,
393 packages=[{'package_name': 'rm', 'version': 'latest'}]))) 418 packages=[{'package_name': 'rm', 'version': 'latest'}])
394 mkreq(_gen_request(properties=dict( 419 with self.assertRaises(datastore_errors.BadValueError):
395 packages=[{'package_name': 'rm', 'version': 'latest'}]))) 420 mkcipdreq(settings='blablah_invalid_protobuf')
421 mkcipdreq()
422 mkcipdreq(packages=[{'package_name': 'rm', 'version': 'latest'}])
396 423
397 with self.assertRaises(TypeError): 424 with self.assertRaises(TypeError):
398 mkreq(_gen_request(properties=dict(dimensions=[]))) 425 mkreq(_gen_request(properties=dict(dimensions=[])))
399 with self.assertRaises(datastore_errors.BadValueError): 426 with self.assertRaises(datastore_errors.BadValueError):
400 mkreq(_gen_request(properties=dict(dimensions={}))) 427 mkreq(_gen_request(properties=dict(dimensions={})))
401 with self.assertRaises(datastore_errors.BadValueError): 428 with self.assertRaises(datastore_errors.BadValueError):
402 mkreq(_gen_request( 429 mkreq(_gen_request(
403 properties=dict(dimensions={u'id': u'b', u'a:': u'b'}))) 430 properties=dict(dimensions={u'id': u'b', u'a:': u'b'})))
404 mkreq(_gen_request( 431 mkreq(_gen_request(
405 properties=dict(dimensions={u'id': u'b', u'a.': u'b'}))) 432 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()) 498 parent = mkreq(_gen_request())
472 # Hack: Would need to know about TaskResultSummary. 499 # Hack: Would need to know about TaskResultSummary.
473 parent_id = task_pack.pack_request_key(parent.key) + '1' 500 parent_id = task_pack.pack_request_key(parent.key) + '1'
474 data = _gen_request( 501 data = _gen_request(
475 properties=dict(idempotent=True), parent_task_id=parent_id) 502 properties=dict(idempotent=True), parent_task_id=parent_id)
476 request = task_request.make_request_clone(mkreq(data)) 503 request = task_request.make_request_clone(mkreq(data))
477 # Differences from make_request() are: 504 # Differences from make_request() are:
478 # - idempotent was reset to False. 505 # - idempotent was reset to False.
479 # - parent_task_id was reset to None. 506 # - parent_task_id was reset to None.
480 expected_properties = { 507 expected_properties = {
508 'cipd_input': {
509 'settings': CIPD_SETTINGS.SerializeToString(),
510 'packages': [{'package_name': 'rm', 'version': PINNED_PACKAGE_VERSION}],
511 },
481 'command': [u'command1', u'arg1'], 512 'command': [u'command1', u'arg1'],
482 'dimensions': { 513 'dimensions': {
483 u'OS': u'Windows-3.1.1', 514 u'OS': u'Windows-3.1.1',
484 u'hostname': u'localhost', 515 u'hostname': u'localhost',
485 u'pool': u'default', 516 u'pool': u'default',
486 }, 517 },
487 'env': {u'foo': u'bar', u'joe': u'2'}, 518 'env': {u'foo': u'bar', u'joe': u'2'},
488 'execution_timeout_secs': 30, 519 'execution_timeout_secs': 30,
489 'extra_args': [], 520 'extra_args': [],
490 'grace_period_secs': 30, 521 'grace_period_secs': 30,
491 'idempotent': False, 522 'idempotent': False,
492 'inputs_ref': { 523 'inputs_ref': {
493 'isolated': None, 524 'isolated': None,
494 'isolatedserver': 'https://isolateserver.appspot.com', 525 'isolatedserver': 'https://isolateserver.appspot.com',
495 'namespace': 'default-gzip', 526 'namespace': 'default-gzip',
496 }, 527 },
497 'io_timeout_secs': None, 528 'io_timeout_secs': None,
498 'packages': [{'package_name': 'rm', 'version': PINNED_PACKAGE_VERSION}],
499 } 529 }
500 # Differences from make_request() are: 530 # Differences from make_request() are:
501 # - parent_task_id was reset to None. 531 # - parent_task_id was reset to None.
502 # - tag 'user:' was replaced 532 # - tag 'user:' was replaced
503 # - user was replaced. 533 # - user was replaced.
504 expected_request = { 534 expected_request = {
505 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, 535 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY,
506 'name': u'Request name (Retry #1)', 536 'name': u'Request name (Retry #1)',
507 'parent_task_id': None, 537 'parent_task_id': None,
508 'priority': 49, 538 'priority': 49,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 ndb.Key(task_request.TaskRequest, 0x7f14acec2fcfffff), 593 ndb.Key(task_request.TaskRequest, 0x7f14acec2fcfffff),
564 task_request.request_id_to_key(0xeb5313d0300000)) 594 task_request.request_id_to_key(0xeb5313d0300000))
565 595
566 596
567 if __name__ == '__main__': 597 if __name__ == '__main__':
568 if '-v' in sys.argv: 598 if '-v' in sys.argv:
569 unittest.TestCase.maxDiff = None 599 unittest.TestCase.maxDiff = None
570 logging.basicConfig( 600 logging.basicConfig(
571 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR) 601 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)
572 unittest.main() 602 unittest.main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698