blob: c36466b335c8fcc77b0ba8deaa56bb71def530ba [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
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
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
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080031from chromite.lib import osutils
Chris Sosa928085e2013-03-08 17:25:30 -080032from chromite.lib import remote_access
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -080033from chromite.lib import vm
34
Chris Sosada9632e2013-03-04 12:28:06 -080035from crostestutils.lib import mount_helper
36from 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
60 or gmerge go to search for binary packages. By default this will
61 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."""
Chris Sosada9632e2013-03-04 12:28:06 -080095 r_mount_point = os.path.join(self.tmpdir, 'm')
96 s_mount_point = os.path.join(self.tmpdir, 's')
Chris Sosab8c2af52013-07-03 10:45:39 -070097 dev_image_path = os.path.join(s_mount_point, 'dev_image')
Chris Sosada9632e2013-03-04 12:28:06 -080098 mount_helper.MountImage(self.working_image_path,
99 r_mount_point, s_mount_point, read_only=False,
100 safe=True)
Chris Sosab8c2af52013-07-03 10:45:39 -0700101 try:
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800102 osutils.RmDir(dev_image_path, sudo=True)
Chris Sosab8c2af52013-07-03 10:45:39 -0700103 finally:
104 mount_helper.UnmountImage(r_mount_point, s_mount_point)
Chris Sosada9632e2013-03-04 12:28:06 -0800105
Chris Sosada9632e2013-03-04 12:28:06 -0800106 def PrepareTest(self):
107 """Pre-test modification to the image and env to setup test."""
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800108 logging.info('Setting up the image %s for vm testing.', self.image_path)
109 vm_path = vm.CreateVMImage(image=self.image_path, board=self.board,
Yu-Ju Hongb933bfc2014-02-19 11:15:34 -0800110 updatable=False)
Chris Sosada9632e2013-03-04 12:28:06 -0800111
112 logging.info('Making copy of the vm image %s to manipulate.', vm_path)
David James45b55dd2013-04-24 09:16:40 -0700113 self.working_image_path = os.path.join(self.tmpdir,
114 os.path.basename(vm_path))
Chris Sosada9632e2013-03-04 12:28:06 -0800115 shutil.copyfile(vm_path, self.working_image_path)
116 logging.debug('Copy of vm image stored at %s.', self.working_image_path)
117
Chris Sosab8c2af52013-07-03 10:45:39 -0700118 logging.info('Wiping /usr/local/bin from the image.')
119 self._WipeDevInstall()
Chris Sosada9632e2013-03-04 12:28:06 -0800120
Achuith Bhandarkar78010f72019-01-03 17:21:52 -0800121 self.port = remote_access.GetUnusedPort()
122 logging.info('Starting the vm on port %d.', self.port)
123 vm_cmd = ['./cros_vm', '--ssh-port=%d' % self.port,
124 '--image-path=%s' % self.working_image_path, '--start']
125 cros_build_lib.RunCommand(vm_cmd, cwd=chromite_constants.CHROMITE_BIN_DIR)
Yu-Ju Honga1dfbf52014-01-31 10:23:03 -0800126
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +0000127 self.device = remote_access.ChromiumOSDevice(
Achuith Bhandarkar78010f72019-01-03 17:21:52 -0800128 remote_access.LOCALHOST, port=self.port, base_dir=self.tmpdir)
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +0000129
Chris Sosada9632e2013-03-04 12:28:06 -0800130 if not self.binhost:
131 logging.info('Starting the devserver.')
Chris Sosaa404a382013-08-22 11:28:38 -0700132 self.devserver = dev_server_wrapper.DevServerWrapper()
133 self.devserver.Start()
Nicolas Norvezc5a20ae2018-03-02 14:49:54 -0800134 self.binhost = self.devserver.GetDevServerURL(
135 ip=self.HOST_IP_ADDRESS, port=self.devserver.port,
Chris Sosac9447962013-03-12 10:12:29 -0700136 sub_dir='static/pkgroot/%s/packages' % self.board)
Chris Sosada9632e2013-03-04 12:28:06 -0800137
138 logging.info('Using binhost %s', self.binhost)
139
140 def TestDevInstall(self):
141 """Tests that we can run dev-install and have python work afterwards."""
142 try:
143 logging.info('Running dev install in the vm.')
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +0000144 self.device.RunCommand(
Chris Sosada9632e2013-03-04 12:28:06 -0800145 ['bash', '-l', '-c',
146 '"/usr/bin/dev_install --yes --binhost %s"' % self.binhost])
147
148 logging.info('Verifying that python works on the image.')
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +0000149 self.device.RunCommand(['sudo', '-u', 'chronos', '--', 'python', '-c',
150 '"print \'hello world\'"'])
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 self.devserver.PrintLog()
154 logging.error('dev-install test failed. See devserver log above for more '
155 'details.')
156 raise TestError('dev-install test failed with: %s' % str(e))
157
Chris Sosada9632e2013-03-04 12:28:06 -0800158 def TestGmerge(self):
159 """Evaluates whether the test passed or failed."""
Chris Sosa928085e2013-03-08 17:25:30 -0800160 logging.info('Testing that gmerge works on the image after dev install.')
Chris Sosada9632e2013-03-04 12:28:06 -0800161 try:
Achuith Bhandarkar518c8e22018-06-08 19:42:04 +0000162 self.device.RunCommand(
Chris Sosac9447962013-03-12 10:12:29 -0700163 ['gmerge', 'gmerge', '--accept_stable', '--usepkg',
Nicolas Norvezc5a20ae2018-03-02 14:49:54 -0800164 '--devserver_url', self.devserver.GetDevServerURL(
165 ip=self.HOST_IP_ADDRESS, port=self.devserver.port),
Chris Sosac9447962013-03-12 10:12:29 -0700166 '--board', self.board])
Yu-Ju Hong5ed02452014-01-30 09:05:00 -0800167 except (cros_build_lib.RunCommandError,
168 remote_access.SSHConnectionError) as e:
Chris Sosada9632e2013-03-04 12:28:06 -0800169 logging.error('gmerge test failed. See log for details')
170 raise TestError('gmerge test failed with: %s' % str(e))
171
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -0700172 def Run(self):
173 try:
174 self.PrepareTest()
175 self.TestDevInstall()
176 self.TestGmerge()
177 logging.info('All tests passed.')
178 finally:
179 self.Cleanup()
180
Chris Sosada9632e2013-03-04 12:28:06 -0800181
182def main():
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -0700183 parser = argparse.ArgumentParser(description=__doc__)
184 parser.add_argument('--binhost', metavar='URL',
185 help='binhost override. By default, starts up a devserver'
186 ' and uses it as the binhost.')
187 parser.add_argument('board', nargs=1, help='board to use.')
188 parser.add_argument('image_path', nargs=1, help='path to test|vm image.')
189 parser.add_argument('-v', '--verbose', default=False, action='store_true',
190 help='Print out added debugging information')
191 options = parser.parse_args()
Chris Sosada9632e2013-03-04 12:28:06 -0800192
193 test_helper.SetupCommonLoggingFormat(verbose=options.verbose)
Achuith Bhandarkarb6bc33d2018-03-28 00:16:47 -0700194 DevModeTest(os.path.realpath(options.image_path[0]), options.board[0],
195 options.binhost).Run()
Chris Sosada9632e2013-03-04 12:28:06 -0800196
197if __name__ == '__main__':
198 main()