%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1997-2009. 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%
%%
-module(big).
-compile([export_all]).
compiler_1() -> ok.
-define(log(Format,Args),mnesia_test_lib:log(Format,Args,?FILE,?LINE)).
-define(warning(Format,Args),?log("<WARNING> " ++ Format,Args)).
-define(error(Format,Args),
mnesia_test_lib:note_error(Format,Args,?FILE,?LINE),
?log("<ERROR> " ++ Format,Args)).
-define(match(ExpectedRes,Expr),
fun() ->
AcTuAlReS = (catch (Expr)),
case AcTuAlReS of
ExpectedRes ->
?log("ok, result as expected: ~p~n",[AcTuAlReS]),
{success,AcTuAlReS};
_ ->
?error("actual result was: ~p~n",[AcTuAlReS]),
{fail,AcTuAlReS}
end
end()).
-define(match_inverse(NotExpectedRes,Expr),
fun() ->
AcTuAlReS = (catch (Expr)),
case AcTuAlReS of
NotExpectedRes ->
?error("actual result was: ~p~n",[AcTuAlReS]),
{fail,AcTuAlReS};
_ ->
?log("ok, result as expected: ~p~n",[AcTuAlReS]),
{success,AcTuAlReS}
end
end()).
-define(match_receive(ExpectedMsg),
?match(ExpectedMsg,mnesia_test_lib:pick_msg())).
%% ExpectedMsgs must be completely bound
-define(match_multi_receive(ExpectedMsgs),
fun() ->
TmPeXpCtEdMsGs = lists:sort(ExpectedMsgs),
?match(TmPeXpCtEdMsGs,
lists:sort(lists:map(fun(_) ->
mnesia_test_lib:pick_msg()
end,
TmPeXpCtEdMsGs)))
end()).
-define(setup(), mnesia_test_lib:setup(?FILE,?LINE)).
-define(start_activities(Nodes),
fun() ->
AcTiViTyPiDs =
lists:map(fun(Node) ->
spawn_link(Node,
mnesia_test_lib,
activity_evaluator,
[self()])
end,
Nodes),
?match_multi_receive(AcTiViTyPiDs)
end()).
-define(start_transactions(Pids),
?match_multi_receive(lists:map(fun(Pid) ->
Pid ! begin_trans,
{Pid,begin_trans}
end,
Pids))).
-define(acquire_nodes(N,Nodes),
mnesia_test_lib:acquire_nodes(N,Nodes,?FILE,?LINE)).
%%% Copyright (C) 1996, Ellemtel Telecommunications Systems Laboratories
%%% Author: Hakan Mattsson [email protected]
%%% Purpose: Evil usage of the API
%%%
%%% Invoke all functions in the API and try to cover all legal uses
%%% cases as well the illegal dito. This is a complement to the
%%% other more explicit test cases.
%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% show/0
%%%
%%% Prints out the complete test case structure
%%%
%%% show/1
%%%
%%% Prints out parts of the test case structure
%%%
%%% test/0
%%%
%%% Run the complete test suite.
%%% Reads Nodes from nodes.profile and starts them if neccessary.
%%% Kills Mnesia and wipes out the Mnesia directories as a starter.
%%%
%%% test/1
%%%
%%% Run parts of the test suite.
%%% Reads Nodes from nodes.profile and starts them if neccessary.
%%% Kills Mnesia and wipes out the Mnesia directories as a starter.
%%%
%%% test/2
%%%
%%% Run parts of the test suite on the given Nodes,
%%% assuming that the nodes are up and running.
%%% Kills Mnesia and wipes out the Mnesia directories as a starter.
%%%
%%% test/3
%%%
%%% Run parts of the test suite on permutations of the given Nodes,
%%% assuming that the nodes are up and running. Uses test/2.
%%% Kills Mnesia and wipes out the Mnesia directories as a starter.
%%%
%%% See the module mnesia_test_lib for further information.
%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
show() -> mnesia_test_lib:show([{?MODULE,all}]).
show(TestCases) -> mnesia_test_lib:show([{?MODULE,TestCases}]).
test() -> mnesia_test_lib:test([{?MODULE,all}]).
test(TestCases) -> mnesia_test_lib:test([{?MODULE,TestCases}]).
test(TestCases,Nodes) -> mnesia_test_lib:test([{?MODULE,TestCases}],Nodes).
test(TestCases,Nodes,Config) -> mnesia_test_lib:test([{?MODULE,TestCases}],Nodes,Config).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
old_all(suite) ->
[
system_info, table_info, error_description,
db_node_lifecycle, start_and_stop, transaction, checkpoint, backup,
table_lifecycle, replica_management, replica_location, index_lifecycle,
trans_access, dirty_access, table_sync, snmp_access, debug_support
].
trans_access(suite) ->
[ {mnesia_dirty_access_test,all} ].
dirty_access(suite) ->
[ {mnesia_trans_access_test,all} ].
%% Get meta info about Mnesia
system_info(suite) -> [];
system_info(Nodes) ->
?match(yes,mnesia:system_info(is_running)),
?match(Nodes,mnesia:system_info(db_nodes)),
?match(Nodes,mnesia:system_info(running_db_nodes)),
?match(true,mnesia:system_info(have_disc)),
?match(A when atom(A),mnesia:system_info(debug)),
?match(L when list(L),mnesia:system_info(directory)),
?match(L when list(L),mnesia:system_info(log_version)),
?match({_,_},mnesia:system_info(schema_version)),
?match(L when list(L),mnesia:system_info(tables)),
?match(L when list(L),mnesia:system_info(local_tables)),
?match(L when list(L),mnesia:system_info(held_locks)),
?match(L when list(L),mnesia:system_info(lock_queue)),
?match(L when list(L),mnesia:system_info(transactions)),
?match(I when integer(I),mnesia:system_info(transaction_failures)),
?match(I when integer(I),mnesia:system_info(transaction_commits)),
?match(I when integer(I),mnesia:system_info(transaction_restarts)),
?match(L when list(L),mnesia:system_info(checkpoints)),
?match(A when atom(A),mnesia:system_info(backup_module)),
?match(true,mnesia:system_info(auto_repair)),
?match({_,_},mnesia:system_info(dump_log_interval)),
?match(A when atom(A),mnesia:system_info(dump_log_update_in_place)),
?match(I when integer(I),mnesia:system_info(transaction_log_writes)),
?match({'EXIT',{aborted,badarg}},mnesia:system_info(ali_baba)),
done.
%% Get meta info about table
table_info(suite) -> [];
table_info(Nodes) ->
[Node1,Node2,Node3] = ?acquire_nodes(3,Nodes),
Tab = table_info,
Type = bag,
ValPos = 3,
Attrs = [k,v],
Arity = length(Attrs) +1,
Schema = [{name,Tab},{type,Type},{attributes,Attrs},{index,[ValPos]},
{disc_only_copies,[Node1]},{ram_copies,[Node2]},{disc_copies,[Node3]}],
?match({atomic,ok}, mnesia:create_table(Schema)),
Size = 10,
Keys = lists:seq(1,Size),
Records = [{Tab,A,7} || A <- Keys],
lists:foreach(fun(Rec) -> ?match(ok,mnesia:dirty_write(Rec)) end,Records),
?match(Mem when integer(Mem),mnesia:table_info(Tab,memory)),
?match(Size,mnesia:table_info(Tab,size)),
?match(Type,mnesia:table_info(Tab,type)),
?match([Node3],mnesia:table_info(Tab,disc_copies)),
?match([Node2],mnesia:table_info(Tab,ram_copies)),
?match([Node1],mnesia:table_info(Tab,disc_only_copies)),
Read = [Node1,Node2,Node3],
?match(true,lists:member(mnesia:table_info(Tab,where_to_read),Read)),
Write = lists:sort([Node1,Node2,Node3]),
?match(Write,lists:sort(mnesia:table_info(Tab,where_to_write))),
WriteLock = lists:sort([Node2,Node3]),
?match([ValPos],mnesia:table_info(Tab,index)),
?match(Arity,mnesia:table_info(Tab,arity)),
?match(Attrs,mnesia:table_info(Tab,attributes)),
?match({Tab,'_','_'},mnesia:table_info(Tab,wild_pattern)),
?match({atomic,Attrs}, mnesia:transaction(fun() ->
mnesia:table_info(Tab,attributes) end)),
done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Add and drop db nodes
db_node_lifecycle(suite) -> [];
db_node_lifecycle(Nodes) ->
[Node1,Node2] = ?acquire_nodes(2,Nodes),
Tab = db_node_lifecycle,
Schema = [{name,Tab},{ram_copies,[Node1,Node2]}],
?match({atomic,ok}, mnesia:create_table(Schema)),
?match({aborted,active}, rpc:call(Node1,mnesia,del_db_node,[Node2])),
?match([], mnesia_test_lib:stop_mnesia(Nodes)),
?match(ok, mnesia:delete_schema(Nodes)),
?match({error,_}, mnesia:create_schema(foo)),
?match({error,_}, mnesia:create_schema([foo])),
?match({error,_}, mnesia:create_schema([foo@bar])),
?match({error,_}, mnesia:start()),
?match(ok, mnesia:create_schema(Nodes)),
?match([],mnesia_test_lib:start_mnesia(Nodes)),
?match({atomic,ok}, rpc:call(Node1,mnesia,del_db_node,[Node2])),
?match({aborted,no_exists}, rpc:call(Node1,mnesia,del_db_node,[Node2])),
?match({aborted,no_exists}, rpc:call(Node1,mnesia,del_db_node,[foo])),
?match({aborted,no_exists}, rpc:call(Node1,mnesia,del_db_node,[foo@bar])),
?match([], mnesia_test_lib:stop_mnesia([Node2])),
?match(ok,mnesia:delete_schema([Node2])),
AddFun = fun() -> ?match({aborted,nested_transaction},
mnesia:add_db_node(Node2)), ok end,
?match({atomic,ok},rpc:call(Node1,mnesia,transaction,[AddFun])),
DelFun = fun() -> ?match({aborted,nested_transaction},
mnesia:del_db_node(Node2)), ok end,
?match({atomic,ok},rpc:call(Node1,mnesia,transaction,[DelFun])),
?match({atomic,ok}, rpc:call(Node1,mnesia,add_db_node,[Node2])),
?match({aborted,already_exists}, rpc:call(Node1,mnesia,add_db_node,[Node2])),
?match([],mnesia_test_lib:start_mnesia([Node2])),
?match({atomic,ok}, mnesia:create_table(Schema)),
done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Start and stop the system
start_and_stop(suite) -> [];
start_and_stop(Nodes) ->
[Node1] = ?acquire_nodes(1,Nodes),
?match(stopped, rpc:call(Node1,mnesia,stop,[])),
?match(stopped, rpc:call(Node1,mnesia,stop,[])),
?match({started,_}, rpc:call(Node1,mnesia,start,[])),
?match({started,_}, rpc:call(Node1,mnesia,start,[])),
?match(stopped, rpc:call(Node1,mnesia,stop,[])),
?match([],mnesia_test_lib:start_mnesia(Nodes)),
done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Checkpoints and backup management
checkpoint(suite) -> [];
checkpoint(Nodes) ->
OneNode = ?acquire_nodes(1,Nodes),
checkpoint(OneNode,Nodes),
TwoNodes = ?acquire_nodes(2,Nodes),
checkpoint(TwoNodes,Nodes).
checkpoint(TabNodes,Nodes) ->
[Node1] = ?acquire_nodes(1,TabNodes),
CreateTab = fun(Type,N,Ns) ->
Tab0 = lists:concat(["local_checkpoint_",Type,N]),
Tab = list_to_atom(Tab0),
Schema = [{name,Tab},{Type,Ns}],
?match({atomic,ok},mnesia:delete_table(Tab)),
?match({atomic,ok},mnesia:create_table(Schema)),
Tab
end,
CreateTabs = fun(Type) ->
CreateTab(Type,1,hd(TabNodes)),
CreateTab(Type,2,TabNodes),
CreateTab(Type,3,lists:last(TabNodes))
end,
Types = [ram_copies,disc_copies,disc_only_copies],
Tabs = lists:append(lists:map(CreateTabs,Types)),
Recs = lists:sort([{T,N,N} || T <- Tabs,N <- lists:seq(1,10)]),
lists:foreach(fun(R) -> ?match(ok,mnesia:dirty_write(R)) end,Recs),
CpName = a_checkpoint_name,
MinArgs = [{name,CpName},{min,Tabs},{allow_remote,false}],
?match({ok,CpName,[Node1]},
rpc:call(Node1,mnesia,activate_checkpoint,[MinArgs])),
?match(ok,rpc:call(Node1,mnesia,deactivate_checkpoint,[CpName])),
MaxArgs = [{name,CpName},{max,Tabs},{allow_remote,true}],
?match({ok,CpName,[Node1]},
rpc:call(Node1,mnesia,activate_checkpoint,[MaxArgs])),
?match(ok,rpc:call(Node1,mnesia,deactivate_checkpoint,[CpName])),
Args = [{name,CpName},{min,Tabs},{allow_remote,false}],
?match({ok,CpName,[Node1]},
rpc:call(Node1,mnesia,activate_checkpoint,[Args])),
Recs2 = lists:sort([{T,K,0} || {T,K,_} <- Recs]),
lists:foreach(fun(R) -> ?match(ok,mnesia:dirty_write(R)) end,Recs2),
?match({atomic,ok},rpc:call(Node1,mnesia,deactivate_checkpoint,[CpName])),
?match({error,no_exists},mnesia:deactivate_checkpoint(CpName)),
?match({error,badarg},mnesia:activate_checkpoint(foo)),
?match({error,badarg},mnesia:activate_checkpoint([{foo,foo}])),
?match({error,badarg},mnesia:activate_checkpoint([{max,foo}])),
?match({error,badarg},mnesia:activate_checkpoint([{min,foo}])),
?match({error,no_exists},mnesia:activate_checkpoint([{min,[foo@bar]}])),
?match({error,badarg},mnesia:activate_checkpoint([{allow_remote,foo}])),
Fun = fun(Tab) -> ?match({atomic,ok},mnesia:delete_table(Tab)) end,
lists:foreach(Fun,Tabs),
done.
backup(suite) ->
[
backup_schema, restore_schema, backup_checkpoint, restore_tables
].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Use and misuse transactions
transaction(suite) -> [];
transaction(Nodes) ->
[Node1] = ?acquire_nodes(1,Nodes),
?match({atomic,ali_baba}, mnesia:transaction(fun() -> ali_baba end)),
?match({aborted,_}, mnesia:transaction(no_fun)),
?match({aborted,_}, mnesia:transaction(?MODULE,no_fun,[foo])),
{success,[A,B,C,D,E,F,G,H]} = ?start_activities(lists:duplicate(8,Node1)),
?start_transactions([A,B,C,D,E,F,G,H]),
A ! fun() -> mnesia:abort(abort_bad_trans) end,
?match_receive({A,{aborted,abort_bad_trans}}),
B ! fun() -> 1 = 2 end,
?match_receive({B,{aborted,_}}),
C ! fun() -> throw(throw_bad_trans) end,
?match_receive({C,{aborted,{throw,throw_bad_trans}}}),
D ! fun() -> exit(exit_bad_trans) end,
?match_receive({D,{aborted,exit_bad_trans}}),
E ! fun() -> exit(normal) end,
?match_receive({E,{aborted,normal}}),
F ! fun() -> exit(abnormal) end,
?match_receive({F,{aborted,abnormal}}),
G ! fun() -> exit(G,abnormal) end,
?match_receive({'EXIT',G,abnormal}),
H ! fun() -> exit(H,kill) end,
?match_receive({'EXIT',H,killed}),
?match({atomic,ali_baba},
mnesia:transaction(fun() -> ali_baba end,infinity)),
?match({atomic,ali_baba},mnesia:transaction(fun() -> ali_baba end,1)),
?match({atomic,ali_baba},mnesia:transaction(fun() -> ali_baba end,0)),
?match({atomic,ali_baba},mnesia:transaction(fun() -> ali_baba end,-1)),
?match({atomic,ali_baba},mnesia:transaction(fun() -> ali_baba end,foo)),
Fun = fun() -> ?match({aborted,nested_transaction},
mnesia:transaction(fun() -> ok end)), ok end,
?match({atomic,ok},mnesia:transaction(Fun)),
done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Create and delete tables
%% Get meta info about table
replica_location(suite) -> [];
replica_location(Nodes) ->
[Node1,Node2,Node3] = ?acquire_nodes(3,Nodes),
Tab = replica_location,
%% Create three replicas
Schema = [{name,Tab},{disc_only_copies,[Node1]},
{ram_copies,[Node2]},{disc_copies,[Node3]}],
?match({atomic,ok}, mnesia:create_table(Schema)),
mnesia_test_lib:verify_replica_location(Tab,[Node1],[Node2],[Node3],Nodes),
%% Delete one replica
?match({atomic,ok}, mnesia:del_table_copy(Tab, Node2)),
mnesia_test_lib:verify_replica_location(Tab,[Node1],[],[Node3],Nodes),
%% Move one replica
?match({atomic,ok}, mnesia:move_table_copy(Tab, Node1, Node2)),
mnesia_test_lib:verify_replica_location(Tab,[Node2],[],[Node3],Nodes),
%% Change replica type
?match({atomic,ok}, mnesia:change_table_copy_type(Tab, Node2,ram_copies)),
mnesia_test_lib:verify_replica_location(Tab,[],[Node2],[Node3],Nodes),
done.
table_lifecycle(suite) -> [];
table_lifecycle(Nodes) ->
[Node1,Node2] = ?acquire_nodes(2,Nodes),
?match({atomic,ok}, mnesia:create_table([{type,bag},
{ram_copies,[Node1]},
{attributes,[rajtan,tajtan]},
{name,order_of_args}])),
?match([],mnesia:dirty_read({order_of_args,4711})),
?match({atomic,ok}, mnesia:create_table([{name,already_exists},
{ram_copies,[Node1]}])),
?match({aborted,already_exists},
mnesia:create_table([{name,already_exists},{ram_copies,[Node1]}])),
?match({aborted,not_a_db_node},
mnesia:create_table([{name,no_node},{ram_copies,[foo]}])),
?match({aborted,not_a_db_node},
mnesia:create_table([{name,no_host},{ram_copies,[foo@bar]}])),
?match({aborted,badarg},
mnesia:create_table([{name,zero_arity},{attributes,[]}])),
?match({aborted,badarg}, mnesia:create_table([])),
?match({aborted,badarg}, mnesia:create_table(atom)),
?match({aborted,badarg},
mnesia:create_table({cstruct,table_name_as_atom})),
?match({aborted,bad_type},
mnesia:create_table([{name,no_host},{ram_copies,foo}])),
?match({aborted,bad_type},
mnesia:create_table([{name,no_host},{disc_only_copies,foo}])),
?match({aborted,bad_type},
mnesia:create_table([{name,no_host},{disc_copies,foo}])),
CreateFun =
fun() -> ?match({aborted,nested_transaction},
mnesia:create_table([{name,nested_trans}])), ok
end,
?match({atomic,ok},mnesia:transaction(CreateFun)),
?match({atomic,ok},mnesia:create_table([{name,remote_tab},
{ram_copies,[Node2]}])),
?match({atomic,ok}, mnesia:create_table([{name,a_brand_new_tab},
{ram_copies,[Node1]}])),
?match([],mnesia:dirty_read({a_brand_new_tab,4711})),
?match({atomic,ok}, mnesia:delete_table(a_brand_new_tab)),
?match({'EXIT',{aborted,no_exists}},
mnesia:dirty_read({a_brand_new_tab,4711})),
?match({aborted,no_exists}, mnesia:delete_table(a_brand_new_tab)),
?match({aborted,badarg}, mnesia:create_table([])),
?match({atomic,ok}, mnesia:create_table([{name,nested_del_trans},
{ram_copies,[Node1]}])),
DeleteFun = fun() -> ?match({aborted,nested_transaction},
mnesia:delete_table(nested_del_trans)), ok end,
?match({atomic,ok}, mnesia:transaction(DeleteFun)),
?match({aborted,bad_type},
mnesia:create_table([{name,create_with_index},{index,2}])),
?match({aborted,bad_index},
mnesia:create_table([{name,create_with_index},{index,[-1]}])),
?match({aborted,bad_index},
mnesia:create_table([{name,create_with_index},{index,[0]}])),
?match({aborted,bad_index},
mnesia:create_table([{name,create_with_index},{index,[1]}])),
?match({aborted,bad_index},
mnesia:create_table([{name,create_with_index},{index,[2]}])),
?match({atomic,ok},
mnesia:create_table([{name,create_with_index},{index,[3]},
{ram_copies,[Node1]}])),
done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Add, drop and move replicas, change storage types
%% Change table layout (only arity change supported)
replica_management(suite) -> [];
replica_management(Nodes) ->
%% add_table_copy/3, del_table_copy/2, move_table_copy/3,
%% change_table_copy_type/3, transform_table/3
[Node1,Node2,Node3] = ?acquire_nodes(3,Nodes),
Tab = replica_management,
Attrs = [k,v],
%%
%% Add, delete and change replicas
%%
?match({atomic,ok},
mnesia:create_table([{name,Tab},{attributes,Attrs},
{ram_copies,[Node1]}])),
mnesia_test_lib:verify_replica_location(Tab,[],[Node1],[],Nodes),
%% R - -
?match({aborted,combine_error},
mnesia:add_table_copy(Tab, Node2, disc_copies)),
?match({aborted,combine_error},
mnesia:change_table_copy_type(Tab, Node1, disc_copies)),
?match({atomic,ok}, mnesia:del_table_copy(Tab,Node1)),
mnesia_test_lib:verify_replica_location(Tab,[],[],[],Nodes),
%% - - -
?match({aborted,no_exists},
mnesia:add_table_copy(Tab, Node3, ram_copies)),
?match({atomic,ok}, mnesia:create_table([{name,Tab},
{attributes,Attrs},
{disc_copies,[Node1]}])),
mnesia_test_lib:verify_replica_location(Tab,[],[],[Node1],Nodes),
%% D - -
?match({aborted,badarg},
mnesia:add_table_copy(Tab, Node2, bad_storage_type)),
?match({atomic,ok}, mnesia:add_table_copy(Tab, Node2, disc_only_copies)),
mnesia_test_lib:verify_replica_location(Tab,[Node2],[],[Node1],Nodes),
%% D DO -
?match({atomic,ok}, mnesia:add_table_copy(Tab, Node3, ram_copies)),
mnesia_test_lib:verify_replica_location(Tab,[Node2],[Node3],[Node1],Nodes),
%% D DO R
?match({atomic,ok},
mnesia:change_table_copy_type(Tab, Node1, disc_only_copies)),
mnesia_test_lib:verify_replica_location(Tab,[Node1,Node2],[Node3],[],Nodes),
%% DO DO R
?match({aborted,already_exists},
mnesia:add_table_copy(Tab, Node3, ram_copies)),
?match({atomic,ok}, mnesia:del_table_copy(Tab, Node1)),
mnesia_test_lib:verify_replica_location(Tab,[Node2],[Node3],[],Nodes),
%% - DO R
?match({aborted,_}, mnesia:del_table_copy(Tab, Node1)),
?match({atomic,ok}, mnesia:add_table_copy(Tab, Node1, disc_copies)),
mnesia_test_lib:verify_replica_location(Tab,[Node2],[Node3],[Node1],Nodes),
%% D DO R
?match({atomic,ok},
mnesia:change_table_copy_type(Tab, Node3, disc_only_copies)),
mnesia_test_lib:verify_replica_location(Tab,[Node2,Node3],[],[Node1],Nodes),
%% D DO DO
?match({atomic,ok}, mnesia:del_table_copy(Tab, Node2)),
mnesia_test_lib:verify_replica_location(Tab,[Node3],[],[Node1],Nodes),
%% D - DO
?match({aborted,already_exists},
mnesia:change_table_copy_type(Tab, Node1, disc_copies)),
%%
%% Move replica
%%
?match({atomic,ok}, mnesia:move_table_copy(Tab,Node1,Node2)),
mnesia_test_lib:verify_replica_location(Tab,[Node3],[],[Node2],Nodes),
%% - D DO
?match({aborted,_}, mnesia:move_table_copy(Tab,Node1,Node2)),
?match([], mnesia_test_lib:stop_mnesia([Node3])),
mnesia_test_lib:verify_replica_location(Tab,[Node3],[],[Node2],
Nodes -- [Node3]),
%% - D DO
?match({atomic,ok}, mnesia:move_table_copy(Tab,Node3,Node1)),
mnesia_test_lib:verify_replica_location(Tab,[Node1],[],[Node2],
Nodes -- [Node3]),
%% DO D -
?match([],mnesia_test_lib:start_mnesia([Node3])),
mnesia_test_lib:verify_replica_location(Tab,[Node1],[],[Node2],Nodes),
%% DO D -
%%
%% Transformer
%%
NewAttrs = Attrs ++ [extra],
Transformer =
fun(Rec) -> list_to_tuple(tuple_to_list(Rec) ++ [initial_value]) end,
?match({atomic,ok}, mnesia:transform_table(Tab, Transformer,NewAttrs)),
?match({atomic,ok}, mnesia:transform_table(Tab, fun(R) -> R end, Attrs)),
?match({aborted,bad_type}, mnesia:transform_table(Tab, Transformer, 0)),
?match({aborted,bad_type}, mnesia:transform_table(Tab, Transformer, -1)),
?match({aborted,badarg}, mnesia:transform_table(Tab, Transformer, [])),
?match({aborted,bad_type}, mnesia:transform_table(Tab, no_fun, NewAttrs)),
NestedFun =
fun() ->
?match({aborted,_},
mnesia:move_table_copy(Tab,Node1,Node2)),
?match({aborted,_},
mnesia:add_table_copy(Tab,Node1,ram_copies)),
?match({aborted,_},
mnesia:del_table_copy(Tab,Node1)),
T = fun(_) -> 4711 end,
?match({aborted,_},
mnesia:transform_table(Tab,Transformer, T)),
ok
end,
?match({atomic,ok},mnesia:transaction(NestedFun)),
done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Add and drop indecies
index_lifecycle(suite) ->
[ add_table_index, create_live_table_index, del_table_index ].
%% Add table index
add_table_index(suite) -> [];
add_table_index(Nodes) ->
[Node1] = ?acquire_nodes(1,Nodes),
Tab = add_table_index,
Schema = [{name,Tab},{attributes,[k,v]},{ram_copies,[Node1]}],
?match({atomic,ok}, mnesia:create_table(Schema)),
ValPos = 3,
BadValPos = ValPos + 1,
?match({aborted,bad_index}, mnesia:add_table_index(Tab,BadValPos)),
?match({aborted,bad_index}, mnesia:add_table_index(Tab,2)),
?match({aborted,bad_index}, mnesia:add_table_index(Tab,1)),
?match({aborted,bad_index}, mnesia:add_table_index(Tab,0)),
?match({aborted,bad_index}, mnesia:add_table_index(Tab,-1)),
?match({atomic,ok}, mnesia:add_table_index(Tab,ValPos)),
?match({aborted,already_exists}, mnesia:add_table_index(Tab,ValPos)),
NestedFun = fun() ->
?match({aborted,nested_transaction},
mnesia:add_table_index(Tab,ValPos)),
ok
end,
?match({atomic,ok},mnesia:transaction(NestedFun)),
done.
create_live_table_index(suite) -> [];
create_live_table_index(Nodes) ->
[Node1] = ?acquire_nodes(1,Nodes),
Tab = create_live_table_index,
Schema = [{name,Tab},{attributes,[k,v]},{ram_copies,[Node1]}],
?match({atomic,ok}, mnesia:create_table(Schema)),
ValPos = 3,
mnesia:dirty_write({Tab,1,2}),
Fun = fun() ->
?match(ok, mnesia:write({Tab,2,2})),
ok
end,
?match({atomic,ok},mnesia:transaction(Fun)),
?match({atomic,ok}, mnesia:add_table_index(Tab,ValPos)),
done.
%% Drop table index
del_table_index(suite) ->[];
del_table_index(Nodes) ->
[Node1] = ?acquire_nodes(1,Nodes),
Tab = del_table_index,
Schema = [{name,Tab},{attributes,[k,v]},{ram_copies,[Node1]}],
?match({atomic,ok}, mnesia:create_table(Schema)),
ValPos = 3,
BadValPos = ValPos + 1,
?match({atomic,ok}, mnesia:add_table_index(Tab,ValPos)),
?match({aborted,no_exists},
mnesia:del_table_index(Tab,BadValPos)),
?match({atomic,ok}, mnesia:del_table_index(Tab,ValPos)),
NestedFun =
fun() ->
?match({aborted,nested_transaction},
mnesia:del_table_index(Tab,ValPos)),
ok
end,
?match({atomic,ok},mnesia:transaction(NestedFun)),
done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Syncronize table with log or disc
%%
table_sync(suite) ->
[ dump_tables, dump_log, change_dump_log_config, wait_for_tables, force_load_table ].
%% Dump ram tables on disc
dump_tables(suite) -> [];
dump_tables(Nodes) ->
[Node1,Node2] = ?acquire_nodes(2,Nodes),
Tab = dump_tables,
Schema = [{name,Tab},{attributes,[k,v]},{ram_copies,[Node2]}],
?match({atomic,ok}, mnesia:create_table(Schema)),
%% Dump 10 records
Size = 10,
Keys = lists:seq(1,Size),
Records = [{Tab,A,7} || A <- Keys],
lists:foreach(fun(Rec) -> ?match(ok,mnesia:dirty_write(Rec)) end,Records),
AllKeys = fun() -> lists:sort(mnesia:all_keys(Tab)) end,
?match({atomic,Keys}, mnesia:transaction(AllKeys)),
?match(ok, mnesia:dump_tables(Tab)),
%% Delete one record
?match(ok,mnesia:dirty_delete({Tab,5})),
Keys2 = lists:delete(5,Keys),
?match({atomic,Keys2}, mnesia:transaction(AllKeys)),
%% Check that all 10 is restored after a stop
?match([], mnesia_test_lib:stop_mnesia([Node1,Node2])),
?match([],mnesia_test_lib:start_mnesia([Node1,Node2])),
?match(ok,mnesia:wait_for_tables([Tab],infinity)),
?match({atomic,Keys}, mnesia:transaction(AllKeys)),
?match(ok, mnesia:dump_tables([foo])),
done.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Make Mnesia table accessible via SNMP
snmp_access(suite) ->
[
snmp_open_table, snmp_close_table,
snmp_get_row, snmp_get_next_index, snmp_get_mnesia_key
].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Check that the debug support has not decayed
debug_support(suite) ->
[ info, schema, schema, kill, lkill ].