blob: 0eee26a936cb72a32335bbd21fdc476349898a37 [file] [log] [blame]
Dan Shi767dced2015-02-01 00:21:07 -08001# Copyright 2015 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Function tests of lxc module. To be able to run this test, following setup
6is required:
7 1. lxc is installed.
8 2. Autotest code exists in /usr/local/autotest, with site-packages installed.
9 (run utils/build_externals.py)
10 3. The user runs the test should have sudo access. Run the test with sudo.
11Note that the test does not require Autotest database and frontend.
12"""
13
14
15import argparse
16import logging
17import os
18import sys
19import tempfile
20import time
21
22import common
Dan Shi7836d252015-04-27 15:33:58 -070023from autotest_lib.client.bin import utils
Dan Shi767dced2015-02-01 00:21:07 -080024from autotest_lib.site_utils import lxc
25
26
27TEST_JOB_ID = 123
Dan Shiafa63872016-02-23 15:32:31 -080028TEST_JOB_FOLDER = '123-debug_user'
Dan Shi767dced2015-02-01 00:21:07 -080029# Create a temp directory for functional tests. The directory is not under /tmp
30# for Moblab to be able to run the test.
31TEMP_DIR = tempfile.mkdtemp(dir=lxc.DEFAULT_CONTAINER_PATH,
32 prefix='container_test_')
33RESULT_PATH = os.path.join(TEMP_DIR, 'results', str(TEST_JOB_ID))
34# Link to download a test package of autotest server package.
35# Ideally the test should stage a build on devserver and download the
36# autotest_server_package from devserver. This test is focused on testing
37# container, so it's prefered to avoid dependency on devserver.
Dan Shi9d41c872016-08-02 15:17:28 -070038AUTOTEST_SERVER_PKG = ('http://storage.googleapis.com/abci-ssp/'
Dan Shi767dced2015-02-01 00:21:07 -080039 'autotest-containers/autotest_server_package.tar.bz2')
40
41# Test log file to be created in result folder, content is `test`.
42TEST_LOG = 'test.log'
43# Name of test script file to run in container.
44TEST_SCRIPT = 'test.py'
45# Test script to run in container to verify autotest code setup.
46TEST_SCRIPT_CONTENT = """
47import sys
48
49# Test import
50import common
51import chromite
52from autotest_lib.server import utils
Dan Shid9094d42015-07-09 18:09:22 -070053from autotest_lib.site_utils import lxc
Dan Shi767dced2015-02-01 00:21:07 -080054
55with open(sys.argv[1], 'w') as f:
56 f.write('test')
Dan Shid9094d42015-07-09 18:09:22 -070057
58# Test installing packages
59lxc.install_packages(['atop', 'libxslt-dev'], ['selenium', 'numpy'])
60
Dan Shi767dced2015-02-01 00:21:07 -080061"""
62# Name of the test control file.
63TEST_CONTROL_FILE = 'attach.1'
64TEST_DUT = '172.27.213.193'
Dan Shiafa63872016-02-23 15:32:31 -080065TEST_RESULT_PATH = lxc.RESULT_DIR_FMT % TEST_JOB_FOLDER
Dan Shi767dced2015-02-01 00:21:07 -080066# Test autoserv command.
67AUTOSERV_COMMAND = (('/usr/bin/python -u /usr/local/autotest/server/autoserv '
68 '-p -r %(result_path)s/%(test_dut)s -m %(test_dut)s '
69 '-u debug_user -l test -s -P %(job_id)s-debug_user/'
70 '%(test_dut)s -n %(result_path)s/%(test_control_file)s '
71 '--verify_job_repo_url') %
72 {'job_id': TEST_JOB_ID,
73 'result_path': TEST_RESULT_PATH,
74 'test_dut': TEST_DUT,
75 'test_control_file': TEST_CONTROL_FILE})
76# Content of the test control file.
77TEST_CONTROL_CONTENT = """
78def run(machine):
79 job.run_test('dummy_PassServer',
80 host=hosts.create_host(machine))
81
82parallel_simple(run, machines)
83"""
84
85
86def setup_logging(log_level=logging.INFO):
87 """Direct logging to stdout.
88
89 @param log_level: Level of logging to redirect to stdout, default to INFO.
90 """
91 logger = logging.getLogger()
92 logger.setLevel(log_level)
93 handler = logging.StreamHandler(sys.stdout)
94 handler.setLevel(log_level)
95 formatter = logging.Formatter('%(asctime)s %(message)s')
96 handler.setFormatter(formatter)
97 logger.handlers = []
98 logger.addHandler(handler)
99
100
101def setup_base(bucket):
102 """Test setup base container works.
103
104 @param bucket: ContainerBucket to interact with containers.
105 """
106 logging.info('Rebuild base container in folder %s.', bucket.container_path)
107 bucket.setup_base()
108 containers = bucket.get_all()
109 logging.info('Containers created: %s', containers.keys())
110
111
112def setup_test(bucket, name, skip_cleanup):
113 """Test container can be created from base container.
114
115 @param bucket: ContainerBucket to interact with containers.
116 @param name: Name of the test container.
117 @param skip_cleanup: Set to True to skip cleanup, used to troubleshoot
118 container failures.
119
120 @return: A Container object created for the test container.
121 """
122 logging.info('Create test container.')
123 os.makedirs(RESULT_PATH)
124 container = bucket.setup_test(name, TEST_JOB_ID, AUTOTEST_SERVER_PKG,
Dan Shiafa63872016-02-23 15:32:31 -0800125 RESULT_PATH, skip_cleanup=skip_cleanup,
126 job_folder=TEST_JOB_FOLDER)
Dan Shi767dced2015-02-01 00:21:07 -0800127
128 # Inject "AUTOSERV/testing_mode: True" in shadow config to test autoserv.
129 container.attach_run('echo $\'[AUTOSERV]\ntesting_mode: True\' >>'
130 ' /usr/local/autotest/shadow_config.ini')
131 return container
132
133
134def test_share(container):
135 """Test container can share files with the host.
136
137 @param container: The test container.
138 """
139 logging.info('Test files written to result directory can be accessed '
140 'from the host running the container..')
141 host_test_script = os.path.join(RESULT_PATH, TEST_SCRIPT)
142 with open(host_test_script, 'w') as script:
143 script.write(TEST_SCRIPT_CONTENT)
144
Dan Shiafa63872016-02-23 15:32:31 -0800145 container_result_path = lxc.RESULT_DIR_FMT % TEST_JOB_FOLDER
Dan Shi767dced2015-02-01 00:21:07 -0800146 container_test_script = os.path.join(container_result_path, TEST_SCRIPT)
147 container_test_script_dest = os.path.join('/usr/local/autotest/utils/',
148 TEST_SCRIPT)
149 container_test_log = os.path.join(container_result_path, TEST_LOG)
150 host_test_log = os.path.join(RESULT_PATH, TEST_LOG)
151 # Move the test script out of result folder as it needs to import common.
152 container.attach_run('mv %s %s' % (container_test_script,
153 container_test_script_dest))
154 container.attach_run('python %s %s' % (container_test_script_dest,
155 container_test_log))
156 if not os.path.exists(host_test_log):
157 raise Exception('Results created in container can not be accessed from '
158 'the host.')
159 with open(host_test_log, 'r') as log:
160 if log.read() != 'test':
161 raise Exception('Failed to read the content of results in '
162 'container.')
163
164
165def test_autoserv(container):
166 """Test container can run autoserv command.
167
168 @param container: The test container.
169 """
170 logging.info('Test autoserv command.')
171 logging.info('Create test control file.')
172 host_control_file = os.path.join(RESULT_PATH, TEST_CONTROL_FILE)
173 with open(host_control_file, 'w') as control_file:
174 control_file.write(TEST_CONTROL_CONTENT)
175
176 logging.info('Run autoserv command.')
177 container.attach_run(AUTOSERV_COMMAND)
178
179 logging.info('Confirm results are available from host.')
180 # Read status.log to check the content is not empty.
181 container_status_log = os.path.join(TEST_RESULT_PATH, TEST_DUT,
182 'status.log')
183 status_log = container.attach_run(command='cat %s' % container_status_log
184 ).stdout
185 if len(status_log) < 10:
186 raise Exception('Failed to read status.log in container.')
187
188
Dan Shi507fdc42015-04-30 10:59:37 -0700189def test_package_install(container):
190 """Test installing package in container.
191
192 @param container: The test container.
193 """
Dan Shid9094d42015-07-09 18:09:22 -0700194 # Packages are installed in TEST_SCRIPT_CONTENT. Verify the packages in
195 # this method.
196 container.attach_run('which atop')
197 container.attach_run('python -c "import selenium"')
Dan Shi507fdc42015-04-30 10:59:37 -0700198
199
Dan Shi7836d252015-04-27 15:33:58 -0700200def test_ssh(container, remote):
201 """Test container can run ssh to remote server.
202
203 @param container: The test container.
204 @param remote: The remote server to ssh to.
205
206 @raise: error.CmdError if container can't ssh to remote server.
207 """
208 logging.info('Test ssh to %s.', remote)
209 container.attach_run('ssh %s -a -x -o StrictHostKeyChecking=no '
210 '-o BatchMode=yes -o UserKnownHostsFile=/dev/null '
211 '-p 22 "true"' % remote)
212
213
Dan Shi767dced2015-02-01 00:21:07 -0800214def parse_options():
215 """Parse command line inputs.
216 """
217 parser = argparse.ArgumentParser()
Dan Shi7836d252015-04-27 15:33:58 -0700218 parser.add_argument('-d', '--dut', type=str,
219 help='Test device to ssh to.',
220 default=None)
221 parser.add_argument('-r', '--devserver', type=str,
222 help='Test devserver to ssh to.',
223 default=None)
Dan Shi767dced2015-02-01 00:21:07 -0800224 parser.add_argument('-v', '--verbose', action='store_true',
225 default=False,
226 help='Print out ALL entries.')
227 parser.add_argument('-s', '--skip_cleanup', action='store_true',
228 default=False,
229 help='Skip deleting test containers.')
230 return parser.parse_args()
231
232
233def main(options):
234 """main script.
235
236 @param options: Options to run the script.
237 """
238 # Force to run the test as superuser.
239 # TODO(dshi): crbug.com/459344 Set remove this enforcement when test
240 # container can be unprivileged container.
Dan Shica3be482015-05-05 23:23:53 -0700241 if utils.sudo_require_password():
242 logging.warn('SSP requires root privilege to run commands, please '
243 'grant root access to this process.')
244 utils.run('sudo true')
Dan Shi767dced2015-02-01 00:21:07 -0800245
246 setup_logging(log_level=(logging.DEBUG if options.verbose
247 else logging.INFO))
248
249 bucket = lxc.ContainerBucket(TEMP_DIR)
250
251 setup_base(bucket)
252 container_test_name = (lxc.TEST_CONTAINER_NAME_FMT %
Dan Shid68d51c2015-04-21 17:00:42 -0700253 (TEST_JOB_ID, time.time(), os.getpid()))
Dan Shi767dced2015-02-01 00:21:07 -0800254 container = setup_test(bucket, container_test_name, options.skip_cleanup)
255 test_share(container)
256 test_autoserv(container)
Dan Shi7836d252015-04-27 15:33:58 -0700257 if options.dut:
258 test_ssh(container, options.dut)
259 if options.devserver:
260 test_ssh(container, options.devserver)
Dan Shid9094d42015-07-09 18:09:22 -0700261 # Packages are installed in TEST_SCRIPT, verify the packages are installed.
Dan Shi507fdc42015-04-30 10:59:37 -0700262 test_package_install(container)
Dan Shi767dced2015-02-01 00:21:07 -0800263 logging.info('All tests passed.')
264
265
266if __name__ == '__main__':
267 options = parse_options()
268 try:
269 main(options)
270 finally:
271 if not options.skip_cleanup:
272 logging.info('Cleaning up temporary directory %s.', TEMP_DIR)
273 try:
274 lxc.ContainerBucket(TEMP_DIR).destroy_all()
275 finally:
Dan Shi7836d252015-04-27 15:33:58 -0700276 utils.run('sudo rm -rf "%s"' % TEMP_DIR)