From 7e493cb4d37015fef78228f5ba7c70565a48bdef Mon Sep 17 00:00:00 2001 From: Chris Sosa Date: Fri, 22 Oct 2010 16:32:30 -0700 Subject: [PATCH] Archive test results and image after running vm suite. Change-Id: Ic6d4a79a7ab58b8043805a6b826f251faa9f3a6c BUG= TEST=Running now (adding unit tests as well) Review URL: http://codereview.chromium.org/4062003 --- bin/cbuildbot.py | 64 +++++++++++++++++++++++++++++++++++++-- bin/cbuildbot_unittest.py | 63 +++++++++++++++++++++++++++++++++++--- bin/cros_run_vm_test | 2 ++ 3 files changed, 123 insertions(+), 6 deletions(-) diff --git a/bin/cbuildbot.py b/bin/cbuildbot.py index 26659ea497..ea082b651a 100755 --- a/bin/cbuildbot.py +++ b/bin/cbuildbot.py @@ -7,9 +7,11 @@ """CBuildbot is wrapper around the build process used by the pre-flight queue""" import errno +import heapq import re import optparse import os +import shutil import sys import cbuildbot_comm @@ -19,6 +21,8 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '../lib')) from cros_build_lib import Die, Info, RunCommand, Warning _DEFAULT_RETRIES = 3 +ARCHIVE_BASE = '/var/www/archive' +ARCHIVE_COUNT = 10 # ======================== Utility functions ================================ @@ -325,11 +329,17 @@ def _RunUnitTests(buildroot): RunCommand(['./cros_run_unit_tests'], cwd=cwd, enter_chroot=True) -def _RunSmokeSuite(buildroot): +def _RunSmokeSuite(buildroot, results_dir): + results_dir_in_chroot = os.path.join(buildroot, 'chroot', + results_dir.lstrip('/')) + if os.path.exists(results_dir_in_chroot): + shutil.rmtree(results_dir_in_chroot) + cwd = os.path.join(buildroot, 'src', 'scripts') RunCommand(['bin/cros_run_vm_test', '--no_graphics', '--test_case=suite_Smoke', + '--results_dir_root=%s' % results_dir, ], cwd=cwd, error_ok=False) @@ -378,6 +388,50 @@ def _UprevPush(buildroot, tracking_branch, board): cwd=cwd) +def _ArchiveTestResults(buildroot, board, archive_dir, test_results_dir): + """Archives the test results into the www dir for later use. + + Takes the results from the test_results_dir and dumps them into the archive + dir specified. This also archives the last qemu image. + + board: Board to find the qemu image. + archive_dir: Path from ARCHIVE_BASE to store image. + test_results_dir: Path from buildroot/chroot to find test results. This must + a subdir of /tmp. + """ + test_results_dir = test_results_dir.lstrip('/') + if not os.path.exists(ARCHIVE_BASE): + os.makedirs(ARCHIVE_BASE) + else: + dir_entries = os.listdir(ARCHIVE_BASE) + if len(dir_entries) >= ARCHIVE_COUNT: + oldest_dirs = heapq.nsmallest((len(dir_entries) - ARCHIVE_COUNT) + 1, + [filename for filename in dir_entries], + key=lambda fn: os.stat(fn).st_mtime) + Info('Removing archive dirs %s' % oldest_dirs) + for oldest_dir in oldest_dirs: + shutil.rmtree(os.path.join(ARCHIVE_BASE, oldest_dir)) + + archive_target = os.path.join(ARCHIVE_BASE, str(archive_dir)) + if os.path.exists(archive_target): + shutil.rmtree(archive_target) + + results_path = os.path.join(buildroot, 'chroot', test_results_dir) + RunCommand(['sudo', 'chmod', '-R', '+r', results_path]) + try: + shutil.copytree(results_path, archive_target) + except: + Warning('Some files could not be copied') + + image_name = 'chromiumos_qemu_image.bin' + image_path = os.path.join(buildroot, 'src', 'build', 'images', board, + 'latest', image_name) + RunCommand(['gzip', '-f', image_path]) + shutil.copyfile(image_path + '.gz', os.path.join(archive_target, + image_name + '.gz')) + + + def _GetConfig(config_name): """Gets the configuration for the build""" default = config['default'] @@ -463,7 +517,13 @@ def main(): if buildconfig['smoke_bvt']: _BuildVMImageForTesting(buildroot) - _RunSmokeSuite(buildroot) + test_results_dir = '/tmp/run_remote_tests.%s' % options.buildnumber + try: + _RunSmokeSuite(buildroot, test_results_dir) + finally: + _ArchiveTestResults(buildroot, buildconfig['board'], + archive_dir=options.buildnumber, + test_results_dir=test_results_dir) if buildconfig['uprev']: # Don't push changes for developers. diff --git a/bin/cbuildbot_unittest.py b/bin/cbuildbot_unittest.py index 57742b9c78..e699f0c9cb 100755 --- a/bin/cbuildbot_unittest.py +++ b/bin/cbuildbot_unittest.py @@ -8,6 +8,9 @@ import __builtin__ import mox +import os +import posix +import shutil import unittest # Fixes circular dependency error. @@ -20,6 +23,7 @@ class CBuildBotTest(mox.MoxTestBase): mox.MoxTestBase.setUp(self) # Always stub RunCommmand out as we use it in every method. self.mox.StubOutWithMock(cbuildbot, 'RunCommand') + self.tracking_branch = 'cros/master' self._test_repos = [['kernel', 'third_party/kernel/files'], ['login_manager', 'platform/login_manager'] ] @@ -102,6 +106,55 @@ class CBuildBotTest(mox.MoxTestBase): # self._test_board) # self.mox.VerifyAll() + def testArchiveTestResults(self): + """Test if we can archive the latest results dir as well as clean up.""" + self.mox.StubOutWithMock(os.path, 'exists') + self.mox.StubOutWithMock(os, 'listdir') + self.mox.StubOutWithMock(os, 'stat') + self.mox.StubOutWithMock(shutil, 'rmtree') + self.mox.StubOutWithMock(shutil, 'copytree') + self.mox.StubOutWithMock(shutil, 'copyfile') + + # Create mock stats so that file2 is older than file1. + dir_listing = ['file1', 'file2'] + stat1 = self.mox.CreateMock(posix.stat_result) + stat2 = self.mox.CreateMock(posix.stat_result) + stat1.st_mtime = 99999 + stat2.st_mtime = 10000 + + # Set vars for call. + buildroot = '/fake_dir' + test_results_dir = 'fake_results_dir' + archive_dir = 1234 + board = 'fake-board' + + # Expected calls. + os.path.exists(cbuildbot.ARCHIVE_BASE).AndReturn(True) + os.listdir(os.path.join(cbuildbot.ARCHIVE_BASE)).AndReturn(dir_listing) + os.stat('file1').AndReturn(stat1) + os.stat('file2').AndReturn(stat2) + # Should remove the oldest path. + shutil.rmtree(os.path.join(cbuildbot.ARCHIVE_BASE, 'file2')) + + # Convenience variables to make archive easier to understand. + path_to_results = os.path.join(buildroot, 'chroot', test_results_dir) + path_to_archive_dir = os.path.join(cbuildbot.ARCHIVE_BASE, str(archive_dir)) + path_to_image = os.path.join(buildroot, 'src', 'build', 'images', board, + 'latest', 'chromiumos_qemu_image.bin') + # Archive logic + os.path.exists(path_to_archive_dir).AndReturn(False) + cbuildbot.RunCommand(['sudo', 'chmod', '-R', '+r', path_to_results]) + shutil.copytree(path_to_results, path_to_archive_dir) + cbuildbot.RunCommand(['gzip', '-f', path_to_image]) + shutil.copyfile(path_to_image + '.gz', os.path.join( + path_to_archive_dir, 'chromiumos_qemu_image.bin.gz')) + + self.mox.ReplayAll() + cbuildbot.ARCHIVE_COUNT = 2 # Set equal to list size so we force clean up. + cbuildbot._ArchiveTestResults(buildroot, board, archive_dir, + test_results_dir) + self.mox.VerifyAll() + # TODO(sosa): Remove once we un-comment above. def testUprevPackages(self): """Test if we get actual revisions in revisions.pfq.""" @@ -114,13 +167,14 @@ class CBuildBotTest(mox.MoxTestBase): m_file.close() cbuildbot.RunCommand(['./cros_mark_as_stable', '--all', + '--board=%s' % self._test_board, '--tracking_branch="cros/master"', 'commit'], cwd='%s/src/scripts' % self._buildroot, enter_chroot=True) self.mox.ReplayAll() - cbuildbot._UprevPackages(self._buildroot, self._revision_file, - self._test_board) + cbuildbot._UprevPackages(self._buildroot, self.tracking_branch, + self._revision_file, self._test_board) self.mox.VerifyAll() def testUprevAllPackages(self): @@ -134,13 +188,14 @@ class CBuildBotTest(mox.MoxTestBase): m_file.close() cbuildbot.RunCommand(['./cros_mark_as_stable', '--all', + '--board=%s' % self._test_board, '--tracking_branch="cros/master"', 'commit'], cwd='%s/src/scripts' % self._buildroot, enter_chroot=True) self.mox.ReplayAll() - cbuildbot._UprevPackages(self._buildroot, self._revision_file, - self._test_board) + cbuildbot._UprevPackages(self._buildroot, self.tracking_branch, + self._revision_file, self._test_board) self.mox.VerifyAll() diff --git a/bin/cros_run_vm_test b/bin/cros_run_vm_test index 8ed9497ff9..cef3d115b9 100755 --- a/bin/cros_run_vm_test +++ b/bin/cros_run_vm_test @@ -17,6 +17,7 @@ get_default_board DEFINE_string board "$DEFAULT_BOARD" \ "The board for which you built autotest." DEFINE_string image_path "" "Full path of the VM image" +DEFINE_string results_dir_root "" "alternate root results directory" DEFINE_string test_case "" "Name of the test case to run" set -e @@ -45,4 +46,5 @@ retry_until_ssh ${MAX_RETRIES} --board=${FLAGS_board} \ --ssh_port=${FLAGS_ssh_port} \ --remote=127.0.0.1 \ + --results_dir_root="${FLAGS_results_dir_root}" \ "${FLAGS_test_case}"