blob: 1409273ac5897fe731a0354bb7ceee3234b4ddb9 [file] [log] [blame]
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -07001#!/usr/bin/env python2
Achuith Bhandarkar78010f72019-01-03 17:21:52 -08002# -*- coding: utf-8 -*-
Chris Sosada9632e2013-03-04 12:28:06 -08003# 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
Mike Frysingerdb50f4f2019-02-24 19:52:59 -05007"""Integration test to test the basic functionality of dev-install.
Chris Sosada9632e2013-03-04 12:28:06 -08008
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
Mike Frysingerdb50f4f2019-02-24 19:52:59 -050012stateful partition.
Chris Sosada9632e2013-03-04 12:28:06 -080013"""
14
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -070015from __future__ import print_function
16
17import argparse
Chris Sosada9632e2013-03-04 12:28:06 -080018import 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
Achuith Bhandarkar78010f72019-01-03 17:21:52 -080027from chromite.lib import constants as chromite_constants
Chris Sosada9632e2013-03-04 12:28:06 -080028from chromite.lib import cros_build_lib
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -070029from chromite.lib import cros_logging as logging
Yu-Ju Hong29111982013-12-20 15:04:41 -080030from chromite.lib import dev_server_wrapper
Mike Frysinger266ff2f2019-09-17 15:38:45 -040031from chromite.lib import image_lib
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080032from chromite.lib import osutils
Chris Sosa928085e2013-03-08 17:25:30 -080033from chromite.lib import remote_access
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080034from chromite.lib import vm
35
Chris Sosada9632e2013-03-04 12:28:06 -080036from crostestutils.lib import test_helper
37
38
Chris Sosada9632e2013-03-04 12:28:06 -080039class TestError(Exception):
40 """Raised on any error during testing. It being raised is a test failure."""
41
42
43class DevModeTest(object):
44 """Wrapper for dev mode tests."""
Nicolas Norvezc5a20ae2018-03-02 14:49:54 -080045
46 # qemu hardcodes 10.0.2.2 as the host from the guest's point of view
47 # https://wiki.qemu.org/Documentation/Networking#User_Networking_.28SLIRP.29
48 # When the host's eth0 IP address is also 10.0.2.*, and the guest tries to
49 # access it, the requests will be handled by qemu and never be seen by the
50 # host. Instead, let the guest always connect to 10.0.2.2.
51 HOST_IP_ADDRESS = '10.0.2.2'
52
Chris Sosada9632e2013-03-04 12:28:06 -080053 def __init__(self, image_path, board, binhost):
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080054 """Initializes DevModeTest.
55
Chris Sosada9632e2013-03-04 12:28:06 -080056 Args:
57 image_path: Filesystem path to the image to test.
58 board: Board of the image under test.
59 binhost: Binhost override. Binhost as defined here is where dev-install
Mike Frysingerdb50f4f2019-02-24 19:52:59 -050060 go to search for binary packages. By default this will
Chris Sosada9632e2013-03-04 12:28:06 -080061 be set to the devserver url of the host running this script.
62 If no override i.e. the default is ok, set to None.
63 """
64 self.image_path = image_path
65 self.board = board
66 self.binhost = binhost
Chris Sosada9632e2013-03-04 12:28:06 -080067 self.tmpdir = tempfile.mkdtemp('DevModeTest')
Chris Sosada9632e2013-03-04 12:28:06 -080068 self.working_image_path = None
69 self.devserver = None
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +000070 self.device = None
Achuith Bhandarkar78010f72019-01-03 17:21:52 -080071 self.port = None
Chris Sosada9632e2013-03-04 12:28:06 -080072
73 def Cleanup(self):
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080074 """Cleans up any state at the end of the test."""
Chris Sosada9632e2013-03-04 12:28:06 -080075 try:
Chris Sosada9632e2013-03-04 12:28:06 -080076 if self.devserver:
77 self.devserver.Stop()
Chris Sosada9632e2013-03-04 12:28:06 -080078 self.devserver = None
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +000079 if self.device:
80 self.device.Cleanup()
81 self.device = None
Achuith Bhandarkar78010f72019-01-03 17:21:52 -080082 if self.port:
83 cros_build_lib.RunCommand(['./cros_vm', '--stop',
84 '--ssh-port=%d' % self.port],
85 cwd=chromite_constants.CHROMITE_BIN_DIR,
86 error_code_ok=True)
87 self.port = None
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080088 osutils.RmDir(self.tmpdir, ignore_missing=True)
Chris Sosada9632e2013-03-04 12:28:06 -080089 self.tmpdir = None
90 except Exception:
Prathmesh Prabhueea4fed2017-10-27 10:25:03 -070091 logging.exception('Received error during cleanup')
Chris Sosada9632e2013-03-04 12:28:06 -080092
Chris Sosab8c2af52013-07-03 10:45:39 -070093 def _WipeDevInstall(self):
94 """Wipes the devinstall state."""
Achuith Bhandarkar85928c42019-04-18 17:02:27 -070095 logging.info('Wiping /usr/local/bin from the image.')
Mike Frysinger266ff2f2019-09-17 15:38:45 -040096 with image_lib.LoopbackPartitions(
97 self.working_image_path, destination=self.tmpdir) as image:
98 image.Mount(('STATE',), mount_opts=())
99 dev_image_path = os.path.join(self.tmpdir, 'dir-STATE', 'dev_image')
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800100 osutils.RmDir(dev_image_path, sudo=True)
Chris Sosada9632e2013-03-04 12:28:06 -0800101
Chris Sosada9632e2013-03-04 12:28:06 -0800102 def PrepareTest(self):
103 """Pre-test modification to the image and env to setup test."""
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800104 logging.info('Setting up the image %s for vm testing.', self.image_path)
105 vm_path = vm.CreateVMImage(image=self.image_path, board=self.board,
Yu-Ju Hongb933bfc2014-02-19 11:15:34 -0800106 updatable=False)
Chris Sosada9632e2013-03-04 12:28:06 -0800107
108 logging.info('Making copy of the vm image %s to manipulate.', vm_path)
David James45b55dd2013-04-24 09:16:40 -0700109 self.working_image_path = os.path.join(self.tmpdir,
110 os.path.basename(vm_path))
Chris Sosada9632e2013-03-04 12:28:06 -0800111 shutil.copyfile(vm_path, self.working_image_path)
112 logging.debug('Copy of vm image stored at %s.', self.working_image_path)
113
Chris Sosab8c2af52013-07-03 10:45:39 -0700114 self._WipeDevInstall()
Chris Sosada9632e2013-03-04 12:28:06 -0800115
Achuith Bhandarkar78010f72019-01-03 17:21:52 -0800116 self.port = remote_access.GetUnusedPort()
117 logging.info('Starting the vm on port %d.', self.port)
118 vm_cmd = ['./cros_vm', '--ssh-port=%d' % self.port,
119 '--image-path=%s' % self.working_image_path, '--start']
120 cros_build_lib.RunCommand(vm_cmd, cwd=chromite_constants.CHROMITE_BIN_DIR)
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800121
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +0000122 self.device = remote_access.ChromiumOSDevice(
Achuith Bhandarkar78010f72019-01-03 17:21:52 -0800123 remote_access.LOCALHOST, port=self.port, base_dir=self.tmpdir)
Achuith Bhandarkar85928c42019-04-18 17:02:27 -0700124 if not self.device.MountRootfsReadWrite():
125 raise TestError('Failed to make rootfs writeable')
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +0000126
Chris Sosada9632e2013-03-04 12:28:06 -0800127 if not self.binhost:
128 logging.info('Starting the devserver.')
Chris Sosaa404a382013-08-22 11:28:38 -0700129 self.devserver = dev_server_wrapper.DevServerWrapper()
130 self.devserver.Start()
Nicolas Norvezc5a20ae2018-03-02 14:49:54 -0800131 self.binhost = self.devserver.GetDevServerURL(
132 ip=self.HOST_IP_ADDRESS, port=self.devserver.port,
Chris Sosac9447962013-03-12 10:12:29 -0700133 sub_dir='static/pkgroot/%s/packages' % self.board)
Chris Sosada9632e2013-03-04 12:28:06 -0800134
135 logging.info('Using binhost %s', self.binhost)
136
137 def TestDevInstall(self):
138 """Tests that we can run dev-install and have python work afterwards."""
139 try:
140 logging.info('Running dev install in the vm.')
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +0000141 self.device.RunCommand(
Chris Sosada9632e2013-03-04 12:28:06 -0800142 ['bash', '-l', '-c',
Mike Frysinger9d4f9302019-09-11 21:51:40 -0400143 '"/usr/bin/dev_install --yes --binhost=%s"' % self.binhost])
Chris Sosada9632e2013-03-04 12:28:06 -0800144
Mike Frysingere3b0ea72019-09-12 01:26:46 -0400145 logging.info('Verifying that all python versions work on the image.')
Mike Frysinger339c5c92019-10-03 17:06:18 -0400146 # Symlinks can be tricky, and running python from one place might work
147 # while it fails from another. Test all the prefixes (and $PATH).
148 for prefix in ('/usr/bin', '/usr/local/bin', '/usr/local/usr/bin', ''):
149 for prog in ('python', 'python2', 'python3'):
150 self.device.RunCommand(['sudo', '-u', 'chronos', '--',
151 os.path.join(prefix, prog),
152 '-c', '"print(\'hello world\')"'])
Yu-Ju Hong5ed02452014-01-30 09:05:00 -0800153 except (cros_build_lib.RunCommandError,
154 remote_access.SSHConnectionError) as e:
Chris Sosada9632e2013-03-04 12:28:06 -0800155 self.devserver.PrintLog()
156 logging.error('dev-install test failed. See devserver log above for more '
157 'details.')
158 raise TestError('dev-install test failed with: %s' % str(e))
159
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -0700160 def Run(self):
161 try:
162 self.PrepareTest()
163 self.TestDevInstall()
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -0700164 logging.info('All tests passed.')
165 finally:
166 self.Cleanup()
167
Chris Sosada9632e2013-03-04 12:28:06 -0800168
169def main():
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -0700170 parser = argparse.ArgumentParser(description=__doc__)
171 parser.add_argument('--binhost', metavar='URL',
172 help='binhost override. By default, starts up a devserver'
173 ' and uses it as the binhost.')
174 parser.add_argument('board', nargs=1, help='board to use.')
175 parser.add_argument('image_path', nargs=1, help='path to test|vm image.')
176 parser.add_argument('-v', '--verbose', default=False, action='store_true',
177 help='Print out added debugging information')
178 options = parser.parse_args()
Chris Sosada9632e2013-03-04 12:28:06 -0800179
180 test_helper.SetupCommonLoggingFormat(verbose=options.verbose)
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -0700181 DevModeTest(os.path.realpath(options.image_path[0]), options.board[0],
182 options.binhost).Run()
Chris Sosada9632e2013-03-04 12:28:06 -0800183
184if __name__ == '__main__':
185 main()