| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The LUCI Authors. All rights reserved. | 2 # Copyright 2014 The LUCI Authors. All rights reserved. |
| 3 # Use of this source code is governed under the Apache License, Version 2.0 | 3 # Use of this source code is governed under the Apache License, Version 2.0 |
| 4 # that can be found in the LICENSE file. | 4 # that can be found in the LICENSE file. |
| 5 | 5 |
| 6 import datetime | 6 import datetime |
| 7 import logging | 7 import logging |
| 8 import random | 8 import random |
| 9 import sys | 9 import sys |
| 10 import unittest | 10 import unittest |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 }) | 68 }) |
| 69 | 69 |
| 70 inputs_ref = properties.pop('inputs_ref', { | 70 inputs_ref = properties.pop('inputs_ref', { |
| 71 'isolatedserver': 'https://isolateserver.appspot.com', | 71 'isolatedserver': 'https://isolateserver.appspot.com', |
| 72 'namespace': 'default-gzip', | 72 'namespace': 'default-gzip', |
| 73 }) | 73 }) |
| 74 | 74 |
| 75 properties = merge(properties, { | 75 properties = merge(properties, { |
| 76 'cipd_input': cipd_input, | 76 'cipd_input': cipd_input, |
| 77 'command': [u'command1', u'arg1'], | 77 'command': [u'command1', u'arg1'], |
| 78 'dimensions': { | 78 'dimensions_flat': [ |
| 79 u'OS': u'Windows-3.1.1', | 79 u'hostname:localhost', |
| 80 u'hostname': u'localhost', | 80 u'os:Windows-3.1.1', |
| 81 u'pool': u'default', | 81 # Test repeated keys. In this case, the bot has to be in both pools. |
| 82 }, | 82 u'pool:default', |
| 83 u'pool:testing', |
| 84 ], |
| 83 'env': {u'foo': u'bar', u'joe': u'2'}, | 85 'env': {u'foo': u'bar', u'joe': u'2'}, |
| 84 'execution_timeout_secs': 30, | 86 'execution_timeout_secs': 30, |
| 85 'grace_period_secs': 30, | 87 'grace_period_secs': 30, |
| 86 'idempotent': False, | 88 'idempotent': False, |
| 87 'inputs_ref': inputs_ref, | 89 'inputs_ref': inputs_ref, |
| 88 'io_timeout_secs': None, | 90 'io_timeout_secs': None, |
| 89 'has_secret_bytes': 'secret_bytes' in kwargs, | 91 'has_secret_bytes': 'secret_bytes' in kwargs, |
| 90 }) | 92 }) |
| 91 properties['dimensions_dict'] = properties.pop('dimensions') | |
| 92 now = utils.utcnow() | 93 now = utils.utcnow() |
| 93 args = { | 94 args = { |
| 94 'created_ts': now, | 95 'created_ts': now, |
| 95 'name': 'Request name', | 96 'name': 'Request name', |
| 96 'priority': 50, | 97 'priority': 50, |
| 97 'properties': properties, | 98 'properties': properties, |
| 98 'expiration_ts': now + datetime.timedelta(seconds=30), | 99 'expiration_ts': now + datetime.timedelta(seconds=30), |
| 99 'tags': [u'tag:1'], | 100 'tags': [u'tag:1'], |
| 100 'user': 'Jesus', | 101 'user': 'Jesus', |
| 101 } | 102 } |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 'version': u'git_revision:deadbeef', | 236 'version': u'git_revision:deadbeef', |
| 236 }, | 237 }, |
| 237 'packages': [{ | 238 'packages': [{ |
| 238 'package_name': u'rm', | 239 'package_name': u'rm', |
| 239 'path': u'bin', | 240 'path': u'bin', |
| 240 'version': u'git_revision:deadbeef', | 241 'version': u'git_revision:deadbeef', |
| 241 }], | 242 }], |
| 242 'server': u'https://chrome-infra-packages.appspot.com' | 243 'server': u'https://chrome-infra-packages.appspot.com' |
| 243 }, | 244 }, |
| 244 'command': [u'command1', u'arg1'], | 245 'command': [u'command1', u'arg1'], |
| 245 'dimensions': { | 246 'dimensions': [ |
| 246 u'OS': u'Windows-3.1.1', | 247 (u'hostname', u'localhost'), |
| 247 u'hostname': u'localhost', | 248 (u'os', u'Windows-3.1.1'), |
| 248 u'pool': u'default', | 249 (u'pool', u'default'), |
| 249 }, | 250 (u'pool', u'testing'), |
| 251 ], |
| 250 'env': {u'foo': u'bar', u'joe': u'2'}, | 252 'env': {u'foo': u'bar', u'joe': u'2'}, |
| 251 'extra_args': [], | 253 'extra_args': [], |
| 252 'execution_timeout_secs': 30, | 254 'execution_timeout_secs': 30, |
| 253 'grace_period_secs': 30, | 255 'grace_period_secs': 30, |
| 254 'idempotent': True, | 256 'idempotent': True, |
| 255 'inputs_ref': { | 257 'inputs_ref': { |
| 256 'isolated': None, | 258 'isolated': None, |
| 257 'isolatedserver': u'https://isolateserver.appspot.com', | 259 'isolatedserver': u'https://isolateserver.appspot.com', |
| 258 'namespace': u'default-gzip', | 260 'namespace': u'default-gzip', |
| 259 }, | 261 }, |
| 260 'io_timeout_secs': None, | 262 'io_timeout_secs': None, |
| 261 'outputs': [], | 263 'outputs': [], |
| 262 'has_secret_bytes': True, | 264 'has_secret_bytes': True, |
| 263 } | 265 } |
| 264 expected_request = { | 266 expected_request = { |
| 265 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, | 267 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, |
| 266 'name': u'Request name', | 268 'name': u'Request name', |
| 267 'parent_task_id': unicode(parent_id), | 269 'parent_task_id': unicode(parent_id), |
| 268 'priority': 49, | 270 'priority': 49, |
| 269 'properties': expected_properties, | 271 'properties': expected_properties, |
| 270 # Intentionally hard code the hash value since it has to be deterministic. | 272 # Intentionally hard code the hash value since it has to be deterministic. |
| 271 # Other unit tests should use the calculated value. | 273 # Other unit tests should use the calculated value. |
| 272 'properties_hash': | 274 'properties_hash': |
| 273 '258e0894f2589a7bc2b46bd563d01f64300ae08938fb14b3d750baff94ba714e', | 275 '40635327d825d2e12ba704b7db72be55dc1dcf195ff881eff558c1be2a9f7ef6', |
| 274 'pubsub_topic': None, | 276 'pubsub_topic': None, |
| 275 'pubsub_userdata': None, | 277 'pubsub_userdata': None, |
| 276 'service_account': u'none', | 278 'service_account': u'none', |
| 277 'tags': [ | 279 'tags': [ |
| 278 u'OS:Windows-3.1.1', | |
| 279 u'hostname:localhost', | 280 u'hostname:localhost', |
| 281 u'os:Windows-3.1.1', |
| 280 u'pool:default', | 282 u'pool:default', |
| 283 u'pool:testing', |
| 281 u'priority:49', | 284 u'priority:49', |
| 282 u'service_account:none', | 285 u'service_account:none', |
| 283 u'tag:1', | 286 u'tag:1', |
| 284 u'user:Jesus', | 287 u'user:Jesus', |
| 285 ], | 288 ], |
| 286 'user': u'Jesus', | 289 'user': u'Jesus', |
| 287 } | 290 } |
| 288 actual = request.to_dict() | 291 actual = request.to_dict() |
| 289 actual.pop('created_ts') | 292 actual.pop('created_ts') |
| 290 actual.pop('expiration_ts') | 293 actual.pop('expiration_ts') |
| (...skipping 23 matching lines...) Expand all Loading... |
| 314 'version': u'git_revision:deadbeef', | 317 'version': u'git_revision:deadbeef', |
| 315 }, | 318 }, |
| 316 'packages': [{ | 319 'packages': [{ |
| 317 'package_name': u'rm', | 320 'package_name': u'rm', |
| 318 'path': u'bin', | 321 'path': u'bin', |
| 319 'version': u'git_revision:deadbeef', | 322 'version': u'git_revision:deadbeef', |
| 320 }], | 323 }], |
| 321 'server': u'https://chrome-infra-packages.appspot.com' | 324 'server': u'https://chrome-infra-packages.appspot.com' |
| 322 }, | 325 }, |
| 323 'command': [u'command1', u'arg1'], | 326 'command': [u'command1', u'arg1'], |
| 324 'dimensions': { | 327 'dimensions': [ |
| 325 u'OS': u'Windows-3.1.1', | 328 (u'hostname', u'localhost'), |
| 326 u'hostname': u'localhost', | 329 (u'os', u'Windows-3.1.1'), |
| 327 u'pool': u'default', | 330 (u'pool', u'default'), |
| 328 }, | 331 (u'pool', u'testing'), |
| 332 ], |
| 329 'env': {u'foo': u'bar', u'joe': u'2'}, | 333 'env': {u'foo': u'bar', u'joe': u'2'}, |
| 330 'extra_args': [], | 334 'extra_args': [], |
| 331 'execution_timeout_secs': 30, | 335 'execution_timeout_secs': 30, |
| 332 'grace_period_secs': 30, | 336 'grace_period_secs': 30, |
| 333 'idempotent': True, | 337 'idempotent': True, |
| 334 'inputs_ref': { | 338 'inputs_ref': { |
| 335 'isolated': None, | 339 'isolated': None, |
| 336 'isolatedserver': u'https://isolateserver.appspot.com', | 340 'isolatedserver': u'https://isolateserver.appspot.com', |
| 337 'namespace': u'default-gzip', | 341 'namespace': u'default-gzip', |
| 338 }, | 342 }, |
| 339 'io_timeout_secs': None, | 343 'io_timeout_secs': None, |
| 340 'outputs': [], | 344 'outputs': [], |
| 341 'has_secret_bytes': True, | 345 'has_secret_bytes': True, |
| 342 } | 346 } |
| 343 expected_request = { | 347 expected_request = { |
| 344 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, | 348 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, |
| 345 'name': u'Request name', | 349 'name': u'Request name', |
| 346 'parent_task_id': unicode(parent_id), | 350 'parent_task_id': unicode(parent_id), |
| 347 'priority': 49, | 351 'priority': 49, |
| 348 'properties': expected_properties, | 352 'properties': expected_properties, |
| 349 # Intentionally hard code the hash value since it has to be deterministic. | 353 # Intentionally hard code the hash value since it has to be deterministic. |
| 350 # Other unit tests should use the calculated value. | 354 # Other unit tests should use the calculated value. |
| 351 'properties_hash': | 355 'properties_hash': |
| 352 '693715e9539552e2ece434e25a665d437cfe4685504a3c7bad6356f9feffee2a', | 356 'cbbf1b58e73a27c15bae48019cd6678a47a4bfb637c63b47af7231e11d82109e', |
| 353 'pubsub_topic': None, | 357 'pubsub_topic': None, |
| 354 'pubsub_userdata': None, | 358 'pubsub_userdata': None, |
| 355 'service_account': u'none', | 359 'service_account': u'none', |
| 356 'tags': [ | 360 'tags': [ |
| 357 u'OS:Windows-3.1.1', | |
| 358 u'hostname:localhost', | 361 u'hostname:localhost', |
| 362 u'os:Windows-3.1.1', |
| 359 u'pool:default', | 363 u'pool:default', |
| 364 u'pool:testing', |
| 360 u'priority:49', | 365 u'priority:49', |
| 361 u'service_account:none', | 366 u'service_account:none', |
| 362 u'tag:1', | 367 u'tag:1', |
| 363 u'user:Jesus', | 368 u'user:Jesus', |
| 364 ], | 369 ], |
| 365 'user': u'Jesus', | 370 'user': u'Jesus', |
| 366 } | 371 } |
| 367 actual = request.to_dict() | 372 actual = request.to_dict() |
| 368 # expiration_ts - created_ts == scheduling_expiration_secs. | 373 # expiration_ts - created_ts == scheduling_expiration_secs. |
| 369 actual.pop('created_ts') | 374 actual.pop('created_ts') |
| (...skipping 14 matching lines...) Expand all Loading... |
| 384 _gen_request(parent_task_id='1d69b9f088008810') | 389 _gen_request(parent_task_id='1d69b9f088008810') |
| 385 | 390 |
| 386 def test_init_new_request_idempotent(self): | 391 def test_init_new_request_idempotent(self): |
| 387 request = mkreq(_gen_request(properties=dict(idempotent=True))) | 392 request = mkreq(_gen_request(properties=dict(idempotent=True))) |
| 388 as_dict = request.to_dict() | 393 as_dict = request.to_dict() |
| 389 self.assertEqual(True, as_dict['properties']['idempotent']) | 394 self.assertEqual(True, as_dict['properties']['idempotent']) |
| 390 # Intentionally hard code the hash value since it has to be deterministic. | 395 # Intentionally hard code the hash value since it has to be deterministic. |
| 391 # Other unit tests should use the calculated value. | 396 # Other unit tests should use the calculated value. |
| 392 # Ensure the algorithm is deterministic. | 397 # Ensure the algorithm is deterministic. |
| 393 self.assertEqual( | 398 self.assertEqual( |
| 394 'c7445927612637c589b72dd47c4657b166a53ac6ecdfd08c167539331a7890d3', | 399 'b4ee0e7018e5fdb414ede87d0da2bc1479211191c5cd6a7af552916d4aa40d25', |
| 395 as_dict['properties_hash']) | 400 as_dict['properties_hash']) |
| 396 | 401 |
| 397 def test_init_new_request_bot_service_account(self): | 402 def test_init_new_request_bot_service_account(self): |
| 398 request = mkreq(_gen_request(service_account_token='bot')) | 403 request = mkreq(_gen_request(service_account_token='bot')) |
| 399 as_dict = request.to_dict() | 404 as_dict = request.to_dict() |
| 400 self.assertEqual('bot', as_dict['service_account']) | 405 self.assertEqual('bot', as_dict['service_account']) |
| 401 self.assertIn(u'service_account:bot', as_dict['tags']) | 406 self.assertIn(u'service_account:bot', as_dict['tags']) |
| 402 | 407 |
| 403 def test_duped(self): | 408 def test_duped(self): |
| 404 # Two TestRequest with the same properties. | 409 # Two TestRequest with the same properties. |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 caches=[dict(name='git_chromium', path='git_cache')], | 544 caches=[dict(name='git_chromium', path='git_cache')], |
| 540 cipd_input=dict(packages=[ | 545 cipd_input=dict(packages=[ |
| 541 dict(package_name='foo', path='git_cache', version='latest')])))) | 546 dict(package_name='foo', path='git_cache', version='latest')])))) |
| 542 mkcachereq() | 547 mkcachereq() |
| 543 mkcachereq(dict(name='git_chromium', path='git_cache')) | 548 mkcachereq(dict(name='git_chromium', path='git_cache')) |
| 544 mkcachereq( | 549 mkcachereq( |
| 545 dict(name='git_chromium', path='git_cache'), | 550 dict(name='git_chromium', path='git_cache'), |
| 546 dict(name='build_chromium', path='out')) | 551 dict(name='build_chromium', path='out')) |
| 547 | 552 |
| 548 # Dimensions. | 553 # Dimensions. |
| 549 with self.assertRaises(TypeError): | |
| 550 mkreq(_gen_request(properties=dict(dimensions=[]))) | |
| 551 with self.assertRaises(datastore_errors.BadValueError): | 554 with self.assertRaises(datastore_errors.BadValueError): |
| 552 mkreq(_gen_request(properties=dict(dimensions={}))) | 555 mkreq(_gen_request(properties=dict(dimensions_flat={}))) |
| 556 with self.assertRaises(datastore_errors.BadValueError): |
| 557 mkreq(_gen_request(properties=dict(dimensions_flat=[]))) |
| 558 with self.assertRaises(datastore_errors.BadValueError): |
| 559 mkreq(_gen_request(properties=dict(dimensions_dict={u'id': u'b'}))) |
| 553 with self.assertRaises(datastore_errors.BadValueError): | 560 with self.assertRaises(datastore_errors.BadValueError): |
| 554 mkreq(_gen_request( | 561 mkreq(_gen_request( |
| 555 properties=dict(dimensions={u'id': u'b', u'a:': u'b'}))) | 562 properties=dict(dimensions_flat=[u'id:b', u'a :b']))) |
| 563 with self.assertRaises(datastore_errors.BadValueError): |
| 564 mkreq(_gen_request( |
| 565 properties=dict(dimensions_flat=[u'id:b', u'a.:b']))) |
| 556 mkreq(_gen_request( | 566 mkreq(_gen_request( |
| 557 properties=dict(dimensions={u'id': u'b', u'a.': u'b'}))) | 567 properties=dict(dimensions_flat=[u'a.:b', u'id:b']))) |
| 558 | 568 |
| 559 # Environment. | 569 # Environment. |
| 560 with self.assertRaises(TypeError): | 570 with self.assertRaises(TypeError): |
| 561 mkreq(_gen_request(properties=dict(env=[]))) | 571 mkreq(_gen_request(properties=dict(env=[]))) |
| 562 with self.assertRaises(TypeError): | 572 with self.assertRaises(TypeError): |
| 563 mkreq(_gen_request(properties=dict(env={u'a': 1}))) | 573 mkreq(_gen_request(properties=dict(env={u'a': 1}))) |
| 564 mkreq(_gen_request(properties=dict(env={}))) | 574 mkreq(_gen_request(properties=dict(env={}))) |
| 565 | 575 |
| 566 # Priority. | 576 # Priority. |
| 567 with self.assertRaises(datastore_errors.BadValueError): | 577 with self.assertRaises(datastore_errors.BadValueError): |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 'version': u'git_revision:deadbeef', | 654 'version': u'git_revision:deadbeef', |
| 645 }, | 655 }, |
| 646 'packages': [{ | 656 'packages': [{ |
| 647 'package_name': u'rm', | 657 'package_name': u'rm', |
| 648 'path': u'bin', | 658 'path': u'bin', |
| 649 'version': u'git_revision:deadbeef', | 659 'version': u'git_revision:deadbeef', |
| 650 }], | 660 }], |
| 651 'server': u'https://chrome-infra-packages.appspot.com' | 661 'server': u'https://chrome-infra-packages.appspot.com' |
| 652 }, | 662 }, |
| 653 'command': [u'command1', u'arg1'], | 663 'command': [u'command1', u'arg1'], |
| 654 'dimensions': { | 664 'dimensions': [ |
| 655 u'OS': u'Windows-3.1.1', | 665 (u'hostname', u'localhost'), |
| 656 u'hostname': u'localhost', | 666 (u'os', u'Windows-3.1.1'), |
| 657 u'pool': u'default', | 667 (u'pool', u'default'), |
| 658 }, | 668 (u'pool', u'testing'), |
| 669 ], |
| 659 'env': {u'foo': u'bar', u'joe': u'2'}, | 670 'env': {u'foo': u'bar', u'joe': u'2'}, |
| 660 'execution_timeout_secs': 30, | 671 'execution_timeout_secs': 30, |
| 661 'extra_args': [], | 672 'extra_args': [], |
| 662 'grace_period_secs': 30, | 673 'grace_period_secs': 30, |
| 663 'idempotent': False, | 674 'idempotent': False, |
| 664 'inputs_ref': { | 675 'inputs_ref': { |
| 665 'isolated': None, | 676 'isolated': None, |
| 666 'isolatedserver': u'https://isolateserver.appspot.com', | 677 'isolatedserver': u'https://isolateserver.appspot.com', |
| 667 'namespace': u'default-gzip', | 678 'namespace': u'default-gzip', |
| 668 }, | 679 }, |
| 669 'io_timeout_secs': None, | 680 'io_timeout_secs': None, |
| 670 'outputs': [], | 681 'outputs': [], |
| 671 'has_secret_bytes': False, | 682 'has_secret_bytes': False, |
| 672 } | 683 } |
| 673 # Differences from new_request() are: | 684 # Differences from new_request() are: |
| 674 # - parent_task_id was reset to None. | 685 # - parent_task_id was reset to None. |
| 675 # - tag 'user:' was replaced | 686 # - tag 'user:' was replaced |
| 676 # - user was replaced. | 687 # - user was replaced. |
| 677 expected_request = { | 688 expected_request = { |
| 678 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, | 689 'authenticated': auth_testing.DEFAULT_MOCKED_IDENTITY, |
| 679 'name': u'Request name (Retry #1)', | 690 'name': u'Request name (Retry #1)', |
| 680 'parent_task_id': None, | 691 'parent_task_id': None, |
| 681 'priority': 49, | 692 'priority': 49, |
| 682 'properties': expected_properties, | 693 'properties': expected_properties, |
| 683 'properties_hash': None, | 694 'properties_hash': None, |
| 684 'pubsub_topic': None, | 695 'pubsub_topic': None, |
| 685 'pubsub_userdata': None, | 696 'pubsub_userdata': None, |
| 686 'service_account': u'none', | 697 'service_account': u'none', |
| 687 'tags': [ | 698 'tags': [ |
| 688 u'OS:Windows-3.1.1', | |
| 689 u'hostname:localhost', | 699 u'hostname:localhost', |
| 700 u'os:Windows-3.1.1', |
| 690 u'pool:default', | 701 u'pool:default', |
| 702 u'pool:testing', |
| 691 u'priority:49', | 703 u'priority:49', |
| 692 u'service_account:none', | 704 u'service_account:none', |
| 693 u'tag:1', | 705 u'tag:1', |
| 694 u'user:mocked@example.com', | 706 u'user:mocked@example.com', |
| 695 ], | 707 ], |
| 696 'user': u'mocked@example.com', | 708 'user': u'mocked@example.com', |
| 697 } | 709 } |
| 698 actual = request.to_dict() | 710 actual = request.to_dict() |
| 699 # expiration_ts - created_ts == deadline_to_run. | 711 # expiration_ts - created_ts == deadline_to_run. |
| 700 actual.pop('created_ts') | 712 actual.pop('created_ts') |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 with self.assertRaises(datastore_errors.BadValueError): | 755 with self.assertRaises(datastore_errors.BadValueError): |
| 744 task_request.SecretBytes(secret_bytes='a'*(20*1024+1)).put() | 756 task_request.SecretBytes(secret_bytes='a'*(20*1024+1)).put() |
| 745 | 757 |
| 746 | 758 |
| 747 if __name__ == '__main__': | 759 if __name__ == '__main__': |
| 748 if '-v' in sys.argv: | 760 if '-v' in sys.argv: |
| 749 unittest.TestCase.maxDiff = None | 761 unittest.TestCase.maxDiff = None |
| 750 logging.basicConfig( | 762 logging.basicConfig( |
| 751 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR) | 763 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR) |
| 752 unittest.main() | 764 unittest.main() |
| OLD | NEW |