33
33
<title>General</title>
35
<p>The Common Test framework uses configuration files to
36
describe data related to a test and/or an SUT (System Under Test).
37
The configuration data makes it possible to change properties without
38
changing the test program itself. Configuration data can for example be:</p>
35
<p>To avoid hard coding data values related to the test and/or SUT (System
36
Under Test) in the test suites, the data may instead be specified by means
37
of configuration files or strings that Common Test reads before
38
the start of a test run. External configuration data makes it possible to
39
change test properties without having to modify the actual test suites
40
using the data. Examples of configuration data:</p>
41
43
<item>Addresses to the test plant or other instruments</item>
42
<item>Filenames for files needed by the test</item>
43
<item>Program names for programs that shall be run by the test</item>
44
<item>Any other variable that is needed by the test</item>
44
<item>User login information</item>
45
<item>Names of files needed by the test</item>
46
<item>Names of programs that should be executed during the test</item>
47
<item>Any other variable needed by the test</item>
84
87
<p>A <c>require</c> statement in the test suite info- or test case
85
88
info-list should look like this:
86
<c>{require,Required}</c> or <c>{require,Name,Required}</c>. The
87
arguments <c>Name</c> and <c>Required</c> are the same as the
89
<c>{require,CfgVarName}</c> or <c>{require,AliasName,CfgVarName}</c>.
90
The arguments <c>AliasName</c> and <c>CfgVarName</c> are the same as the
88
91
arguments to <c>ct:require/[1,2]</c> which are described in the
89
92
reference manual for <seealso marker="ct">ct</seealso>.
90
<c>Name</c> becomes an alias for the configuration variable
91
<c>Required</c>, and can be used as reference to the configuration
92
data value. The configuration variable may be associated with an
93
<c>AliasName</c> becomes an alias for the configuration variable,
94
and can be used as reference to the configuration data value.
95
The configuration variable may be associated with an
93
96
arbitrary number of alias names, but each name must be unique within
94
97
the same test suite. There are two main uses for alias names:</p>
183
<title>Examples</title>
186
<title>User specific configuration data formats</title>
188
<p>It is possible for the user to specify configuration data on a
189
different format than key-value tuples in a text file, as described
190
so far. The data can e.g. be read from arbitrary files, fetched from
191
the web over http, or requested from a user specific process.
192
To support this, Common Test provides a callback module plugin
193
mechanism to handle configuration data.</p>
196
<title>Default callback modules for handling configuration data</title>
197
<p>The Common Test application includes default callback modules
198
for handling configuration data specified in standard config files
199
(see above) and in xml files:</p>
202
<c>ct_config_plain</c> - for reading configuration files with
203
key-value tuples (standard format). This handler will be used to
204
parse configuration files if no user callback is specified.
207
<c>ct_config_xml</c> - for reading configuration data from XML
214
<title>Using XML configuration files</title>
215
<p>This is an example of an XML configuration file:</p>
219
<ftp>"targethost"</ftp>
220
<username>"tester"</username>
221
<password>"letmein"</password>
223
<lm_directory>"/test/loadmodules"</lm_directory>
226
<p>This configuration file, once read, will produce the same configuration
227
variables as the following text file:</p>
229
{ftp_host, [{ftp,"targethost"},
231
{password,"letmein"}]}.
233
{lm_directory, "/test/loadmodules"}.</pre>
237
<title>How to implement a user specific handler</title>
239
<p>The user specific handler can be written to handle special
240
configuration file formats. The parameter can be either file
241
name(s) or configuration string(s) (the empty list is valid).</p>
243
<p>The callback module implementing the handler is responsible for
244
checking correctness of configuration strings.</p>
246
<p>To perform validation of the configuration strings, the callback module
247
should have the following function exported:</p>
249
<p><c>Callback:check_parameter/1</c></p>
250
<p>The input argument will be passed from Common Test, as defined in the test
251
specification or given as an option to <c>ct_run</c> or <c>ct:run_test</c>.</p>
253
<p>The return value should be any of the following values indicating if given
254
configuration parameter is valid:</p>
257
<c>{ok, {file, FileName}}</c> - parameter is a file name and
261
<c>{ok, {config, ConfigString}}</c> - parameter is a config string
265
<c>{error, {nofile, FileName}}</c> - there is no file with the given
266
name in the current directory,
269
<c>{error, {wrong_config, ConfigString}}</c> - the configuration string
274
<p>To perform reading of configuration data - initially before the tests
275
start, or as a result of data being reloaded during test execution -
276
the following function should be exported from the callback module:</p>
278
<p><c>Callback:read_config/1</c></p>
280
<p>The input argument is the same as for the <c>check_parameter/1</c> function.</p>
281
<p>The return value should be either:</p>
285
<c>{ok, Config}</c> - if the configuration variables are read successfully,
288
<c>{error, Error, ErrorDetails}</c> - if the callback module fails to
289
proceed with the given configuration parameters.
292
<p><c>Config</c> is the proper Erlang key-value list, with possible
293
key-value sublists as values, like for the configuration file
297
[{ftp_host, [{ftp, "targethost"}, {username, "tester"}, {password, "letmein"}]},
298
{lm_directory, "/test/loadmodules"}]</pre>
305
<title>Examples of configuration data handling</title>
185
307
<p>A config file for using the FTP client to access files on a remote
186
308
host could look like this:</p>
189
311
{ftp_host, [{ftp,"targethost"},
190
312
{username,"tester"},
191
{password,"letmein"}]}.
313
{password,"letmein"}]}.
193
315
{lm_directory, "/test/loadmodules"}.</pre>
194
<p>Example of how to assert that the configuration data is available and
317
<p>The XML version shown in the chapter above can also be used, but it should be
318
explicitly specified that the <c>ct_config_xml</c> callback module is to be
319
used by Common Test.</p>
321
<p>Example of how to assert that the configuration data is available and
195
322
use it for an FTP session:</p>
197
324
init_per_testcase(ftptest, Config) ->
198
325
{ok,_} = ct_ftp:open(ftp),
201
328
end_per_testcase(ftptest, _Config) ->
202
329
ct_ftp:close(ftp).
205
332
[{require,ftp,ftp_host},
206
{require,lm_directory}].
333
{require,lm_directory}].
208
335
ftptest(Config) ->
209
Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
336
Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
210
337
Local = filename:join(?config(priv_dir,Config), "loadmodule"),
211
338
ok = ct_ftp:recv(ftp, Remote, Local),
214
341
<p>An example of how the above functions could be rewritten
215
342
if necessary to open multiple connections to the FTP server:</p>
227
354
[{require,ftp_host},
228
{require,lm_directory}].
355
{require,lm_directory}].
230
357
ftptest(Config) ->
231
Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
358
Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
232
359
Local = filename:join(?config(priv_dir,Config), "loadmodule"),
233
360
[Handle | MoreHandles] = ?config(ftp_handles,Config),
234
361
ok = ct_ftp:recv(Handle, Remote, Local),
367
<title>Example of user specific configuration handler</title>
368
<p>A simple configuration handling driver which will ask an external server for
369
configuration data can be implemented this way:</p>
371
-module(config_driver).
372
-export([read_config/1, check_parameter/1]).
374
read_config(ServerName)->
375
ServerModule = list_to_atom(ServerName),
376
ServerModule:start(),
377
ServerModule:get_config().
379
check_parameter(ServerName)->
380
ServerModule = list_to_atom(ServerName),
381
case code:is_loaded(ServerModule) of
383
{ok, {config, ServerName}};
385
case code:load_file(ServerModule) of
386
{module, ServerModule}->
387
{ok, {config, ServerName}};
389
{error, {wrong_config, "File not found: " ++ ServerName ++ ".beam"}}
393
<p>The configuration string for this driver may be "config_server", if the
394
config_server.erl module below is compiled and exists in the code path
395
during test execution:</p>
397
-module(config_server).
398
-export([start/0, stop/0, init/1, get_config/0, loop/0]).
400
-define(REGISTERED_NAME, ct_test_config_server).
403
case whereis(?REGISTERED_NAME) of
405
spawn(?MODULE, init, [?REGISTERED_NAME]),
413
register(Name, self()),
417
call(self(), get_config).
422
call(Client, Request)->
423
case whereis(?REGISTERED_NAME) of
425
{error, not_started, Request};
427
Pid ! {Client, Request},
432
{error, timeout, Request}
441
{D,T} = erlang:localtime(),
443
[{localtime, [{date, D}, {time, T}]},
444
{node, erlang:node()},
446
{config_server_pid, self()},
447
{config_server_vsn, ?vsn}],
452
case whereis(?REGISTERED_NAME) of
459
<p>In this example, the handler also provides the ability to dynamically reload
460
configuration variables. If <c>ct:reload_config(localtime)</c> is called from
461
the test case function, all variables loaded with <c>config_driver:read_config/1</c>
462
will be updated with their latest values, and the new value for variable
463
<c>localtime</c> will be returned.</p>