blob: f1ef3743cb795758bdf9f8bd617a4b4cd966ea87 [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
Chris Sosab8c2af52013-07-03 10:45:39 -070015import getpass
Chris Sosada9632e2013-03-04 12:28:06 -080016import logging
17import optparse
18import os
19import shutil
Chris Sosada9632e2013-03-04 12:28:06 -080020import sys
21import tempfile
22
23import constants
24sys.path.append(constants.SOURCE_ROOT)
25sys.path.append(constants.CROS_PLATFORM_ROOT)
26
27from chromite.lib import cros_build_lib
Yu-Ju Hong29111982013-12-20 15:04:41 -080028from chromite.lib import dev_server_wrapper
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080029from chromite.lib import osutils
Chris Sosa928085e2013-03-08 17:25:30 -080030from chromite.lib import remote_access
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080031from chromite.lib import vm
32
Chris Sosada9632e2013-03-04 12:28:06 -080033from crostestutils.lib import mount_helper
34from crostestutils.lib import test_helper
35
36
Chris Sosada9632e2013-03-04 12:28:06 -080037class TestError(Exception):
38 """Raised on any error during testing. It being raised is a test failure."""
39
40
41class DevModeTest(object):
42 """Wrapper for dev mode tests."""
43 def __init__(self, image_path, board, binhost):
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080044 """Initializes DevModeTest.
45
Chris Sosada9632e2013-03-04 12:28:06 -080046 Args:
47 image_path: Filesystem path to the image to test.
48 board: Board of the image under test.
49 binhost: Binhost override. Binhost as defined here is where dev-install
50 or gmerge go to search for binary packages. By default this will
51 be set to the devserver url of the host running this script.
52 If no override i.e. the default is ok, set to None.
53 """
54 self.image_path = image_path
55 self.board = board
56 self.binhost = binhost
Chris Sosada9632e2013-03-04 12:28:06 -080057 self.tmpdir = tempfile.mkdtemp('DevModeTest')
Chris Sosada9632e2013-03-04 12:28:06 -080058 self.working_image_path = None
59 self.devserver = None
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080060 self.vm = None
61 self.device = None
Chris Sosada9632e2013-03-04 12:28:06 -080062
63 def Cleanup(self):
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080064 """Cleans up any state at the end of the test."""
Chris Sosada9632e2013-03-04 12:28:06 -080065 try:
Chris Sosada9632e2013-03-04 12:28:06 -080066 if self.devserver:
67 self.devserver.Stop()
68
69 self.devserver = None
Yu-Ju Hong640d4d02014-02-20 15:52:11 -080070 if self.device:
71 self.device.Cleanup()
72
73 self.device = None
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080074 self.vm.Stop()
75 self.vm = None
76 osutils.RmDir(self.tmpdir, ignore_missing=True)
Chris Sosada9632e2013-03-04 12:28:06 -080077 self.tmpdir = None
78 except Exception:
79 logging.warning('Received error during cleanup', exc_info=True)
80
Chris Sosab8c2af52013-07-03 10:45:39 -070081 def _WipeDevInstall(self):
82 """Wipes the devinstall state."""
Chris Sosada9632e2013-03-04 12:28:06 -080083 r_mount_point = os.path.join(self.tmpdir, 'm')
84 s_mount_point = os.path.join(self.tmpdir, 's')
Chris Sosab8c2af52013-07-03 10:45:39 -070085 dev_image_path = os.path.join(s_mount_point, 'dev_image')
Chris Sosada9632e2013-03-04 12:28:06 -080086 mount_helper.MountImage(self.working_image_path,
87 r_mount_point, s_mount_point, read_only=False,
88 safe=True)
Chris Sosab8c2af52013-07-03 10:45:39 -070089 try:
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080090 osutils.RmDir(dev_image_path, sudo=True)
Chris Sosab8c2af52013-07-03 10:45:39 -070091 finally:
92 mount_helper.UnmountImage(r_mount_point, s_mount_point)
Chris Sosada9632e2013-03-04 12:28:06 -080093
Chris Sosada9632e2013-03-04 12:28:06 -080094 def PrepareTest(self):
95 """Pre-test modification to the image and env to setup test."""
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080096 logging.info('Setting up the image %s for vm testing.', self.image_path)
97 vm_path = vm.CreateVMImage(image=self.image_path, board=self.board,
98 full=False)
Chris Sosada9632e2013-03-04 12:28:06 -080099
100 logging.info('Making copy of the vm image %s to manipulate.', vm_path)
David James45b55dd2013-04-24 09:16:40 -0700101 self.working_image_path = os.path.join(self.tmpdir,
102 os.path.basename(vm_path))
Chris Sosada9632e2013-03-04 12:28:06 -0800103 shutil.copyfile(vm_path, self.working_image_path)
104 logging.debug('Copy of vm image stored at %s.', self.working_image_path)
105
Chris Sosab8c2af52013-07-03 10:45:39 -0700106 logging.info('Wiping /usr/local/bin from the image.')
107 self._WipeDevInstall()
Chris Sosada9632e2013-03-04 12:28:06 -0800108
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800109 self.vm = vm.VMInstance(self.working_image_path, tempdir=self.tmpdir)
110 logging.info('Starting the vm on port %d.', self.vm.port)
111 self.vm.Start()
112
113 self.device = remote_access.ChromiumOSDevice(
Yu-Ju Hong640d4d02014-02-20 15:52:11 -0800114 remote_access.LOCALHOST, port=self.vm.port, base_dir=self.tmpdir)
Chris Sosa068c1e92013-03-17 22:54:20 -0700115
Chris Sosada9632e2013-03-04 12:28:06 -0800116 if not self.binhost:
117 logging.info('Starting the devserver.')
Chris Sosaa404a382013-08-22 11:28:38 -0700118 self.devserver = dev_server_wrapper.DevServerWrapper()
119 self.devserver.Start()
Chris Sosada9632e2013-03-04 12:28:06 -0800120 self.binhost = dev_server_wrapper.DevServerWrapper.GetDevServerURL(
Chris Sosac9447962013-03-12 10:12:29 -0700121 sub_dir='static/pkgroot/%s/packages' % self.board)
Chris Sosada9632e2013-03-04 12:28:06 -0800122
123 logging.info('Using binhost %s', self.binhost)
124
125 def TestDevInstall(self):
126 """Tests that we can run dev-install and have python work afterwards."""
127 try:
128 logging.info('Running dev install in the vm.')
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800129 self.device.RunCommand(
Chris Sosada9632e2013-03-04 12:28:06 -0800130 ['bash', '-l', '-c',
131 '"/usr/bin/dev_install --yes --binhost %s"' % self.binhost])
132
133 logging.info('Verifying that python works on the image.')
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800134 self.device.RunCommand(['sudo', '-u', 'chronos', '--', 'python', '-c',
135 '"print \'hello world\'"'])
Yu-Ju Hong5ed02452014-01-30 09:05:00 -0800136 except (cros_build_lib.RunCommandError,
137 remote_access.SSHConnectionError) as e:
Chris Sosada9632e2013-03-04 12:28:06 -0800138 self.devserver.PrintLog()
139 logging.error('dev-install test failed. See devserver log above for more '
140 'details.')
141 raise TestError('dev-install test failed with: %s' % str(e))
142
Chris Sosada9632e2013-03-04 12:28:06 -0800143 def TestGmerge(self):
144 """Evaluates whether the test passed or failed."""
Chris Sosa928085e2013-03-08 17:25:30 -0800145 logging.info('Testing that gmerge works on the image after dev install.')
Chris Sosada9632e2013-03-04 12:28:06 -0800146 try:
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800147 self.device.RunCommand(
Chris Sosac9447962013-03-12 10:12:29 -0700148 ['gmerge', 'gmerge', '--accept_stable', '--usepkg',
149 '--devserver_url', self.devserver.GetDevServerURL(),
150 '--board', self.board])
Yu-Ju Hong5ed02452014-01-30 09:05:00 -0800151 except (cros_build_lib.RunCommandError,
152 remote_access.SSHConnectionError) as e:
Chris Sosada9632e2013-03-04 12:28:06 -0800153 logging.error('gmerge test failed. See log for details')
154 raise TestError('gmerge test failed with: %s' % str(e))
155
156
157def main():
158 usage = ('%s <board> <path_to_[test|vm]_image>. '
159 'See --help for more options' % os.path.basename(sys.argv[0]))
160 parser = optparse.OptionParser(usage)
161 parser.add_option('--binhost', metavar='URL',
162 help='binhost override. By default, starts up a devserver '
163 'and uses it as the binhost.')
164 parser.add_option('-v', '--verbose', default=False, action='store_true',
165 help='Print out added debugging information')
166
167 (options, args) = parser.parse_args()
168
169 if len(args) != 2:
170 parser.print_usage()
171 parser.error('Need board and path to test image.')
172
173 board = args[0]
174 image_path = os.path.realpath(args[1])
175
176 test_helper.SetupCommonLoggingFormat(verbose=options.verbose)
177
178 test = DevModeTest(image_path, board, options.binhost)
179 try:
180 test.PrepareTest()
181 test.TestDevInstall()
Chris Sosa928085e2013-03-08 17:25:30 -0800182 test.TestGmerge()
Chris Sosada9632e2013-03-04 12:28:06 -0800183 logging.info('All tests passed.')
184 finally:
185 test.Cleanup()
186
187
188if __name__ == '__main__':
189 main()