%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1997-2011. 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%
%%
%%
%%% Author: Hakan Mattsson [email protected]
%%% Purpose: Nice shortcuts intended for testing of Mnesia
%%%
%%% See the mnesia_SUITE module about the structure of
%%% the test suite.
%%%
%%% See the mnesia_test_lib module about the test case execution.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-module(mt).
-author('[email protected]').
-export([
t/0, t/1, t/2, t/3, % Run test cases
loop/1, loop/2, loop/3, % loop test cases
doc/0, doc/1, % Generate test case doc
struct/0, struct/1, % View test suite struct
shutdown/0, ping/0, start_nodes/0, % Node admin
read_config/0, write_config/1 % Config admin
]).
-include("mnesia_test_lib.hrl").
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Aliases for the (sub) test suites
alias(all) -> mnesia_SUITE;
alias(atomicity) -> mnesia_atomicity_test;
alias(backup) -> mnesia_evil_backup;
alias(config) -> mnesia_config_test;
alias(consistency) -> mnesia_consistency_test;
alias(dirty) -> mnesia_dirty_access_test;
alias(durability) -> mnesia_durability_test;
alias(evil) -> mnesia_evil_coverage_test;
alias(qlc) -> mnesia_qlc_test;
alias(examples) -> mnesia_examples_test;
alias(frag) -> mnesia_frag_test;
alias(heavy) -> {mnesia_SUITE, heavy};
alias(install) -> mnesia_install_test;
alias(isolation) -> mnesia_isolation_test;
alias(light) -> {mnesia_SUITE, light};
alias(measure) -> mnesia_measure_test;
alias(medium) -> {mnesia_SUITE, medium};
alias(nice) -> mnesia_nice_coverage_test;
alias(recover) -> mnesia_recover_test;
alias(recovery) -> mnesia_recovery_test;
alias(registry) -> mnesia_registry_test;
alias(suite) -> mnesia_SUITE;
alias(trans) -> mnesia_trans_access_test;
alias(Other) -> Other.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Resolves the name of test suites and test cases
%% according to the alias definitions. Single atoms
%% are assumed to be the name of a test suite.
resolve(Suite0) when is_atom(Suite0) ->
case alias(Suite0) of
Suite when is_atom(Suite) ->
{Suite, all};
{Suite, Case} ->
{Suite, is_group(Suite,Case)}
end;
resolve({Suite0, Case}) when is_atom(Suite0), is_atom(Case) ->
case alias(Suite0) of
Suite when is_atom(Suite) ->
{Suite, is_group(Suite,Case)};
{Suite, Case2} ->
{Suite, is_group(Suite,Case2)}
end;
resolve(List) when is_list(List) ->
[resolve(Case) || Case <- List].
is_group(Mod, Case) ->
try {_,_,_} = lists:keyfind(Case, 1, Mod:groups()),
{group, Case}
catch _:{badmatch,_} ->
Case
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Run one or more test cases
%% Run the default test case with default config
t() ->
t(read_test_case()).
%% Resolve the test case name and run the test case
%% The test case is noted as default test case
%% and the outcome of the tests are written to
%% to a file.
t(silly) ->
mnesia_install_test:silly();
t(diskless) ->
%% Run the default test case with default config,
%% but diskless
t(read_test_case(), diskless);
t(Case) ->
%% Use the default config
t(Case, read_config()).
t(Case, Config) when Config == diskless ->
%% Run the test case with default config, but diskless
Config2 = [{diskless, true} | read_config()],
t(Case, Config2);
t(Mod, Fun) when is_atom(Mod), is_atom(Fun) ->
%% Run the test case with default config
t({Mod, Fun}, read_config());
t(RawCase, Config) when is_list(Config) ->
%% Resolve the test case name and run the test case
Case = resolve(RawCase),
write_test_case(Case),
Res = mnesia_test_lib:test(Case, Config),
append_test_case_info(Case, Res).
t(Mod, Fun, Config) when Config == diskless ->
t({Mod, Fun}, diskless).
config_fname() ->
"mnesia_test_case_config".
%% Read default config file
read_config() ->
Fname = config_fname(),
mnesia_test_lib:log("Consulting file ~s...~n", [Fname]),
case file:consult(Fname) of
{ok, Config} ->
mnesia_test_lib:log("Read config ~w~n", [Config]),
Config;
_Error ->
Config = mnesia_test_lib:default_config(),
mnesia_test_lib:log("<>WARNING<> Using default config: ~w~n", [Config]),
Config
end.
%% Write new default config file
write_config(Config) when is_list(Config) ->
Fname = config_fname(),
{ok, Fd} = file:open(Fname, write),
write_list(Fd, Config),
file:close(Fd).
write_list(Fd, [H | T]) ->
ok = io:format(Fd, "~p.~n",[H]),
write_list(Fd, T);
write_list(_, []) ->
ok.
test_case_fname() ->
"mnesia_test_case_info".
%% Read name of test case
read_test_case() ->
Fname = test_case_fname(),
case file:open(Fname, [read]) of
{ok, Fd} ->
Res = io:read(Fd, []),
file:close(Fd),
case Res of
{ok, TestCase} ->
mnesia_test_lib:log("Using test case ~w from file ~s~n",
[TestCase, Fname]),
TestCase;
{error, _} ->
default_test_case(Fname)
end;
{error, _} ->
default_test_case(Fname)
end.
default_test_case(Fname) ->
TestCase = all,
mnesia_test_lib:log("<>WARNING<> Cannot read file ~s, "
"using default test case: ~w~n",
[Fname, TestCase]),
TestCase.
write_test_case(TestCase) ->
Fname = test_case_fname(),
{ok, Fd} = file:open(Fname, write),
ok = io:format(Fd, "~p.~n",[TestCase]),
file:close(Fd).
append_test_case_info(TestCase, TestCaseInfo) ->
Fname = test_case_fname(),
{ok, Fd} = file:open(Fname, [read, write]),
ok = io:format(Fd, "~p.~n",[TestCase]),
ok = io:format(Fd, "~p.~n",[TestCaseInfo]),
file:close(Fd),
TestCaseInfo.
%% Generate HTML pages from the test case structure
doc() ->
doc(suite).
doc(Case) ->
mnesia_test_lib:doc(resolve(Case)).
%% Display out the test case structure
struct() ->
struct(suite).
struct(Case) ->
mnesia_test_lib:struct([resolve(Case)]).
%% Shutdown all nodes with erlang:halt/0
shutdown() ->
mnesia_test_lib:shutdown().
%% Ping all nodes in config spec
ping() ->
Config = read_config(),
Nodes = mnesia_test_lib:select_nodes(all, Config, ?FILE, ?LINE),
[{N, net_adm:ping(N)} || N <- Nodes].
%% Slave start all nodes in config spec
start_nodes() ->
Config = read_config(),
Nodes = mnesia_test_lib:select_nodes(all, Config, ?FILE, ?LINE),
mnesia_test_lib:init_nodes(Nodes, ?FILE, ?LINE),
ping().
%% loop one testcase /suite until it fails
loop(Case) ->
loop_1(Case,-1,read_config()).
loop(M,F) when is_atom(F) ->
loop_1({M,F},-1,read_config());
loop(Case,N) when is_integer(N) ->
loop_1(Case, N,read_config()).
loop(M,F,N) when is_integer(N) ->
loop_1({M,F},N,read_config()).
loop_1(Case,N,Config) when N /= 0 ->
io:format("Loop test ~p ~n", [abs(N)]),
case ok_result(Res = t(Case,Config)) of
true ->
loop_1(Case,N-1,Config);
error ->
Res
end;
loop_1(_,_,_) ->
ok.
ok_result([{_T,{ok,_,_}}|R]) ->
ok_result(R);
ok_result([{_T,{TC,List}}|R]) when is_tuple(TC), is_list(List) ->
ok_result(List) andalso ok_result(R);
ok_result([]) -> true;
ok_result(_) -> error.