[TOC]
Autotest documentation on GitHub:
This would be a good read if you want to familiarize yourself with the basic
Autotest concepts.
Gentoo Portage ebuild/eclass Information:
Getting to know the package build system we use.
ChromiumOS specific Portage FAQ:
Learning something about the way we use portage.
To familiarize with autotest concepts, you should start with the upstream
Autotest documentation at: https://github.com/autotest/autotest/wiki/AutotestApi
The rest of this document is going to use some terms and only explain them
vaguely.
At a high level, tests are organized in test cases, each test case being either
server or client, with one main .py file named the same as the test case, and
one or more control files. In order to be able to perform all tasks on a given
test, autotest expects tests to be placed in a monolithic file structure
of:
/client/tests/
/client/site_tests/
/server/tests/
/server/site_tests/
Each test directory has to have at least a control file, but typically also has
a main job module (named the same as the test case). Furthermore, if it needs
any additional files checked in, they are typically placed in a files/
directory, and separate projects that can be built with a Makefile inside thesrc/
directory.
Due to structural limitations in Chromium OS, it is not possible to store all
test cases in this structure in a single large source repository as upstream
autotest source would (placed at third_party/autotest/files/
in Chromium OS).
In particular, the following has been required in the past:
Furthermore, it has been desired to generally build everything that is not
strongly ordered in parallel, significantly decreasing build times. That,
however, requires proper dependency tree declaration and being able to specify
which test cases require what dependencies, in addition to being able to
process different "independent" parts of a single source repository in
parallel.
This leads to the ebuild workflow, which generally allows compositing any
number of sources in any format into a single monolithic tree, whose contents
depend on build parameters.
This allows using standard autotest workflow without any change, however,
unlike what upstream does, the tests aren’t run directly from the source
repository, rather from a staging read-only install location. This leads to
certain differences in workflow:
/build/${board}/usr/local/autotest/
) may not beNOTE: This assumes some basic knowledge of how ebuilds in Chromium OS work.
Further documentation is available at http://www.chromium.org/chromium-os/how-tos-and-troubleshooting/portage-build-faq
An autotest ebuild is an ebuild that produces test cases and installs them into
the staging area. It has three general tasks:
src_unpack()
.setup()
function of the appropriate test. Typically, this is not needed.Autotest eclass is inherited by all autotest ebuilds, only requires a
number of variables specified and works by itself otherwise. Most variables
describe the locations and listings of work that needs to be done:
Location variables define the paths to directories containing the test
files:
AUTOTEST_{CLIENT,SERVER}_{TESTS,SITE_TESTS}
AUTOTEST_{DEPS,PROFILERS,CONFIG}
These typically only need to be specified if they differ from the defaults
(which follow the upstream directory structure)
List variables (AUTOTEST_*_LIST
) define the list of deps, profilers,
configs that should be handled by this ebuild.
Each ebuild usually operates on a single source repository. That does not
always have to hold true, however, and in case of autotest, many ebuilds check
out the sources of the same source repository (*autotest.git*). Invariably, this
means that they have to be careful to not install the same files and split the
sources between themselves to avoid file install collisions.
If more than one autotest ebuild operates on the same source repository, they
have to use the above variables to define mutually exclusive slices in order
to not collide during installation. Generally, if we have a source repository
with client site_tests A and B, you can have either:
As soon as an overlap between ebuilds happens, either an outside mechanism has
to ensure the overlapping tests are never enabled at the same time, or file
collisions happen.
Fundamentally, a test has two main phases:
run_*()
- This is is the main part that performs all testing and issetup()
- This function, present in the test case’s main .py file isDuring building using emerge, autotest will call a setup()
function of all
test cases/deps involved. This is supposed to prepare everything. Typically,
this will invoke make on a Makefile present in the test’s src/ directory, but
can involve any other transformation of sources (also be empty if there’s
nothing to build).
Note, however, that setup()
is implicitly called many times as test
initialization even during run_*()
step, so it should be a noop on reentry
that merely verifies everything is in order.
Unlike run_*()
functions, setup()
gets called both during the prepare phase
which happens on the host and target alike. This creates a problem with
code that is being depended on or directly executed during setup()
. Python
modules that are imported in any pathway leading to setup()
are needed both
in the host chroot and on the target board to properly support the test. Any
binaries would need to be compiled using the host compiler and either ensured
that they will be skipped on the target (incremental setup()
runs) or
cross-compiled again and dynamically chosen while running on target.
More importantly, in Chromium OS scenario, doing any write operations
inside the setup()
function will lead to access denied failures, because
tests are being run from the intermediate read-only location.
Given the above, building is as easy as emerge-ing the autotest ebuild that
contains our test. $ emerge-${board} ${test_ebuild}
Currently, tests are organized within these notable ebuilds: (see
FAQ full list):
Test cases built by ebuilds generally come in large bundles. Sometimes, only a
subset, or generally a different set of the tests provided by a given ebuild is
desired. That is achieved using a
USE_EXPANDed
flag called TESTS.
All USE flags (and therefore tests) have a default state, either enabled (+) or
disabled (-), specified directly in the ebuild, that can be manually overridden
from the commandline. There are two ways to do that.
Non-Incremental - Simply override the default selection by an entirely new
selection, ignoring the defaults. This is useful if you develop a single
test and don’t want to waste time building the others.
$ TESTS="test1 test2" emerge-${board} ${ebuild}
Incremental - All USE_EXPAND flags are also accessible as USE flags, with
the appropriate prefix, and can be used incrementally to selectively
enable/disable tests in addition to the defaults. This can be useful if you
aim to enable a test that is disabled by default and want to test locally.
$ USE="test_to_be_enabled -test_to_be_disabled" emerge-${board} \
${ebuild}
For operations across all tests, following incremental USE wildcard is
supported by portage: "tests_*" to select all tests at once (or - to
de-select).
NOTE: Both Incremental and Non-Incremental methods can be set/overriden by
(in this order): the ebuild (default values), make.profile, make.conf,
/etc/portage, commandline (see above). That means that any settings provided on
the emerge commandline override everything else.
NOTE: In order to run tests on your device, it needs to have a
test-enabled image.
When running tests, fundamentally, you want to either:
Run sets of tests manually - Use case: Developing test cases
Take your local test sources, modify them, and then attempt to run them on a
target machine using autotest. You are generally responsible for making sure
that the machine is imaged to a test image, and the image contains all the
dependencies needed to support your tests.
Verify a given image - Use case: Developing the projects subject to testing
Take an image, re-image the target device and run a test suite on it. This
requires either use of build-time autotest artifacts or their reproduction
by not modifying or resyncing your sources after an image has been built.
Autotests are run with a tool called
test_that.
VM tests are conveniently wrapped into a script cros_run_vm_tests
that sets up
the VM using a given image and then calls test_that
. This is run by builders
to test using the Smoke suite.
If you want to run your tests in a VM (see
here
cros_run_vm_test
starts up a VM and runs autotests using the portspecified (defaults to 9222). As an example:
$ cros_run_vm_test --autotest=suite:smoke \
--image-path=<my_image_to_start or don't set to use most recent build> \
--board=amd64-generic
The emulator command line redirects localhost port 9222 to the emulated
machine's port 22 to allow you to ssh into the emulator. For Chromium OS to
actually listen on this port you must append the --test_image
parameter
when you run the ./image_to_vm.sh
script, or perhaps run themod_image_for_test.sh
script instead.
You can then run tests on the correct ssh port with something like
$ test_that --board=x86-generic localhost:9222 'f:.*platform_BootPerf/control'
To set the sudo password run set_shared_user_password. Then within the
emulator you can press Ctrl-Alt-T to get a terminal, and sudo using this
password. This will also allow you to ssh into the unit with, e.g.
$ ssh -p 9222 root@localhost
Warning: After
crbug/710629,
'betty' is the only board regularly run through pre-CQ and CQ VMTest and so
is the most likely to work at ToT. 'betty' is based on 'amd64-generic',
so 'amd64-generic' is likely to also work for most (non-ARC) tests.
For information regarding the layout structure please refer to the following:
autotest-results-logs
Running autotest will result in a lot of information going by which is probably
not too informative if you have not used autotest before. At the end of thetest_that
run, you will see a summary of pass/failure status, along with
performance results:
22:44:30 INFO | Using installation dir /home/autotest
22:44:30 ERROR| Could not install autotest from repos
22:44:32 INFO | Installation of autotest completed
22:44:32 INFO | GOOD ---- Autotest.install timestamp=1263509072 localtime=Jan 14 22:44:32
22:44:33 INFO | Executing /home/autotest/bin/autotest /home/autotest/control phase 0
22:44:36 INFO | START ---- ---- timestamp=1263509075 localtime=Jan 14 14:44:35
22:44:36 INFO | START sleeptest sleeptest timestamp=1263509076 localtime=Jan 14 14:44:36
22:44:36 INFO | Bundling /usr/local/autotest/client/tests/sleeptest into test-sleeptest.tar.bz2
22:44:40 INFO | GOOD sleeptest sleeptest timestamp=1263509079 localtime=Jan 14 14:44:39 completed successfully
22:44:40 INFO | END GOOD sleeptest sleeptest timestamp=1263509079 localtime=Jan 14 14:44:39
22:44:42 INFO | END GOOD ---- ---- timestamp=1263509082 localtime=Jan 14 14:44:42
22:44:44 INFO | Client complete
22:44:45 INFO | Finished processing control file
test_that
will leave around a temp directory populated with diagnostic information:
Finished running tests. Results can be found in /tmp/test_that_results_j8GoWH or /tmp/test_that_latest
This directory will contain a directory per test run. Each directory contains
the logs pertaining to that test run.
In that directory some interesting files are:
${TEST}/debug/client.DEBUG - the most detailed output from running the
client-side test
Suites provide a mechanism to group tests together in test groups. They also
serve as hooks for automated runs of tests verifying various builds. Most
importantly, that is the BVT (board verification tests) and Smoke (a subset of
BVT that can run in a VM).
Please refer to the suites documentation.
For understanding and writing the actual python code for autotest, please refer
to the Developer FAQ
Currently, all code should be placed in a standard layout inside the
autotest.git repository, unless otherwise is necessary for technical reasons.
Regardless, the following text assumes that code is placed in generally any
repository.
For a test to be fully functional in Chromium OS, it has to be associated with
an ebuild. It is generally possible to run tests without an ebuild usingtest_that
but discouraged, as the same will not function with other parts of
the system.
The choice of ebuild depends on the location of its sources. Structuring tests
into more smaller ebuilds (as opposed to one ebuild per source repository)
serves two purposes:
Current ebuild structure is largely a result of breaking off the biggest
blockers for parallelism, ie. tests depending on chrome or similar packages,
and as such, using any of the current ebuilds should be sufficient. (see FAQ
for listing of ebuilds)
After choosing the proper ebuild to add your test into, the test (in the form
“+tests_”) needs to be added to IUSE_TESTS list that all autotest
ebuilds have. Failing to do so will simply make ebuilds ignore your tests
entirely. As with all USE flags, prepending it with + means the test will be
enabled by default, and should be the default, unless you want to keep the test
experimental for your own use, or turn the USE flag on explicitly by other
means, eg. in a config for a particular board only.
Should a new ebuild be started, it should be added to
chromeos-base/autotest-all package, which is a meta-ebuild depending on all
autotest ebuild packages that can be built. autotest-all is used by the build
system to automatically build all tests that we have and therefore keep them
from randomly breaking.
Autotest uses deps to provide a de-facto dependencies into the ecosystem. A dep
is a directory in ‘**client/deps**’ with a structure similar to a test case
without a control file. A test case that depends on a dep will invoke the dep’ssetup()
function in its own setup()
function and will be able to access the
files provided by the dep. Note that autotest deps have nothing to do with
system dependencies.
As the calls to a dep are internal autotest code, it is not possible to
automatically detect these and make them an inter-package dependencies on the
ebuild level. For that reason, deps should either be
provided by the same ebuild that builds test
that consume them, or ebuild dependencies need to be declared manually between
the dep ebuild and the test ebuild that uses it. An autotest-deponly
eclass exists to provide solution for ebuilds that build only deps and no
tests. A number of deponly ebuilds already exist.
Common deps are:
Generally, the naming convention runs like this:
<component>_<TestName>
That convention names the directory containing the test code. It also names
the .py file containing the test code, and the class of the Autotest test.
If there's only one control file, it's named control. The test's NAME in the
control file is <component>_<TestName>, like the directory and .py
file.
If there are multiple control files for a test, they are named
control.<testcase>. These tests' NAMEs are then
<component>_<TestName>.<testcase>.
Set up the environment.
$ cd ~/trunk/src/third_party/autotest/files/
$ export TESTS=”<the test cases to iterate on>”
$ EBUILD=<the ebuild that contains TEST>
$ board=<the board on which to develop>
Ensure cros_workon is started
$ cros_workon --board=${board} start ${EBUILD}
$ repo sync # Necessary only if you use minilayout.
Make modifications (on first run, you may want to just do 3,4 to verify
everything works before you touch it & break it)
$ ...
Build test (TESTS= is not necessary if you exported it before)
$ emerge-$board $EBUILD
Run test to make sure it works before you touch it
$ test_that <machine IP> ${TESTS}
Go to 2) to iterate
Clean up environment
$ cros_workon --board=${board} stop ${EBUILD}
$ unset TESTS
When creating a test, the following steps should be done/verified.
Find the appropriate ebuild package and start working on it:
$ cros_workon --board=${board} start <package>
Add the new test into the IUSE_TESTS list of 9999 ebuild
Try building: (make sure it’s the 9999 version being built)
$ TESTS=<test> emerge-$board <package>
Try running:
$ test_that <IP> <test>
Iterate on 4,5 and modify source until happy with the initial version.
Cleanup
$ cros_workon --board=${board} stop <package>
Removing a test from one ebuild and adding to another in the same revision
causes portage file collisions unless counter-measures are taken. Generally,
some things routinely go wrong in this process, so this checklist should serve
to help that.
Add a blocker. Since bar installs files owned by foo-0.0.1-r100 and earlier,
the blocker’s format will be:
RDEPEND="!<=foo-0.0.1-r100"
Add a dependency to the new version of bar into
chromeos-base/autotest-all-0.0.1
RDEPEND="bar"
Change the dependency of foo in chromeos-base/autotest-all-0.0.1 to be
version locked to the new rev:
RDEPEND=">foo-0.0.1-r100"
Uprev (move) autotest-all-0.0.1-rX symlink by one.
Set up a proper portage build chroot setup. Go through the normal process
of setup_board if you haven't already.
$ ./build_packages --board=${BOARD}
Build test image.
$ ./build_image --board=${BOARD} test
Install the Chromium OS testing image to your target machine. This is
through the standard mechanisms: either USB, or by reimaging a device
currently running a previously built Chromium OS image modded for test, or
by entering the shell on the machine and forcing an auto update to your
machine when it's running a dev server. For clarity we'll walk through two
common ways below, but if you already know about this, just do what you
normally do.
$ ./image_to_usb.sh --to /dev/sdX --board=${BOARD} \
--image_name=chromiumos_test_image.bin
$ ./image_to_live.sh --remote=${REMOTE_IP} \
--image=`./get_latest_image.sh \
--board=${BOARD}`/chromiumos_test_image.bin
This will automatically start dev server, ssh to your machine, cause it to
update to from that dev server using memento_updater, reboot, wait for reboot,
print out the new version updated to, and shut down your dev server.
Note that the list of ebuilds may differ per board, as each board has
potentially different list of overlays. To find all autotest ebuilds for board
foo, you can run: $ board=foo $ for dir in $(portageq-${board} envvar PORTDIR_OVERLAY); do find . -name '*.ebuild' | xargs grep "inherit.*autotest" | grep "9999" | \ cut -f1 -d: | \ sed -e 's/.*\/\([^/]*\)\/\([^/]*\)\/.*\.ebuild/\1\/\2/' done
(Getting: "WARNING: 'portageq envvar PORTDIR_OVERLAY' is deprecated. Use
'portageq repositories_configuration' instead." Please fix documentation.)
All ebuilds have lists of tests exported as USE_EXPANDed lists called
TESTS. An
expanded use can be searched for in the same way as other use flags, but with
the appropriate prefix, in this case, you would search for
tests_greattests_TestsEverything’: $ use_search=tests_greattests_TestsEverything $ equery-$board hasuse $use_search * Searching for USE flag tests_greattests_TestsEverything ... * [I-O] [ ] some_ebuild_package_name:0
This will however only work on ebuilds which are already installed, ie.
their potentially outdated versions.
Alternatively, you can run a pretended emerge (emerge -p) of all autotest
ebuilds and scan the output. $ emerge -p ${all_ebuilds_from_Q1} |grep -C 10 “${use_search}”
Generally speaking, one has to look at the ebuild source to figure that
question out (and it shouldn’t be hard). However, all present autotest ebuilds
(at the time of this writing) are also ‘cros-workon’, and for those, this
should always work: $ ebuild_search=foo $ ebuild $(equery-$board which $ebuild_search) info CROS_WORKON_SRCDIR=”/home/you/trunk/src/third_party/foo” CROS_WORKON_PROJECT=”chromiumos/third_party/foo”
You can run a pretended emerge on the ebuild and observe the ‘TESTS=’
statement:
```
$ ebuild_name=foo
$ emerge-$board -pv ${ebuild_name}
These are the packages that would be merged, in order:
Calculating dependencies... done!
[ebuild R ] foo-foo_version to /build/$board/ USE="autox hardened tpmtools
xset -buildcheck -opengles" TESTS="enabled_test1 enabled_test2 ... enabled_testN
-disabled_test1 ...disabled_testN" 0 kB [1]
```
Alternately, you can use equery, which will list tests with the USE_EXPAND
prefix: $ equery-$board uses ${ebuild_name} [ Legend : U - final flag setting for installation] [ : I - package is installed with flag ] [ Colors : set, unset ] * Found these USE flags for chromeos-base/autotest-tests-9999: U I + + autotest : <unknown> + + autotest : <unknown> + + autox : <unknown> + + buildcheck : <unknown> + + hardened : activate default security enhancements for toolchain (gcc, glibc, binutils) - - opengles : <unknown> + + tests_enabled_test : <unknown> - - tests_disabled_test : <unknown>
You should ‘workon’ and always cros_workon start all ebuilds that have files
that you touched. If you’re interested in a particular file/directory, that
is installed in /build/$board/usr/local/autotest/
and would like know which
package has provided that file, you can use equery:
$ equery-$board belongs /build/${board}/usr/local/autotest/client/site_tests/foo_bar/foo_bar.py
* Searching for <filename> ...
chromeos-base/autotest-tests-9999 (<filename>)
DON’T forget to do equery-$board. Just equery will also work, only never
return anything useful.
As a rule of thumb, if you work on anything from the core autotest framework or
shared libraries (anything besides
{server,client}/{test,site_tests,deps,profilers,config}), it belongs to
chromeos-base/autotest. Individual test case will each belong to a particular
ebuild, see Q2.
It is important to cros_workon start every ebuild involved.
Your test’s setup()
function (which runs on the host before being uploaded) is
probably trying to write into the read-only intermediate location. See
explanation.