Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / docs / how_to_extend_layout_test_framework.md
blob32d3b33f1aa043b27926ce0b6cb6d42242de64d0
1 # How to Extend the Layout Test Framework
3 The Layout Test Framework that Blink uses is a regression testing tool that is
4 multi-platform and it has a large amount of tools that help test varying types
5 of regression, such as pixel diffs, text diffs, etc. The framework is mainly
6 used by Blink, however it was made to be extensible so that other projects can
7 use it test different parts of chrome (such as Print Preview). This is a guide
8 to help people who want to actually the framework to test whatever they want.
10 [TOC]
12 ## Background
14 Before you can start actually extending the framework, you should be familiar
15 with how to use it. This wiki is basically all you need to learn how to use it
16 http://www.chromium.org/developers/testing/webkit-layout-tests
18 ## How to Extend the Framework
20 There are two parts to actually extending framework to test a piece of software.
21 The first part is extending certain files in:
22 [/third_party/Webkit/Tools/Scripts/webkitpy/layout_tests/](/third_party/Webkit/Tools/Scripts/webkitpy/layout_tests/)
23 The code in `webkitpy/layout_tests` is the layout test framework itself
25 The second part is creating a driver (program) to actually communicate the
26 layout test framework. This part is significantly more tricky and dependant on
27 what exactly exactly is being tested.
29 ### Part 1
31 This part isn’t too difficult. There are basically two classes that need to be
32 extended (ideally, just inherited from). These classes are:
34 *   `Driver`. Located in `layout_tests/port/driver.py`. Each instance of this is
35     the class that will actually an instance of the program that produces the
36     test data (program in Part 2).
37 *   `Port`. Located in `layout_tests/port/base.py`. This class is responsible
38     creating drivers with the correct settings, giving access to certain OS
39     functionality to access expected files, etc.
41 #### Extending Driver
43 As said, Driver launches the program from Part 2. Said program will communicate
44 with the driver class to receive instructions and send back data. All of the
45 work for driver gets done in `Driver.run_test`. Everything else is a helper or
46 initialization function.
48 `run_test()` steps:
50 1.  On the very first call of this function, it will actually run the test
51     program. On every subsequent call to this function, at the beginning it will
52     verify that the process doesn’t need to be restarted, and if it does, it
53     will create a new instance of the test program.
54 1.  It will then create a command to send the program
55     *   This command generally consists of an html file path for the test
56         program to navigate to.
57     *   After creating it, the command is sent
58 1.  After the command has been sent, it will then wait for data from the
59     program.
60     *   It will actually wait for 2 blocks of data.
61         *   The first part being text or audio data. This part is required (the
62             program will always send something, even an empty string)
63         *   The second block is optional and is image data and an image hash
64             (md5) this block of data is used for pixel tests
65 1.  After it has received all the data, it will proceed to check if the program
66     has timed out or crashed, and if so fail this instance of the test (it can
67     be retried later if need be).
69 Luckily, `run_test()` most likely doesn’t need to be overridden unless extra
70 blocks of data need to be sent to/read from the test program. However, you do
71 need to know how it works because it will influence what functions you need to
72 override. Here are the ones you’re probably going to need to override
74     cmd_line
76 This function creates a set of command line arguments to run the test program,
77 so the function will almost certainly need to be overridden.
79 It creates the command line to run the program. `Driver` uses `subprocess.popen`
80 to create the process, which takes the name of the test program and any options
81 it might need.
83 The first item in the list of arguments should be the path to test program using
84 this function:
86     self._port._path_to_driver()
88 This is an absolute path to the test program. This is the bare minimum you need
89 to get the driver to launch the test program, however if you have options you
90 need to append, just append them to the list.
92     start
94 If your program has any special startup needs, then this will be the place to
95 put it.
97 That’s mostly it. The Driver class has almost all the functionality you could
98 want, so there isn’t much to override here. If extra data needs to be read or
99 sent, extra data members should be added to `ContentBlock`.
101 #### Extending Port
103 This class is responsible for providing functionality such as where to look for
104 tests, where to store test results, what driver to run, what timeout to use,
105 what kind of files can be run, etc. It provides a lot of functionality, however
106 it isn’t really sufficient because it doesn’t account of platform specific
107 problems, therefore port itself shouldn’t be extend. Instead LinuxPort, WinPort,
108 and MacPort (and maybe the android port class) should be extended as they
109 provide platform specific overrides/extensions that implement most of the
110 important functionality. While there are many functions in Port, overriding one
111 function will affect most of the other ones to get the desired behavior. For
112 example, if `layout_tests_dir()` is overriden, not only will the code look for
113 tests in that directory, but it will find the correct TestExpectations file, the
114 platform specific expected files, etc.
116 Here are some of the functions that most likely need to be overridden.
118 *   `driver_class`
119     *   This should be overridden to allow the testing program to actually run.
120         By default the code will run content_shell, which might or might not be
121         what you want.
122     *   It should be overridden to return the driver extension class created
123         earlier. This function doesn’t return an instance on the driver, just
124         the class itself.
125 *   `driver_name`
126     *   This should return the name of the program test p. By default it returns
127         ‘content_shell’, but you want to have it return the program you want to
128         run, such as `chrome` or `browser_tests`.
129 *   `layout_tests_dir`
130     *   This tells the port where to look for all the and everything associated
131         with them such as resources files.
132     *   By default it returns absolute path to the webkit tests.
133     *   If you are planning on running something in the chromium src/ directory,
134         there are helper functions to allow you to return a path relative to the
135         base of the chromium src directory.
137 The rest of the functions can definitely be overridden for your projects
138 specific needs, however these are the bare minimum needed to get it running.
139 There are also functions you can override to make certain actions that aren’t on
140 by default always take place. For example, the layout test framework always
141 checks for system dependencies unless you pass in a switch. If you want them
142 disabled for your project, just override `check_sys_deps` to always return OK.
143 This way you don’t need to pass in so many switches.
145 As said earlier, you should override LinuxPort, MacPort, and/or WinPort. You
146 should create a class that implements the platform independent overrides (such
147 as `driver_class`) and then create a separate class for each platform specific
148 port of your program that inherits from the class with the independent overrides
149 and the platform port you want. For example, you might want to have a different
150 timeout for your project, but on Windows the timeout needs to be vastly
151 different than the others. In this case you can just create a default override
152 that every class uses except your Windows port. In that port you can just
153 override the function again to provide the specific timeout you need. This way
154 you don’t need to maintain the same function on each platform if they all do the
155 same thing.
157 For `Driver` and `Port` that’s basically it unless you need to make many odd
158 modifications. Lots of functionality is already there so you shouldn’t really
159 need to do much.
161 ### Part 2
163 This is the part where you create the program that your driver class launches.
164 This part is very application dependent, so it will not be a guide on how
165 implement certain features, just what should be implemented and the order in
166 which events should occur and some guidelines about what to do/not do. For a
167 good example of how to implement your test program, look at MockDRT in
168 `mock_drt.pyin` the same directory as `base.py` and `driver.py`. It goes through
169 all the steps described below and is very clear and concise. It is written in
170 python, but your driver can be anything that can be run by `subprocess.popen`
171 and has stdout, stdin, stderr.
173 #### Goals
175 Your goal for this part of the project is to create a program (or extend a
176 program) to interface with the layout test framework. The layout test framework
177 will communicate with this program to tell it what to do and it will accept data
178 from this program to perform the regression testing or create new base line
179 files.
181 #### Structure
183 This is how your code should be laid out.
185 1.  Initialization
186     *   The creation of any directories or the launching of any programs should
187         be done here and should be done once.
188     *   After the program is initialized, “#READY\n” should be sent to progress
189         the `run_test()` in the driver.
190 1.  Infinite Loop (!)
191     *   After initialization, your program needs to actually wait for input,
192         then process that input to carry out the test. In the context of layout
193         testing, the `content_shell` needs to wait for an html file to navigate
194         to, render it, then convert that rendering to a PNG. It does this
195         constantly, until a signal/message is sent to indicate that no more
196         tests should be processed
197     *   Details:
198         *   The first thing you need is your test file path and any other
199             additional information about the test that is required (this is sent
200             during the write() step in `run_tests()` is `driver.py`. This
201             information will be passed through stdin and is just one large
202             string, with each part of the command being split with apostrophes
203             (ex: “/path’foo” is path to the test file, then foo is some setting
204             that your program might need).
205         *   After that, your program should act on this input, how it does this
206             is dependent on your program, however in `content_shell`, this would
207             be the part where it navigates to the test file, then renders it.
208             After the program acts on the input, it needs to send some text to
209             the driver code to indicate that it has acted on the input. This
210             text will indicate something that you want to test. For example, if
211             you want to make sure you program always prints “foo” you should
212             send it to the driver. If the program every prints “bar” (or
213             anything else), that would indicate a failure and the test will
214             fail.
215         *   Then you need to send any image data in the same manner as you did
216             for step 2.
217         *   Cleanup everything related to processing the input from step i, then
218             go back to step 1.
219             *   This is where the ‘infinite’ loop part comes in, your program
220             should constantly accept input from the driver until the driver
221             indicates that there are no more tests to run. The driver does this
222             by closing stdin, which will cause std::cin to go into a bad state.
223             However, you can also modify the driver to send a special string
224             such as ‘QUIT’ to exit the while loop.
226 That’s basically what the skeleton of your program should be.
228 ### Details
230 This is information about how to do some specific things, such as sending data
231 to the layout test framework.
233 *   Content Blocks
234     *   The layout test framework accepts output from your program in blocks of
235         data through stdout. Therefore, printing to stdout is really sending
236         data to the layout test framework.
237     *   Structure of block
238         *   “Header: Data\n”
239             *   Header indicates what type of data will be sent through. A list
240                 of valid headers is listed in `Driver.py`.
241             *   Data is the data that you actually want to send. For pixel
242                 tests, you want to send the actual PNG data here.
243             *   The newline is needed to indicate the end of a header.
244         * End of a content block
245             *   To indicate the end of a a content block and cause the driver to
246                 progress, you need to write “#EOF\n” to stdout (mandatory) and
247                 to stderr for certain types of content, such as image data.
248         * Multiple headers per block
249             *   Some blocks require different sets of data. For PNGs, not only
250                 is the PNG needed, but so is a hash of the bitmap used to create
251                 the PNG.
252             *   In this case this is how your output should look.
253                 *   “Content-type: image/png\n”
254                 *   “ActualHash: hashData\n”
255                 *   “Content-Length: lengthOfPng\n”
256                 *   “pngdata”
257                     *   This part doesn’t need a header specifying that you are
258                         sending png data, just send it
259                 *   “#EOF\n” on both stdout and stderr
260             *   To see the structure of the data required, look at the
261                 `read_block` functions in Driver.py