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

Side by Side Diff: bin/cros_au_test_harness.py

Issue 6348022: Revert "Passes cache location to tests and runs the tests in parallel." (Closed) Base URL: http://git.chromium.org/git/crosutils.git@master
Patch Set: Created 9 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | bin/cros_run_vm_update » ('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/python 1 #!/usr/bin/python
2 2
3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """This module runs a suite of Auto Update tests. 7 """This module runs a suite of Auto Update tests.
8 8
9 The tests can be run on either a virtual machine or actual device depending 9 The tests can be run on either a virtual machine or actual device depending
10 on parameters given. Specific tests can be run by invoking --test_prefix. 10 on parameters given. Specific tests can be run by invoking --test_prefix.
11 Verbose is useful for many of the tests if you want to see individual commands 11 Verbose is useful for many of the tests if you want to see individual commands
12 being run during the update process. 12 being run during the update process.
13 """ 13 """
14 14
15 import optparse 15 import optparse
16 import os 16 import os
17 import re 17 import re
18 import subprocess
19 import sys 18 import sys
20 import threading 19 import threading
21 import time 20 import time
22 import unittest 21 import unittest
23 import urllib 22 import urllib
24 23
25 sys.path.append(os.path.join(os.path.dirname(__file__), '../lib')) 24 sys.path.append(os.path.join(os.path.dirname(__file__), '../lib'))
26 from cros_build_lib import Die 25 from cros_build_lib import Die
27 from cros_build_lib import GetIPAddress
28 from cros_build_lib import Info 26 from cros_build_lib import Info
29 from cros_build_lib import ReinterpretPathForChroot 27 from cros_build_lib import ReinterpretPathForChroot
30 from cros_build_lib import RunCommand 28 from cros_build_lib import RunCommand
31 from cros_build_lib import RunCommandCaptureOutput 29 from cros_build_lib import RunCommandCaptureOutput
32 from cros_build_lib import Warning 30 from cros_build_lib import Warning
33 31
34 import cros_test_proxy 32 import cros_test_proxy
35 33
36 global dev_server_cache
37
38 34
39 class UpdateException(Exception): 35 class UpdateException(Exception):
40 """Exception thrown when _UpdateImage or _UpdateUsingPayload fail""" 36 """Exception thrown when _UpdateImage or _UpdateUsingPayload fail"""
41 def __init__(self, code, stdout): 37 def __init__(self, code, stdout):
42 self.code = code 38 self.code = code
43 self.stdout = stdout 39 self.stdout = stdout
44 40
45 41
46 class AUTest(object): 42 class AUTest(object):
47 """Abstract interface that defines an Auto Update test.""" 43 """Abstract interface that defines an Auto Update test."""
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 output = RunCommand([ 462 output = RunCommand([
467 '%s/run_remote_tests.sh' % self.crosutils, 463 '%s/run_remote_tests.sh' % self.crosutils,
468 '--remote=%s' % self.remote, 464 '--remote=%s' % self.remote,
469 self.verify_suite, 465 self.verify_suite,
470 ], error_ok=True, enter_chroot=False, redirect_stdout=True) 466 ], error_ok=True, enter_chroot=False, redirect_stdout=True)
471 return self.AssertEnoughTestsPassed(self, output, percent_required_to_pass) 467 return self.AssertEnoughTestsPassed(self, output, percent_required_to_pass)
472 468
473 469
474 class VirtualAUTest(unittest.TestCase, AUTest): 470 class VirtualAUTest(unittest.TestCase, AUTest):
475 """Test harness for updating virtual machines.""" 471 """Test harness for updating virtual machines."""
472 vm_image_path = None
476 473
477 # VM Constants. 474 # VM Constants.
478 _FULL_VDISK_SIZE = 6072 475 _FULL_VDISK_SIZE = 6072
479 _FULL_STATEFULFS_SIZE = 3074 476 _FULL_STATEFULFS_SIZE = 3074
480 477 _KVM_PID_FILE = '/tmp/harness_pid'
481 # Class variables used to acquire individual VM variables per test.
482 _vm_lock = threading.Lock()
483 _next_port = 9222
484 478
485 def _KillExistingVM(self, pid_file): 479 def _KillExistingVM(self, pid_file):
486 if os.path.exists(pid_file): 480 if os.path.exists(pid_file):
487 Warning('Existing %s found. Deleting and killing process' % 481 Warning('Existing %s found. Deleting and killing process' %
488 pid_file) 482 pid_file)
489 RunCommand(['./cros_stop_vm', '--kvm_pid=%s' % pid_file], 483 RunCommand(['./cros_stop_vm', '--kvm_pid=%s' % pid_file],
490 cwd=self.crosutilsbin) 484 cwd=self.crosutilsbin)
491 485
492 assert not os.path.exists(pid_file) 486 assert not os.path.exists(pid_file)
493 487
494 def _AcquireUniquePortAndPidFile(self):
495 """Acquires unique ssh port and pid file for VM."""
496 with VirtualAUTest._vm_lock:
497 self._ssh_port = VirtualAUTest._next_port
498 self._kvm_pid_file = '/tmp/kvm.%d' % self._ssh_port
499 VirtualAUTest._next_port += 1
500
501 def setUp(self): 488 def setUp(self):
502 """Unit test overriden method. Is called before every test.""" 489 """Unit test overriden method. Is called before every test."""
503 AUTest.setUp(self) 490 AUTest.setUp(self)
504 self.vm_image_path = None 491 self._KillExistingVM(self._KVM_PID_FILE)
505 self._AcquireUniquePortAndPidFile()
506 self._KillExistingVM(self._kvm_pid_file)
507
508 def tearDown(self):
509 self._KillExistingVM(self._kvm_pid_file)
510 492
511 @classmethod 493 @classmethod
512 def ProcessOptions(cls, parser, options): 494 def ProcessOptions(cls, parser, options):
513 """Processes vm-specific options.""" 495 """Processes vm-specific options."""
514 AUTest.ProcessOptions(parser, options) 496 AUTest.ProcessOptions(parser, options)
515 cls.board = options.board 497 cls.board = options.board
516 498
517 # Communicate flags to tests. 499 # Communicate flags to tests.
518 cls.graphics_flag = '' 500 cls.graphics_flag = ''
519 if options.no_graphics: cls.graphics_flag = '--no_graphics' 501 if options.no_graphics: cls.graphics_flag = '--no_graphics'
(...skipping 18 matching lines...) Expand all
538 os.path.dirname(image_path)), 520 os.path.dirname(image_path)),
539 '--vdisk_size=%s' % self._FULL_VDISK_SIZE, 521 '--vdisk_size=%s' % self._FULL_VDISK_SIZE,
540 '--statefulfs_size=%s' % self._FULL_STATEFULFS_SIZE, 522 '--statefulfs_size=%s' % self._FULL_STATEFULFS_SIZE,
541 '--board=%s' % self.board, 523 '--board=%s' % self.board,
542 '--test_image'], enter_chroot=True) 524 '--test_image'], enter_chroot=True)
543 525
544 Info('Using %s as base' % self.vm_image_path) 526 Info('Using %s as base' % self.vm_image_path)
545 self.assertTrue(os.path.exists(self.vm_image_path)) 527 self.assertTrue(os.path.exists(self.vm_image_path))
546 528
547 def _UpdateImage(self, image_path, src_image_path='', stateful_change='old', 529 def _UpdateImage(self, image_path, src_image_path='', stateful_change='old',
548 proxy_port=''): 530 proxy_port=None):
549 """Updates VM image with image_path.""" 531 """Updates VM image with image_path."""
550 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change) 532 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
551 if src_image_path and self._first_update: 533 if src_image_path and self._first_update:
552 src_image_path = self.vm_image_path 534 src_image_path = self.vm_image_path
553 self._first_update = False 535 self._first_update = False
554 536
555 # Check image payload cache first. 537 cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
556 update_id = _GenerateUpdateId(target=image_path, src=src_image_path) 538 '--update_image_path=%s' % image_path,
557 cache_path = dev_server_cache[update_id] 539 '--vm_image_path=%s' % self.vm_image_path,
558 if cache_path: 540 '--snapshot',
559 Info('Using cache %s' % cache_path) 541 self.graphics_flag,
560 update_url = DevServerWrapper.GetDevServerURL(proxy_port, cache_path) 542 '--persist',
561 cmd = ['%s/cros_run_vm_update' % self.crosutilsbin, 543 '--kvm_pid=%s' % self._KVM_PID_FILE,
562 '--vm_image_path=%s' % self.vm_image_path, 544 stateful_change_flag,
563 '--snapshot', 545 '--src_image=%s' % src_image_path,
564 self.graphics_flag, 546 ]
565 '--persist', 547
566 '--kvm_pid=%s' % self._kvm_pid_file, 548 if proxy_port:
567 '--ssh_port=%s' % self._ssh_port, 549 cmd.append('--proxy_port=%s' % proxy_port)
568 stateful_change_flag,
569 '--update_url=%s' % update_url,
570 ]
571 else:
572 cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
573 '--update_image_path=%s' % image_path,
574 '--vm_image_path=%s' % self.vm_image_path,
575 '--snapshot',
576 self.graphics_flag,
577 '--persist',
578 '--kvm_pid=%s' % self._kvm_pid_file,
579 '--ssh_port=%s' % self._ssh_port,
580 stateful_change_flag,
581 '--src_image=%s' % src_image_path,
582 '--proxy_port=%s' % proxy_port
583 ]
584 550
585 if self.verbose: 551 if self.verbose:
586 try: 552 try:
587 RunCommand(cmd) 553 RunCommand(cmd)
588 except Exception, e: 554 except Exception, e:
589 raise UpdateException(1, e.message) 555 raise UpdateException(1, e.message)
590 else: 556 else:
591 (code, stdout, stderr) = RunCommandCaptureOutput(cmd) 557 (code, stdout, stderr) = RunCommandCaptureOutput(cmd)
592 if code != 0: 558 if code != 0:
593 raise UpdateException(code, stdout) 559 raise UpdateException(code, stdout)
594 560
595 def _UpdateUsingPayload(self, update_path, stateful_change='old', 561 def _UpdateUsingPayload(self, update_path, stateful_change='old',
596 proxy_port=None): 562 proxy_port=None):
597 """Updates a vm image using cros_run_vm_update.""" 563 """Updates a vm image using cros_run_vm_update."""
598 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change) 564 stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
599 cmd = ['%s/cros_run_vm_update' % self.crosutilsbin, 565 cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
600 '--payload=%s' % update_path, 566 '--payload=%s' % update_path,
601 '--vm_image_path=%s' % self.vm_image_path, 567 '--vm_image_path=%s' % self.vm_image_path,
602 '--snapshot', 568 '--snapshot',
603 self.graphics_flag, 569 self.graphics_flag,
604 '--persist', 570 '--persist',
605 '--kvm_pid=%s' % self._kvm_pid_file, 571 '--kvm_pid=%s' % self._KVM_PID_FILE,
606 '--ssh_port=%s' % self._ssh_port,
607 stateful_change_flag, 572 stateful_change_flag,
608 ] 573 ]
609 574
610 if proxy_port: 575 if proxy_port:
611 cmd.append('--proxy_port=%s' % proxy_port) 576 cmd.append('--proxy_port=%s' % proxy_port)
612 577
613 if self.verbose: 578 if self.verbose:
614 try: 579 try:
615 RunCommand(cmd) 580 RunCommand(cmd)
616 except Exception, e: 581 except Exception, e:
617 raise UpdateException(1, e.message) 582 raise UpdateException(1, e.message)
618 else: 583 else:
619 (code, stdout, stderr) = RunCommandCaptureOutput(cmd) 584 (code, stdout, stderr) = RunCommandCaptureOutput(cmd)
620 if code != 0: 585 if code != 0:
621 raise UpdateException(code, stdout) 586 raise UpdateException(code, stdout)
622 587
623 def VerifyImage(self, percent_required_to_pass): 588 def VerifyImage(self, percent_required_to_pass):
624 """Runs vm smoke suite to verify image.""" 589 """Runs vm smoke suite to verify image."""
625 # image_to_live already verifies lsb-release matching. This is just 590 # image_to_live already verifies lsb-release matching. This is just
626 # for additional steps. 591 # for additional steps.
627 592
628 commandWithArgs = ['%s/cros_run_vm_test' % self.crosutilsbin, 593 commandWithArgs = ['%s/cros_run_vm_test' % self.crosutilsbin,
629 '--image_path=%s' % self.vm_image_path, 594 '--image_path=%s' % self.vm_image_path,
630 '--snapshot', 595 '--snapshot',
631 '--persist', 596 '--persist',
632 '--kvm_pid=%s' % self._kvm_pid_file, 597 '--kvm_pid=%s' % self._KVM_PID_FILE,
633 '--ssh_port=%s' % self._ssh_port,
634 self.verify_suite, 598 self.verify_suite,
635 ] 599 ]
636 600
637 if self.graphics_flag: 601 if self.graphics_flag:
638 commandWithArgs.append(self.graphics_flag) 602 commandWithArgs.append(self.graphics_flag)
639 603
640 output = RunCommand(commandWithArgs, error_ok=True, enter_chroot=False, 604 output = RunCommand(commandWithArgs, error_ok=True, enter_chroot=False,
641 redirect_stdout=True) 605 redirect_stdout=True)
642 return self.AssertEnoughTestsPassed(self, output, percent_required_to_pass) 606 return self.AssertEnoughTestsPassed(self, output, percent_required_to_pass)
643 607
644 608
645 class GenerateVirtualAUDeltasTest(VirtualAUTest): 609 class GenerateVirtualAUDeltasTest(VirtualAUTest):
646 """Class the overrides VirtualAUTest and stores deltas we will generate.""" 610 """Class the overrides VirtualAUTest and stores deltas we will generate."""
647 delta_list = {} 611 delta_list = {}
648 612
649 def setUp(self): 613 def setUp(self):
650 AUTest.setUp(self) 614 AUTest.setUp(self)
651 615
652 def tearDown(self):
653 pass
654
655 def _UpdateImage(self, image_path, src_image_path='', stateful_change='old', 616 def _UpdateImage(self, image_path, src_image_path='', stateful_change='old',
656 proxy_port=None): 617 proxy_port=None):
657 if src_image_path and self._first_update: 618 if src_image_path and self._first_update:
658 src_image_path = self.vm_image_path 619 src_image_path = self.vm_image_path
659 self._first_update = False 620 self._first_update = False
660 621
622 image_path = ReinterpretPathForChroot(image_path)
623 if src_image_path:
624 src_image_path = ReinterpretPathForChroot(src_image_path)
661 if not self.delta_list.has_key(image_path): 625 if not self.delta_list.has_key(image_path):
662 self.delta_list[image_path] = set([src_image_path]) 626 self.delta_list[image_path] = set([src_image_path])
663 else: 627 else:
664 self.delta_list[image_path].add(src_image_path) 628 self.delta_list[image_path].add(src_image_path)
665 629
666 def AttemptUpdateWithPayloadExpectedFailure(self, payload, expected_msg): 630 def AttemptUpdateWithPayloadExpectedFailure(self, payload, expected_msg):
667 pass 631 pass
668 632
669 def VerifyImage(self, percent_required_to_pass): 633 def VerifyImage(self, percent_required_to_pass):
670 pass 634 pass
671 635
672 636
673 class ParallelJob(threading.Thread): 637 class ParallelJob(threading.Thread):
674 """Small wrapper for threading. Thread that releases a semaphores on exit.""" 638 """Small wrapper for threading.Thread that releases a semaphore on exit."""
675 639 def __init__(self, semaphore, target, args):
676 def __init__(self, starting_semaphore, ending_semaphore, target, args):
677 """Initializes an instance of a job.
678
679 Args:
680 starting_semaphore: Semaphore used by caller to wait on such that
681 there isn't more than a certain number of threads running. Should
682 be initialized to a value for the number of threads wanting to be run
683 at a time.
684 ending_semaphore: Semaphore is released every time a job ends. Should be
685 initialized to 0 before starting first job. Should be acquired once for
686 each job. Threading.Thread.join() has a bug where if the run function
687 terminates too quickly join() will hang forever.
688 target: The func to run.
689 args: Args to pass to the fun.
690 """
691 threading.Thread.__init__(self, target=target, args=args) 640 threading.Thread.__init__(self, target=target, args=args)
692 self._target = target 641 self._target = target
693 self._args = args 642 self._args = args
694 self._starting_semaphore = starting_semaphore 643 self._semaphore = semaphore
695 self._ending_semaphore = ending_semaphore
696 self._output = None 644 self._output = None
697 self._completed = False 645 self._completed = False
698 646
699 def run(self): 647 def run(self):
700 """Thread override. Runs the method specified and sets output."""
701 try: 648 try:
702 self._output = self._target(*self._args) 649 threading.Thread.run(self)
703 finally: 650 finally:
704 # From threading.py to avoid a refcycle.
705 del self._target, self._args
706 # Our own clean up.
707 self._Cleanup() 651 self._Cleanup()
708 self._completed = True 652 self._completed = True
709 653
710 def GetOutput(self): 654 def GetOutput(self):
711 """Returns the output of the method run."""
712 assert self._completed, 'GetOutput called before thread was run.' 655 assert self._completed, 'GetOutput called before thread was run.'
713 return self._output 656 return self._output
714 657
715 def _Cleanup(self): 658 def _Cleanup(self):
716 """Releases semaphores for a waiting caller.""" 659 self._semaphore.release()
717 self._starting_semaphore.release()
718 self._ending_semaphore.release()
719 660
720 def __str__(self): 661 def __str__(self):
721 return '%s(%s)' % (self._target, self._args) 662 return '%s(%s)' % (self._target, self._args)
722 663
723 664
724 class DevServerWrapper(threading.Thread):
725 """A Simple wrapper around a devserver instance."""
726
727 def __init__(self):
728 self.proc = None
729 threading.Thread.__init__(self)
730
731 def run(self):
732 # Kill previous running instance of devserver if it exists.
733 RunCommand(['sudo', 'pkill', '-f', 'devserver.py', ], error_ok=True,
734 print_cmd=False)
735 self.proc = subprocess.Popen(['sudo',
736 './start_devserver',
737 '--archive_dir=./static',
738 '--client_prefix=ChromeOSUpdateEngine',
739 '--production',
740 ])
741 self.proc.communicate()
742
743 def Stop(self):
744 """Kills the devserver instance."""
745 self.proc.kill()
746
747 @classmethod
748 def GetDevServerURL(cls, port, sub_dir):
749 """Returns the dev server url for a given port and sub directory."""
750 ip_addr = GetIPAddress()
751 if not port: port = 8080
752 url = 'http://%(ip)s:%(port)s/%(dir)s' % {'ip': ip_addr,
753 'port': str(port),
754 'dir': sub_dir}
755 return url
756
757
758 def _GenerateUpdateId(target, src):
759 """Returns a simple representation id of target and src paths."""
760 if src:
761 return '%s->%s' % (target, src)
762 else:
763 return target
764
765
766 def _RunParallelJobs(number_of_sumultaneous_jobs, jobs, jobs_args): 665 def _RunParallelJobs(number_of_sumultaneous_jobs, jobs, jobs_args):
767 """Runs set number of specified jobs in parallel. 666 """Runs set number of specified jobs in parallel.
768 667
769 Args: 668 Args:
770 number_of_simultaneous_jobs: Max number of threads to be run in parallel. 669 number_of_simultaneous_jobs: Max number of threads to be run in parallel.
771 jobs: Array of methods to run. 670 jobs: Array of methods to run.
772 jobs_args: Array of args associated with method calls. 671 jobs_args: Array of args associated with method calls.
773 Returns: 672 Returns:
774 Returns an array of results corresponding to each thread. 673 Returns an array of results corresponding to each thread.
775 """ 674 """
776 def _TwoTupleize(x, y): 675 def _TwoTupleize(x, y):
777 return (x, y) 676 return (x, y)
778 677
779 threads = [] 678 threads = []
780 job_start_semaphore = threading.Semaphore(number_of_sumultaneous_jobs) 679 job_pool_semaphore = threading.Semaphore(number_of_sumultaneous_jobs)
781 join_semaphore = threading.Semaphore(0)
782 assert len(jobs) == len(jobs_args), 'Length of args array is wrong.' 680 assert len(jobs) == len(jobs_args), 'Length of args array is wrong.'
783 681
784 # Create the parallel jobs. 682 # Create the parallel jobs.
785 for job, args in map(_TwoTupleize, jobs, jobs_args): 683 for job, args in map(_TwoTupleize, jobs, jobs_args):
786 thread = ParallelJob(job_start_semaphore, join_semaphore, target=job, 684 thread = ParallelJob(job_pool_semaphore, target=job, args=args)
787 args=args)
788 threads.append(thread) 685 threads.append(thread)
789 686
790 # We use a semaphore to ensure we don't run more jobs that required. 687 # We use a semaphore to ensure we don't run more jobs that required.
791 # After each thread finishes, it releases (increments semaphore). 688 # After each thread finishes, it releases (increments semaphore).
792 # Acquire blocks of num jobs reached and continues when a thread finishes. 689 # Acquire blocks of num jobs reached and continues when a thread finishes.
793 for next_thread in threads: 690 for next_thread in threads:
794 job_start_semaphore.acquire(blocking=True) 691 job_pool_semaphore.acquire(blocking=True)
795 Info('Starting job %s' % next_thread) 692 Info('Starting %s' % next_thread)
796 next_thread.start() 693 next_thread.start()
797 694
798 # Wait on the rest of the threads to finish. 695 # Wait on the rest of the threads to finish.
799 for thread in threads: 696 for thread in threads:
800 join_semaphore.acquire(blocking=True) 697 thread.join()
801 698
802 return [thread.GetOutput() for thread in threads] 699 return [thread.GetOutput() for thread in threads]
803 700
804 701
805 def _PrepareTestSuite(parser, options, test_class):
806 """Returns a prepared test suite given by the options and test class."""
807 test_class.ProcessOptions(parser, options)
808 test_loader = unittest.TestLoader()
809 test_loader.testMethodPrefix = options.test_prefix
810 return test_loader.loadTestsFromTestCase(test_class)
811
812
813 def _PregenerateUpdates(parser, options): 702 def _PregenerateUpdates(parser, options):
814 """Determines all deltas that will be generated and generates them. 703 """Determines all deltas that will be generated and generates them.
815 704
816 This method effectively pre-generates the dev server cache for all tests. 705 This method effectively pre-generates the dev server cache for all tests.
817 706
818 Args: 707 Args:
819 parser: parser from main. 708 parser: parser from main.
820 options: options from parsed parser. 709 options: options from parsed parser.
821 Returns: 710 Returns:
822 Dictionary of Update Identifiers->Relative cache locations. 711 Array of output from generating updates.
823 """ 712 """
824 def _GenerateVMUpdate(target, src): 713 def _GenerateVMUpdate(target, src):
825 """Generates an update using the devserver.""" 714 """Generates an update using the devserver."""
826 target = ReinterpretPathForChroot(target) 715 RunCommand(['sudo',
827 if src: 716 './start_devserver',
828 src = ReinterpretPathForChroot(src) 717 '--pregenerate_update',
829 718 '--exit',
830 return RunCommand(['sudo', 719 '--image=%s' % target,
831 './start_devserver', 720 '--src_image=%s' % src,
832 '--pregenerate_update', 721 '--for_vm'
833 '--exit', 722 ], enter_chroot=True)
834 '--image=%s' % target,
835 '--src_image=%s' % src,
836 '--for_vm',
837 ], redirect_stdout=True, enter_chroot=True,
838 print_cmd=False)
839 723
840 # Get the list of deltas by mocking out update method in test class. 724 # Get the list of deltas by mocking out update method in test class.
841 test_suite = _PrepareTestSuite(parser, options, GenerateVirtualAUDeltasTest) 725 GenerateVirtualAUDeltasTest.ProcessOptions(parser, options)
726 test_loader = unittest.TestLoader()
727 test_loader.testMethodPrefix = options.test_prefix
728 test_suite = test_loader.loadTestsFromTestCase(GenerateVirtualAUDeltasTest)
842 test_result = unittest.TextTestRunner(verbosity=0).run(test_suite) 729 test_result = unittest.TextTestRunner(verbosity=0).run(test_suite)
843 730
844 Info('The following delta updates are required.') 731 Info('The following delta updates are required.')
845 update_ids = []
846 jobs = [] 732 jobs = []
847 args = [] 733 args = []
848 for target, srcs in GenerateVirtualAUDeltasTest.delta_list.items(): 734 for target, srcs in GenerateVirtualAUDeltasTest.delta_list.items():
849 for src in srcs: 735 for src in srcs:
850 update_id = _GenerateUpdateId(target=target, src=src) 736 if src:
851 print >> sys.stderr, 'AU: %s' % update_id 737 print >> sys.stderr, 'DELTA AU %s -> %s' % (src, target)
852 update_ids.append(update_id) 738 else:
739 print >> sys.stderr, 'FULL AU %s' % target
740
853 jobs.append(_GenerateVMUpdate) 741 jobs.append(_GenerateVMUpdate)
854 args.append((target, src)) 742 args.append((target, src))
855 743
856 raw_results = _RunParallelJobs(options.jobs, jobs, args) 744 results = _RunParallelJobs(options.jobs, jobs, args)
857 results = [] 745 return results
858
859 # Parse the output.
860 key_line_re = re.compile('^PREGENERATED_UPDATE=([\w/.]+)')
861 for result in raw_results:
862 for line in result.splitlines():
863 match = key_line_re.search(line)
864 if match:
865 # Convert blah/blah/update.gz -> update/blah/blah.
866 path_to_update_gz = match.group(1).rstrip()
867 (path_to_update_dir, _, _) = path_to_update_gz.rpartition('/update.gz')
868 results.append('/'.join(['update', path_to_update_dir]))
869 break
870
871 assert len(raw_results) == len(results), \
872 'Insufficient number cache directories returned.'
873
874 # Build the dictionary from our id's and returned cache paths.
875 cache_dictionary = {}
876 for index, id in enumerate(update_ids):
877 cache_dictionary[id] = results[index]
878
879 return cache_dictionary
880
881
882 def _RunTestsInParallel(parser, options, test_class):
883 """Runs the tests given by the options and test_class in parallel."""
884 threads = []
885 args = []
886 test_suite = _PrepareTestSuite(parser, options, test_class)
887 for test in test_suite:
888 test_name = test.id()
889 test_case = unittest.TestLoader().loadTestsFromName(test_name)
890 threads.append(unittest.TextTestRunner().run)
891 args.append(test_case)
892
893 results = _RunParallelJobs(options.jobs, threads, args)
894 if not (test_result.wasSuccessful() for test_result in results):
895 Die('Test harness was not successful')
896 746
897 747
898 def main(): 748 def main():
899 parser = optparse.OptionParser() 749 parser = optparse.OptionParser()
900 parser.add_option('-b', '--base_image', 750 parser.add_option('-b', '--base_image',
901 help='path to the base image.') 751 help='path to the base image.')
902 parser.add_option('-r', '--board', 752 parser.add_option('-r', '--board',
903 help='board for the images.') 753 help='board for the images.')
904 parser.add_option('--no_delta', action='store_false', default=True, 754 parser.add_option('--no_delta', action='store_false', default=True,
905 dest='delta', 755 dest='delta',
(...skipping 14 matching lines...) Expand all
920 parser.add_option('-p', '--type', default='vm', 770 parser.add_option('-p', '--type', default='vm',
921 help='type of test to run: [vm, real]. Default: vm.') 771 help='type of test to run: [vm, real]. Default: vm.')
922 parser.add_option('--verbose', default=True, action='store_true', 772 parser.add_option('--verbose', default=True, action='store_true',
923 help='Print out rather than capture output as much as ' 773 help='Print out rather than capture output as much as '
924 'possible.') 774 'possible.')
925 (options, leftover_args) = parser.parse_args() 775 (options, leftover_args) = parser.parse_args()
926 776
927 if leftover_args: 777 if leftover_args:
928 parser.error('Found extra options we do not support: %s' % leftover_args) 778 parser.error('Found extra options we do not support: %s' % leftover_args)
929 779
930 # Figure out the test_class.
931 if options.type == 'vm': test_class = VirtualAUTest 780 if options.type == 'vm': test_class = VirtualAUTest
932 elif options.type == 'real': test_class = RealAUTest 781 elif options.type == 'real': test_class = RealAUTest
933 else: parser.error('Could not parse harness type %s.' % options.type) 782 else: parser.error('Could not parse harness type %s.' % options.type)
934 783
935 # TODO(sosa): Caching doesn't really make sense on non-vm images (yet). 784 # TODO(sosa): Caching doesn't really make sense on non-vm images (yet).
936 global dev_server_cache 785 if options.type == 'vm':
937 if options.type == 'vm' and options.jobs > 1: 786 _PregenerateUpdates(parser, options)
938 dev_server_cache = _PregenerateUpdates(parser, options)
939 my_server = DevServerWrapper()
940 my_server.start()
941 try:
942 _RunTestsInParallel(parser, options, test_class)
943 finally:
944 my_server.Stop()
945 787
946 else: 788 # Run the test suite.
947 dev_server_cache = None 789 test_class.ProcessOptions(parser, options)
948 test_suite = _PrepareTestSuite(parser, options, test_class) 790 test_loader = unittest.TestLoader()
949 test_result = unittest.TextTestRunner(verbosity=2).run(test_suite) 791 test_loader.testMethodPrefix = options.test_prefix
950 if not test_result.wasSuccessful(): 792 test_suite = test_loader.loadTestsFromTestCase(test_class)
951 Die('Test harness was not successful.') 793 test_result = unittest.TextTestRunner(verbosity=2).run(test_suite)
794 if not test_result.wasSuccessful():
795 Die('Test harness was not successful.')
952 796
953 797
954 if __name__ == '__main__': 798 if __name__ == '__main__':
955 main() 799 main()
OLDNEW
« no previous file with comments | « no previous file | bin/cros_run_vm_update » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698