blob: 3eb98398ef9f5294c78c5892a319399bb0e43220 [file] [log] [blame]
Chris Sosada9632e2013-03-04 12:28:06 -08001#!/usr/bin/python
2#
3# Copyright (c) 2013 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"""Integration test to test the basic functionality of dev-install and gmerge.
8
9This module contains a test that runs some sanity integration tests against
10a VM. First it starts a VM test image and turns it into a base image by wiping
11all of the stateful partition. Once done, runs dev_install to restore the
12stateful partition and then runs gmerge.
13"""
14
15import logging
16import optparse
17import os
18import shutil
Chris Sosada9632e2013-03-04 12:28:06 -080019import sys
20import tempfile
21
22import constants
23sys.path.append(constants.SOURCE_ROOT)
24sys.path.append(constants.CROS_PLATFORM_ROOT)
25
26from chromite.lib import cros_build_lib
Yu-Ju Hong29111982013-12-20 15:04:41 -080027from chromite.lib import dev_server_wrapper
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080028from chromite.lib import osutils
Chris Sosa928085e2013-03-08 17:25:30 -080029from chromite.lib import remote_access
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080030from chromite.lib import vm
31
Chris Sosada9632e2013-03-04 12:28:06 -080032from crostestutils.lib import mount_helper
33from crostestutils.lib import test_helper
34
35
Chris Sosada9632e2013-03-04 12:28:06 -080036class TestError(Exception):
37 """Raised on any error during testing. It being raised is a test failure."""
38
39
40class DevModeTest(object):
41 """Wrapper for dev mode tests."""
Nicolas Norvezc5a20ae2018-03-02 14:49:54 -080042
43 # qemu hardcodes 10.0.2.2 as the host from the guest's point of view
44 # https://wiki.qemu.org/Documentation/Networking#User_Networking_.28SLIRP.29
45 # When the host's eth0 IP address is also 10.0.2.*, and the guest tries to
46 # access it, the requests will be handled by qemu and never be seen by the
47 # host. Instead, let the guest always connect to 10.0.2.2.
48 HOST_IP_ADDRESS = '10.0.2.2'
49
Chris Sosada9632e2013-03-04 12:28:06 -080050 def __init__(self, image_path, board, binhost):
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080051 """Initializes DevModeTest.
52
Chris Sosada9632e2013-03-04 12:28:06 -080053 Args:
54 image_path: Filesystem path to the image to test.
55 board: Board of the image under test.
56 binhost: Binhost override. Binhost as defined here is where dev-install
57 or gmerge go to search for binary packages. By default this will
58 be set to the devserver url of the host running this script.
59 If no override i.e. the default is ok, set to None.
60 """
61 self.image_path = image_path
62 self.board = board
63 self.binhost = binhost
Chris Sosada9632e2013-03-04 12:28:06 -080064 self.tmpdir = tempfile.mkdtemp('DevModeTest')
Chris Sosada9632e2013-03-04 12:28:06 -080065 self.working_image_path = None
66 self.devserver = None
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080067 self.vm = None
68 self.device = None
Chris Sosada9632e2013-03-04 12:28:06 -080069
70 def Cleanup(self):
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080071 """Cleans up any state at the end of the test."""
Chris Sosada9632e2013-03-04 12:28:06 -080072 try:
Chris Sosada9632e2013-03-04 12:28:06 -080073 if self.devserver:
74 self.devserver.Stop()
Chris Sosada9632e2013-03-04 12:28:06 -080075 self.devserver = None
Yu-Ju Hong640d4d02014-02-20 15:52:11 -080076 if self.device:
77 self.device.Cleanup()
Yu-Ju Hong640d4d02014-02-20 15:52:11 -080078 self.device = None
Prathmesh Prabhueea4fed2017-10-27 10:25:03 -070079 if self.vm:
80 self.vm.Stop()
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080081 self.vm = None
82 osutils.RmDir(self.tmpdir, ignore_missing=True)
Chris Sosada9632e2013-03-04 12:28:06 -080083 self.tmpdir = None
84 except Exception:
Prathmesh Prabhueea4fed2017-10-27 10:25:03 -070085 logging.exception('Received error during cleanup')
Chris Sosada9632e2013-03-04 12:28:06 -080086
Chris Sosab8c2af52013-07-03 10:45:39 -070087 def _WipeDevInstall(self):
88 """Wipes the devinstall state."""
Chris Sosada9632e2013-03-04 12:28:06 -080089 r_mount_point = os.path.join(self.tmpdir, 'm')
90 s_mount_point = os.path.join(self.tmpdir, 's')
Chris Sosab8c2af52013-07-03 10:45:39 -070091 dev_image_path = os.path.join(s_mount_point, 'dev_image')
Chris Sosada9632e2013-03-04 12:28:06 -080092 mount_helper.MountImage(self.working_image_path,
93 r_mount_point, s_mount_point, read_only=False,
94 safe=True)
Chris Sosab8c2af52013-07-03 10:45:39 -070095 try:
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080096 osutils.RmDir(dev_image_path, sudo=True)
Chris Sosab8c2af52013-07-03 10:45:39 -070097 finally:
98 mount_helper.UnmountImage(r_mount_point, s_mount_point)
Chris Sosada9632e2013-03-04 12:28:06 -080099
Chris Sosada9632e2013-03-04 12:28:06 -0800100 def PrepareTest(self):
101 """Pre-test modification to the image and env to setup test."""
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800102 logging.info('Setting up the image %s for vm testing.', self.image_path)
103 vm_path = vm.CreateVMImage(image=self.image_path, board=self.board,
Yu-Ju Hongb933bfc2014-02-19 11:15:34 -0800104 updatable=False)
Chris Sosada9632e2013-03-04 12:28:06 -0800105
106 logging.info('Making copy of the vm image %s to manipulate.', vm_path)
David James45b55dd2013-04-24 09:16:40 -0700107 self.working_image_path = os.path.join(self.tmpdir,
108 os.path.basename(vm_path))
Chris Sosada9632e2013-03-04 12:28:06 -0800109 shutil.copyfile(vm_path, self.working_image_path)
110 logging.debug('Copy of vm image stored at %s.', self.working_image_path)
111
Chris Sosab8c2af52013-07-03 10:45:39 -0700112 logging.info('Wiping /usr/local/bin from the image.')
113 self._WipeDevInstall()
Chris Sosada9632e2013-03-04 12:28:06 -0800114
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800115 self.vm = vm.VMInstance(self.working_image_path, tempdir=self.tmpdir)
116 logging.info('Starting the vm on port %d.', self.vm.port)
117 self.vm.Start()
118
119 self.device = remote_access.ChromiumOSDevice(
Yu-Ju Hong640d4d02014-02-20 15:52:11 -0800120 remote_access.LOCALHOST, port=self.vm.port, base_dir=self.tmpdir)
Chris Sosa068c1e92013-03-17 22:54:20 -0700121
Chris Sosada9632e2013-03-04 12:28:06 -0800122 if not self.binhost:
123 logging.info('Starting the devserver.')
Chris Sosaa404a382013-08-22 11:28:38 -0700124 self.devserver = dev_server_wrapper.DevServerWrapper()
125 self.devserver.Start()
Nicolas Norvezc5a20ae2018-03-02 14:49:54 -0800126 self.binhost = self.devserver.GetDevServerURL(
127 ip=self.HOST_IP_ADDRESS, port=self.devserver.port,
Chris Sosac9447962013-03-12 10:12:29 -0700128 sub_dir='static/pkgroot/%s/packages' % self.board)
Chris Sosada9632e2013-03-04 12:28:06 -0800129
130 logging.info('Using binhost %s', self.binhost)
131
132 def TestDevInstall(self):
133 """Tests that we can run dev-install and have python work afterwards."""
134 try:
135 logging.info('Running dev install in the vm.')
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800136 self.device.RunCommand(
Chris Sosada9632e2013-03-04 12:28:06 -0800137 ['bash', '-l', '-c',
138 '"/usr/bin/dev_install --yes --binhost %s"' % self.binhost])
139
140 logging.info('Verifying that python works on the image.')
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800141 self.device.RunCommand(['sudo', '-u', 'chronos', '--', 'python', '-c',
142 '"print \'hello world\'"'])
Yu-Ju Hong5ed02452014-01-30 09:05:00 -0800143 except (cros_build_lib.RunCommandError,
144 remote_access.SSHConnectionError) as e:
Chris Sosada9632e2013-03-04 12:28:06 -0800145 self.devserver.PrintLog()
146 logging.error('dev-install test failed. See devserver log above for more '
147 'details.')
148 raise TestError('dev-install test failed with: %s' % str(e))
149
Chris Sosada9632e2013-03-04 12:28:06 -0800150 def TestGmerge(self):
151 """Evaluates whether the test passed or failed."""
Chris Sosa928085e2013-03-08 17:25:30 -0800152 logging.info('Testing that gmerge works on the image after dev install.')
Chris Sosada9632e2013-03-04 12:28:06 -0800153 try:
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800154 self.device.RunCommand(
Chris Sosac9447962013-03-12 10:12:29 -0700155 ['gmerge', 'gmerge', '--accept_stable', '--usepkg',
Nicolas Norvezc5a20ae2018-03-02 14:49:54 -0800156 '--devserver_url', self.devserver.GetDevServerURL(
157 ip=self.HOST_IP_ADDRESS, port=self.devserver.port),
Chris Sosac9447962013-03-12 10:12:29 -0700158 '--board', self.board])
Yu-Ju Hong5ed02452014-01-30 09:05:00 -0800159 except (cros_build_lib.RunCommandError,
160 remote_access.SSHConnectionError) as e:
Chris Sosada9632e2013-03-04 12:28:06 -0800161 logging.error('gmerge test failed. See log for details')
162 raise TestError('gmerge test failed with: %s' % str(e))
163
164
165def main():
166 usage = ('%s <board> <path_to_[test|vm]_image>. '
167 'See --help for more options' % os.path.basename(sys.argv[0]))
168 parser = optparse.OptionParser(usage)
169 parser.add_option('--binhost', metavar='URL',
170 help='binhost override. By default, starts up a devserver '
171 'and uses it as the binhost.')
172 parser.add_option('-v', '--verbose', default=False, action='store_true',
173 help='Print out added debugging information')
174
175 (options, args) = parser.parse_args()
176
177 if len(args) != 2:
178 parser.print_usage()
179 parser.error('Need board and path to test image.')
180
181 board = args[0]
182 image_path = os.path.realpath(args[1])
183
184 test_helper.SetupCommonLoggingFormat(verbose=options.verbose)
185
186 test = DevModeTest(image_path, board, options.binhost)
187 try:
188 test.PrepareTest()
189 test.TestDevInstall()
Chris Sosa928085e2013-03-08 17:25:30 -0800190 test.TestGmerge()
Chris Sosada9632e2013-03-04 12:28:06 -0800191 logging.info('All tests passed.')
192 finally:
193 test.Cleanup()
194
195
196if __name__ == '__main__':
197 main()