xref: /aosp_15_r20/external/autotest/autotest_lib/docs/best-practices.md (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Autotest Best Practices
2*9c5db199SXin LiWhen the ChromeOS team started using autotest, we tried our best to figure out
3*9c5db199SXin Lihow to fit our code and our tests into the upstream style with little guidance
4*9c5db199SXin Liand poor documentation.  This went poorly.  With the benefit of hindsight,
5*9c5db199SXin Liwe’re going to lay out some best-practices that we’d like to enforce going
6*9c5db199SXin Liforward.  In many cases, there is legacy code that contradicts this style; we
7*9c5db199SXin Lishould go through and refactor that code to fit these guidelines as time
8*9c5db199SXin Liallows.
9*9c5db199SXin Li
10*9c5db199SXin Li## Upstream Documentation
11*9c5db199SXin Li
12*9c5db199SXin LiThere is a sizeable volume of general Autotest documentation available on
13*9c5db199SXin Ligithub:
14*9c5db199SXin Lihttps://github.com/autotest/autotest/wiki
15*9c5db199SXin Li
16*9c5db199SXin Li## Coding style
17*9c5db199SXin Li
18*9c5db199SXin LiBasically PEP-8.  See [docs/coding-style.md](coding-style.md)
19*9c5db199SXin Li
20*9c5db199SXin Li## Where should my code live?
21*9c5db199SXin Li
22*9c5db199SXin Li| Type of Code              | Relative Path           |
23*9c5db199SXin Li|---------------------------|-------------------------|
24*9c5db199SXin Li| client-side tests         | client/site_tests/      |
25*9c5db199SXin Li| server-side tests         | server/site_tests       |
26*9c5db199SXin Li| common library code       | client/common_lib/cros/ |
27*9c5db199SXin Li| server-only library code  | server/cros             |
28*9c5db199SXin Li
29*9c5db199SXin Li
30*9c5db199SXin Li## Writing tests
31*9c5db199SXin Li
32*9c5db199SXin LiAn autotest is really defined by its control file.  A control file contains
33*9c5db199SXin Liimportant metadata about the test (name, author, description, duration, what
34*9c5db199SXin Lisuite it’s in, etc) and then pulls in and executes the actual test code.  This
35*9c5db199SXin Litest code can be shared among multiple distinct test cases by parameterizing it
36*9c5db199SXin Liand passing those parameters in from separate control files.
37*9c5db199SXin Li
38*9c5db199SXin LiAutotests *must*:
39*9c5db199SXin Li
40*9c5db199SXin Li * Be self-contained: assume nothing about the condition of the device
41*9c5db199SXin Li * Be hermetic: requiring the Internet to be reachable in order for your test
42*9c5db199SXin Li   to succeed is unacceptable.
43*9c5db199SXin Li * Be automatic: avoid user interaction and run-time specification of input
44*9c5db199SXin Li   values.
45*9c5db199SXin Li * Be integration tests: if you can test the feature in a unit test (or a
46*9c5db199SXin Li   chrome browser test), do so.
47*9c5db199SXin Li * Prefer object composition to inheritance: avoid subclassing test.test to
48*9c5db199SXin Li   implement common functionality for multiple tests.  Instead, create a class
49*9c5db199SXin Li   that your tests can instantiate to perform common operations.  This enables
50*9c5db199SXin Li   us to write tests that use both PyAuto and Servo without dealing with
51*9c5db199SXin Li   multiple inheritance, for example.
52*9c5db199SXin Li * Be deterministic: a test should not validate the timing of some operation.
53*9c5db199SXin Li   Instead, write a test that records the timing in performance keyvals so that
54*9c5db199SXin Li   we can track the numbers over time.
55*9c5db199SXin Li
56*9c5db199SXin LiAutotests *must not*:
57*9c5db199SXin Li
58*9c5db199SXin Li * Put significant logic in the control file: control files are really just
59*9c5db199SXin Li   python, so one can put arbitrary logic in there.  Don’t.  Run your test
60*9c5db199SXin Li   code, perhaps with some parameters.
61*9c5db199SXin Li
62*9c5db199SXin LiAutotests *may*:
63*9c5db199SXin Li
64*9c5db199SXin Li * Share parameterized fixtures: a test is defined by a control file.  Control
65*9c5db199SXin Li   files import and run test code, and can pass simple parameters to the code
66*9c5db199SXin Li   they run through a well-specified interface.
67*9c5db199SXin Li
68*9c5db199SXin LiAutotest has a notion of both client-side tests and server-side tests.  Code in
69*9c5db199SXin Lia client-side test runs only on the device under test (DUT), and as such isn’t
70*9c5db199SXin Licapable of maintaining state across reboots or handling a failed suspend/resume
71*9c5db199SXin Liand the like.  If possible, an autotest should be written as a client-side
72*9c5db199SXin Litest.  A ‘server’ test runs on the autotest server, but gets assigned a DUT
73*9c5db199SXin Lijust like a client-side test.  It can use various autotest primitives (and
74*9c5db199SXin Lilibrary code written by the CrOS team) to manipulate that device.  Most, if not
75*9c5db199SXin Liall, tests that use Servo or remote power management should be server-side
76*9c5db199SXin Litests, as an example.
77*9c5db199SXin Li
78*9c5db199SXin LiAdding a test involves putting a control file and a properly-written test
79*9c5db199SXin Liwrapper in the right place in the source tree.  There are conventions that must
80*9c5db199SXin Libe followed, and a variety of primitives available for use.  When writing any
81*9c5db199SXin Licode, whether client-side test, server-side test, or library, have a strong
82*9c5db199SXin Libias towards using autotest utility code.  This keeps the codebase consistent.
83*9c5db199SXin Li
84*9c5db199SXin Li
85*9c5db199SXin Li## Writing a test
86*9c5db199SXin Li
87*9c5db199SXin LiThis section explains considerations and requirements for any autotest, whether
88*9c5db199SXin Liclient or server.
89*9c5db199SXin Li
90*9c5db199SXin Li### Control files
91*9c5db199SXin Li
92*9c5db199SXin LiUpstream documentation
93*9c5db199SXin LiOur local conventions for autotest control files deviate from the above a bit,
94*9c5db199SXin Libut the indication about which fields are mandatory still holds.
95*9c5db199SXin Li
96*9c5db199SXin Li| Variable     | Required | Value                                                                                                                                                                                                                                                                                                                                    |
97*9c5db199SXin Li|--------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
98*9c5db199SXin Li| AUTHOR       | Yes      | A comma-delimited string of at least one responsible engineer and a backup engineer -- or at worst a backup mailing list. i.e. AUTHOR = ‘msb, snanda’                                                                                                                                                                                    |
99*9c5db199SXin Li| DEPENDENCIES | No       | list of tags known to the HW test lab.                                                                                                                                                                                                                                                                                                   |
100*9c5db199SXin Li| DOC          | Yes      | Long description of the test, pass/fail criteria                                                                                                                                                                                                                                                                                         |
101*9c5db199SXin Li| NAME         | Yes      | Display name of the test. Generally this is the directory where your test lives e.g. hardware_TPMCheck. If you are using multiple run_test calls in the same control file or multiple control files with one test wrapper in the same suite, problems arise with the displaying of your test name. crosbug.com/35795. When in doubt ask. |
102*9c5db199SXin Li| SYNC\_COUNT  | No       | Integer >= 1.  Number of simultaneous devices needed for a test run.                                                                                                                                                                                                                                                                     |
103*9c5db199SXin Li| TIME         | Yes      | Test duration: 'FAST' (<1m), 'MEDIUM' (<10m), 'LONG' (<20m), 'LENGTHY' (>30m)                                                                                                                                                                                                                                                            |
104*9c5db199SXin Li| TEST\_TYPE   | Yes      | Client or Server                                                                                                                                                                                                                                                                                                                         |
105*9c5db199SXin Li| ATTRIBUTES   | No       | Comma separated list of attribute tags to apply to this control file, used in composing suites. For instance, 'suite:foo, suite:bar'.                                                                                                                                                                                                    |
106*9c5db199SXin Li
107*9c5db199SXin Li### Running tests in suites
108*9c5db199SXin Li
109*9c5db199SXin LiMake sure that the suite name is listed in `site_utils/attribute_allowlist.txt`,
110*9c5db199SXin Lithen add the appropriate attribute to the ATTRIBUTES field in tests that make
111*9c5db199SXin Liup the test suite.  For instance:
112*9c5db199SXin Li
113*9c5db199SXin Li```
114*9c5db199SXin Li...
115*9c5db199SXin LiATTRIBUTES = 'suite:suite-a, suite:suite-b'
116*9c5db199SXin Li...
117*9c5db199SXin Li```
118*9c5db199SXin Li
119*9c5db199SXin Liwould indicate that the control file above should be run as part of both
120*9c5db199SXin Li`suite-a` and `suite-b`.
121*9c5db199SXin Li
122*9c5db199SXin Li### Pure python
123*9c5db199SXin Li
124*9c5db199SXin LiLie, cheat and steal to keep your tests in pure python.  It will be easier to
125*9c5db199SXin Lidebug failures, it will be easier to generate meaningful error output, it will
126*9c5db199SXin Libe simpler to get your tests installed and run, and it will be simpler for the
127*9c5db199SXin Lilab team to build tools that allow you to quickly iterate.
128*9c5db199SXin Li
129*9c5db199SXin LiShelling out to existing command-line tools is done fairly often, and isn’t a
130*9c5db199SXin Literrible thing.  The test author can wind up having to do a lot of output
131*9c5db199SXin Liparsing, which is often brittle, but this can be a decent tradeoff in lieu of
132*9c5db199SXin Lihaving to reimplement large pieces of functionality in python.
133*9c5db199SXin Li
134*9c5db199SXin LiNote that you will need to be sure that any commands you use are installed on
135*9c5db199SXin Lithe host.  For a client-side test, “the host” means “the DUT”.  For a
136*9c5db199SXin Liserver-side test, “the host” typically means “the system running autoserv”;
137*9c5db199SXin Lihowever, if you use SiteHost.run(), the command will run on the DUT.  On the
138*9c5db199SXin Liserver, your tests will have access to all tools common to both a typical CrOS
139*9c5db199SXin Lichroot environment and standard Goobuntu.
140*9c5db199SXin Li
141*9c5db199SXin LiIf you want to use a tool on the DUT, it may be appropriate to include it as a
142*9c5db199SXin Lidependency of the chromeos-base/chromeos-test package.  This ensures that the
143*9c5db199SXin Litool is pre-installed on every test image for every device, and will always be
144*9c5db199SXin Liavailable for use.  Otherwise, the tool must be installed as an autotest “dep”.
145*9c5db199SXin Li
146*9c5db199SXin Li_Never install your own shell scripts and call them._  Anything you can do in
147*9c5db199SXin Lishell, you can do in python.
148*9c5db199SXin Li
149*9c5db199SXin Li### Reporting failures
150*9c5db199SXin Li
151*9c5db199SXin LiAutotest supports several kinds of failure statuses:
152*9c5db199SXin Li
153*9c5db199SXin Li| Status   | Exception         | Reason                                                                                                                                                                                                                                                                                                                   |
154*9c5db199SXin Li|----------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
155*9c5db199SXin Li| WARN     | error.TestWarn    | error.TestWarn should be used when side effects to the test running are encountered but are not directly related to the test running. For example, if you are testing Wifi and powerd crashes. *Currently* there are not any clear usecases for this and error.TestWarn should be generally avoided until further notice. |
156*9c5db199SXin Li| TEST\_NA | error.TestNAError | This test does not apply in the current environment.                                                                                                                                                                                                                                                                     |
157*9c5db199SXin Li| ERROR    | error.TestError   | The test was unable to validate the desired behavior.                                                                                                                                                                                                                                                                    |
158*9c5db199SXin Li| FAIL     | error.TestFail    | The test determined the desired behavior failed to occur.                                                                                                                                                                                                                                                                |
159*9c5db199SXin Li
160*9c5db199SXin Li
161*9c5db199SXin Li### Considerations when writing client-side tests
162*9c5db199SXin Li
163*9c5db199SXin LiAll client-side tests authored at Google must live in the client/site\_tests sub-directory of the autotest source tree.
164*9c5db199SXin Li
165*9c5db199SXin Li###Compiling and executing binaries
166*9c5db199SXin Li
167*9c5db199SXin LiIt is possible to compile source that’s included with your test and use the
168*9c5db199SXin Liproducts at test runtime.  The build infrastructure will compile this code for
169*9c5db199SXin Lithe appropriate target architecture and package it up along with the rest of
170*9c5db199SXin Liyour test’s resources, but this increases your development iteration time as
171*9c5db199SXin Liyou need to actually re-build and re-package your test to deploy it to the
172*9c5db199SXin Lidevice.  While we hope to improve tooling support for this use case in the
173*9c5db199SXin Lifuture, avoiding this issue is the ideal.
174*9c5db199SXin Li
175*9c5db199SXin LiIf you can’t avoid this, here’s how to get your code compiled and installed as
176*9c5db199SXin Lia part of your test:
177*9c5db199SXin Li1. Create a src/ directory next to your control file.
178*9c5db199SXin Li2. Put your source, including its Makefile, in src/
179*9c5db199SXin Li3. define a method in your test class called “setup(self)” that takes no arguments.
180*9c5db199SXin Li4. setup(self) should perform all tasks necessary to build your tool.  There are some helpful utility functions in client/common_lib/utils.py.  Trivial example:
181*9c5db199SXin Li
182*9c5db199SXin Li```
183*9c5db199SXin Li    def setup(self):
184*9c5db199SXin Li        os.chdir(self.srcdir)
185*9c5db199SXin Li        utils.make('OUT_DIR=.')
186*9c5db199SXin Li```
187*9c5db199SXin Li
188*9c5db199SXin Li### Reusing code (“fixtures”)
189*9c5db199SXin Li
190*9c5db199SXin LiAny autotest is, essentially, a single usage of a re-usable test fixture.  This
191*9c5db199SXin Liis because run\_once() in your test wrapper can take any arguments you want.  As
192*9c5db199SXin Lisuch, multiple control files can re-use the same wrapper -- and should, where
193*9c5db199SXin Liit makes sense.
194*9c5db199SXin Li
195*9c5db199SXin Li### Considerations when writing server-side tests
196*9c5db199SXin Li
197*9c5db199SXin LiAll server-side tests authored at Google must live in the server/site\_tests
198*9c5db199SXin Lisub-directory of the autotest source tree.
199*9c5db199SXin Li
200*9c5db199SXin LiIt should be even easier to keep the server-side of a test in pure python, as
201*9c5db199SXin Liyou should simply be driving the DUT and verifying state.
202*9c5db199SXin Li
203*9c5db199SXin Li### When/why to write a server-side test
204*9c5db199SXin Li
205*9c5db199SXin LiServer-side tests are appropriate when some operation in the test can't be
206*9c5db199SXin Liexecuted on the DUT.  The prototypical example is rebooting the DUT.  Other
207*9c5db199SXin Liexamples include tests that manipulate the network around the DUT (e.g. WiFi
208*9c5db199SXin Litests), tests that power off the DUT, and tests that rely on a Servo attached
209*9c5db199SXin Lito the DUT.
210*9c5db199SXin Li
211*9c5db199SXin LiOne simple criterion for whether to write a server-side test is this:  Is the
212*9c5db199SXin LiDUT an object that the test must manipulate?  If the answer is “yes”, then a
213*9c5db199SXin Liserver-side test makes sense.
214*9c5db199SXin Li
215*9c5db199SXin Li### Control files for server-side tests
216*9c5db199SXin Li
217*9c5db199SXin LiServer-side tests commonly operate on the DUT as an object.  Autotest
218*9c5db199SXin Lirepresents the DUT with an instance of class Host; the instance is constructed
219*9c5db199SXin Liand passed to the test from the control file.  Creating the host object in the
220*9c5db199SXin Licontrol file can be done using certain definitions present in the global
221*9c5db199SXin Lienvironment of every control file:
222*9c5db199SXin Li
223*9c5db199SXin Li * Function hosts.create\_host() will create a host object from a string with
224*9c5db199SXin Li   the name of the host (an IP address as a string is also acceptable).
225*9c5db199SXin Li * Variable machines is a list of the host names available to the test.
226*9c5db199SXin Li
227*9c5db199SXin LiBelow is a sample fragment for a control file that runs a simple server side test in parallel on all the hosts specified for the test.  The fragment is a complete control file, except for the missing boilerplate comments and documentation definitions required in all control files.
228*9c5db199SXin Li
229*9c5db199SXin Li```
230*9c5db199SXin Lidef run(machine):
231*9c5db199SXin Li    host = hosts.create_host(machine)
232*9c5db199SXin Li    job.run_test("platform_ServerTest", host=host)
233*9c5db199SXin Li
234*9c5db199SXin Liparallel_simple(run, machines)
235*9c5db199SXin Li```
236*9c5db199SXin Li
237*9c5db199SXin LiNote:  The sample above relies on a common convention that the run\_once()
238*9c5db199SXin Limethod of a server-side test defines an argument named host with a default
239*9c5db199SXin Livalue, e.g.
240*9c5db199SXin Li
241*9c5db199SXin Li```
242*9c5db199SXin Lidef run_once(self, host=None):
243*9c5db199SXin Li    # … test code goes here.
244*9c5db199SXin Li```
245*9c5db199SXin Li
246*9c5db199SXin Li### Operations on Host objects
247*9c5db199SXin Li
248*9c5db199SXin LiA Host object supports various methods to operate on a DUT.  Below is a short list of important methods supported by instances of Host:
249*9c5db199SXin Li
250*9c5db199SXin Li * run(command) - run a shell command on the host
251*9c5db199SXin Li * reboot() - reboot the host, and wait for it to be back on the network
252*9c5db199SXin Li * wait_up() - wait for the host to be active on the network
253*9c5db199SXin Li * wait_down() - wait until the host is no longer on the network, or until it is known to have rebooted.
254*9c5db199SXin Li
255*9c5db199SXin LiMore details, including a longer list of available methods, and more about how
256*9c5db199SXin Lithey work can be found in the Autotest documentation for autoserv and Autotest
257*9c5db199SXin Lidocumentation for Host.
258*9c5db199SXin Li
259*9c5db199SXin Li### Servo-based tests
260*9c5db199SXin Li
261*9c5db199SXin LiFor server-side tests that use a servo-attached DUT, the host object has a
262*9c5db199SXin Liservo attribute.  If Autotest determines that the DUT has a Servo attached, the
263*9c5db199SXin Liservo attribute will be a valid instance of a Servo client object; otherwise
264*9c5db199SXin Lithe attribute will be None.
265*9c5db199SXin Li
266*9c5db199SXin LiFor a DUT in the lab, Autotest will automatically determine whether there is a
267*9c5db199SXin Liservo available; however, if a test requires Servo, its control file must have
268*9c5db199SXin Liadditional code to guarantee a properly initialized servo object on the host.
269*9c5db199SXin Li
270*9c5db199SXin LiBelow is a code snippet outlining the requirements; portions of the control file have been omitted for brevity:
271*9c5db199SXin Li
272*9c5db199SXin Li```
273*9c5db199SXin Li# ... Standard boilerplate variable assignments...
274*9c5db199SXin LiDEPENDENCIES = "servo_state:WORKING"
275*9c5db199SXin Li# ... more standard boilerplate...
276*9c5db199SXin Li# servo_state:WORKING - servo is present and can provide required functionality
277*9c5db199SXin Li# servo_state:BROKEN - servo is present but cannot provide required functionality
278*9c5db199SXin Li
279*9c5db199SXin Liargs_dict = utils.args_to_dict(args)
280*9c5db199SXin Liservo_args = hosts.SiteHost.get_servo_arguments(args_dict)
281*9c5db199SXin Li
282*9c5db199SXin Lidef run(machine):
283*9c5db199SXin Li    host = hosts.create_host(machine, servo_args=servo_args)
284*9c5db199SXin Li    job.run_test("platform_SampleServoTest", host=host)
285*9c5db199SXin Li
286*9c5db199SXin Liparallel_simple(run, machines)
287*9c5db199SXin Li```
288*9c5db199SXin Li
289*9c5db199SXin LiThe `DEPENDENCIES` setting guarantees that if the test is scheduled in the lab,
290*9c5db199SXin Liit will be assigned to a DUT that has a servo.
291*9c5db199SXin Li
292*9c5db199SXin LiThe setting of `servo_args` guarantees two distinct things:  First, it forces
293*9c5db199SXin Lichecks that will make sure that the Servo is functioning properly; this
294*9c5db199SXin Liguarantees that the host's `servo` attribute will not be None.  Second, the code
295*9c5db199SXin Liallows you to pass necessary servo specific command-line arguments to
296*9c5db199SXin Li`test_that`.
297*9c5db199SXin Li
298*9c5db199SXin LiIf the test control file follows the formula above, the test can be reliably called in a variety of ways:
299*9c5db199SXin Li * When used for hosts in the lab, the host’s servo object will use the servo attached to the host, and the test can assume that the servo object is not None.
300*9c5db199SXin Li * If you start servod manually on your desktop using the default port, you can use test_that without any special options.
301*9c5db199SXin Li * If you need to specify a non-default host or port number (e.g. because servod is remote, or because you have more than one servo board), you can specify them with commands like these:
302*9c5db199SXin Li
303*9c5db199SXin Li```
304*9c5db199SXin Litest_that --args=”servo_host=...” …
305*9c5db199SXin Litest_that --args=”servo_port=...” …
306*9c5db199SXin Litest_that --args=”servo_host=... servo_port=...” ...
307*9c5db199SXin Li```
308*9c5db199SXin Li
309*9c5db199SXin Li### Calling client-side tests from a server-side test
310*9c5db199SXin Li
311*9c5db199SXin LiCommonly, server-side tests need to do more on the DUT than simply run short
312*9c5db199SXin Lishell commands.  In those cases, a client-side test should be written and
313*9c5db199SXin Liinvoked from the server-side test.  In particular, a client side test allows
314*9c5db199SXin Lithe client side code to be written in Python that uses standard Autotest
315*9c5db199SXin Liinfrastructure, such as various utility modules or the logging infrastructure.
316*9c5db199SXin Li
317*9c5db199SXin LiBelow is a short snippet showing the standard form for calling a client-side
318*9c5db199SXin Litest from server-side code:
319*9c5db199SXin Li
320*9c5db199SXin Li```
321*9c5db199SXin Lifrom autotest_lib.server import autotest
322*9c5db199SXin Li
323*9c5db199SXin Li    # ... inside some function, e.g. in run_once()
324*9c5db199SXin Li    client_at = autotest.Autotest(host)
325*9c5db199SXin Li    client_at.run_test("platform_ClientTest")
326*9c5db199SXin Li```
327*9c5db199SXin Li
328*9c5db199SXin Li### Writing library code
329*9c5db199SXin Li
330*9c5db199SXin LiThere is a large quantity of Chromium OS specific code in the autotest
331*9c5db199SXin Licodebase.  Much of this exists to provide re-usable modules that enable tests
332*9c5db199SXin Lito talk to system services.  The guidelines from above apply here as well.
333*9c5db199SXin LiThis code should be as pure python as possible, though it is reasonable to
334*9c5db199SXin Lishell out to command line tools from time to time.  In some cases we’ve done
335*9c5db199SXin Lithis where we could (now) use the service’s DBus APIs directly.  If you’re
336*9c5db199SXin Liadding code to allow tests to communicate with your service, it is strongly
337*9c5db199SXin Lirecommended that you use DBus where possible, instead of munging config files
338*9c5db199SXin Lidirectly or using command-line tools.
339*9c5db199SXin Li
340*9c5db199SXin LiCurrently, our library code lives in a concerning variety of places in the
341*9c5db199SXin Liautotest tree.  This is due to a poor initial understanding of how to do
342*9c5db199SXin Lithings, and new code should follow the following conventions instead:
343*9c5db199SXin Li
344*9c5db199SXin Li * Used only in server-side tests: server/cros
345*9c5db199SXin Li * Used in both server- and client-side tests, or only client:
346*9c5db199SXin Li   client/common\_lib/cros
347*9c5db199SXin Li
348*9c5db199SXin Li### Adding test deps
349*9c5db199SXin Li
350*9c5db199SXin LiThis does not refer to the optional `DEPENDENCIES` field in test control files.
351*9c5db199SXin LiRather, this section discusses how and when to use code/data/tools that are not
352*9c5db199SXin Lipre-installed on test images, and should (or can) not be included right in with
353*9c5db199SXin Lithe test source.
354*9c5db199SXin Li
355*9c5db199SXin LiUnfortunately, there is no hard-and-fast rule here.  Generally, if this is some
356*9c5db199SXin Lismall tool or blob of data you need for a single test, you should include it as
357*9c5db199SXin Lidiscussed above in Writing client-side tests.  If you’re writing the tool, and
358*9c5db199SXin Liit has use for developers as well as in one or more tests that you’re writing,
359*9c5db199SXin Lithen make it a first-class CrOS project.  Write an ebuild, write unit tests,
360*9c5db199SXin Liand then add it to the test image by default.  This can be done by RDEPENDing
361*9c5db199SXin Lion your new test package from the chromeos-test ebuild.
362*9c5db199SXin Li
363*9c5db199SXin LiIf your code/data falls in the middle (useful to several tests, not to devs),
364*9c5db199SXin Liand/or is large (hundreds of megabytes as opposed to tens) then using an
365*9c5db199SXin Liautotest ‘dep’ may be the right choice.  Conceptually, an autotest test dep is
366*9c5db199SXin Lisimply another kind of archive that the autotest infrastructure knows how to
367*9c5db199SXin Lifetch and unpack.  There are two components to including a dependency from an
368*9c5db199SXin Liautotest test -- setup during build time and installing it on your DUT when
369*9c5db199SXin Lirunning a test.  The setup phase must be run from your tests setup() method
370*9c5db199SXin Lilike so:
371*9c5db199SXin Li
372*9c5db199SXin Li```
373*9c5db199SXin Lidef setup(self):
374*9c5db199SXin Li  self.job.setup_dep([‘mydep’])
375*9c5db199SXin Li  logging.debug(‘mydep is at %s’ % (os.path.join(self.autodir,
376*9c5db199SXin Lideps/mydep’))
377*9c5db199SXin Li```
378*9c5db199SXin Li
379*9c5db199SXin LiThe above gets run when you “build” the test.
380*9c5db199SXin Li
381*9c5db199SXin LiThe other half of this equation is actually installing the dependency so you
382*9c5db199SXin Lican use it while running a test.  To do this, add the following to either your
383*9c5db199SXin Lirun\_once or initialize methods:
384*9c5db199SXin Li
385*9c5db199SXin Li```
386*9c5db199SXin Li        dep = dep_name
387*9c5db199SXin Li        dep_dir = os.path.join(self.autodir, 'deps', dep=dep)
388*9c5db199SXin Li        self.job.install_pkg(dep, 'dep', dep_dir)
389*9c5db199SXin Li```
390*9c5db199SXin Li
391*9c5db199SXin Li
392*9c5db199SXin LiYou can now reference the content of your dep using dep_dir.
393*9c5db199SXin Li
394*9c5db199SXin LiNow that you know how to include a dep, the next question is how to write one.
395*9c5db199SXin LiBefore you read further, you should check out client/deps/\* for many examples
396*9c5db199SXin Liof deps in our autotest tree.
397*9c5db199SXin Li
398*9c5db199SXin Li### Create a dep from a third-party package
399*9c5db199SXin Li
400*9c5db199SXin LiThere are many examples of how to do this in the client/deps directory already.
401*9c5db199SXin LiThe key component is to check in a tarball of the version of the dependency
402*9c5db199SXin Liyou’d like to include under client/deps/your\_dep.
403*9c5db199SXin Li
404*9c5db199SXin LiAll deps require a control file and an actual python module by the same name.
405*9c5db199SXin LiThey will also need a copy of common.py to import utils.update\_version. Both
406*9c5db199SXin Lithe control and common are straightforward, the python module does all the
407*9c5db199SXin Limagic.
408*9c5db199SXin Li
409*9c5db199SXin LiThe deps python module follows a standard convention: a setup function and a
410*9c5db199SXin Licall to utils.update\_version.  update\_version is used instead of directly
411*9c5db199SXin Licalling setup as it maintains additional versioning logic ensuring setup is
412*9c5db199SXin Lionly done 1x per dep. The following is its method signature:
413*9c5db199SXin Li
414*9c5db199SXin Li```
415*9c5db199SXin Lidef update_version(srcdir, preserve_srcdir, new_version, install,
416*9c5db199SXin Li                   *args, **dargs)
417*9c5db199SXin Li```
418*9c5db199SXin Li
419*9c5db199SXin Li
420*9c5db199SXin LiNotably, install should be a pointer to your setup function and `*args` should
421*9c5db199SXin Libe filled in with params to said setup function.
422*9c5db199SXin Li
423*9c5db199SXin LiIf you are using a tarball, your setup function should look something like:
424*9c5db199SXin Li
425*9c5db199SXin Li```
426*9c5db199SXin Lidef setup(tarball, my_dir)
427*9c5db199SXin Li    utils.extract_tarball_to_dir(tarball, my_dir)
428*9c5db199SXin Li    os.chdir(my_dir)
429*9c5db199SXin Li    utils.make() # this assumes your tarball has a Makefile.
430*9c5db199SXin Li```
431*9c5db199SXin Li
432*9c5db199SXin LiAnd you would invoke this with:
433*9c5db199SXin Li
434*9c5db199SXin Li```
435*9c5db199SXin Liutils.update_version(os.getcwd(), True, version, setup, tarball_path,
436*9c5db199SXin Li                     os.getcwd())
437*9c5db199SXin Li```
438*9c5db199SXin Li
439*9c5db199SXin Li
440*9c5db199SXin LiNote: The developer needs to call this because def setup is a function they are
441*9c5db199SXin Lidefining that can take any number of arguments or install the dep in any way
442*9c5db199SXin Lithey see fit. The above example uses tarballs but some are distributed as
443*9c5db199SXin Listraight source under the src dir so their setup function only takes a top
444*9c5db199SXin Lilevel path. We could avoid this by forcing a convention but that would be
445*9c5db199SXin Liartificially constraining the deps mechanism.
446*9c5db199SXin Li
447*9c5db199SXin LiOnce you’ve created the dep, you will also have to add the dep to the
448*9c5db199SXin Liautotest-deps package in chromiumos-overlay/chromeos-base/autotest-deps,
449*9c5db199SXin Li‘cros\_workon start’ it, and re-emerge it.
450*9c5db199SXin Li
451*9c5db199SXin Li### Create a dep from other chrome-os packages
452*9c5db199SXin Li
453*9c5db199SXin LiOne can also create autotest deps from code that lives in other CrOS packages,
454*9c5db199SXin Lior from build products generated by other packages.  This is similar as above
455*9c5db199SXin Libut you can reference code using the `CHROMEOS_ROOT` env var that points to the
456*9c5db199SXin Liroot of the CrOS source checkout, or the SYSROOT env var (which points to
457*9c5db199SXin Li/build/<board>) to refer to build products.  Again, read the above. Here’s an
458*9c5db199SXin Liexample of the former with the files I want in
459*9c5db199SXin Lichromeos\_tree/chromite/my\_dep/\* where this will be the python code in
460*9c5db199SXin Liautotest/files/client/deps/my\_dep/my\_dep.py module.
461*9c5db199SXin Li
462*9c5db199SXin Li```
463*9c5db199SXin Liimport common, os, shutil
464*9c5db199SXin Lifrom autotest_lib.client.bin import utils
465*9c5db199SXin Li
466*9c5db199SXin Liversion = 1
467*9c5db199SXin Li
468*9c5db199SXin Lidef setup(setup_dir):
469*9c5db199SXin Li    my_dep_dir = os.path.join(os.environ['CHROMEOS_ROOT'], 'chromite',
470*9c5db199SXin Li                              'buildbot')
471*9c5db199SXin Li    shutil.copytree(my_dep_dir, setup_dir)
472*9c5db199SXin Li
473*9c5db199SXin Li
474*9c5db199SXin Liwork_dir = os.path.join(os.getcwd(), 'src')
475*9c5db199SXin Liutils.update_version(os.getcwd(), True, version, setup, work_dir)
476*9c5db199SXin Li```
477