the Chromium logo

The Chromium Projects

Writing and Developing Tests

For understanding and writing the actual python code for autotest, please refer to the Writing Tests FAQ.

For understanding test deps, refer to the Test Deps FAQ.

For understanding how to test your changes, refer to the Testing Your Changes FAQ.

Writing a test

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, either using run_remote_tests --build or calling autoserv directly with the correct options, but discouraged, as the same will not function with other parts of the system.

Making a new test work with ebuilds

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:

Deps

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’s setup() 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:

Working on a test

As mentioned, while working on a test, it is necessary to always propagate any source changes using the emerge step. This can be either a manual emerge (instant) or cros build-packages (longer, rebuilds all dependencies as well). For cros-workon ebuilds, this means first starting to work on all ebuilds that are affected. (Which ebuilds are these?):

$ cros_workon --board=${board} start <list of ebuilds>

As described, all autotest ebuilds have a selectable list of tests, most of which can be disabled and only the one test that is being worked on can be built selectively, saving time.

$ TESTS=testname emerge-${board} <list of ebuilds>
$ run_remote_tests.sh --remote=<ip> testname

Note: If tests have interdependencies not handled via deps, those cannot be automatically detected, and you have to include all tests that are being depended on. An example of that would be an old-style test suite, which is really just a control file calling other tests selectively via hardcoded names. In order to make that work, you have to determine the list of tests accordingly, before you run the suite.

Anatomy of test.test

This section describes the pieces of test.test that are available to use, describing what each does and when it could be used.

Attributes

job backreference to the job this test instance is part of

outputdir eg. results/<job>/<testname.tag>

resultsdir eg. results/<job>/<testname.tag>/results

profdir eg. results/<job>/<testname.tag>/profiling

debugdir eg. results/<job>/<testname.tag>/debug

bindir eg. tests/<test>

src eg. tests/<test>/src

tmpdir eg. tmp/<tempname>_<testname.tag>

initialize()

Everytime a test runs this function runs. For example, if you have iterations=100 set this will run 100 times. Use this when you need to do something like ensure a package is there.

setup()

setup() runs the first time the test is set up. This is often used for compiling source code one should not need to recompile the source for the test for every iteration or install the same

run_once()

This is called by job.run_test N times, where N is controlled by the interations parameter to run_test (Defaulting to one). it also gets called an additional time with profilers turn on, if any profilers are enabled.

postprocess_iteration()

This processes any results generated by the test iteration and writes them out into a keyval. It's generally not called for the profiling iteration, as that may have difference performance implications.

warmup()

Test naming conventions

(TODO) We don’t have any. These need to be defined and documented here.