blob: 55ee91c2352b86ff988a17e1dcdb300bacf49ed4 [file] [log] [blame]
Tan Gao6f9f71a2010-09-10 16:31:26 -07001#!/usr/bin/python
2#
3# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Tests for build_image.
8
9Note:
10 Some of the Shell scripts invoked in child process require sudo access.
11 Be prepared to enter your password when prompted.
12
13Sample usage:
14 # run all test cases
15 python build_image_test.py
16
17 # run a specific test
18 python build_image_test.py BuildImageTest.testBuildImageWithoutBoardExit
19"""
20
21import logging
22import os
23import re
24import sys
25import unittest
26sys.path.append(os.path.join(os.path.dirname(__file__), '../lib'))
27from cros_build_lib import RunCommand
28
29
30logging.basicConfig(level=logging.INFO)
31
32
33# TODO(tgao): move this into cros_build_lib.py
34def IsInsideChroot():
35 """Returns True if we are inside chroot."""
36 return os.path.exists('/etc/debian_chroot')
37
38
39def GetSrcRoot():
40 """Get absolute path to src/scripts/ directory.
41
42 Assuming test script will always be run from descendent of src/scripts.
43
44 Returns:
45 A string, absolute path to src/scripts directory. None if not found.
46 """
47 src_root = None
48 match_str = '/src/scripts/'
49 test_script_path = os.path.abspath('.')
50 logging.debug('test_script_path = %r', test_script_path)
51
52 path_list = re.split(match_str, test_script_path)
53 logging.debug('path_list = %r', path_list)
54 if path_list:
55 src_root = os.path.join(path_list[0], match_str.strip('/'))
56 logging.debug('src_root = %r', src_root)
57 else:
58 logging.debug('No %r found in %r', match_str, test_script_path)
59
60 return src_root
61
62
63# TODO(tgao): move this into cros_build_lib.py
64def GetChromeosVersion(str_obj):
65 """Helper method to parse output for CHROMEOS_VERSION_STRING.
66
67 Args:
68 str_obj: a string, which may contain Chrome OS version info.
69
70 Returns:
71 A string, value of CHROMEOS_VERSION_STRING environment variable set by
72 chromeos_version.sh. Or None if not found.
73 """
74 match = re.search('CHROMEOS_VERSION_STRING=([0-9_.]+)', str_obj)
75 if match and match.group(1):
76 logging.info('CHROMEOS_VERSION_STRING = %s', match.group(1))
77 return match.group(1)
78
79 logging.info('CHROMEOS_VERSION_STRING NOT found')
80 return None
81
82
83# TODO(tgao): move this into cros_build_lib.py
84def GetOutputImageDir(board, cros_version):
85 """Construct absolute path to output image directory.
86
87 Args:
88 board: a string.
89 cros_version: a string, Chrome OS version.
90
91 Returns:
92 a string: absolute path to output directory.
93 """
94 src_root = GetSrcRoot()
95 rel_path = 'build/images/%s' % board
96 # ASSUME: --build_attempt always sets to 1
97 version_str = '-'.join([cros_version, 'a1'])
98 output_dir = os.path.join(os.path.dirname(src_root), rel_path, version_str)
99 logging.info('output_dir = %s', output_dir)
100 return output_dir
101
102
103class BuildImageTest(unittest.TestCase):
104 """Test suite for build_image script."""
105
106 def setUp(self):
107 if not IsInsideChroot():
108 raise RuntimeError('This script must be run from inside chroot.')
109
110 def _CheckStringPresent(self, query_list, check_stdout=False):
111 """Check for presence of specific queries.
112
113 Args:
114 query_list: a list of strings to look for.
115 check_stdout: a boolean. True == use stdout from child process.
116 Otherwise use its stderr.
117 """
118 for query in query_list:
119 # Source error string defined in src/scripts/build_image
120 if check_stdout:
121 self.assertNotEqual(-1, self.output.find(query))
122 else:
123 self.assertNotEqual(-1, self.error.find(query))
124
125 def _RunBuildImageCmd(self, cmd, assert_success=True):
126 """Run build_image with flags.
127
128 Args:
129 cmd: a string.
130 assert_success: a boolean. True == check child process return code is 0.
131 False otherwise.
132 """
133 logging.info('About to run command: %s', cmd)
134 cmd_result = RunCommand(
135 cmd, error_ok=True, exit_code=True, redirect_stdout=True,
136 redirect_stderr=True, shell=True)
137 self.output = cmd_result.output
138 self.error = cmd_result.error
139 logging.info('output =\n%r', self.output)
140 logging.info('error =\n%s', self.error)
141
142 message = 'cmd should have failed! error:\n%s' % self.error
143 if assert_success:
144 self.assertEqual(0, cmd_result.returncode)
145 else:
146 self.assertNotEqual(0, cmd_result.returncode, message)
147
148 def _VerifyOutputImagesExist(self, image_dir, image_list):
149 """Verify output images exist in image_dir.
150
151 Args:
152 image_dir: a string, absolute path to output directory with images.
153 image_list: a list of strings, names of output images.
154 """
155 for i in image_list:
156 image_path = os.path.join(image_dir, i)
157 self.assertTrue(os.path.exists(image_path))
158
159 def testWithoutBoardExit(self):
160 """Fail when no --board is specified."""
161 self._RunBuildImageCmd('./build_image --board=""', assert_success=False)
162 self._CheckStringPresent(['ERROR', '--board is required'])
163
164 def testIncompatibleInstallFlags(self):
165 """Fail when both --factory_install and --dev_install are set."""
166 cmd = './build_image --board=x86-generic --factory_install --dev_install'
167 self._RunBuildImageCmd(cmd, assert_success=False)
168 self._CheckStringPresent(['ERROR', 'Incompatible flags'])
169
170 def testIncompatibleRootfsFlags(self):
171 """Fail when rootfs partition is not large enough."""
172 cmd = ('./build_image --board=x86-generic --rootfs_size=100'
173 ' --rootfs_hash_pad=10 --rootfs_partition_size=20')
174 self._RunBuildImageCmd(cmd, assert_success=False)
175 self._CheckStringPresent(['ERROR', 'bigger than partition'])
176
177 def _BuildImageForBoard(self, board, image_list):
178 """Build image for specific board type.
179
180 Args:
181 board: a string.
182 image_list: a list of strings, names of output images.
183 """
184 cmd = './build_image --board=%s' % board
185 logging.info('If all goes well, it takes ~5 min. to build an image...')
186 self._RunBuildImageCmd(cmd)
187 self._CheckStringPresent(['Image created in', 'copy to USB keyfob'],
188 check_stdout=True)
189 chromeos_version_str = GetChromeosVersion(self.output)
190 image_dir = GetOutputImageDir(board, chromeos_version_str)
191 self._VerifyOutputImagesExist(image_dir, image_list)
192
193 def testBuildX86Generic(self):
194 """Verify we can build an x86-generic image."""
195 self._BuildImageForBoard(
196 'x86-generic', ['chromiumos_image.bin', 'chromiumos_base_image.bin'])
197
198
199if __name__ == '__main__':
200 unittest.main()