diff options
Diffstat (limited to 'lib/test_server/src/ts.erl')
-rw-r--r-- | lib/test_server/src/ts.erl | 860 |
1 files changed, 0 insertions, 860 deletions
diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl deleted file mode 100644 index d6d2e865e2..0000000000 --- a/lib/test_server/src/ts.erl +++ /dev/null @@ -1,860 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2014. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%%%------------------------------------------------------------------- -%%% File : ts.erl -%%% Purpose : Frontend for running tests. -%%%------------------------------------------------------------------- - --module(ts). - --export([run/0, run/1, run/2, run/3, run/4, run/5, - tests/0, tests/1, - install/0, install/1, - bench/0, bench/1, bench/2, benchmarks/0, - smoke_test/0, smoke_test/1,smoke_test/2, smoke_tests/0, - estone/0, estone/1, - cross_cover_analyse/1, - compile_testcases/0, compile_testcases/1, - help/0]). --export([i/0, l/1, r/0, r/1, r/2, r/3]). - -%%%---------------------------------------------------------------------- -%%% This module, ts, is the interface to all of the functionality of -%%% the TS framework. The picture below shows the relationship of -%%% the modules: -%%% -%%% +-- ts_install --+------ ts_autoconf_win32 -%%% | -%%% ts ---+ +------ ts_erl_config -%%% | | ts_lib -%%% +-- ts_run -----+------ ts_make -%%% | | ts_filelib -%%% | +------ ts_make_erl -%%% | -%%% +-- ts_benchmark -%%% -%%% The modules ts_lib and ts_filelib contains utilities used by -%%% the other modules. -%%% -%%% Module Description -%%% ------ ----------- -%%% ts Frontend to the test server framework. Contains all -%%% interface functions. -%%% ts_install Installs the test suite. On Unix, `autoconf' is -%%% is used; on Windows, ts_autoconf_win32 is used. -%%% The result is written to the file `variables'. -%%% ts_run Supervises running of the tests. -%%% ts_autconf_win32 An `autoconf' for Windows. -%%% ts_autconf_cross_env `autoconf' for other platforms (cross environment) -%%% ts_erl_config Finds out information about the Erlang system, -%%% for instance the location of erl_interface. -%%% This works for either an installed OTP or an Erlang -%%% system running in a git repository/source tree. -%%% ts_make Interface to run the `make' program on Unix -%%% and other platforms. -%%% ts_make_erl A corrected version of the standar Erlang module -%%% make (used for rebuilding test suites). -%%% ts_lib Miscellanous utility functions, each used by several -%%% other modules. -%%% ts_benchmark Supervises otp benchmarks and collects results. -%%%---------------------------------------------------------------------- - --include_lib("kernel/include/file.hrl"). --include("ts.hrl"). - --define( - install_help, - [ - " ts:install() - Install TS with no Options.\n" - " ts:install([Options]) - Install TS with Options\n" - "\n", - "Installation options supported:\n", - " {longnames, true} - Use fully qualified hostnames\n", - " {verbose, Level} - Sets verbosity level for TS output (0,1,2), 0 is\n" - " quiet(default).\n" - " {crossroot, ErlTop}\n" - " - Erlang root directory on build host, ~n" - " normally same value as $ERL_TOP\n" - " {crossenv, [{Key,Val}]}\n" - " - Environmentals used by test configure on build host\n" - " {crossflags, FlagsString}\n" - " - Flags used by test configure on build host\n" - " {xcomp, XCompFile}\n" - " - The xcomp file to use for cross compiling the~n" - " testcases. Using this option will override any~n" - " cross* configurations given to ts. Note that you~n" - " have to have a correct ERL_TOP as well.~n" - ]). - -help() -> - case filelib:is_file(?variables) of - false -> help(uninstalled); - true -> help(installed) - end. - -help(uninstalled) -> - H = ["TS is not installed yet. To install use:\n\n"], - show_help([H,?install_help]); -help(installed) -> - H = ["Run functions:\n", - " ts:run() - Run all available tests.\n", - " ts:run(Spec) - Run all tests in given test spec file.\n", - " The spec file is actually ../*_test/Spec.spec\n", - " ts:run([Specs]) - Run all tests in all given test spec files.\n", - " ts:run(Spec, Mod) - Run a single test suite.\n", - " ts:run(Spec, Mod, Case)\n", - " - Run a single test case.\n", - " All above run functions can have an additional Options argument\n", - " which is a list of options.\n", - "\n", - "Run options supported:\n", - " batch - Do not start a new xterm\n", - " {verbose, Level} - Same as the verbosity option for install\n", - " verbose - Same as {verbose, 1}\n", - " {vars, Vars} - Variables in addition to the 'variables' file\n", - " Can be any of the install options\n", - " {trace, TraceSpec}- Start call trace on target and slave nodes\n", - " TraceSpec is the name of a file containing\n", - " trace specifications or a list of trace\n", - " specification elements.\n", - " {config, Path} - Specify which directory ts should get it's \n" - " config files from. The files should follow\n" - " the convention lib/test_server/src/ts*.config.\n" - " These config files can also be specified by\n" - " setting the TEST_CONFIG_PATH environment\n" - " variable to the directory where the config\n" - " files are. The default location is\n" - " tests/test_server/.\n" - "\n", - "Supported trace information elements\n", - " {tp | tpl, Mod, [] | match_spec()}\n", - " {tp | tpl, Mod, Func, [] | match_spec()}\n", - " {tp | tpl, Mod, Func, Arity, [] | match_spec()}\n", - " {ctp | ctpl, Mod}\n", - " {ctp | ctpl, Mod, Func}\n", - " {ctp | ctpl, Mod, Func, Arity}\n", - "\n", - "Support functions:\n", - " ts:tests() - Shows all available families of tests.\n", - " ts:tests(Spec) - Shows all available test modules in Spec,\n", - " i.e. ../Spec_test/*_SUITE.erl\n", - " ts:estone() - Run estone_SUITE in kernel application with\n" - " no run options\n", - " ts:estone(Opts) - Run estone_SUITE in kernel application with\n" - " the given run options\n", - " ts:cross_cover_analyse(Level)\n" - " - Used after ts:run with option cover or \n" - " cover_details. Analyses modules specified with\n" - " a 'cross' statement in the cover spec file.\n" - " Level can be 'overview' or 'details'.\n", - " ts:compile_testcases()~n" - " ts:compile_testcases(Apps)~n" - " - Compile all testcases for usage in a cross ~n" - " compile environment." - " \n" - "Benchmark functions:\n" - " ts:benchmarks() - Get all available families of benchmarks\n" - " ts:bench() - Runs all benchmarks\n" - " ts:bench(Spec) - Runs all benchmarks in the given spec file.\n" - " The spec file is actually ../*_test/Spec_bench.spec\n\n" - " ts:bench can take the same Options argument as ts:run.\n" - "Smoke test functions:\n" - " ts:smoke_tests() - Get all available families of smoke tests\n" - " ts:smoke_test() - Runs all smoke tests\n" - " ts:smoke_test(Spec)\n" - " - Runs all smoke tests in the given spec file.\n" - " The spec file is actually ../*_test/Spec_smoke.spec\n\n" - " ts:smoke_test can take the same Options argument as ts:run.\n" - "\n" - "Installation (already done):\n" - ], - show_help([H,?install_help]). - -show_help(H) -> - io:format(lists:flatten(H)). - - -%% Installs tests. -install() -> - ts_install:install(install_local,[]). -install(Options) when is_list(Options) -> - ts_install:install(install_local,Options). - -%% run/0 -%% Runs all specs found by ts:tests(), if any, or returns -%% {error, no_tests_available}. (batch) -run() -> - case ts:tests() of - [] -> - {error, no_tests_available}; - _ -> - check_and_run(fun(Vars) -> run_all(Vars) end) - end. -run_all(_Vars) -> - run_some(tests(), [batch]). - -run_some([], _Opts) -> - ok; -run_some([{Spec,Mod}|Specs], Opts) -> - case run(Spec, Mod, Opts) of - ok -> ok; - Error -> io:format("~p: ~p~n",[{Spec,Mod},Error]) - end, - run_some(Specs, Opts); -run_some([Spec|Specs], Opts) -> - case run(Spec, Opts) of - ok -> ok; - Error -> io:format("~p: ~p~n",[Spec,Error]) - end, - run_some(Specs, Opts). - -%% Runs one test spec (interactive). -run(Testspec) when is_atom(Testspec) -> - Options=check_test_get_opts(Testspec, []), - File = atom_to_list(Testspec), - run_test(File, [{spec,[File++".spec"]}], Options); - -%% This can be used from command line, e.g. -%% erl -s ts run all_tests <config> -%% When using the all_tests flag and running with cover, one can also -%% use the cross_cover_analysis flag. -run([all_tests|Config0]) -> - AllAtomsFun = fun(X) when is_atom(X) -> true; - (_) -> false - end, - Config1 = - case lists:all(AllAtomsFun,Config0) of - true -> - %% Could be from command line - lists:map(fun(Conf)->to_erlang_term(Conf) end,Config0)--[batch]; - false -> - Config0--[batch] - end, - %% Make sure there is exactly one occurence of 'batch' - Config2 = [batch|Config1], - - R = run(tests(),Config2), - - case check_for_cross_cover_analysis_flag(Config2) of - false -> - ok; - Level -> - cross_cover_analyse(Level) - end, - - R; - -%% ts:run(ListOfTests) -run(List) when is_list(List) -> - run(List, [batch]). - -run(List, Opts) when is_list(List), is_list(Opts) -> - run_some(List, Opts); - -%% run/2 -%% Runs one test spec with list of suites or with options -run(Testspec, ModsOrConfig) when is_atom(Testspec), - is_list(ModsOrConfig) -> - case is_list_of_suites(ModsOrConfig) of - false -> - run(Testspec, {config_list,ModsOrConfig}); - true -> - run_some([{Testspec,M} || M <- ModsOrConfig], - [batch]) - end; -run(Testspec, {config_list,Config}) -> - Options=check_test_get_opts(Testspec, Config), - IsSmoke=proplists:get_value(smoke,Config), - File=atom_to_list(Testspec), - WhatToDo = - case Testspec of - %% Known to exist but fails generic tests below - emulator -> test; - system -> test; - erl_interface -> test; - epmd -> test; - _ -> - case code:lib_dir(Testspec) of - {error,bad_name} -> - %% Application does not exist - skip; - Path -> - case file:read_file_info(filename:join(Path,"ebin")) of - {ok,#file_info{type=directory}} -> - %% Erlang application is built - test; - _ -> - case filelib:wildcard( - filename:join([Path,"priv","*.jar"])) of - [] -> - %% The application is not built - skip; - [_|_] -> - %% Java application is built - test - end - end - end - end, - Spec = - case WhatToDo of - skip -> - create_skip_spec(Testspec, tests(Testspec)); - test when IsSmoke -> - File++"_smoke.spec"; - test -> - File++".spec" - end, - run_test(File, [{spec,[Spec]}], Options); -%% Runs one module in a spec (interactive) -run(Testspec, Mod) when is_atom(Testspec), is_atom(Mod) -> - run_test({atom_to_list(Testspec),Mod}, - [{suite,Mod}], - [interactive]). - -%% run/3 -%% Run one module in a spec with Config -run(Testspec, Mod, Config) when is_atom(Testspec), - is_atom(Mod), - is_list(Config) -> - Options=check_test_get_opts(Testspec, Config), - run_test({atom_to_list(Testspec),Mod}, - [{suite,Mod}], Options); -%% Run multiple modules with Config -run(Testspec, Mods, Config) when is_atom(Testspec), - is_list(Mods), - is_list(Config) -> - run_some([{Testspec,M} || M <- Mods], Config); -%% Runs one test case in a module. -run(Testspec, Mod, Case) when is_atom(Testspec), - is_atom(Mod), - is_atom(Case) -> - Options=check_test_get_opts(Testspec, []), - Args = [{suite,Mod},{testcase,Case}], - run_test(atom_to_list(Testspec), Args, Options); -%% Runs one or more groups in a module. -run(Testspec, Mod, Grs={group,_Groups}) when is_atom(Testspec), - is_atom(Mod) -> - Options=check_test_get_opts(Testspec, []), - Args = [{suite,Mod},Grs], - run_test(atom_to_list(Testspec), Args, Options); -%% Runs one or more test cases in a module. -run(Testspec, Mod, TCs={testcase,_Cases}) when is_atom(Testspec), - is_atom(Mod) -> - Options=check_test_get_opts(Testspec, []), - Args = [{suite,Mod},TCs], - run_test(atom_to_list(Testspec), Args, Options). - -%% run/4 -%% Run one test case in a module with Options. -run(Testspec, Mod, Case, Config) when is_atom(Testspec), - is_atom(Mod), - is_atom(Case), - is_list(Config) -> - Options=check_test_get_opts(Testspec, Config), - Args = [{suite,Mod},{testcase,Case}], - run_test(atom_to_list(Testspec), Args, Options); -%% Run one or more test cases in a module with Options. -run(Testspec, Mod, {testcase,Cases}, Config) when is_atom(Testspec), - is_atom(Mod) -> - run(Testspec, Mod, Cases, Config); -run(Testspec, Mod, Cases, Config) when is_atom(Testspec), - is_atom(Mod), - is_list(Cases), - is_list(Config) -> - Options=check_test_get_opts(Testspec, Config), - Args = [{suite,Mod},Cases], - run_test(atom_to_list(Testspec), Args, Options); -%% Run one or more groups in a module with Options. -run(Testspec, Mod, Grs={group,_Groups}, Config) when is_atom(Testspec), - is_atom(Mod) -> - Options=check_test_get_opts(Testspec, Config), - Args = [{suite,Mod},Grs], - run_test(atom_to_list(Testspec), Args, Options). - -%% run/5 -%% Run one or more test cases in a group with Options. -run(Testspec, Mod, Group, Cases, Config) when is_atom(Testspec), - is_atom(Mod), - is_list(Config) -> - Group1 = if is_tuple(Group) -> Group; true -> {group,Group} end, - Cases1 = if is_tuple(Cases) -> Cases; true -> {testcase,Cases} end, - Options=check_test_get_opts(Testspec, Config), - Args = [{suite,Mod},Group1,Cases1], - run_test(atom_to_list(Testspec), Args, Options). - -is_list_of_suites(List) -> - lists:all(fun(Suite) -> - S = if is_atom(Suite) -> atom_to_list(Suite); - true -> Suite - end, - try lists:last(string:tokens(S,"_")) of - "SUITE" -> true; - "suite" -> true; - _ -> false - catch - _:_ -> false - end - end, List). - -%% Create a spec to skip all SUITES, this is used when the application -%% to be tested is not part of the OTP release to be tested. -create_skip_spec(Testspec, SuitesToSkip) -> - {ok,Cwd} = file:get_cwd(), - TestspecString = atom_to_list(Testspec), - Specname = TestspecString++"_skip.spec", - {ok,D} = file:open(filename:join([filename:dirname(Cwd), - TestspecString++"_test",Specname]), - [write]), - TestDir = "\"../"++TestspecString++"_test\"", - io:format(D,"{suites, "++TestDir++", all}.~n",[]), - io:format(D,"{skip_suites, "++TestDir++", ~w, \"Skipped as application" - " is not in path!\"}.",[SuitesToSkip]), - Specname. - -%% Check testspec to be valid and get possible Options -%% from the config. -check_test_get_opts(Testspec, Config) -> - validate_test(Testspec), - Mode = configmember(batch, {batch, interactive}, Config), - Vars = configvars(Config), - Trace = get_config(trace,Config), - ConfigPath = get_config(config,Config), - KeepTopcase = configmember(keep_topcase, {keep_topcase,[]}, Config), - Cover = configcover(Testspec,Config), - lists:flatten([Vars,Mode,Trace,KeepTopcase,Cover,ConfigPath]). - -to_erlang_term(Atom) -> - String = atom_to_list(Atom), - {ok, Tokens, _} = erl_scan:string(lists:append([String, ". "])), - {ok, Term} = erl_parse:parse_term(Tokens), - Term. - -%% Validate that a Testspec really is a testspec, -%% and exit if not. -validate_test(Testspec) -> - case lists:member(Testspec, tests()) of - true -> - ok; - false -> - io:format("This testspec does not seem to be " - "available.~n Please try ts:tests() " - "to see available tests.~n"), - exit(self(), {error, test_not_available}) - end. - -configvars(Config) -> - case lists:keysearch(vars, 1, Config) of - {value, {vars, List}} -> - List0 = special_vars(Config), - Key = fun(T) -> element(1,T) end, - DelDupList = - lists:filter(fun(V) -> - case lists:keysearch(Key(V),1,List0) of - {value,_} -> false; - _ -> true - end - end, List), - {vars, [List0|DelDupList]}; - _ -> - {vars, special_vars(Config)} - end. - -%% Allow some shortcuts in the Options... -special_vars(Config) -> - SpecVars = - case lists:member(verbose, Config) of - true -> - [{verbose, 1}]; - false -> - case lists:keysearch(verbose, 1, Config) of - {value, {verbose, Lvl}} -> - [{verbose, Lvl}]; - _ -> - [{verbose, 0}] - end - end, - SpecVars1 = - case lists:keysearch(diskless, 1, Config) of - {value,{diskless, true}} -> - [{diskless, true} | SpecVars]; - _ -> - SpecVars - end, - case lists:keysearch(testcase_callback, 1, Config) of - {value,{testcase_callback, CBM, CBF}} -> - [{ts_testcase_callback, {CBM,CBF}} | SpecVars1]; - {value,{testcase_callback, CB}} -> - [{ts_testcase_callback, CB} | SpecVars1]; - _ -> - SpecVars1 - end. - -get_config(Key,Config) -> - case lists:keysearch(Key,1,Config) of - {value,Value} -> Value; - false -> [] - end. - -configcover(Testspec,[cover|_]) -> - {cover,Testspec,default_coverfile(Testspec),overview}; -configcover(Testspec,[cover_details|_]) -> - {cover,Testspec,default_coverfile(Testspec),details}; -configcover(Testspec,[{cover,File}|_]) -> - {cover,Testspec,File,overview}; -configcover(Testspec,[{cover_details,File}|_]) -> - {cover,Testspec,File,details}; -configcover(Testspec,[_H|T]) -> - configcover(Testspec,T); -configcover(_Testspec,[]) -> - []. - -default_coverfile(Testspec) -> - {ok,Cwd} = file:get_cwd(), - CoverFile = filename:join([filename:dirname(Cwd), - atom_to_list(Testspec)++"_test", - atom_to_list(Testspec)++".cover"]), - case filelib:is_file(CoverFile) of - true -> - CoverFile; - false -> - none - end. - -configmember(Member, {True, False}, Config) -> - case lists:member(Member, Config) of - true -> - True; - false -> - False - end. - - -check_for_cross_cover_analysis_flag(Config) -> - check_for_cross_cover_analysis_flag(Config,false,false). -check_for_cross_cover_analysis_flag([cover|Config],false,false) -> - check_for_cross_cover_analysis_flag(Config,overview,false); -check_for_cross_cover_analysis_flag([cover|_Config],false,true) -> - overview; -check_for_cross_cover_analysis_flag([cover_details|Config],false,false) -> - check_for_cross_cover_analysis_flag(Config,details,false); -check_for_cross_cover_analysis_flag([cover_details|_Config],false,true) -> - details; -check_for_cross_cover_analysis_flag([cross_cover_analysis|Config],false,_) -> - check_for_cross_cover_analysis_flag(Config,false,true); -check_for_cross_cover_analysis_flag([cross_cover_analysis|_Config],Level,_) -> - Level; -check_for_cross_cover_analysis_flag([_|Config],Level,CrossFlag) -> - check_for_cross_cover_analysis_flag(Config,Level,CrossFlag); -check_for_cross_cover_analysis_flag([],_,_) -> - false. - -%% Returns a list of available test suites. - -tests() -> - {ok, Cwd} = file:get_cwd(), - ts_lib:specs(Cwd). - -tests(Spec) -> - {ok, Cwd} = file:get_cwd(), - ts_lib:suites(Cwd, atom_to_list(Spec)). - -%% Benchmark related functions - -bench() -> - bench([]). - -bench(Opts) when is_list(Opts) -> - bench(benchmarks(),Opts); -bench(Spec) -> - bench([Spec],[]). - -bench(Spec, Opts) when is_atom(Spec) -> - bench([Spec],Opts); -bench(Specs, Opts) -> - check_and_run(fun(Vars) -> ts_benchmark:run(Specs, Opts, Vars) end). - -benchmarks() -> - ts_benchmark:benchmarks(). - -smoke_test() -> - smoke_test([]). - -smoke_test(Opts) when is_list(Opts) -> - smoke_test(smoke_tests(),Opts); -smoke_test(Spec) -> - smoke_test([Spec],[]). - -smoke_test(Spec, Opts) when is_atom(Spec) -> - smoke_test([Spec],Opts); -smoke_test(Specs, Opts) -> - run(Specs, [{smoke,true}|Opts]). - -smoke_tests() -> - {ok, Cwd} = file:get_cwd(), - ts_lib:specialized_specs(Cwd,"smoke"). - -%% -%% estone/0, estone/1 -%% Opts = same as Opts or Config for the run(...) function, -%% e.g. [batch] -%% -estone() -> run(emulator,estone_SUITE). -estone(Opts) when is_list(Opts) -> run(emulator,estone_SUITE,Opts). - -%% -%% cross_cover_analyse/1 -%% Level = details | overview -%% Can be called on any node after a test (with cover) is -%% completed. The node's current directory must be the same as when -%% the tests were run. -%% -cross_cover_analyse([Level]) -> - cross_cover_analyse(Level); -cross_cover_analyse(Level) -> - Apps = get_last_app_tests(), - test_server_ctrl:cross_cover_analyse(Level,Apps). - -get_last_app_tests() -> - AllTests = filelib:wildcard(filename:join(["*","*_test.logs"])), - {ok,RE} = re:compile("^[^/]*/[^\.]*\.(.*)_test\.logs$"), - get_last_app_tests(AllTests,RE,[]). - -get_last_app_tests([Dir|Dirs],RE,Acc) -> - NewAcc = - case re:run(Dir,RE,[{capture,all,list}]) of - {match,[Dir,AppStr]} -> - Dir1 = filename:dirname(Dir), % cover logs in ct_run.<t> dir - App = list_to_atom(AppStr), - case lists:keytake(App,1,Acc) of - {value,{App,LastDir},Rest} -> - if Dir1 > LastDir -> - [{App,Dir1}|Rest]; - true -> - Acc - end; - false -> - [{App,Dir1} | Acc] - end; - _ -> - Acc - end, - get_last_app_tests(Dirs,RE,NewAcc); -get_last_app_tests([],_,Acc) -> - Acc. - -%%% Implementation. - -check_and_run(Fun) -> - case file:consult(?variables) of - {ok, Vars} -> - check_and_run(Fun, Vars); - {error, Error} when is_atom(Error) -> - {error, not_installed}; - {error, Reason} -> - {error, {bad_installation, file:format_error(Reason)}} - end. - -check_and_run(Fun, Vars) -> - Platform = ts_install:platform_id(Vars), - case lists:keysearch(platform_id, 1, Vars) of - {value, {_, Platform}} -> - case catch apply(Fun, [Vars]) of - {'EXIT', Reason} -> - exit(Reason); - Other -> - Other - end; - {value, {_, OriginalPlatform}} -> - io:format("These test suites were installed for '~s'.\n", - [OriginalPlatform]), - io:format("But the current platform is '~s'.\nPlease " - "install for this platform before running " - "any tests.\n", [Platform]), - {error, inconsistent_platforms}; - false -> - {error, {bad_installation, no_platform}} - end. - -run_test(File, Args, Options) -> - check_and_run(fun(Vars) -> run_test(File, Args, Options, Vars) end). - -run_test(File, Args, Options, Vars) -> - ts_run:run(File, Args, Options, Vars). - - -%% This module provides some convenient shortcuts to running -%% the test server from within a started Erlang shell. -%% (This are here for backwards compatibility.) -%% -%% r() -%% r(Opts) -%% r(SpecOrMod) -%% r(SpecOrMod, Opts) -%% r(Mod, Case) -%% r(Mod, Case, Opts) -%% Each of these functions starts the test server if it -%% isn't already running, then runs the test case(s) selected -%% by the aguments. -%% SpecOrMod can be a module name or the name of a test spec file, -%% with the extension .spec or .spec.OsType. The module Mod will -%% be reloaded before running the test cases. -%% Opts = [Opt], -%% Opt = {Cover,AppOrCoverFile} | {Cover,App,CoverFile} -%% Cover = cover | cover_details -%% AppOrCoverFile = App | CoverFile -%% App = atom(), an application name -%% CoverFile = string(), name of a cover file -%% (see doc of test_server_ctrl:cover/2/3) -%% -%% i() -%% Shows information about the jobs being run, by dumping -%% the process information for the test_server. -%% -%% l(Mod) -%% This function reloads a module just like c:l/1, but works -%% even for a module in one of the sticky library directories -%% (for instance, lists can be reloaded). - -%% Runs all tests cases in the current directory. - -r() -> - r([]). -r(Opts) when is_list(Opts), is_atom(hd(Opts)) -> - ensure_ts_started(Opts), - test_server_ctrl:add_dir("current_dir", "."); - -%% Checks if argument is a spec file or a module -%% (spec file must be named "*.spec" or "*.spec.OsType") -%% If module, reloads module and runs all test cases in it. -%% If spec, runs all test cases in it. - -r(SpecOrMod) -> - r(SpecOrMod,[]). -r(SpecOrMod,Opts) when is_list(Opts) -> - ensure_ts_started(Opts), - case filename:extension(SpecOrMod) of - [] -> - l(SpecOrMod), - test_server_ctrl:add_module(SpecOrMod); - ".spec" -> - test_server_ctrl:add_spec(SpecOrMod); - _ -> - Spec2 = filename:rootname(SpecOrMod), - case filename:extension(Spec2) of - ".spec" -> - %% *.spec.Type - test_server_ctrl:add_spec(SpecOrMod); - _ -> - {error, unknown_filetype} - end - end; - -%% Reloads the given module and runs the given test case in it. - -r(Mod, Case) -> - r(Mod,Case,[]). -r(Mod, Case, Opts) -> - ensure_ts_started(Opts), - l(Mod), - test_server_ctrl:add_case(Mod, Case). - -%% Shows information about the jobs being run. - -i() -> - ensure_ts_started([]), - hformat("Job", "Current", "Total", "Success", "Failed", "Skipped"), - i(test_server_ctrl:jobs()). - -i([{Name, Pid}|Rest]) when is_pid(Pid) -> - {dictionary, PI} = process_info(Pid, dictionary), - {value, {_, CaseNum}} = lists:keysearch(test_server_case_num, 1, PI), - {value, {_, Cases}} = lists:keysearch(test_server_cases, 1, PI), - {value, {_, Failed}} = lists:keysearch(test_server_failed, 1, PI), - {value, {_, {UserSkipped,AutoSkipped}}} = lists:keysearch(test_server_skipped, 1, PI), - {value, {_, Ok}} = lists:keysearch(test_server_ok, 1, PI), - nformat(Name, CaseNum, Cases, Ok, Failed, UserSkipped+AutoSkipped), - i(Rest); -i([]) -> - ok. - -hformat(A1, A2, A3, A4, A5, A6) -> - io:format("~-20s ~8s ~8s ~8s ~8s ~8s~n", [A1,A2,A3,A4,A5,A6]). - -nformat(A1, A2, A3, A4, A5, A6) -> - io:format("~-20s ~8w ~8w ~8w ~8w ~8w~n", [A1,A2,A3,A4,A5,A6]). - -%% Force load of a module even if it is in a sticky directory. - -l(Mod) -> - case do_load(Mod) of - {error, sticky_directory} -> - Dir = filename:dirname(code:which(Mod)), - code:unstick_dir(Dir), - do_load(Mod), - code:stick_dir(Dir); - X -> - X - end. - - -ensure_ts_started(Opts) -> - Pid = case whereis(test_server_ctrl) of - undefined -> - test_server_ctrl:start(); - P when is_pid(P) -> - P - end, - case Opts of - [{Cover,AppOrCoverFile}] when Cover==cover; Cover==cover_details -> - test_server_ctrl:cover(AppOrCoverFile,cover_type(Cover)); - [{Cover,App,CoverFile}] when Cover==cover; Cover==cover_details -> - test_server_ctrl:cover(App,CoverFile,cover_type(Cover)); - _ -> - ok - end, - Pid. - -cover_type(cover) -> overview; -cover_type(cover_details) -> details. - -do_load(Mod) -> - code:purge(Mod), - code:load_file(Mod). - - -compile_testcases() -> - compile_datadirs("../*/*_data"). - -compile_testcases(App) when is_atom(App) -> - compile_testcases([App]); -compile_testcases([App | T]) -> - compile_datadirs(io_lib:format("../~s_test/*_data", [App])), - compile_testcases(T); -compile_testcases([]) -> - ok. - -compile_datadirs(DataDirs) -> - {ok,Variables} = file:consult("variables"), - - lists:foreach(fun(Dir) -> - ts_lib:make_non_erlang(Dir, Variables) - end, - filelib:wildcard(DataDirs)). |