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 + lib/common_test/src/ct_config.erl | 4 +- lib/common_test/src/ct_config_plain.erl | 2 +- lib/common_test/src/ct_config_xml.erl | 2 +- lib/common_test/src/ct_run.erl | 10 +- lib/common_test/src/ct_testspec.erl | 4 +- .../config/test/config_driver.erl | 2 +- lib/common_test/vsn.mk | 2 +- 9 files changed, 246 insertions(+), 24 deletions(-) (limited to 'lib/common_test') 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

diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl index 4b99d8db88..5623b80592 100755 --- a/lib/common_test/src/ct_config.erl +++ b/lib/common_test/src/ct_config.erl @@ -685,7 +685,7 @@ check_callback_load(Callback)-> end. check_config_files(Configs)-> - lists:keysearch(nok, 1, + lists:keysearch(error, 1, lists:flatten( lists:map(fun({Callback, Files})-> case check_callback_load(Callback) of @@ -695,7 +695,7 @@ check_config_files(Configs)-> end, Files); {error, _}-> - {nok, {callback, Callback}} + {error, {callback, Callback}} end end, Configs))). diff --git a/lib/common_test/src/ct_config_plain.erl b/lib/common_test/src/ct_config_plain.erl index 327fc66b40..0fed58e45a 100755 --- a/lib/common_test/src/ct_config_plain.erl +++ b/lib/common_test/src/ct_config_plain.erl @@ -71,7 +71,7 @@ check_parameter(File)-> true-> {ok, {file, File}}; false-> - {nok, {nofile, File}} + {error, {nofile, File}} end. read_config_terms(Bin) when is_binary(Bin) -> diff --git a/lib/common_test/src/ct_config_xml.erl b/lib/common_test/src/ct_config_xml.erl index e14bb0f9f9..111d1426c9 100755 --- a/lib/common_test/src/ct_config_xml.erl +++ b/lib/common_test/src/ct_config_xml.erl @@ -42,7 +42,7 @@ check_parameter(File)-> true-> {ok, {file, File}}; false-> - {nok, {nofile, File}} + {error, {nofile, File}} end. % actual reading of the config diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 0e7da60821..92c2334a80 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -245,11 +245,11 @@ check_and_install_configfiles(Configs, LogDir, EvHandlers) -> false-> install([{config,Configs}, {event_handler,EvHandlers}], LogDir); - {value, {nok, {nofile, File}}} -> + {value, {error, {nofile, File}}} -> {error,{cant_read_config_file,File}}; - {value, {nok, {wrong_config, Message}}}-> + {value, {error, {wrong_config, Message}}}-> {error,{wrong_config, Message}}; - {value, {nok, {callback, File}}} -> + {value, {error, {callback, File}}} -> {error,{cant_load_callback_module,File}} end. @@ -702,9 +702,9 @@ check_config_file(Callback, File)-> ?abs(File); {ok, {config, _}}-> File; - {nok, {wrong_config, Message}}-> + {error, {wrong_config, Message}}-> exit({wrong_config, {Callback, Message}}); - {nok, {nofile, File}}-> + {error, {nofile, File}}-> exit({no_such_file, ?abs(File)}) end. diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl index ea30ccc13b..5248a6e319 100644 --- a/lib/common_test/src/ct_testspec.erl +++ b/lib/common_test/src/ct_testspec.erl @@ -321,9 +321,9 @@ get_absfile(Callback, FullName,#testspec{spec_dir=SpecDir}) -> filename:join(Dir,File); {ok, {config, FullName}}-> FullName; - {nok, {nofile, FullName}}-> + {error, {nofile, FullName}}-> FullName; - {nok, {wrong_config, FullName}}-> + {error, {wrong_config, FullName}}-> FullName end. diff --git a/lib/common_test/test/ct_config_SUITE_data/config/test/config_driver.erl b/lib/common_test/test/ct_config_SUITE_data/config/test/config_driver.erl index 670639f7c7..073cb66ac2 100644 --- a/lib/common_test/test/ct_config_SUITE_data/config/test/config_driver.erl +++ b/lib/common_test/test/ct_config_SUITE_data/config/test/config_driver.erl @@ -41,6 +41,6 @@ check_parameter(ServerName)-> {module, ServerModule}-> {ok, {config, ServerName}}; {error, nofile}-> - {nok, {wrong_config, "File not found: " ++ ServerName ++ ".beam"}} + {error, {wrong_config, "File not found: " ++ ServerName ++ ".beam"}} end end. diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk index cdb8e1f71c..2947c6a152 100644 --- a/lib/common_test/vsn.mk +++ b/lib/common_test/vsn.mk @@ -1,3 +1,3 @@ -COMMON_TEST_VSN = 1.4.8 +COMMON_TEST_VSN = 1.5 -- cgit v1.2.3