~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to lib/common_test/doc/src/ct_hooks_chapter.xml

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?xml version="1.0" encoding="UTF-8" ?>
 
2
<!DOCTYPE chapter SYSTEM "chapter.dtd">
 
3
 
 
4
<chapter>
 
5
  <header>
 
6
    <copyright>
 
7
      <year>2011</year><year>2011</year>
 
8
      <holder>Ericsson AB. All Rights Reserved.</holder>
 
9
    </copyright>
 
10
    <legalnotice>
 
11
      The contents of this file are subject to the Erlang Public License,
 
12
      Version 1.1, (the "License"); you may not use this file except in
 
13
      compliance with the License. You should have received a copy of the
 
14
      Erlang Public License along with this software. If not, it can be
 
15
      retrieved online at http://www.erlang.org/.
 
16
 
 
17
      Software distributed under the License is distributed on an "AS IS"
 
18
      basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 
19
      the License for the specific language governing rights and limitations
 
20
      under the License.
 
21
 
 
22
    </legalnotice>
 
23
 
 
24
    <title>Common Test Hooks</title>
 
25
    <prepared>Lukas Larsson</prepared>
 
26
    <docno></docno>
 
27
    <date></date>
 
28
    <rev></rev>
 
29
    <file>ct_hooks_chapter.xml</file>
 
30
  </header>
 
31
 
 
32
  <marker id="general"></marker>
 
33
  <section>
 
34
    <title>General</title>
 
35
    <warning><p>This feature is in alpha release right now. This means that the 
 
36
        interface may change in the future and that there may be bugs. We 
 
37
        encourage you to use this feature, but be prepared 
 
38
        that there might be bugs and that the interface might change
 
39
        inbetween releases.</p></warning>
 
40
    <p>
 
41
      The <em>Common Test Hook</em> (henceforth called CTH) framework allows 
 
42
      extensions of the default behaviour of Common Test by means of hooks 
 
43
      before and after all test suite calls. CTHs allow advanced Common Test
 
44
      users to abstract out behaviour which is common to multiple test suites
 
45
      without littering all test suites with library calls. Some example 
 
46
      usages are: logging, starting and monitoring external systems, 
 
47
      building C files needed by the tests and much more!</p>
 
48
 
 
49
    <p>In brief, Common Test Hooks allows you to:</p>
 
50
 
 
51
    <list>
 
52
      <item>Manipulate the runtime config before each suite 
 
53
      configuration call</item>
 
54
      <item>Manipulate the return of all suite configuration calls and in 
 
55
      extension the result of the test themselves.</item>
 
56
    </list>
 
57
    
 
58
    <p>The following sections describe how to use CTHs, when they are run 
 
59
      and how to manipulate your test results in a CTH</p>
 
60
 
 
61
    <warning><p>When executing within a CTH all timetraps are shutoff. So
 
62
        if your CTH never returns, the entire test run will be stalled!</p>
 
63
    </warning>
 
64
 
 
65
  </section>
 
66
  
 
67
  <marker id="installing"></marker>
 
68
  <section>
 
69
    <title>Installing a CTH</title>
 
70
    <p>There are multiple ways to install a CTH in your test run. You can do it
 
71
      for all tests in a run, for specific test suites and for specific groups 
 
72
      within a test suite. If you want a CTH to be present in all test suites 
 
73
      within your test run there are three different ways to accomplish that.
 
74
    </p>
 
75
 
 
76
    <list>
 
77
      <item>Add <c>-ct_hooks</c> as an argument to 
 
78
      <seealso marker="run_test_chapter#ct_run">ct_run</seealso>. 
 
79
      To add multiple CTHs using this method append them to each other
 
80
      using the keyword <c>and</c>, i.e. 
 
81
      <c>ct_run -ct_hooks cth1 [{debug,true}] and cth2 ...</c>.</item>
 
82
      <item>Add the <c>ct_hooks</c> tag to your 
 
83
      <seealso marker="run_test_chapter#test_specifications">
 
84
      Test Specification</seealso></item>
 
85
      <item>Add the <c>ct_hooks</c> tag to your call to 
 
86
      <seealso marker="ct#run_test-1">ct:run_test/1</seealso></item>
 
87
    </list>
 
88
 
 
89
    <p>You can also add CTHs within a test suite. This is done by returning
 
90
    <c>{ct_hooks,[CTH]}</c> in the config list from 
 
91
    <seealso marker="common_test#Module:suite-0">suite/0</seealso>,
 
92
    <seealso marker="common_test#Module:init_per_suite-1">
 
93
      init_per_suite/1</seealso> or
 
94
      <seealso marker="common_test#Module:init_per_group-2">
 
95
    init_per_group/2</seealso>. <c>CTH</c> in this case can be either
 
96
    only the module name of the CTH or a tuple with the module name and the
 
97
    initial arguments to the CTH. Eg:
 
98
    <c>{ct_hooks,[my_cth_module]}</c> or 
 
99
    <c>{ct_hooks,[{my_cth_module,[{debug,true}]}]}</c></p>
 
100
 
 
101
    <section>
 
102
      <title>Overriding CTHs</title>
 
103
      <p>By default each installation of a CTH will cause a new instance of it
 
104
        to be activated. This can cause problems if you want to be able to 
 
105
        override CTHs in test specifications while still having them in the
 
106
        suite info function. The 
 
107
        <seealso marker="ct_hooks#Module:id-1">id/1</seealso>
 
108
        callback exists to address this problem. By returning the same
 
109
        <c>id</c> in both places, Common Test knows that this CTH
 
110
        has already been installed and will not try to install it again.</p>
 
111
    </section>
 
112
 
 
113
  </section>
 
114
 
 
115
  <marker id="scope"/>
 
116
  <section>
 
117
    <title>CTH Scope</title>
 
118
    <p>Once the CTH is installed into a certain test run it will be there until
 
119
      its scope is expired. The scope of a CTH depends on when it is 
 
120
      installed.
 
121
      The <seealso marker="ct_hooks#Module:init-2">init/2</seealso> is 
 
122
      called at the beginning of the scope and the 
 
123
      <seealso marker="ct_hooks#Module:terminate-1">terminate/1
 
124
    </seealso> function is called when the scope ends.</p>
 
125
    <table>
 
126
      <row>
 
127
        <cell><em>CTH Installed in</em></cell>
 
128
        <cell><em>CTH scope begins before</em></cell>
 
129
        <cell><em>CTH scope ends after</em></cell>
 
130
      </row>
 
131
      <row>
 
132
        <cell><seealso marker="run_test_chapter#ct_run">ct_run</seealso></cell>
 
133
        <cell>the first test suite is to be run.</cell>
 
134
        <cell>the last test suite has been run.</cell>
 
135
      </row>
 
136
      <row>
 
137
        <cell><seealso marker="ct#run_test-1">ct:run_test</seealso></cell>
 
138
        <cell>the first test suite is to be run.</cell>
 
139
        <cell>the last test suite has been run.</cell>
 
140
      </row>
 
141
      <row>
 
142
        <cell><seealso marker="run_test_chapter#test_specifications">
 
143
          Test Specification</seealso></cell>
 
144
        <cell>the first test suite is to be run.</cell>
 
145
        <cell>the last test suite has been run.</cell>
 
146
      </row>
 
147
      <row>
 
148
        <cell><seealso marker="common_test#Module:suite-0">suite/0
 
149
        </seealso></cell>
 
150
        <cell><seealso marker="ct_hooks#Module:pre_init_per_suite-3">
 
151
            pre_init_per_suite/3</seealso> is called.</cell>
 
152
        <cell><seealso marker="ct_hooks#Module:post_end_per_suite-4">
 
153
          post_end_per_suite/4</seealso> has been called for that test suite.</cell>
 
154
      </row>
 
155
      <row>
 
156
        <cell><seealso marker="common_test#Module:init_per_suite-1">
 
157
          init_per_suite/1</seealso></cell>
 
158
        <cell><seealso marker="ct_hooks#Module:post_init_per_suite-4">
 
159
            post_init_per_suite/4</seealso> is called.</cell>
 
160
        <cell><seealso marker="ct_hooks#Module:post_end_per_suite-4">
 
161
          post_end_per_suite/4</seealso> has been called for that test suite.</cell>
 
162
      </row>
 
163
      <row>
 
164
        <cell><seealso marker="common_test#Module:init_per_group-2">
 
165
          init_per_group/2</seealso></cell>
 
166
        <cell><seealso marker="ct_hooks#Module:post_init_per_group-4">
 
167
            post_init_per_group/4</seealso> is called.</cell>
 
168
        <cell><seealso marker="ct_hooks#Module:post_end_per_suite-4">
 
169
          post_end_per_group/4</seealso> has been called for that group.</cell>
 
170
      </row>
 
171
    <tcaption>Scope of a CTH</tcaption>
 
172
    </table>
 
173
    
 
174
    <section>
 
175
      <title>CTH Processes and Tables</title>
 
176
      <p>CTHs are run with the same process scoping as normal test suites
 
177
        i.e. a different process will execute the init_per_suite hooks then the
 
178
        init_per_group or per_testcase hooks. So if you want to spawn a 
 
179
        process in the CTH you cannot link with the CTH process as it will exit 
 
180
        after the post hook ends. Also if you for some reason need an ETS 
 
181
        table with your CTH, you will have to spawn a process which handles 
 
182
        it.</p>
 
183
    </section>
 
184
    
 
185
  </section>
 
186
 
 
187
  <marker id="manipulating"/>
 
188
  <section>
 
189
    <title>Manipulating tests</title>
 
190
    <p>It is through CTHs possible to manipulate the results of tests and 
 
191
    configuration functions. The main purpose of doing this with CTHs is to
 
192
    allow common patterns to be abstracted out from test test suites and applied to
 
193
    multiple test suites without duplicating any code. All of the callback
 
194
    functions for a CTH follow a common interface, this interface is 
 
195
    described below.</p>
 
196
 
 
197
    <p>It is only possible to hook into test function which exists in the test 
 
198
      suite. So in order for a CTH to hook in before 
 
199
      <seealso marker="common_test#Module:init_per_suite-1">init_per_suite</seealso>, 
 
200
      the <seealso marker="common_test#Module:init_per_suite-1">init_per_suite</seealso> 
 
201
      function must exist in the test suite.</p>
 
202
 
 
203
    <marker id="pre"/>
 
204
    <section>
 
205
      <title>Pre Hooks</title>
 
206
      <p>
 
207
        It is possible in a CTH to hook in behaviour before 
 
208
        <seealso marker="common_test#Module:init_per_suite-1">init_per_suite</seealso>, 
 
209
        <seealso marker="common_test#Module:init_per_suite-1">init_per_group</seealso>, 
 
210
        <seealso marker="common_test#Module:init_per_suite-1">init_per_testcase</seealso>, 
 
211
        <seealso marker="common_test#Module:init_per_suite-1">end_per_group</seealso> and 
 
212
        <seealso marker="common_test#Module:init_per_suite-1">end_per_suite</seealso>. 
 
213
        This is done in the CTH functions called pre_&lt;name of function&gt;.
 
214
        All of these functions take the same three arguments: <c>Name</c>, 
 
215
        <c>Config</c> and <c>CTHState</c>. The return value of the CTH function
 
216
        is always a combination of an result for the suite/group/test and an 
 
217
        updated <c>CTHState</c>. If you want the test suite to continue on 
 
218
        executing you should return the config list which you want the test to 
 
219
        use as the result. If you for some reason want to skip/fail the test, 
 
220
        return a tuple with <c>skip</c> or <c>fail</c> and a reason as the 
 
221
        result. Example:
 
222
      </p>
 
223
      <code>pre_init_per_suite(SuiteName, Config, CTHState) -&gt;
 
224
  case db:connect() of
 
225
    {error,_Reason} -&gt;
 
226
      {{fail, "Could not connect to DB"}, CTHState};
 
227
    {ok, Handle} -&gt;
 
228
      {[{db_handle, Handle} | Config], CTHState#state{ handle = Handle }}
 
229
  end.</code>
 
230
        
 
231
    </section>
 
232
    
 
233
    <marker id="post"/>
 
234
    <section>
 
235
      <title>Post Hooks</title>
 
236
      <p>It is also possible in a CTH to hook in behaviour after 
 
237
      <seealso marker="common_test#Module:init_per_suite-1">init_per_suite</seealso>, 
 
238
      <seealso marker="common_test#Module:init_per_suite-1">init_per_group</seealso>, 
 
239
      <seealso marker="common_test#Module:init_per_suite-1">end_per_testcase</seealso>, 
 
240
      <seealso marker="common_test#Module:init_per_suite-1">end_per_group</seealso> and 
 
241
      <seealso marker="common_test#Module:init_per_suite-1">end_per_suite</seealso>.
 
242
      This is done in the CTH functions called post_&lt;name of function&gt;. 
 
243
      All of these function take the same four arguments: <c>Name</c>, 
 
244
      <c>Config</c>, <c>Return</c> and <c>CTHState</c>. <c>Config</c> in this
 
245
      case is the same <c>Config</c> as the testcase is called with. 
 
246
      <c>Return</c> is the value returned by the testcase. If the testcase 
 
247
      failed by crashing, <c>Return</c> will be 
 
248
      <c>{'EXIT',{{Error,Reason},Stacktrace}}</c>.</p>
 
249
      
 
250
      <p>The return value of the CTH function is always a combination of an
 
251
        result for the suite/group/test and an updated <c>CTHState</c>. If
 
252
        you want the callback to not affect the outcome of the test you should
 
253
        return the <c>Return</c> data as it is given to the CTH. You can also
 
254
        modify the result of the test. By returning the <c>Config</c> list
 
255
        with the <c>tc_status</c> element removed you can recover from a test 
 
256
        failure. As in all the pre hooks, it is also possible to fail/skip
 
257
        the test case in the post hook. Example: </p>
 
258
 
 
259
      <code>post_end_per_testcase(_TC, Config, {'EXIT',{_,_}}, CTHState) -&gt;
 
260
  case db:check_consistency() of
 
261
    true ->
 
262
      %% DB is good, pass the test.
 
263
      {proplists:delete(tc_status, Config), CTHState};
 
264
    false ->
 
265
      %% DB is not good, mark as skipped instead of failing
 
266
      {{skip, "DB is inconsisten!"}, CTHState}
 
267
  end;
 
268
post_end_per_testcase(_TC, Config, Return, CTHState) -&gt;
 
269
  %% Do nothing if tc does not crash.
 
270
  {Return, CTHState}.</code>
 
271
 
 
272
      <note>Recovering from a testcase failure using CTHs should only be done as
 
273
        a last resort. If used wrongly it could become very difficult to 
 
274
        determine which tests pass or fail in a test run</note>
 
275
  
 
276
    </section>
 
277
 
 
278
    <marker id="skip_n_fail"/>
 
279
    <section>
 
280
      <title>Skip and Fail hooks</title>
 
281
      <p>
 
282
        After any post hook has been executed for all installed CTHs, 
 
283
        <seealso marker="ct_hooks#Module:on_tc_fail-3">on_tc_fail</seealso>
 
284
        or <seealso marker="ct_hooks#Module:on_tc_fail-3">on_tc_skip</seealso> 
 
285
        might be called if the testcase failed or was skipped 
 
286
        respectively. You cannot affect the outcome of the tests any further at 
 
287
        this point. 
 
288
      </p>
 
289
    </section>
 
290
 
 
291
  </section>
 
292
 
 
293
  <marker id="example"/>
 
294
  <section>
 
295
     <title>Example CTH</title>
 
296
     <p>The CTH below will log information about a test run into a format 
 
297
       parseable by <seealso marker="kernel:file#consult-1">file:consult/1</seealso>.
 
298
     </p>
 
299
     <code>%%% @doc Common Test Example Common Test Hook module.
 
300
-module(example_cth).
 
301
 
 
302
%% Callbacks
 
303
-export([id/1]).
 
304
-export([init/2]).
 
305
 
 
306
-export([pre_init_per_suite/3]).
 
307
-export([post_init_per_suite/4]).
 
308
-export([pre_end_per_suite/3]).
 
309
-export([post_end_per_suite/4]).
 
310
 
 
311
-export([pre_init_per_group/3]).
 
312
-export([post_init_per_group/4]).
 
313
-export([pre_end_per_group/3]).
 
314
-export([post_end_per_group/4]).
 
315
 
 
316
-export([pre_init_per_testcase/3]).
 
317
-export([post_end_per_testcase/4]).
 
318
 
 
319
-export([on_tc_fail/3]).
 
320
-export([on_tc_skip/3]).
 
321
 
 
322
-export([terminate/1]).
 
323
 
 
324
-record(state, { file_handle, total, suite_total, ts, tcs, data }).
 
325
 
 
326
%% @doc Return a unique id for this CTH.
 
327
id(Opts) ->
 
328
  proplists:get_value(filename, Opts, "/tmp/file.log").
 
329
 
 
330
%% @doc Always called before any other callback function. Use this to initiate
 
331
%% any common state. 
 
332
init(Id, Opts) ->
 
333
    {ok,D} = file:open(Id,[write]),
 
334
    #state{ file_handle = D, total = 0, data = [] }.
 
335
 
 
336
%% @doc Called before init_per_suite is called. 
 
337
pre_init_per_suite(Suite,Config,State) ->
 
338
    {Config, State#state{ suite_total = 0, tcs = [] }}.
 
339
 
 
340
%% @doc Called after init_per_suite.
 
341
post_init_per_suite(Suite,Config,Return,State) ->
 
342
    {Return, State}.
 
343
 
 
344
%% @doc Called before end_per_suite. 
 
345
pre_end_per_suite(Suite,Config,State) ->
 
346
    {Config, State}.
 
347
 
 
348
%% @doc Called after end_per_suite. 
 
349
post_end_per_suite(Suite,Config,Return,State) ->
 
350
    Data = {suites, Suite, State#state.suite_total, lists:reverse(State#state.tcs)},
 
351
    {Return, State#state{ data = [Data | State#state.data] ,
 
352
                          total = State#state.total + State#state.suite_total } }.
 
353
 
 
354
%% @doc Called before each init_per_group.
 
355
pre_init_per_group(Group,Config,State) ->
 
356
    {Config, State}.
 
357
 
 
358
%% @doc Called after each init_per_group.
 
359
post_init_per_group(Group,Config,Return,State) ->
 
360
    {Return, State}.
 
361
 
 
362
%% @doc Called after each end_per_group. 
 
363
pre_end_per_group(Group,Config,State) ->
 
364
    {Config, State}.
 
365
 
 
366
%% @doc Called after each end_per_group. 
 
367
post_end_per_group(Group,Config,Return,State) ->
 
368
    {Return, State}.
 
369
 
 
370
%% @doc Called before each test case.
 
371
pre_init_per_testcase(TC,Config,State) ->
 
372
    {Config, State#state{ ts = now(), total = State#state.suite_total + 1 } }.
 
373
 
 
374
%% @doc Called after each test case.
 
375
post_end_per_testcase(TC,Config,Return,State) ->
 
376
    TCInfo = {testcase, TC, Return, timer:now_diff(now(), State#state.ts)},
 
377
    {Return, State#state{ ts = undefined, tcs = [TCInfo | State#state.tcs] } }.
 
378
 
 
379
%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
 
380
%% post_end_per_group and post_end_per_testcase if the suite, group or test case failed.
 
381
on_tc_fail(TC, Reason, State) ->
 
382
    State.
 
383
 
 
384
%% @doc Called when a test case is skipped by either user action
 
385
%% or due to an init function failing.  
 
386
on_tc_skip(TC, Reason, State) ->
 
387
    State.
 
388
 
 
389
%% @doc Called when the scope of the CTH is done
 
390
terminate(State) ->
 
391
    io:format(State#state.file_handle, "~p.~n",
 
392
               [{test_run, State#state.total, State#state.data}]),
 
393
    file:close(State#state.file_handle),
 
394
    ok.</code>
 
395
  </section>
 
396
 
 
397
</chapter>
 
398
 
 
399
 
 
400
 
 
401