aboutsummaryrefslogtreecommitdiffstats
path: root/lib/common_test/doc/src/config_file_chapter.xml
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common_test/doc/src/config_file_chapter.xml')
-rw-r--r--lib/common_test/doc/src/config_file_chapter.xml558
1 files changed, 277 insertions, 281 deletions
diff --git a/lib/common_test/doc/src/config_file_chapter.xml b/lib/common_test/doc/src/config_file_chapter.xml
index c7fd6e0b28..62ebfccb98 100644
--- a/lib/common_test/doc/src/config_file_chapter.xml
+++ b/lib/common_test/doc/src/config_file_chapter.xml
@@ -35,18 +35,18 @@
<section>
<title>General</title>
- <p>To avoid hard coding data values related to the test and/or SUT (System
- Under Test) in the test suites, the data may instead be specified by means
- of configuration files or strings that Common Test reads before
+ <p>To avoid hard-coding data values related to the test and/or System
+ Under Test (SUT) in the test suites, the data can instead be specified through
+ configuration files or strings that <c>Common Test</c> reads before
the start of a test run. External configuration data makes it possible to
- change test properties without having to modify the actual test suites
- using the data. Examples of configuration data:</p>
+ change test properties without modifying the test suites
+ using the data. Examples of configuration data follows:</p>
- <list>
+ <list type="bulleted">
<item>Addresses to the test plant or other instruments</item>
<item>User login information</item>
<item>Names of files needed by the test</item>
- <item>Names of programs that should be executed during the test</item>
+ <item>Names of programs to be executed during the test</item>
<item>Any other variable needed by the test</item>
</list>
@@ -57,154 +57,150 @@
<p>A configuration file can contain any number of elements of the type:</p>
<pre>
- {CfgVarName,Value}.</pre>
+ {CfgVarName,Value}.</pre>
<p>where</p>
<pre>
- CfgVarName = atom()
- Value = term() | [{CfgVarName,Value}]</pre>
+ CfgVarName = atom()
+ Value = term() | [{CfgVarName,Value}]</pre>
</section>
<section>
- <title>Requiring and reading configuration data</title>
+ <title>Requiring and Reading Configuration Data</title>
<marker id="require_config_data"></marker>
<p>In a test suite, one must <em>require</em> that a configuration
- variable (<c>CfgVarName</c> in the definition above) exists before
- attempting to read the associated value in a test case or config function.</p>
-
- <p><c>require</c> is an assert statement that can be part of the <seealso
- marker="write_test_chapter#suite">test suite info function</seealso> or
- <seealso marker="write_test_chapter#info_function">test case info
- function</seealso>. If the required variable is not available, the
- test is skipped (unless a default value has been specified, see the
- <seealso marker="write_test_chapter#info_function">test case info
- function</seealso> chapter for details). There is also a function
- <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> which can be called from a test case
- in order to check if a specific variable is available. The return
+ variable (<c>CfgVarName</c> in the previous definition) exists before
+ attempting to read the associated value in a test case or configuration function.</p>
+
+ <p><c>require</c> is an assert statement, which can be part of the <seealso
+ marker="write_test_chapter#suite">Test Suite Information Function</seealso> or
+ <seealso marker="write_test_chapter#info_function">Test Case Information
+ Function</seealso>. If the required variable is unavailable, the
+ test is skipped (unless a default value has been specified, see section
+ <seealso marker="write_test_chapter#info_function">Test Case Information
+ Function</seealso> for details). Also, function
+ <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> can be called
+ from a test case to check if a specific variable is available. The return
value from this function must be checked explicitly and appropriate
- action be taken depending on the result (e.g. to skip the test case
- if the variable in question doesn't exist).</p>
+ action be taken depending on the result (for example, to skip the test case
+ if the variable in question does not exist).</p>
- <p>A <c>require</c> statement in the test suite info- or test case
- info-list should look like this:
+ <p>A <c>require</c> statement in the test suite information case or test case
+ information-list is to look like
<c>{require,CfgVarName}</c> or <c>{require,AliasName,CfgVarName}</c>.
The arguments <c>AliasName</c> and <c>CfgVarName</c> are the same as the
- arguments to <seealso marker="ct#require-1"><c>ct:require/1/2</c></seealso> which are described in the
- reference manual for <seealso marker="ct">ct</seealso>.
+ arguments to <seealso marker="ct#require-1"><c>ct:require/1,2</c></seealso>.
<c>AliasName</c> becomes an alias for the configuration variable,
and can be used as reference to the configuration data value.
- The configuration variable may be associated with an
- arbitrary number of alias names, but each name must be unique within
- the same test suite. There are two main uses for alias names:</p>
- <list>
- <item>They may be introduced to identify connections (see below).</item>
- <item>They may used to help adapt configuration data to a test suite
+ The configuration variable can be associated with any
+ number of alias names, but each name must be unique within
+ the same test suite. The two main uses for alias names follows:</p>
+ <list type="bulleted">
+ <item>To identify connections (described later).</item>
+ <item>To help adapt configuration data to a test suite
(or test case) and improve readability.</item>
</list>
- <p>To read the value of a config variable, use the function
- <seealso marker="ct#get_config-1"><c>get_config/1/2/3</c></seealso>
- which is also described in the reference
- manual for <seealso marker="ct">ct</seealso>.</p>
- <p>Example:</p>
+ <p>To read the value of a configuration variable, use function
+ <seealso marker="ct#get_config-1"><c>get_config/1,2,3</c></seealso>.
+ </p>
+ <p><em>Example:</em></p>
<pre>
- suite() ->
- [{require, domain, 'CONN_SPEC_DNS_SUFFIX'}].
+ suite() ->
+ [{require, domain, 'CONN_SPEC_DNS_SUFFIX'}].
- ...
-
- testcase(Config) ->
- Domain = ct:get_config(domain),
- ...</pre>
+ ...
+
+ testcase(Config) ->
+ Domain = ct:get_config(domain),
+ ...</pre>
</section>
<section>
- <title>Using configuration variables defined in multiple files</title>
+ <title>Using Configuration Variables Defined in Multiple Files</title>
<p>If a configuration variable is defined in multiple files and you
- want to access all possible values, you may use the <seealso marker="ct#get_config-3"><c>ct:get_config/3</c></seealso>
- function and specify <c>all</c> in the options list. The values will then
- be returned in a list and the order of the elements corresponds to the order
- that the config files were specified at startup. Please see
- the <seealso marker="ct">ct</seealso> reference manual for details.</p>
+ want to access all possible values, use function
+ <seealso marker="ct#get_config-3"><c>ct:get_config/3</c></seealso>
+ and specify <c>all</c> in the options list. The values are then
+ returned in a list and the order of the elements corresponds to the order
+ that the configuration files were specified at startup.</p>
</section>
<section>
- <title>Encrypted configuration files</title>
+ <title>Encrypted Configuration Files</title>
<marker id="encrypted_config_files"></marker>
- <p>It is possible to encrypt configuration files containing sensitive data
- if these files must be stored in open and shared directories.</p>
- <p>Call <seealso marker="ct#encrypt_config_file-2"><c>ct:encrypt_config_file/2/3</c></seealso> to have Common Test encrypt a
- specified file using the DES3 function in the OTP <c>crypto</c> application.
- The encrypted file can then be used as a regular configuration file,
- in combination with other encrypted files or normal text files. The key
- for decrypting the configuration file must be provided when running the test,
- however. This can be done by means of the <c>decrypt_key</c> or
- <c>decrypt_file</c> flag/option, or a key file in a predefined location.</p>
+ <p>Configuration files containing sensitive data can be encrypted
+ if they must be stored in open and shared directories.</p>
+ <p>To have <c>Common Test</c> encrypt a
+ specified file using function <c>DES3</c> in application <c>Crypto</c>,
+ call <seealso marker="ct#encrypt_config_file-2"><c>ct:encrypt_config_file/2,3</c></seealso>
+ The encrypted file can then be used as a regular configuration file
+ in combination with other encrypted files or normal text files. However, the
+ key for decrypting the configuration file must be provided when running the test.
+ This can be done with flag/option <c>decrypt_key</c> or
+ <c>decrypt_file</c>, or a key file in a predefined location.</p>
- <p>Common Test also provides decryption functions,
- <seealso marker="ct#decrypt_config_file-2"><c>ct:decrypt_config_file/2/3</c></seealso>, for recreating the original text
- files.</p>
-
- <p>Please see the <seealso marker="ct">ct</seealso> reference manual for
- more information.</p>
+ <p><c>Common Test</c> also provides decryption functions,
+ <seealso marker="ct#decrypt_config_file-2"><c>ct:decrypt_config_file/2,3</c></seealso>,
+ for recreating the original text files.</p>
</section>
<section>
- <title>Opening connections by using configuration data</title>
- <p>There are two different methods for opening a connection
- by means of the support functions in e.g. <seealso marker="ct_ssh"><c>ct_ssh</c></seealso>, <seealso marker="ct_ftp"><c>ct_ftp</c></seealso>,
- and <seealso marker="ct_telnet"><c>ct_telnet</c></seealso>:</p>
- <list>
+ <title>Opening Connections Using Configuration Data</title>
+ <p>Two different methods for opening a connection using the support functions
+ in, for example, <seealso marker="ct_ssh"><c>ct_ssh</c></seealso>,
+ <seealso marker="ct_ftp"><c>ct_ftp</c></seealso>, and
+ <seealso marker="ct_telnet"><c>ct_telnet</c></seealso> follows:</p>
+ <list type="bulleted">
<item>Using a configuration target name (an alias) as reference.</item>
<item>Using the configuration variable as reference.</item>
</list>
<p>When a target name is used for referencing the configuration data
- (that specifies the connection to be opened), the same name may be used
+ (that specifies the connection to be opened), the same name can be used
as connection identity in all subsequent calls related to the connection
- (also for closing it). It's only possible to have one open connection
- per target name. If attempting to open a new connection using a name
- already associated with an open connection, Common Test will
- return the already existing handle so that the previously opened connection
- will be used. This is a practical feature since it makes it possible to
+ (also for closing it). Only one open connection per target name
+ is possible. If you attempt to open a new connection using a name
+ already associated with an open connection, <c>Common Test</c>
+ returns the already existing handle so the previously opened connection
+ is used. This feature makes it possible to
call the function for opening a particular connection whenever
- useful. An action like this will not necessarily open any new
- connections unless it's required (which could be the case if e.g. the
- previous connection has been closed unexpectedly by the server).
- Another benefit of using named connections is that it's not
- necessary to pass handle references around in the suite for these
- connections.
+ useful. An action like this does not necessarily open any new
+ connections unless it is required (which could be the case if, for example,
+ the previous connection has been closed unexpectedly by the server).
+ Using named connections also removes the need to pass handle references
+ around in the suite for these connections.
</p>
<p>When a configuration variable name is used as reference to the data
specifying the connection, the handle returned as a result of opening
the connection must be used in all subsequent calls (also for closing
the connection). Repeated calls to the open function with the same
- variable name as reference will result in multiple connections
- being opened. This can be useful e.g. if a test case needs to open
+ variable name as reference results in multiple connections being opened.
+ This can be useful, for example, if a test case needs to open
multiple connections to the same server on the target node (using the
same configuration data for each connection).
</p>
</section>
<section>
- <title>User specific configuration data formats</title>
+ <title>User-Specific Configuration Data Formats</title>
- <p>It is possible for the user to specify configuration data on a
+ <p>The user can specify configuration data on a
different format than key-value tuples in a text file, as described
- so far. The data can e.g. be read from arbitrary files, fetched from
- the web over http, or requested from a user specific process.
- To support this, Common Test provides a callback module plugin
+ so far. The data can, for example, be read from any files, fetched from
+ the web over HTTP, or requested from a user-specific process.
+ To support this, <c>Common Test</c> provides a callback module plugin
mechanism to handle configuration data.</p>
<section>
- <title>Default callback modules for handling configuration data</title>
- <p>The Common Test application includes default callback modules
- for handling configuration data specified in standard config files
- (see above) and in xml files:</p>
- <list>
+ <title>Default Callback Modules for Handling Configuration Data</title>
+ <p><c>Common Test</c> includes default callback modules
+ for handling configuration data specified in standard configuration files
+ (described earlier) and in XML files as follows:</p>
+ <list type="bulleted">
<item>
<c>ct_config_plain</c> - for reading configuration files with
- key-value tuples (standard format). This handler will be used to
+ key-value tuples (standard format). This handler is used to
parse configuration files if no user callback is specified.
</item>
<item>
@@ -215,59 +211,59 @@
</section>
<section>
- <title>Using XML configuration files</title>
- <p>This is an example of an XML configuration file:</p>
- <pre><![CDATA[
-<config>
+ <title>Using XML Configuration Files</title>
+ <p>An example of an XML configuration file follows:</p>
+ <pre>
+ <![CDATA[
+ <config>
<ftp_host>
<ftp>"targethost"</ftp>
<username>"tester"</username>
<password>"letmein"</password>
</ftp_host>
<lm_directory>"/test/loadmodules"</lm_directory>
-</config>]]></pre>
+ </config>]]></pre>
- <p>This configuration file, once read, will produce the same configuration
+ <p>Once read, this file produces the same configuration
variables as the following text file:</p>
<pre>
-{ftp_host, [{ftp,"targethost"},
- {username,"tester"},
- {password,"letmein"}]}.
+ {ftp_host, [{ftp,"targethost"},
+ {username,"tester"},
+ {password,"letmein"}]}.
-{lm_directory, "/test/loadmodules"}.</pre>
+ {lm_directory, "/test/loadmodules"}.</pre>
</section>
<section>
- <title>How to implement a user specific handler</title>
+ <title>Implement a User-Specific Handler</title>
- <p>The user specific handler can be written to handle special
+ <p>The user-specific handler can be written to handle special
configuration file formats. The parameter can be either file
- name(s) or configuration string(s) (the empty list is valid).</p>
+ names or configuration strings (the empty list is valid).</p>
<p>The callback module implementing the handler is responsible for
- checking correctness of configuration strings.</p>
+ checking the correctness of configuration strings.</p>
- <p>To perform validation of the configuration strings, the callback module
- should have the following function exported:</p>
+ <p>To validate the configuration strings, the callback module
+ is to have function <c>Callback:check_parameter/1</c> exported.</p>
- <p><c>Callback:check_parameter/1</c></p>
- <p>The input argument will be passed from Common Test, as defined in the test
- specification or given as an option to <c>ct_run</c> or <c>ct:run_test</c>.</p>
+ <p>The input argument is passed from <c>Common Test</c>, as defined in the test
+ specification, or specified as an option to <c>ct_run</c> or <c>ct:run_test</c>.</p>
- <p>The return value should be any of the following values indicating if given
+ <p>The return value is to be any of the following values, indicating if the specified
configuration parameter is valid:</p>
- <list>
+ <list type="bulleted">
<item>
- <c>{ok, {file, FileName}}</c> - parameter is a file name and
- the file exists,
+ <c>{ok, {file, FileName}}</c> - the parameter is a file name and
+ the file exists.
</item>
<item>
- <c>{ok, {config, ConfigString}}</c> - parameter is a config string
- and it is correct,
+ <c>{ok, {config, ConfigString}}</c> - the parameter is a configuration string
+ and it is correct.
</item>
<item>
- <c>{error, {nofile, FileName}}</c> - there is no file with the given
- name in the current directory,
+ <c>{error, {nofile, FileName}}</c> - there is no file with the specified
+ name in the current directory.
</item>
<item>
<c>{error, {wrong_config, ConfigString}}</c> - the configuration string
@@ -275,196 +271,196 @@
</item>
</list>
- <p>To perform reading of configuration data - initially before the tests
- start, or as a result of data being reloaded during test execution -
- the following function should be exported from the callback module:</p>
-
- <p><c>Callback:read_config/1</c></p>
+ <p>The function <c>Callback:read_config/1</c> is to be exported from the
+ callback module to read configuration data, initially before the tests
+ start, or as a result of data being reloaded during test execution.
+ The input argument is the same as for function <c>check_parameter/1</c>.</p>
- <p>The input argument is the same as for the <c>check_parameter/1</c> function.</p>
- <p>The return value should be either:</p>
+ <p>The return value is to be either of the following:</p>
- <list>
+ <list type="bulleted">
<item>
- <c>{ok, Config}</c> - if the configuration variables are read successfully,
+ <c>{ok, Config}</c> - if the configuration variables are read successfully.
</item>
<item>
<c>{error, {Error, ErrorDetails}}</c> - if the callback module fails to
- proceed with the given configuration parameters.
+ proceed with the specified configuration parameters.
</item>
</list>
<p><c>Config</c> is the proper Erlang key-value list, with possible
- key-value sublists as values, like for the configuration file
- example above:</p>
+ key-value sublists as values, like the earlier configuration file
+ example:</p>
<pre>
- [{ftp_host, [{ftp, "targethost"}, {username, "tester"}, {password, "letmein"}]},
- {lm_directory, "/test/loadmodules"}]</pre>
+ [{ftp_host, [{ftp, "targethost"}, {username, "tester"}, {password, "letmein"}]},
+ {lm_directory, "/test/loadmodules"}]</pre>
</section>
</section>
<section>
- <title>Examples of configuration data handling</title>
+ <title>Examples of Configuration Data Handling</title>
- <p>A config file for using the FTP client to access files on a remote
- host could look like this:</p>
+ <p>A configuration file for using the FTP client to access files on a remote
+ host can look as follows:</p>
<pre>
- {ftp_host, [{ftp,"targethost"},
- {username,"tester"},
- {password,"letmein"}]}.
+ {ftp_host, [{ftp,"targethost"},
+ {username,"tester"},
+ {password,"letmein"}]}.
- {lm_directory, "/test/loadmodules"}.</pre>
+ {lm_directory, "/test/loadmodules"}.</pre>
- <p>The XML version shown in the chapter above can also be used, but it should be
+ <p>The XML version shown earlier can also be used, but it is to be
explicitly specified that the <c>ct_config_xml</c> callback module is to be
- used by Common Test.</p>
+ used by <c>Common Test</c>.</p>
- <p>Example of how to assert that the configuration data is available and
- use it for an FTP session:</p>
+ <p>The following is an example of how to assert that the configuration data is available
+ and can be used for an FTP session:</p>
<pre>
- init_per_testcase(ftptest, Config) ->
- {ok,_} = ct_ftp:open(ftp),
- Config.
-
- end_per_testcase(ftptest, _Config) ->
- ct_ftp:close(ftp).
-
- ftptest() ->
- [{require,ftp,ftp_host},
- {require,lm_directory}].
-
- ftptest(Config) ->
- Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
- Local = filename:join(?config(priv_dir,Config), "loadmodule"),
- ok = ct_ftp:recv(ftp, Remote, Local),
- ...</pre>
+ init_per_testcase(ftptest, Config) ->
+ {ok,_} = ct_ftp:open(ftp),
+ Config.
+
+ end_per_testcase(ftptest, _Config) ->
+ ct_ftp:close(ftp).
+
+ ftptest() ->
+ [{require,ftp,ftp_host},
+ {require,lm_directory}].
+
+ ftptest(Config) ->
+ Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
+ Local = filename:join(?config(priv_dir,Config), "loadmodule"),
+ ok = ct_ftp:recv(ftp, Remote, Local),
+ ...</pre>
- <p>An example of how the above functions could be rewritten
- if necessary to open multiple connections to the FTP server:</p>
+ <p>The following is an example of how the functions in the previous example
+ can be rewritten if it is necessary to open multiple connections to the
+ FTP server:</p>
<pre>
- init_per_testcase(ftptest, Config) ->
- {ok,Handle1} = ct_ftp:open(ftp_host),
- {ok,Handle2} = ct_ftp:open(ftp_host),
- [{ftp_handles,[Handle1,Handle2]} | Config].
-
- end_per_testcase(ftptest, Config) ->
- lists:foreach(fun(Handle) -> ct_ftp:close(Handle) end,
- ?config(ftp_handles,Config)).
-
- ftptest() ->
- [{require,ftp_host},
- {require,lm_directory}].
-
- ftptest(Config) ->
- Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
- Local = filename:join(?config(priv_dir,Config), "loadmodule"),
- [Handle | MoreHandles] = ?config(ftp_handles,Config),
- ok = ct_ftp:recv(Handle, Remote, Local),
- ...</pre>
+ init_per_testcase(ftptest, Config) ->
+ {ok,Handle1} = ct_ftp:open(ftp_host),
+ {ok,Handle2} = ct_ftp:open(ftp_host),
+ [{ftp_handles,[Handle1,Handle2]} | Config].
+
+ end_per_testcase(ftptest, Config) ->
+ lists:foreach(fun(Handle) -> ct_ftp:close(Handle) end,
+ ?config(ftp_handles,Config)).
+
+ ftptest() ->
+ [{require,ftp_host},
+ {require,lm_directory}].
+
+ ftptest(Config) ->
+ Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
+ Local = filename:join(?config(priv_dir,Config), "loadmodule"),
+ [Handle | MoreHandles] = ?config(ftp_handles,Config),
+ ok = ct_ftp:recv(Handle, Remote, Local),
+ ...</pre>
</section>
<section>
- <title>Example of user specific configuration handler</title>
- <p>A simple configuration handling driver which will ask an external server for
- configuration data can be implemented this way:</p>
+ <title>Example of User-Specific Configuration Handler</title>
+ <p>A simple configuration handling driver, asking an external server for
+ configuration data, can be implemented as follows:</p>
<pre>
--module(config_driver).
--export([read_config/1, check_parameter/1]).
-
-read_config(ServerName)->
- ServerModule = list_to_atom(ServerName),
- ServerModule:start(),
- ServerModule:get_config().
-
-check_parameter(ServerName)->
- ServerModule = list_to_atom(ServerName),
- case code:is_loaded(ServerModule) of
- {file, _}->
- {ok, {config, ServerName}};
- false->
- case code:load_file(ServerModule) of
- {module, ServerModule}->
- {ok, {config, ServerName}};
- {error, nofile}->
- {error, {wrong_config, "File not found: " ++ ServerName ++ ".beam"}}
- end
- end.</pre>
-
- <p>The configuration string for this driver may be "config_server", if the
- config_server.erl module below is compiled and exists in the code path
+ -module(config_driver).
+ -export([read_config/1, check_parameter/1]).
+
+ read_config(ServerName)->
+ ServerModule = list_to_atom(ServerName),
+ ServerModule:start(),
+ ServerModule:get_config().
+
+ check_parameter(ServerName)->
+ ServerModule = list_to_atom(ServerName),
+ case code:is_loaded(ServerModule) of
+ {file, _}->
+ {ok, {config, ServerName}};
+ false->
+ case code:load_file(ServerModule) of
+ {module, ServerModule}->
+ {ok, {config, ServerName}};
+ {error, nofile}->
+ {error, {wrong_config, "File not found: " ++ ServerName ++ ".beam"}}
+ end
+ end.</pre>
+
+ <p>The configuration string for this driver can be <c>config_server</c>, if the
+ <c>config_server.erl</c> module that follows is compiled and exists in the code path
during test execution:</p>
<pre>
--module(config_server).
--export([start/0, stop/0, init/1, get_config/0, loop/0]).
-
--define(REGISTERED_NAME, ct_test_config_server).
-
-start()->
- case whereis(?REGISTERED_NAME) of
- undefined->
- spawn(?MODULE, init, [?REGISTERED_NAME]),
- wait();
- _Pid->
- ok
- end,
- ?REGISTERED_NAME.
-
-init(Name)->
- register(Name, self()),
- loop().
-
-get_config()->
- call(self(), get_config).
-
-stop()->
- call(self(), stop).
-
-call(Client, Request)->
- case whereis(?REGISTERED_NAME) of
- undefined->
- {error, {not_started, Request}};
- Pid->
- Pid ! {Client, Request},
- receive
- Reply->
- {ok, Reply}
- after 4000->
- {error, {timeout, Request}}
- end
- end.
-
-loop()->
- receive
- {Pid, stop}->
- Pid ! ok;
- {Pid, get_config}->
- {D,T} = erlang:localtime(),
- Pid !
- [{localtime, [{date, D}, {time, T}]},
- {node, erlang:node()},
- {now, erlang:now()},
- {config_server_pid, self()},
- {config_server_vsn, ?vsn}],
- ?MODULE:loop()
- end.
-
-wait()->
- case whereis(?REGISTERED_NAME) of
- undefined->
- wait();
- _Pid->
- ok
- end.</pre>
-
- <p>In this example, the handler also provides the ability to dynamically reload
- configuration variables. If <c>ct:reload_config(localtime)</c> is called from
+ -module(config_server).
+ -export([start/0, stop/0, init/1, get_config/0, loop/0]).
+
+ -define(REGISTERED_NAME, ct_test_config_server).
+
+ start()->
+ case whereis(?REGISTERED_NAME) of
+ undefined->
+ spawn(?MODULE, init, [?REGISTERED_NAME]),
+ wait();
+ _Pid->
+ ok
+ end,
+ ?REGISTERED_NAME.
+
+ init(Name)->
+ register(Name, self()),
+ loop().
+
+ get_config()->
+ call(self(), get_config).
+
+ stop()->
+ call(self(), stop).
+
+ call(Client, Request)->
+ case whereis(?REGISTERED_NAME) of
+ undefined->
+ {error, {not_started, Request}};
+ Pid->
+ Pid ! {Client, Request},
+ receive
+ Reply->
+ {ok, Reply}
+ after 4000->
+ {error, {timeout, Request}}
+ end
+ end.
+
+ loop()->
+ receive
+ {Pid, stop}->
+ Pid ! ok;
+ {Pid, get_config}->
+ {D,T} = erlang:localtime(),
+ Pid !
+ [{localtime, [{date, D}, {time, T}]},
+ {node, erlang:node()},
+ {now, erlang:now()},
+ {config_server_pid, self()},
+ {config_server_vsn, ?vsn}],
+ ?MODULE:loop()
+ end.
+
+ wait()->
+ case whereis(?REGISTERED_NAME) of
+ undefined->
+ wait();
+ _Pid->
+ ok
+ end.</pre>
+
+ <p>Here, the handler also provides for dynamically reloading of
+ configuration variables. If
+ <seealso marker="ct#reload_config-1"><c>ct:reload_config(localtime)</c></seealso> is called from
the test case function, all variables loaded with <c>config_driver:read_config/1</c>
- will be updated with their latest values, and the new value for variable
- <c>localtime</c> will be returned.</p>
+ are updated with their latest values, and the new value for variable
+ <c>localtime</c> is returned.</p>
</section>
</chapter>