blob: a294387926f9d1b37205f49349a584ed23681797 [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."""
42 def __init__(self, image_path, board, binhost):
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080043 """Initializes DevModeTest.
44
Chris Sosada9632e2013-03-04 12:28:06 -080045 Args:
46 image_path: Filesystem path to the image to test.
47 board: Board of the image under test.
48 binhost: Binhost override. Binhost as defined here is where dev-install
49 or gmerge go to search for binary packages. By default this will
50 be set to the devserver url of the host running this script.
51 If no override i.e. the default is ok, set to None.
52 """
53 self.image_path = image_path
54 self.board = board
55 self.binhost = binhost
Chris Sosada9632e2013-03-04 12:28:06 -080056 self.tmpdir = tempfile.mkdtemp('DevModeTest')
Chris Sosada9632e2013-03-04 12:28:06 -080057 self.working_image_path = None
58 self.devserver = None
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080059 self.vm = None
60 self.device = None
Chris Sosada9632e2013-03-04 12:28:06 -080061
62 def Cleanup(self):
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080063 """Cleans up any state at the end of the test."""
Chris Sosada9632e2013-03-04 12:28:06 -080064 try:
Chris Sosada9632e2013-03-04 12:28:06 -080065 if self.devserver:
66 self.devserver.Stop()
Chris Sosada9632e2013-03-04 12:28:06 -080067 self.devserver = None
Yu-Ju Hong640d4d02014-02-20 15:52:11 -080068 if self.device:
69 self.device.Cleanup()
Yu-Ju Hong640d4d02014-02-20 15:52:11 -080070 self.device = None
Prathmesh Prabhueea4fed2017-10-27 10:25:03 -070071 if self.vm:
72 self.vm.Stop()
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080073 self.vm = None
74 osutils.RmDir(self.tmpdir, ignore_missing=True)
Chris Sosada9632e2013-03-04 12:28:06 -080075 self.tmpdir = None
76 except Exception:
Prathmesh Prabhueea4fed2017-10-27 10:25:03 -070077 logging.exception('Received error during cleanup')
Chris Sosada9632e2013-03-04 12:28:06 -080078
Chris Sosab8c2af52013-07-03 10:45:39 -070079 def _WipeDevInstall(self):
80 """Wipes the devinstall state."""
Chris Sosada9632e2013-03-04 12:28:06 -080081 r_mount_point = os.path.join(self.tmpdir, 'm')
82 s_mount_point = os.path.join(self.tmpdir, 's')
Chris Sosab8c2af52013-07-03 10:45:39 -070083 dev_image_path = os.path.join(s_mount_point, 'dev_image')
Chris Sosada9632e2013-03-04 12:28:06 -080084 mount_helper.MountImage(self.working_image_path,
85 r_mount_point, s_mount_point, read_only=False,
86 safe=True)
Chris Sosab8c2af52013-07-03 10:45:39 -070087 try:
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080088 osutils.RmDir(dev_image_path, sudo=True)
Chris Sosab8c2af52013-07-03 10:45:39 -070089 finally:
90 mount_helper.UnmountImage(r_mount_point, s_mount_point)
Chris Sosada9632e2013-03-04 12:28:06 -080091
Chris Sosada9632e2013-03-04 12:28:06 -080092 def PrepareTest(self):
93 """Pre-test modification to the image and env to setup test."""
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080094 logging.info('Setting up the image %s for vm testing.', self.image_path)
95 vm_path = vm.CreateVMImage(image=self.image_path, board=self.board,
Yu-Ju Hongb933bfc2014-02-19 11:15:34 -080096 updatable=False)
Chris Sosada9632e2013-03-04 12:28:06 -080097
98 logging.info('Making copy of the vm image %s to manipulate.', vm_path)
David James45b55dd2013-04-24 09:16:40 -070099 self.working_image_path = os.path.join(self.tmpdir,
100 os.path.basename(vm_path))
Chris Sosada9632e2013-03-04 12:28:06 -0800101 shutil.copyfile(vm_path, self.working_image_path)
102 logging.debug('Copy of vm image stored at %s.', self.working_image_path)
103
Chris Sosab8c2af52013-07-03 10:45:39 -0700104 logging.info('Wiping /usr/local/bin from the image.')
105 self._WipeDevInstall()
Chris Sosada9632e2013-03-04 12:28:06 -0800106
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800107 self.vm = vm.VMInstance(self.working_image_path, tempdir=self.tmpdir)
108 logging.info('Starting the vm on port %d.', self.vm.port)
109 self.vm.Start()
110
111 self.device = remote_access.ChromiumOSDevice(
Yu-Ju Hong640d4d02014-02-20 15:52:11 -0800112 remote_access.LOCALHOST, port=self.vm.port, base_dir=self.tmpdir)
Chris Sosa068c1e92013-03-17 22:54:20 -0700113
Chris Sosada9632e2013-03-04 12:28:06 -0800114 if not self.binhost:
115 logging.info('Starting the devserver.')
Chris Sosaa404a382013-08-22 11:28:38 -0700116 self.devserver = dev_server_wrapper.DevServerWrapper()
117 self.devserver.Start()
Yu-Ju Hong0dbc2b92014-07-14 17:19:17 -0700118 self.binhost = self.devserver.GetURL(
Chris Sosac9447962013-03-12 10:12:29 -0700119 sub_dir='static/pkgroot/%s/packages' % self.board)
Chris Sosada9632e2013-03-04 12:28:06 -0800120
121 logging.info('Using binhost %s', self.binhost)
122
123 def TestDevInstall(self):
124 """Tests that we can run dev-install and have python work afterwards."""
125 try:
126 logging.info('Running dev install in the vm.')
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800127 self.device.RunCommand(
Chris Sosada9632e2013-03-04 12:28:06 -0800128 ['bash', '-l', '-c',
129 '"/usr/bin/dev_install --yes --binhost %s"' % self.binhost])
130
131 logging.info('Verifying that python works on the image.')
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800132 self.device.RunCommand(['sudo', '-u', 'chronos', '--', 'python', '-c',
133 '"print \'hello world\'"'])
Yu-Ju Hong5ed02452014-01-30 09:05:00 -0800134 except (cros_build_lib.RunCommandError,
135 remote_access.SSHConnectionError) as e:
Chris Sosada9632e2013-03-04 12:28:06 -0800136 self.devserver.PrintLog()
137 logging.error('dev-install test failed. See devserver log above for more '
138 'details.')
139 raise TestError('dev-install test failed with: %s' % str(e))
140
Chris Sosada9632e2013-03-04 12:28:06 -0800141 def TestGmerge(self):
142 """Evaluates whether the test passed or failed."""
Chris Sosa928085e2013-03-08 17:25:30 -0800143 logging.info('Testing that gmerge works on the image after dev install.')
Chris Sosada9632e2013-03-04 12:28:06 -0800144 try:
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800145 self.device.RunCommand(
Chris Sosac9447962013-03-12 10:12:29 -0700146 ['gmerge', 'gmerge', '--accept_stable', '--usepkg',
Yu-Ju Hong0dbc2b92014-07-14 17:19:17 -0700147 '--devserver_url', self.devserver.GetURL(),
Chris Sosac9447962013-03-12 10:12:29 -0700148 '--board', self.board])
Yu-Ju Hong5ed02452014-01-30 09:05:00 -0800149 except (cros_build_lib.RunCommandError,
150 remote_access.SSHConnectionError) as e:
Chris Sosada9632e2013-03-04 12:28:06 -0800151 logging.error('gmerge test failed. See log for details')
152 raise TestError('gmerge test failed with: %s' % str(e))
153
154
155def main():
156 usage = ('%s <board> <path_to_[test|vm]_image>. '
157 'See --help for more options' % os.path.basename(sys.argv[0]))
158 parser = optparse.OptionParser(usage)
159 parser.add_option('--binhost', metavar='URL',
160 help='binhost override. By default, starts up a devserver '
161 'and uses it as the binhost.')
162 parser.add_option('-v', '--verbose', default=False, action='store_true',
163 help='Print out added debugging information')
164
165 (options, args) = parser.parse_args()
166
167 if len(args) != 2:
168 parser.print_usage()
169 parser.error('Need board and path to test image.')
170
171 board = args[0]
172 image_path = os.path.realpath(args[1])
173
174 test_helper.SetupCommonLoggingFormat(verbose=options.verbose)
175
176 test = DevModeTest(image_path, board, options.binhost)
177 try:
178 test.PrepareTest()
179 test.TestDevInstall()
Chris Sosa928085e2013-03-08 17:25:30 -0800180 test.TestGmerge()
Chris Sosada9632e2013-03-04 12:28:06 -0800181 logging.info('All tests passed.')
182 finally:
183 test.Cleanup()
184
185
186if __name__ == '__main__':
187 main()