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

Side by Side Diff: appengine/swarming/local_smoke_test.py

Issue 2870793002: swarming: fix support for raw command + isolated file (Closed)
Patch Set: . Created 3 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 | « no previous file | appengine/swarming/server/task_request.py » ('j') | client/swarming.py » ('J')
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 """Integration test for the Swarming server, Swarming bot and Swarming client. 6 """Integration test for the Swarming server, Swarming bot and Swarming client.
7 7
8 It starts both a Swarming server and a Swarming bot and triggers tasks with the 8 It starts both a Swarming server and a Swarming bot and triggers tasks with the
9 Swarming client to ensure the system works end to end. 9 Swarming client to ensure the system works end to end.
10 """ 10 """
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 67
68 RESULT_HEY_OUTPUTS_REF = { 68 RESULT_HEY_OUTPUTS_REF = {
69 u'isolated': u'5c64883277eb00bceafe3659f182e194cffc5d96', 69 u'isolated': u'5c64883277eb00bceafe3659f182e194cffc5d96',
70 u'isolatedserver': u'http://localhost:10050', 70 u'isolatedserver': u'http://localhost:10050',
71 u'namespace': u'default-gzip', 71 u'namespace': u'default-gzip',
72 u'view_url': 72 u'view_url':
73 u'http://localhost:10050/browse?namespace=default-gzip' 73 u'http://localhost:10050/browse?namespace=default-gzip'
74 '&hash=5c64883277eb00bceafe3659f182e194cffc5d96', 74 '&hash=5c64883277eb00bceafe3659f182e194cffc5d96',
75 } 75 }
76 76
77 RESULT_HEY2_ISOLATED_OUT = {
78 u'isolated': u'0616f86b24065a0595e58088925567ae54a8157c',
79 u'isolatedserver': u'http://localhost:10050',
80 u'namespace': u'default-gzip',
81 u'view_url':
82 u'http://localhost:10050/browse?namespace=default-gzip'
83 '&hash=0616f86b24065a0595e58088925567ae54a8157c',
84 }
85
86 RESULT_HEY2_OUTPUTS_REF = {
87 u'isolated': u'0616f86b24065a0595e58088925567ae54a8157c',
88 u'isolatedserver': u'http://localhost:10050',
89 u'namespace': u'default-gzip',
90 u'view_url':
91 u'http://localhost:10050/browse?namespace=default-gzip'
92 '&hash=0616f86b24065a0595e58088925567ae54a8157c',
93 }
94
77 RESULT_SECRET_OUTPUT = { 95 RESULT_SECRET_OUTPUT = {
78 u'isolated': u'd2eca4d860e4f1728272f6a736fd1c9ac6e98c4f', 96 u'isolated': u'd2eca4d860e4f1728272f6a736fd1c9ac6e98c4f',
79 u'isolatedserver': u'http://localhost:10050', 97 u'isolatedserver': u'http://localhost:10050',
80 u'namespace': u'default-gzip', 98 u'namespace': u'default-gzip',
81 u'view_url': 99 u'view_url':
82 u'http://localhost:10050/browse?namespace=default-gzip' 100 u'http://localhost:10050/browse?namespace=default-gzip'
83 '&hash=d2eca4d860e4f1728272f6a736fd1c9ac6e98c4f', 101 '&hash=d2eca4d860e4f1728272f6a736fd1c9ac6e98c4f',
84 } 102 }
85 103
86 104
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 h, tmp = tempfile.mkstemp(prefix='swarming_smoke_test', suffix='.json') 147 h, tmp = tempfile.mkstemp(prefix='swarming_smoke_test', suffix='.json')
130 os.close(h) 148 os.close(h)
131 try: 149 try:
132 cmd = [ 150 cmd = [
133 '--user', 'joe@localhost', 151 '--user', 'joe@localhost',
134 '-d', 'pool', 'default', 152 '-d', 'pool', 'default',
135 '--dump-json', tmp, 153 '--dump-json', tmp,
136 '--task-name', name, 154 '--task-name', name,
137 '-I', self._isolate_server, 155 '-I', self._isolate_server,
138 '--namespace', 'default-gzip', 156 '--namespace', 'default-gzip',
139 isolated_hash, 157 '-s', isolated_hash,
140 ] 158 ]
141 if extra: 159 if extra:
142 cmd.extend(extra) 160 cmd.extend(extra)
143 assert not self._run('trigger', cmd) 161 assert not self._run('trigger', cmd)
144 with open(tmp, 'rb') as f: 162 with open(tmp, 'rb') as f:
145 data = json.load(f) 163 data = json.load(f)
146 task_id = data['tasks'].popitem()[1]['task_id'] 164 task_id = data['tasks'].popitem()[1]['task_id']
147 logging.debug('task_id = %s', task_id) 165 logging.debug('task_id = %s', task_id)
148 return task_id 166 return task_id
149 finally: 167 finally:
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 bot = None 285 bot = None
268 286
269 @classmethod 287 @classmethod
270 def setUpClass(cls): 288 def setUpClass(cls):
271 cls.dimensions = os_utilities.get_dimensions() 289 cls.dimensions = os_utilities.get_dimensions()
272 290
273 def setUp(self): 291 def setUp(self):
274 super(Test, self).setUp() 292 super(Test, self).setUp()
275 # Reset the bot's cache at the start of each task, so that the cache reuse 293 # Reset the bot's cache at the start of each task, so that the cache reuse
276 # data becomes deterministic. 294 # data becomes deterministic.
295 # Main caveat is 'isolated_upload' as the isolate server is not cleared.
277 self.bot.wipe_cache() 296 self.bot.wipe_cache()
278 297
279 def gen_expected(self, **kwargs): 298 def gen_expected(self, **kwargs):
280 return gen_expected(bot_dimensions=self.dimensions, **kwargs) 299 return gen_expected(bot_dimensions=self.dimensions, **kwargs)
281 300
282 def test_raw_bytes(self): 301 def test_raw_bytes(self):
283 # A string of a letter 'A', UTF-8 BOM then UTF-16 BOM then UTF-EDBCDIC then 302 # A string of a letter 'A', UTF-8 BOM then UTF-16 BOM then UTF-EDBCDIC then
284 # invalid UTF-8 and the letter 'B'. It is double escaped so it can be passed 303 # invalid UTF-8 and the letter 'B'. It is double escaped so it can be passed
285 # down the shell. 304 # down the shell.
286 invalid_bytes = 'A\\xEF\\xBB\\xBF\\xFE\\xFF\\xDD\\x73\\x66\\x73\\xc3\\x28B' 305 invalid_bytes = 'A\\xEF\\xBB\\xBF\\xFE\\xFF\\xDD\\x73\\x66\\x73\\xc3\\x28B'
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 'print(\'hi\')', 420 'print(\'hi\')',
402 'with open(os.path.join(sys.argv[1], \'result.txt\'), \'wb\') as f:', 421 'with open(os.path.join(sys.argv[1], \'result.txt\'), \'wb\') as f:',
403 ' f.write(\'hey\')')) 422 ' f.write(\'hey\')'))
404 expected_summary = self.gen_expected( 423 expected_summary = self.gen_expected(
405 name=u'isolated_task', 424 name=u'isolated_task',
406 isolated_out=RESULT_HEY_ISOLATED_OUT, 425 isolated_out=RESULT_HEY_ISOLATED_OUT,
407 performance_stats={ 426 performance_stats={
408 u'isolated_download': { 427 u'isolated_download': {
409 u'initial_number_items': u'0', 428 u'initial_number_items': u'0',
410 u'initial_size': u'0', 429 u'initial_size': u'0',
411 u'items_cold': [112, 200], 430 u'items_cold': sorted([len(hello_world), 200]),
412 u'items_hot': [], 431 u'items_hot': [],
413 }, 432 },
414 u'isolated_upload': { 433 u'isolated_upload': {
415 u'items_cold': [3, 118], 434 u'items_cold': [3, 118],
416 u'items_hot': [], 435 u'items_hot': [],
417 }, 436 },
418 }, 437 },
419 outputs=[u'hi\n'], 438 outputs=[u'hi\n'],
420 outputs_ref=RESULT_HEY_OUTPUTS_REF) 439 outputs_ref=RESULT_HEY_OUTPUTS_REF)
421 expected_files = {os.path.join('0', 'result.txt'): 'hey'} 440 expected_files = {os.path.join('0', 'result.txt'): 'hey'}
422 self._run_isolated( 441 self._run_isolated(
423 hello_world, 'isolated_task', ['--', '${ISOLATED_OUTDIR}'], 442 hello_world, 'isolated_task', ['--', '${ISOLATED_OUTDIR}'],
424 expected_summary, expected_files) 443 expected_summary, expected_files)
425 444
445 def test_isolated_command(self):
446 # Command is specified in Swarming task, still with isolated file.
447 hello_world = '\n'.join((
448 'import os',
449 'import sys',
450 'print(\'hi\')',
451 'with open(os.path.join(sys.argv[1], \'result.txt\'), \'wb\') as f:',
452 ' f.write(\'hey2\')'))
453 expected_summary = self.gen_expected(
454 name=u'separate_cmd',
455 isolated_out=RESULT_HEY2_ISOLATED_OUT,
456 performance_stats={
457 u'isolated_download': {
458 u'initial_number_items': u'0',
459 u'initial_size': u'0',
460 u'items_cold': sorted([len(hello_world), 157]),
461 u'items_hot': [],
462 },
463 u'isolated_upload': {
464 u'items_cold': [4, 118],
465 u'items_hot': [],
466 },
467 },
468 outputs=[u'hi\n'],
469 outputs_ref=RESULT_HEY2_OUTPUTS_REF)
470 expected_files = {os.path.join('0', 'result.txt'): 'hey2'}
471 self._run_isolated(
472 hello_world, 'separate_cmd',
473 ['--raw-cmd', '--', 'python', 'hello_world.py', '${ISOLATED_OUTDIR}'],
474 expected_summary, expected_files,
475 isolated_content={'variables': {'files': ['hello_world.py']}})
476
426 def test_isolated_hard_timeout(self): 477 def test_isolated_hard_timeout(self):
427 # Make an isolated file, archive it, have it time out. Similar to 478 # Make an isolated file, archive it, have it time out. Similar to
428 # test_hard_timeout. The script doesn't handle signal so it failed the grace 479 # test_hard_timeout. The script doesn't handle signal so it failed the grace
429 # period. 480 # period.
430 hello_world = '\n'.join(( 481 hello_world = '\n'.join((
431 'import os', 482 'import os',
432 'import sys', 483 'import sys',
433 'import time', 484 'import time',
434 'sys.stdout.write(\'hi\\n\')', 485 'sys.stdout.write(\'hi\\n\')',
435 'sys.stdout.flush()', 486 'sys.stdout.flush()',
436 'time.sleep(120)', 487 'time.sleep(120)',
437 'with open(os.path.join(sys.argv[1], \'result.txt\'), \'wb\') as f:', 488 'with open(os.path.join(sys.argv[1], \'result.txt\'), \'wb\') as f:',
438 ' f.write(\'hey\')')) 489 ' f.write(\'hey\')'))
439 expected_summary = self.gen_expected( 490 expected_summary = self.gen_expected(
440 name=u'isolated_hard_timeout', 491 name=u'isolated_hard_timeout',
441 exit_codes=[SIGNAL_TERM], 492 exit_codes=[SIGNAL_TERM],
442 failure=True, 493 failure=True,
443 performance_stats={ 494 performance_stats={
444 u'isolated_download': { 495 u'isolated_download': {
445 u'initial_number_items': u'0', 496 u'initial_number_items': u'0',
446 u'initial_size': u'0', 497 u'initial_size': u'0',
447 u'items_cold': [172, 200], 498 u'items_cold': sorted([len(hello_world), 200]),
448 u'items_hot': [], 499 u'items_hot': [],
449 }, 500 },
450 u'isolated_upload': { 501 u'isolated_upload': {
451 u'items_cold': [], 502 u'items_cold': [],
452 u'items_hot': [], 503 u'items_hot': [],
453 }, 504 },
454 }, 505 },
455 state=0x40) # task_result.State.TIMED_OUT 506 state=0x40) # task_result.State.TIMED_OUT
456 # Hard timeout is enforced by run_isolated, I/O timeout by task_runner. 507 # Hard timeout is enforced by run_isolated, I/O timeout by task_runner.
457 self._run_isolated( 508 self._run_isolated(
(...skipping 25 matching lines...) Expand all
483 ' print(\'ioerror\')', 534 ' print(\'ioerror\')',
484 'with open(os.path.join(sys.argv[1], \'result.txt\'), \'wb\') as f:', 535 'with open(os.path.join(sys.argv[1], \'result.txt\'), \'wb\') as f:',
485 ' f.write(\'hey\')')) 536 ' f.write(\'hey\')'))
486 expected_summary = self.gen_expected( 537 expected_summary = self.gen_expected(
487 name=u'isolated_hard_timeout_grace', 538 name=u'isolated_hard_timeout_grace',
488 isolated_out=RESULT_HEY_ISOLATED_OUT, 539 isolated_out=RESULT_HEY_ISOLATED_OUT,
489 performance_stats={ 540 performance_stats={
490 u'isolated_download': { 541 u'isolated_download': {
491 u'initial_number_items': u'0', 542 u'initial_number_items': u'0',
492 u'initial_size': u'0', 543 u'initial_size': u'0',
493 u'items_cold': [200, 407], 544 u'items_cold': sorted([200, len(hello_world)]),
494 u'items_hot': [], 545 u'items_hot': [],
495 }, 546 },
496 u'isolated_upload': { 547 u'isolated_upload': {
497 u'items_cold': [], 548 u'items_cold': [],
498 u'items_hot': [3, 118], 549 u'items_hot': [3, 118],
499 }, 550 },
500 }, 551 },
501 outputs=[u'hi\ngot signal 15\n'], 552 outputs=[u'hi\ngot signal 15\n'],
502 outputs_ref=RESULT_HEY_OUTPUTS_REF, 553 outputs_ref=RESULT_HEY_OUTPUTS_REF,
503 failure=True, 554 failure=True,
504 state=0x40) # task_result.State.TIMED_OUT 555 state=0x40) # task_result.State.TIMED_OUT
505 expected_files = {os.path.join('0', 'result.txt'): 'hey'} 556 expected_files = {os.path.join('0', 'result.txt'): 'hey'}
506 # Hard timeout is enforced by run_isolated, I/O timeout by task_runner. 557 # Hard timeout is enforced by run_isolated, I/O timeout by task_runner.
507 self._run_isolated( 558 self._run_isolated(
508 hello_world, 'isolated_hard_timeout_grace', 559 hello_world, 'isolated_hard_timeout_grace',
509 ['--hard-timeout', '1', '--', '${ISOLATED_OUTDIR}'], 560 ['--hard-timeout', '1', '--', '${ISOLATED_OUTDIR}'],
510 expected_summary, expected_files) 561 expected_summary, expected_files)
511 562
512 def test_idempotent_reuse(self): 563 def test_idempotent_reuse(self):
513 hello_world = 'print "hi"\n' 564 hello_world = 'print "hi"\n'
514 expected_summary = self.gen_expected( 565 expected_summary = self.gen_expected(
515 name=u'idempotent_reuse', 566 name=u'idempotent_reuse',
516 performance_stats={ 567 performance_stats={
517 u'isolated_download': { 568 u'isolated_download': {
518 u'initial_number_items': u'0', 569 u'initial_number_items': u'0',
519 u'initial_size': u'0', 570 u'initial_size': u'0',
520 u'items_cold': [11, 199], 571 u'items_cold': sorted([len(hello_world), 199]),
521 u'items_hot': [], 572 u'items_hot': [],
522 }, 573 },
523 u'isolated_upload': { 574 u'isolated_upload': {
524 u'items_cold': [], 575 u'items_cold': [],
525 u'items_hot': [], 576 u'items_hot': [],
526 }, 577 },
527 }, 578 },
528 properties_hash = 579 properties_hash =
529 u'082928de84d0a65839d227dcea2f5a947898929c77c1602b68c46d7d4588c1f5', 580 u'082928de84d0a65839d227dcea2f5a947898929c77c1602b68c46d7d4588c1f5',
530 ) 581 )
(...skipping 23 matching lines...) Expand all
554 with open(os.path.join(sys.argv[1], 'sekret'), 'w') as f: 605 with open(os.path.join(sys.argv[1], 'sekret'), 'w') as f:
555 print >> f, data['swarming']['secret_bytes'].decode('base64') 606 print >> f, data['swarming']['secret_bytes'].decode('base64')
556 """) 607 """)
557 expected_summary = self.gen_expected( 608 expected_summary = self.gen_expected(
558 name=u'secret_bytes', 609 name=u'secret_bytes',
559 isolated_out=RESULT_SECRET_OUTPUT, 610 isolated_out=RESULT_SECRET_OUTPUT,
560 performance_stats={ 611 performance_stats={
561 u'isolated_download': { 612 u'isolated_download': {
562 u'initial_number_items': u'0', 613 u'initial_number_items': u'0',
563 u'initial_size': u'0', 614 u'initial_size': u'0',
564 u'items_cold': [200, 241], 615 u'items_cold': sorted([200, len(hello_world)]),
565 u'items_hot': [], 616 u'items_hot': [],
566 }, 617 },
567 u'isolated_upload': { 618 u'isolated_upload': {
568 u'items_cold': [7, 114], 619 u'items_cold': [7, 114],
569 u'items_hot': [], 620 u'items_hot': [],
570 }, 621 },
571 }, 622 },
572 outputs_ref=RESULT_SECRET_OUTPUT, 623 outputs_ref=RESULT_SECRET_OUTPUT,
573 ) 624 )
574 h, tmp = tempfile.mkstemp(prefix='swarming_smoke_test_secret') 625 h, tmp = tempfile.mkstemp(prefix='swarming_smoke_test_secret')
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 }, 695 },
645 }, 696 },
646 ) 697 )
647 self._run_isolated( 698 self._run_isolated(
648 script, 'cache_second', 699 script, 'cache_second',
649 ['--named-cache', 'fuu', 'p/b', '--', '${ISOLATED_OUTDIR}/yo'], 700 ['--named-cache', 'fuu', 'p/b', '--', '${ISOLATED_OUTDIR}/yo'],
650 expected_summary, 701 expected_summary,
651 {'0/yo': 'Yo!'}) 702 {'0/yo': 'Yo!'})
652 703
653 def _run_isolated(self, hello_world, name, args, expected_summary, 704 def _run_isolated(self, hello_world, name, args, expected_summary,
654 expected_files, deduped=False): 705 expected_files, deduped=False, isolated_content=None):
706 """Runs hello_world.py as an isolated file."""
655 # Shared code for all test_isolated_* test cases. 707 # Shared code for all test_isolated_* test cases.
656 tmpdir = tempfile.mkdtemp(prefix='swarming_smoke') 708 tmpdir = tempfile.mkdtemp(prefix='swarming_smoke')
657 try: 709 try:
658 isolate_path = os.path.join(tmpdir, 'i.isolate') 710 isolate_path = os.path.join(tmpdir, 'i.isolate')
659 isolated_path = os.path.join(tmpdir, 'i.isolated') 711 isolated_path = os.path.join(tmpdir, 'i.isolated')
660 with open(isolate_path, 'wb') as f: 712 with open(isolate_path, 'wb') as f:
661 json.dump(ISOLATE_HELLO_WORLD, f) 713 json.dump(isolated_content or ISOLATE_HELLO_WORLD, f)
662 with open(os.path.join(tmpdir, 'hello_world.py'), 'wb') as f: 714 with open(os.path.join(tmpdir, 'hello_world.py'), 'wb') as f:
663 f.write(hello_world) 715 f.write(hello_world)
664 isolated_hash = self.client.isolate(isolate_path, isolated_path) 716 isolated_hash = self.client.isolate(isolate_path, isolated_path)
665 task_id = self.client.task_trigger_isolated( 717 task_id = self.client.task_trigger_isolated(
666 name, isolated_hash, extra=args) 718 name, isolated_hash, extra=args)
667 actual_summary, actual_files = self.client.task_collect(task_id) 719 actual_summary, actual_files = self.client.task_collect(task_id)
668 self.assertResults(expected_summary, actual_summary, deduped=deduped) 720 self.assertResults(expected_summary, actual_summary, deduped=deduped)
669 actual_files.pop('summary.json') 721 actual_files.pop('summary.json')
670 self.assertEqual(expected_files, actual_files) 722 self.assertEqual(expected_files, actual_files)
671 return task_id 723 return task_id
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
821 if bot is not None and bot.poll() is None: 873 if bot is not None and bot.poll() is None:
822 bot.kill() 874 bot.kill()
823 bot.wait() 875 bot.wait()
824 finally: 876 finally:
825 cleanup(bot, client, servers, failed or verbose, leak) 877 cleanup(bot, client, servers, failed or verbose, leak)
826 return int(failed) 878 return int(failed)
827 879
828 880
829 if __name__ == '__main__': 881 if __name__ == '__main__':
830 sys.exit(main()) 882 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | appengine/swarming/server/task_request.py » ('j') | client/swarming.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698