From a9c315929d96c7d0d0e5e79f8fc0ba0c7f17e94d Mon Sep 17 00:00:00 2001 From: Andrey Pampukha Date: Mon, 15 Mar 2010 15:26:02 +0100 Subject: Changed return value tags for config file handling Return value tags modified and various documentation updates made (work in progress). --- lib/common_test/doc/src/config_file_chapter.xml | 241 ++++++++++++++++++++++-- lib/common_test/doc/src/run_test_chapter.xml | 3 + 2 files changed, 233 insertions(+), 11 deletions(-) (limited to 'lib/common_test/doc/src') diff --git a/lib/common_test/doc/src/config_file_chapter.xml b/lib/common_test/doc/src/config_file_chapter.xml index a22a5270c1..ef07ef6154 100644 --- a/lib/common_test/doc/src/config_file_chapter.xml +++ b/lib/common_test/doc/src/config_file_chapter.xml @@ -4,7 +4,7 @@
- 20042009 + 20042010 Ericsson AB. All Rights Reserved. @@ -180,7 +180,123 @@
- Examples + Using own configuration data formats + +

The nature of the configuration variables can be not only plain text + files with the key-value tuples, but they can be loaded from the files in + various formats, fetched via http from the Web, or can be loaded with help + of some driver process. For this purpose, mechanism of plugging in user + configuration handling callback modules is implemented in the Common Test.

+ +
+ Standard callback modules for loading configuration variables +

Two callback modules for handling of configuration files are provided + with the Common Test application:

+ + + ct_config_plain - for reading configuration files with + key-value tuples (traditional format). This handler will be tried to + parse configuration file, if no user callback is specified. + + + ct_config_xml - for reading configuration data from the XML + files. + + +
+ +
+ Using XML configuration files + +

This is an example of the XML configuration file:

+ +
+      
+    
+        "targethost"
+        "tester"
+        "letmein"
+    
+    "/test/loadmodules"
+]]>
+      
+ +

This configuration file, once read, will produce the same configuration + variables as the following "traditional" file:

+
+{ftp_host, [{ftp,"targethost"},
+            {username,"tester"},
+            {password,"letmein"}]}.
+
+{lm_directory, "/test/loadmodules"}.
+      
+
+ +
+ Implementing of the own handler + +

Own handler can be written to handle special configuration file formats. + The parameter can be either file name or configuration string (empty list + is valid).

+

The callback module is completely responsible for the + configuration string correctness checks during runtime.

+ +

Callback module should have the following functions exported:

+

One for checking configuration parameter

+ +

Callback:check_parameter/1

+

Input value will be passed from the Common Test, as defined in the test + specification or given as an option to the run_test.

+

Return value should be any of the following value indicating if given + configuration parameter is valid:

+ + + {ok, {file, FileName}} - parameter is a file name and + file exists; + + + {ok, {config, ConfigString}} - parameter is a config string + and it is correct; + + + {error, {nofile, FileName}} - there is no file with the given + name in the current directory; + + + {error, {wrong_config, ConfigString}} - configuration string + is wrong. + + + +

And second function performs reading of the configuration variables:

+

Callback:read_config/1

+

Input value is the same as for check_parameter/1 function

+

Return value should be either:

+ + + + {ok, Config} - is configuration variables read successfully; + + + {error, Error, ErrorDetails} - if callback module failed to + proceed. + + +

Above, the Config variable is the key-value list, possibly nested, + e.g. for the configuration files above it will be the following

+ +
+        [{ftp_host, [{ftp, "targethost"}, {username, "tester"}, {password, "letmein"}]},
+        {lm_directory, "/test/loadmodules"}]
+      
+ +
+ +
+ +
+ Examples of the configuration files

A config file for using the FTP client to access files on a remote host could look like this:

@@ -188,28 +304,33 @@
     {ftp_host, [{ftp,"targethost"},
                 {username,"tester"},
-	        {password,"letmein"}]}.
+                {password,"letmein"}]}.
 
     {lm_directory, "/test/loadmodules"}.
+ +

XML version shown in chapter above can also be used, but it should be + explicitly specified that ct_config_xml callback module is to be + used.

+

Example of how to assert that the configuration data is available and use it for an FTP session:

     init_per_testcase(ftptest, Config) ->
         {ok,_} = ct_ftp:open(ftp),
-	Config.
+        Config.
 
     end_per_testcase(ftptest, _Config) ->
         ct_ftp:close(ftp).
 
     ftptest() ->
         [{require,ftp,ftp_host},
-	 {require,lm_directory}].
+         {require,lm_directory}].
 
     ftptest(Config) ->
-	Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
+        Remote = filename:join(ct:get_config(lm_directory), "loadmodX"),
         Local = filename:join(?config(priv_dir,Config), "loadmodule"),
         ok = ct_ftp:recv(ftp, Remote, Local),
-	...
+ ...

An example of how the above functions could be rewritten if necessary to open multiple connections to the FTP server:

@@ -217,7 +338,7 @@ init_per_testcase(ftptest, Config) -> {ok,Handle1} = ct_ftp:open(ftp_host), {ok,Handle2} = ct_ftp:open(ftp_host), - [{ftp_handles,[Handle1,Handle2]} | Config]. + [{ftp_handles,[Handle1,Handle2]} | Config]. end_per_testcase(ftptest, Config) -> lists:foreach(fun(Handle) -> ct_ftp:close(Handle) end, @@ -225,17 +346,115 @@ ftptest() -> [{require,ftp_host}, - {require,lm_directory}]. + {require,lm_directory}]. ftptest(Config) -> - Remote = filename:join(ct:get_config(lm_directory), "loadmodX"), + 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), - ... + ...
+
+ Example of own configuration handler +

Simple configuration hanling "driver" can be implemented this way:

+
+-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.
+    
+

Configuration string for this driver may be "config_server", if the + config_server.erl module below is built and is exist in the code path:

+
+-module(config_server).
+-export([start/0, stop/0, init/1, get_config/0, loop/0]).
+
+-define(REGISTERED_NAME, ct_test_config_server).
+-define(vsn, 0.1).
+
+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.
+    
+

There two modules provide the ability to dynamically reload configuration + variables. If the ct:reload_config(localtime) is called from the test + case, all variables which were loaded with the config_driver above, will be + updated with the new values.

+
+ diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml index d731d18783..b7e9ab88e3 100644 --- a/lib/common_test/doc/src/run_test_chapter.xml +++ b/lib/common_test/doc/src/run_test_chapter.xml @@ -111,11 +111,14 @@ -dir ]]> -suite ]]> + -suite ]]> + -suite -group -case ]]>

Examples:

$ run_test -config $CFGS/sys1.cfg $CFGS/sys2.cfg -dir $SYS1_TEST $SYS2_TEST

+

$ run_test -userconfig ct_config_xml $CFGS/sys1.xml $CFGS/sys2.xml -dir $SYS1_TEST $SYS2_TEST

$ run_test -suite $SYS1_TEST/setup_SUITE $SYS2_TEST/config_SUITE

$ run_test -suite $SYS1_TEST/setup_SUITE -case start stop

$ run_test -suite $SYS1_TEST/setup_SUITE -group installation -case start stop

-- cgit v1.2.3