1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 1997-2013. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: %%
   21: -module(mnesia_config_test).
   22: -author('hakan@erix.ericsson.se').
   23: 
   24: -include("mnesia_test_lib.hrl").
   25:  
   26: -record(test_table,{i,a1,a2,a3}).
   27: -record(test_table2,{i, b}).
   28: 
   29: -export([
   30: 	all/0,groups/0,init_per_group/2,end_per_group/2,
   31: 	 access_module/1,
   32: 	 auto_repair/1,
   33: 	 backup_module/1,
   34: 	 debug/1,
   35: 	 dir/1,
   36: 	 dump_log_load_regulation/1,
   37: 	
   38: 	 dump_log_update_in_place/1,
   39: 	 event_module/1,
   40: 	 ignore_fallback_at_startup/1,
   41: 	 inconsistent_database/1,
   42: 	 max_wait_for_decision/1,
   43: 	 send_compressed/1,
   44: 
   45: 	 app_test/1,
   46: 	
   47: 	 schema_merge/1,
   48: 	 unknown_config/1,
   49: 
   50: 	 dump_log_time_threshold/1,
   51: 	 dump_log_write_threshold/1,
   52: 	 
   53: 	 start_one_disc_full_then_one_disc_less/1,
   54: 	 start_first_one_disc_less_then_one_disc_full/1,
   55: 	 start_first_one_disc_less_then_two_more_disc_less/1,
   56: 	 schema_location_and_extra_db_nodes_combinations/1,
   57: 	 table_load_to_disc_less_nodes/1,
   58: 	
   59: 	 dynamic_basic/1,
   60: 	 dynamic_ext/1,
   61: 	 dynamic_bad/1,
   62: 
   63: 	 init_per_testcase/2,
   64: 	 end_per_testcase/2,
   65: 	 c_nodes/0
   66: 	]).
   67: 
   68: -export([check_logs/1]).
   69: 
   70: -define(init(N, Config),
   71: 	mnesia_test_lib:prepare_test_case([{init_test_case, [mnesia]},
   72: 					   delete_schema,
   73: 					   {reload_appls, [mnesia]}],
   74: 					  N, Config, ?FILE, ?LINE)).
   75: -define(acquire(N, Config),
   76: 	mnesia_test_lib:prepare_test_case([{init_test_case, [mnesia]},
   77: 					   delete_schema,
   78: 					   {reload_appls, [mnesia]},
   79: 					   create_schema,
   80: 					   {start_appls, [mnesia]}],
   81: 					  N, Config, ?FILE, ?LINE)).
   82: -define(acquire_schema(N, Config),
   83: 	mnesia_test_lib:prepare_test_case([{init_test_case, [mnesia]},
   84: 					    delete_schema,
   85: 					    {reload_appls, [mnesia]},
   86: 					    create_schema],
   87: 					  N, Config, ?FILE, ?LINE)).
   88: -define(cleanup(N, Config),
   89: 	mnesia_test_lib:prepare_test_case([{reload_appls, [mnesia]}],
   90: 					  N, Config, ?FILE, ?LINE)).
   91: -define(trans(Fun),
   92: 	?match({atomic, ok}, mnesia:transaction(Fun))).
   93: 
   94: init_per_testcase(Func, Conf) ->
   95:     mnesia_test_lib:init_per_testcase(Func, Conf).
   96: 
   97: end_per_testcase(Func, Conf) ->
   98:     mnesia_test_lib:end_per_testcase(Func, Conf).
   99: 
  100: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  101: 
  102: 
  103: all() -> 
  104:     [access_module, auto_repair, backup_module, debug, dir,
  105:      dump_log_load_regulation, {group, dump_log_thresholds},
  106:      dump_log_update_in_place,
  107:      event_module, ignore_fallback_at_startup,
  108:      inconsistent_database, max_wait_for_decision,
  109:      send_compressed, app_test, {group, schema_config},
  110:      unknown_config].
  111: 
  112: groups() -> 
  113:     [{dump_log_thresholds, [],
  114:       [dump_log_time_threshold, dump_log_write_threshold]},
  115:      {schema_config, [],
  116:       [start_one_disc_full_then_one_disc_less,
  117:        start_first_one_disc_less_then_one_disc_full,
  118:        start_first_one_disc_less_then_two_more_disc_less,
  119:        schema_location_and_extra_db_nodes_combinations,
  120:        table_load_to_disc_less_nodes, schema_merge,
  121:        {group, dynamic_connect}]},
  122:      {dynamic_connect, [],
  123:       [dynamic_basic, dynamic_ext, dynamic_bad]}].
  124: 
  125: init_per_group(_GroupName, Config) ->
  126:     Config.
  127: 
  128: end_per_group(_GroupName, Config) ->
  129:     Config.
  130: 
  131: 
  132: 
  133: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  134: 
  135: access_module(doc) ->
  136:     ["Replace the activity access module with another module and ",
  137:      "use it to read and write to some alternate table storage"];
  138: access_module(suite) -> [];
  139: access_module(Config) when is_list(Config) ->
  140:     Nodes = ?acquire_schema(1, Config),
  141:     ?match(ok, mnesia:start([{access_module, mnesia_frag}])),
  142: 
  143:     ?match(mnesia_frag, mnesia:system_info(access_module)),
  144: 
  145:     access_tab(ram_copies, Nodes),
  146:     case mnesia_test_lib:diskless(Config) of
  147: 	true -> skip;
  148: 	false -> 
  149: 	    access_tab(disc_copies, Nodes)
  150: 		,  access_tab(disc_only_copies, Nodes)
  151:     end,
  152: 
  153:     ?verify_mnesia(Nodes, []),
  154:     ?cleanup(1, Config).
  155: 
  156: access_tab(Storage, Nodes) ->
  157:     Tab = list_to_atom(lists:concat([access_tab_, Storage])),
  158:     RecName = some_access,
  159:     Attr = val,
  160:     TabDef = [{Storage, Nodes},
  161: 	      {type, bag},
  162: 	      {index, [Attr]},
  163: 	      {record_name, RecName}],
  164:     ?match({atomic,ok}, mnesia:create_table(Tab, TabDef)),
  165: 
  166:     Activity = fun(Kind) ->
  167: 		       A = [Kind, Tab, RecName, Attr, Nodes],
  168: 		       io:format("kind: ~w, storage: ~w~n", [Kind, Storage]),
  169: 		       mnesia:activity(Kind, fun do_access/5, A)
  170: 	       end,
  171:     ModActivity = fun(Kind, M) ->
  172: 			  io:format("kind: ~w, storage: ~w. module: ~w~n",
  173: 				    [Kind, Storage, M]),
  174: 			  A = [Kind, Tab, RecName, Attr, Nodes],
  175: 			  mnesia:activity(Kind, fun do_access/5, A, M)
  176: 	       end,
  177:     ?match(ok, Activity(transaction)),
  178:     ?match(ok, Activity({transaction, 47})),
  179:     ?match(ok, ModActivity(transaction, mnesia)),
  180:     ?match(ok, ModActivity(transaction, mnesia_frag)),
  181:     
  182:     ?match(ok, Activity(async_dirty)),
  183:     ?match(ok, Activity(sync_dirty)),
  184:     case Storage of
  185: 	ram_copies ->
  186: 	    ?match(ok, Activity(ets));
  187: 	_ ->
  188: 	    ignore
  189:     end.
  190: 
  191: do_access(Kind, Tab, RecName, Attr, Nodes) ->
  192:     Tens = lists:sort([{RecName, 1, 10}, {RecName, 3, 10}]),
  193:     {OptNodes, OptTens} = 
  194: 	case Kind of
  195: 	    transaction -> {Nodes, Tens};
  196: 	    {transaction, _} -> {Nodes, Tens};
  197: 	    async_dirty -> {[], Tens};
  198: 	    sync_dirty -> {[], Tens};
  199: 	    ets -> {[], []}
  200: 	end,
  201:     ?match(RecName, mnesia:table_info(Tab, record_name)),
  202:     
  203:     ?match(ok, mnesia:write(Tab, {RecName, 1, 10}, write)),
  204:     ?match(ok, mnesia:write(Tab, {RecName, 2, 20}, sticky_write)),
  205:     ?match(ok, mnesia:write(Tab, {RecName, 2, 21}, sticky_write)),
  206:     ?match(ok, mnesia:write(Tab, {RecName, 2, 22}, write)),
  207:     ?match(ok, mnesia:write(Tab, {RecName, 3, 10}, write)),
  208: 
  209:     Twos = [{RecName, 2, 20}, {RecName, 2, 21}, {RecName, 2, 22}],
  210:     ?match(Twos, lists:sort(mnesia:read(Tab, 2, read))),
  211:     
  212:     ?match(ok, mnesia:delete_object(Tab, {RecName, 2, 21}, sticky_write)),
  213: 
  214:     TenPat = {RecName, '_', 10},
  215:     ?match(Tens, lists:sort(mnesia:match_object(Tab, TenPat, read))),
  216:     ?match(OptTens, lists:sort(mnesia:index_match_object(Tab, TenPat, Attr, read) )),
  217:     ?match(OptTens, lists:sort(mnesia:index_read(Tab, 10, Attr))),
  218:     Keys = [1, 2, 3],
  219:     ?match(Keys, lists:sort(mnesia:all_keys(Tab))),
  220: 
  221:     First = mnesia:first(Tab),
  222:     Mid   = mnesia:next(Tab, First),
  223:     Last  = mnesia:next(Tab, Mid),
  224:     ?match('$end_of_table', mnesia:next(Tab, Last)),
  225:     ?match(Keys, lists:sort([First,Mid,Last])),
  226: 
  227:     %% For set and bag these last, prev works as first and next
  228:     First2 = mnesia:last(Tab),
  229:     Mid2   = mnesia:prev(Tab, First2),
  230:     Last2  = mnesia:prev(Tab, Mid2),
  231:     ?match('$end_of_table', mnesia:prev(Tab, Last2)),
  232:     ?match(Keys, lists:sort([First2,Mid2,Last2])),
  233: 
  234:     ?match([ok, ok, ok], [mnesia:delete(Tab, K, write) || K <- Keys]),
  235:     W = wild_pattern,
  236:     ?match([], mnesia:match_object(Tab, mnesia:table_info(Tab, W), read)),
  237:     ?log("Safe fixed ~p~n", [catch ets:info(Tab, safe_fixed)]),
  238:     ?log("Fixed ~p ~n", [catch ets:info(Tab, fixed)]),
  239:     
  240:     ?match(OptNodes, mnesia:lock({global, some_lock_item, Nodes}, write)),
  241:     ?match(OptNodes, mnesia:lock({global, some_lock_item, Nodes}, read)),
  242:     ?match(OptNodes, mnesia:lock({table, Tab}, read)),
  243:     ?match(OptNodes, mnesia:lock({table, Tab}, write)),
  244:     
  245:     ok.
  246: 
  247: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  248: auto_repair(doc) ->
  249:     ["Try the auto_repair mechanism on the various disk_logs and dets files.",
  250:      "",
  251:      "The case tests both normal values of the parameter, and also",
  252:      "one crazy value.",
  253:      "The test of the real auto_repair functionality is made in the",
  254:      "dets suite"
  255:     ];
  256: auto_repair(suite) -> [];
  257: auto_repair(Config) when is_list(Config) ->
  258:     ?init(1, Config),
  259:     ?match(ok, mnesia:start()),			% Check default true
  260:     ?match(true, mnesia:system_info(auto_repair)),
  261:     ?match(stopped, mnesia:stop()),
  262:     ?match(ok, mnesia:start([{auto_repair, true}])),
  263:     ?match(true, mnesia:system_info(auto_repair)),
  264:     ?match(stopped, mnesia:stop()),
  265:     ?match(ok, mnesia:start([{auto_repair, false}])),
  266:     ?match(false, mnesia:system_info(auto_repair)),
  267:     ?match(stopped, mnesia:stop()),
  268:     ?match({error, {bad_type, auto_repair, your_mama}},
  269: 	   mnesia:start([{auto_repair, your_mama}])),
  270:      ?match(stopped, mnesia:stop()),
  271:     ?cleanup(1, Config),
  272:     ok.
  273: 
  274: 
  275: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  276: 
  277: backup_module(doc) ->
  278:     ["Replace the backup module with another module and use it to",
  279:      "read and write to an alternate backup media, e.g stored in",
  280:      "the internal state of a simple process."];
  281: backup_module(suite) -> [];
  282: backup_module(Config) when is_list(Config) ->
  283:     Nodes = ?acquire_schema(1, Config),
  284:     ?match(ok, mnesia:start([{backup_module, mnesia_config_backup}])),
  285:     ?match({atomic,ok},
  286: 	   mnesia:create_table(test_table,
  287: 			       [{disc_copies, Nodes},
  288: 				{attributes,
  289: 				 record_info(fields,test_table)}])),
  290:     
  291:     ?match({atomic,ok},
  292: 	   mnesia:create_table(test_table2,
  293: 			       [{disc_copies, Nodes},
  294: 				{attributes,
  295: 				 record_info(fields,test_table2)}])),
  296:     %% Write in test table 
  297:     ?trans(fun() -> mnesia:write(#test_table{i=1}) end),
  298:     ?trans(fun() -> mnesia:write(#test_table{i=2}) end),
  299:     
  300:     %% Write in test table 2
  301:     ?trans(fun() -> mnesia:write(#test_table2{i=3}) end),
  302:     ?trans(fun() -> mnesia:write(#test_table2{i=4}) end),
  303:     mnesia_test_lib:sync_tables(Nodes, [test_table, test_table2]),
  304:     
  305:     File = whow,
  306:     %% Now make a backup
  307:     ?match(ok, mnesia:backup(File)),
  308: 
  309:     ?match(ok, mnesia:install_fallback(File)),
  310:     
  311:     %% Now add things
  312:     ?trans(fun() -> mnesia:write(#test_table{i=2.5}) end),
  313:     ?trans(fun() -> mnesia:write(#test_table2{i=3.5}) end),
  314: 
  315:     mnesia_test_lib:kill_mnesia(Nodes),
  316:     receive after 2000 -> ok end,
  317:     ?match([], mnesia_test_lib:start_mnesia(Nodes, [test_table, test_table2])),
  318: 
  319:     %% Now check newly started tables
  320:     ?match({atomic, [1,2]}, 
  321: 	   mnesia:transaction(fun() -> lists:sort(mnesia:all_keys(test_table)) end)),
  322:     ?match({atomic, [3,4]}, 
  323: 	   mnesia:transaction(fun() -> lists:sort(mnesia:all_keys(test_table2)) end)),
  324:     
  325:     file:delete(File),
  326:     ?verify_mnesia(Nodes, []),
  327:     ?cleanup(1, Config),
  328:     ok.
  329: 
  330: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  331: debug(doc) ->
  332:     ["Try out the four debug levels and ensure that the",
  333:     "expected events are generated."];
  334: debug(suite) -> [];
  335: debug(Config) when is_list(Config) ->
  336:     Nodes = ?init(1, Config),
  337:     case application:get_env(mnesia,debug) of
  338: 	undefined ->
  339: 	    ?match(none, mnesia:system_info(debug));
  340: 	{ok, false} ->
  341: 	    ?match(none, mnesia:system_info(debug));
  342: 	{ok, true} ->
  343: 	    ?match(debug, mnesia:system_info(debug));
  344: 	{ok, Env} ->
  345: 	    ?match(Env, mnesia:system_info(debug))
  346:     end,
  347: 
  348:     ?match(ok, mnesia:start([{debug, verbose}])),
  349:     ?match(verbose, mnesia:system_info(debug)),
  350:     mnesia_test_lib:kill_mnesia(Nodes),
  351:     receive after 2000 -> ok end,
  352: 
  353:     ?match(ok, mnesia:start([{debug, debug}])),
  354:     ?match(debug, mnesia:system_info(debug)),
  355:     mnesia_test_lib:kill_mnesia(Nodes),
  356:     receive after 2000 -> ok end,
  357: 
  358:     ?match(ok, mnesia:start([{debug, trace}])),
  359:     ?match(trace, mnesia:system_info(debug)),
  360:     mnesia_test_lib:kill_mnesia(Nodes),
  361:     receive after 2000 -> ok end,
  362: 
  363:     ?match(ok, mnesia:start([{debug, true}])),
  364:     ?match(debug, mnesia:system_info(debug)),
  365:     mnesia_test_lib:kill_mnesia(Nodes),
  366:     receive after 2000 -> ok end,
  367: 
  368:     ?match(ok, mnesia:start([{debug, false}])),
  369:     ?match(none, mnesia:system_info(debug)),
  370: 
  371:     ?verify_mnesia(Nodes, []),
  372:     ?cleanup(1, Config),
  373:     ok.
  374: 
  375: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  376: dir(doc) ->
  377:     ["Try to use alternate Mnesia directories"];
  378: dir(suite) -> [];
  379: dir(Config) when is_list(Config) ->
  380:     Nodes = ?init(1, Config),
  381: 
  382:     ?match(ok, mnesia:start([{dir, tuff}])),
  383:     Dir = filename:join([element(2, file:get_cwd()), "tuff"]),
  384:     ?match(Dir, mnesia:system_info(directory)),
  385:     mnesia_test_lib:kill_mnesia(Nodes),
  386:  
  387:     ?cleanup(1, Config),
  388:     ok.
  389: 
  390: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  391: dump_log_update_in_place(doc) ->
  392:     ["Change the update in place policy for the transaction log dumper."];
  393: dump_log_update_in_place(suite) -> [];
  394: dump_log_update_in_place(Config) when is_list(Config) ->
  395:     Nodes = ?acquire(1, Config),
  396:     ?match(true, mnesia:system_info(dump_log_update_in_place)),
  397:     ?match({atomic,ok},
  398: 	   mnesia:create_table(test_table,
  399: 			       [{disc_copies, Nodes},
  400: 				{attributes,
  401: 				 record_info(fields,test_table)}])),
  402:     
  403:     mnesia_test_lib:kill_mnesia(Nodes),
  404:     receive after 2000 -> ok end,
  405:     
  406:     ?match(ok, mnesia:start([{dump_log_update_in_place, false}])),
  407:     ?match(false, mnesia:system_info(dump_log_update_in_place)),
  408: 
  409:     mnesia_test_lib:sync_tables(Nodes, [schema, test_table]),
  410: 
  411:     %% Now provoke some log dumps
  412: 
  413:     L = lists:map(
  414: 	  fun(Num) ->
  415: 		  %% Write something on one end ...
  416: 		  mnesia:transaction(
  417: 		    fun() ->
  418: 			    mnesia:write(#test_table{i=Num}) end
  419: 		   ) end,
  420: 	  lists:seq(1, 110)),
  421:     
  422:     L2 = lists:duplicate(110, {atomic, ok}),
  423: 
  424:     %% If this fails then some of the 110 writes above failed
  425:     ?match(true, L==L2),
  426:     if  L==L2 -> ok;
  427: 	true -> 
  428: 	    ?verbose("***** List1 len: ~p, List2 len: ~p~n",
  429: 		      [length(L), length(L2)]),
  430: 	    ?verbose("L: ~p~nL2:~p~n", [L, L2])
  431:     end,
  432:     
  433:     %% If we still can write, then Mnesia is probably alive
  434:     ?trans(fun() -> mnesia:write(#test_table{i=115}) end),
  435:     
  436:     ?verify_mnesia(Nodes, []),
  437:     ?cleanup(1, Config),
  438:     ok.
  439: 
  440: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  441: 
  442: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  443: dump_log_write_threshold(doc)->
  444:     ["This test case must be rewritten.",
  445:      "Dump logs are tested by doing transactions, then killing Mnesia and ",
  446:      "then examining the table data files and see if they are correct.",
  447:      "The test_table is used as a counter, test_table. is stepped once ",
  448:      "for each transaction."];
  449: dump_log_write_threshold(suite)->[];
  450: dump_log_write_threshold(Config) when is_list(Config) ->
  451:     [N1] = ?acquire_schema(1, Config),
  452: 
  453:     Threshold = 3,
  454:     ?match(ok,mnesia:start([{dump_log_write_threshold, Threshold}])),
  455: 
  456:     ?match({atomic,ok},
  457: 	   mnesia:create_table(test_table,
  458: 			       [{disc_copies, [N1]},
  459: 				{attributes,
  460: 				 record_info(fields,test_table)}])),
  461:     ?match(dumped, mnesia:dump_log()),
  462:     
  463:     ?match(ok, do_trans(2)),				% Shall not have dumped
  464:     check_logs(0),
  465:     
  466:     ?match(ok, do_trans(Threshold - 2)),			% Trigger a dump
  467:     receive after 1000 -> ok end,
  468:     check_logs(Threshold),
  469: 
  470:     
  471:     ?match(ok, do_trans(Threshold - 1)),   
  472:     ?match(dumped, mnesia:dump_log()),   %% This should trigger ets2dcd dump
  473:     check_logs(0),                       %% and leave no dcl file
  474:     
  475:     ?match(stopped, mnesia:stop()),
  476: 
  477:     %% Check bad threshold value
  478:     ?match({error,{bad_type,dump_log_write_threshold,0}},
  479: 	   mnesia:start([{dump_log_write_threshold,0}])),
  480: 
  481:     ?verify_mnesia([], [N1]),
  482:     ?cleanup(1, Config),
  483:     ok.
  484: 
  485: 
  486: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  487: dump_log_time_threshold(doc)->
  488:     ["See doc on above."];
  489: dump_log_time_threshold(suite)->[];
  490: dump_log_time_threshold(Config) when is_list(Config) ->
  491:     Nodes = ?acquire_schema(1, Config),
  492:     Time = 4000,
  493: 
  494:     %% Check bad threshold value
  495:     ?match({error,{bad_type,dump_log_time_threshold,0}},
  496: 	   mnesia:start([{dump_log_time_threshold,0}])),
  497:     
  498:     
  499:     ?match(ok,mnesia:start([{dump_log_write_threshold,100},
  500: 			    {dump_log_time_threshold, Time}])),
  501:     
  502:     ?match({atomic,ok},mnesia:create_table(test_table,
  503: 					   [{disc_copies, Nodes},
  504: 					    {attributes,
  505: 					     record_info(fields,
  506: 							 test_table)}])),
  507:     
  508:     %% Check that nothing is dumped when within time threshold
  509:     ?match(ok, do_trans(1)),
  510:     check_logs(0),
  511:     
  512:     ?match(Time, mnesia:system_info(dump_log_time_threshold)),
  513: 
  514:     %% Check that things get dumped when time threshold exceeded
  515:     ?match(ok, do_trans(5)),
  516:     receive after Time+2000 -> ok end,
  517:     check_logs(6),
  518:     
  519:     ?verify_mnesia([node()], []),
  520:     ?cleanup(1, Config),
  521:     ok.
  522: 
  523: %%%%%%%%
  524: %% 
  525: %% Help functions for dump log
  526: 
  527: %% Do a transaction N times
  528: do_trans(0) -> ok;
  529: do_trans(N) ->
  530:     Fun = fun() ->
  531: 		  XX=incr(),
  532: 		  mnesia:write(#test_table{i=XX})
  533: 	  end,
  534:     {atomic, ok} = mnesia:transaction(Fun),
  535:     do_trans(N-1).
  536: 
  537: %% An increasing number
  538: incr() ->
  539:     case get(bloody_counter) of
  540: 	undefined -> put(bloody_counter, 2), 1;
  541: 	Num -> put(bloody_counter, Num+1)
  542:     end.
  543: 
  544: %%
  545: %% Check that the correct number of transactions have been recorded.
  546: %%-record(test_table,{i,a1,a2,a3}).
  547: check_logs(N) ->    
  548:     File = mnesia_lib:tab2dcl(test_table),    
  549:     Args = [{file, File}, {name, testing}, {repair, true}, {mode, read_only}],
  550: 
  551:     if N == 0 ->
  552: 	    ?match(false, mnesia_lib:exists(File));
  553:        true ->
  554: 	    ?match(true, mnesia_lib:exists(File)),
  555: 	    ?match({ok, _Log}, disk_log:open(Args)),
  556: 	    
  557: 	    {Cont, Terms} = disk_log:chunk(testing, start),
  558: 	    ?match(eof, disk_log:chunk(testing, Cont)),
  559: 	    %%?verbose("N: ~p, L: ~p~n", [N, L]),
  560: 	    disk_log:close(testing),
  561: 	    
  562: 	    %% Correct number of records in file
  563: 	    ?match({N, N}, {N, length(Terms) -1 })  %% Ignore Header
  564:     end.
  565: 
  566: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  567: 
  568: dump_log_load_regulation(doc) ->
  569:     ["Test the load regulation of the dumper"];
  570: dump_log_load_regulation(suite) ->
  571:     [];
  572: dump_log_load_regulation(Config) when is_list(Config) ->
  573:     Nodes = ?acquire_nodes(1, Config),
  574:     Param = dump_log_load_regulation,
  575: 
  576:     %% Normal 
  577:     NoReg = false,
  578:     ?match(NoReg, mnesia:system_info(Param)),
  579:     ?match([], mnesia_test_lib:stop_mnesia(Nodes)),
  580: 
  581:     %% Bad
  582:     Bad = arne_anka,
  583:     ?match({error, {bad_type, Param, Bad}},
  584: 	   mnesia:start([{Param, Bad}])),
  585: 
  586:     %% Regulation activated
  587:     Reg = true,
  588:     ?match(ok,mnesia:start([{Param, Reg}])),
  589:     ?match(Reg, mnesia:system_info(Param)),
  590: 
  591:     Args =
  592: 	[{db_nodes, Nodes},
  593: 	 {driver_nodes, Nodes},
  594: 	 {replica_nodes, Nodes},
  595: 	 {n_drivers_per_node, 5},
  596: 	 {n_branches, length(Nodes) * 10},
  597: 	 {n_accounts_per_branch, 5},
  598: 	 {replica_type, disc_copies},
  599: 	 {stop_after, timer:seconds(15)},
  600: 	 {report_interval, timer:seconds(3)},
  601: 	 {use_running_mnesia, true},
  602: 	 {reuse_history_id, true}],
  603:     
  604:     ?match({ok, _}, mnesia_tpcb:start(Args)),
  605:     
  606:     ?verify_mnesia(Nodes, []),
  607:     ?cleanup(1, Config),
  608:     ok.
  609: 
  610: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  611: 
  612: ignore_fallback_at_startup(doc) ->
  613:     ["Start Mnesia without rollback of the database to the fallback. ",
  614:      "Once Mnesia has been (re)started the installed fallback should",
  615:      "be handled as a normal active fallback.",
  616:      "Install a customized event module which disables the termination",
  617:      "of Mnesia when mnesia_down occurrs with an active fallback."].
  618: 
  619: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  620: 
  621: max_wait_for_decision(doc) ->
  622:     ["Provoke Mnesia to make a forced decision of the outome",
  623:      "of a heavy weight transaction."].
  624:      
  625: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  626: 
  627: send_compressed(doc) -> [];
  628: send_compressed(suite) -> [];
  629: send_compressed(Config) ->
  630:     [N1,N2] = Nodes = ?acquire_nodes(2, Config),
  631:     ?match({atomic,ok}, mnesia:create_table(t0, [{ram_copies,[N1,N2]}])),
  632:     ?match({atomic,ok}, mnesia:create_table(t1, [{disc_copies,[N1,N2]}])),
  633:     ?match({atomic,ok}, mnesia:create_table(t2, [{disc_only_copies,[N1,N2]}])),
  634: 
  635:     Max = 1000,
  636:     Create = fun(Tab) -> [mnesia:write({Tab, N, {N, "FILLER-123490878345asdasd"}})
  637: 			  || N <- lists:seq(1, Max)],
  638: 			 ok
  639: 	     end,
  640:     
  641:     ?match([], mnesia_test_lib:kill_mnesia([N2])),
  642:     
  643:     ?match([], mnesia_test_lib:kill_mnesia([N1])),
  644:     ?match(ok, mnesia:start([{send_compressed, 9}])),
  645:     ?match(ok, mnesia:wait_for_tables([t0,t1,t2], 5000)),
  646: 
  647:     ?match({atomic, ok}, mnesia:transaction(Create, [t0])),
  648:     ?match({atomic, ok}, mnesia:transaction(Create, [t1])),
  649:     ?match({atomic, ok}, mnesia:transaction(Create, [t2])),
  650:     
  651:     ?match([], mnesia_test_lib:start_mnesia([N2], [t0,t1,t2])),
  652:     
  653:     Verify = fun(Tab) ->		     
  654: 		     [ [{Tab,N,{N,_}}] = mnesia:read(Tab, N) || N <- lists:seq(1, Max)],
  655: 		     ok
  656: 	     end,
  657:     ?match({atomic, ok}, rpc:call(N1, mnesia, transaction, [Verify, [t0]])),
  658:     ?match({atomic, ok}, rpc:call(N1, mnesia, transaction, [Verify, [t1]])),
  659:     ?match({atomic, ok}, rpc:call(N1, mnesia, transaction, [Verify, [t2]])),
  660:     
  661:     ?match({atomic, ok}, rpc:call(N2, mnesia, transaction, [Verify, [t0]])),
  662:     ?match({atomic, ok}, rpc:call(N2, mnesia, transaction, [Verify, [t1]])),
  663:     ?match({atomic, ok}, rpc:call(N2, mnesia, transaction, [Verify, [t2]])),
  664:     
  665:     ?verify_mnesia(Nodes, []),
  666:     ?cleanup(1, Config),
  667:     ok.
  668: 
  669: app_test(doc) -> [];
  670: app_test(suite) -> [];
  671: app_test(_Config) ->
  672:     ?match(ok,test_server:app_test(mnesia)),
  673:     ok.
  674: 
  675: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  676: 
  677: event_module(doc) ->
  678:     ["Replace the event module with another module and use it as",
  679:      "receiver of the various system and table events. Provoke",
  680:      "coverage of all kinds of events."];
  681: event_module(suite) -> [];
  682: event_module(Config) when is_list(Config) ->
  683:     Filter = fun({mnesia_system_event,{mnesia_info, _, _}}) -> false;
  684: 		(_) -> true
  685: 	     end,
  686:     
  687:     [_N1, N2]=Nodes=?acquire_schema(2, Config),
  688: 
  689:     Def = case mnesia_test_lib:diskless(Config) of 
  690: 	      true -> [{event_module, mnesia_config_event},
  691: 		       {extra_db_nodes, Nodes}];
  692: 	      false  ->
  693: 		  [{event_module, mnesia_config_event}]
  694: 	  end,
  695: 
  696:     ?match({[ok, ok], []}, rpc:multicall(Nodes, mnesia, start, [Def])),
  697:     receive after 1000 -> ok end,
  698:     mnesia_event ! {get_log, self()},
  699:     DebugLog1 = receive 
  700: 		    {log, L1} -> L1
  701: 		after 10000 -> [timeout]
  702: 		end,
  703:     ?match([{mnesia_system_event,{mnesia_up,N2}}],
  704: 	   lists:filter(Filter, DebugLog1)),
  705:     mnesia_test_lib:kill_mnesia([N2]),
  706:     receive after 2000 -> ok end,
  707: 
  708:     ?match({[ok], []}, rpc:multicall([N2], mnesia, start, [])),
  709: 
  710:     receive after 1000 -> ok end,
  711:     mnesia_event ! {get_log, self()},
  712:     DebugLog = receive 
  713: 		   {log, L} -> L
  714: 	       after 10000 -> [timeout]
  715: 	       end,
  716:     ?match([{mnesia_system_event,{mnesia_up,N2}},
  717: 	    {mnesia_system_event,{mnesia_down,N2}},
  718: 	    {mnesia_system_event,{mnesia_up, N2}}],
  719: 	   lists:filter(Filter, DebugLog)),
  720:     ?verify_mnesia(Nodes, []),
  721:     ?cleanup(1, Config),
  722:     ok.
  723: 
  724: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  725: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  726: start_one_disc_full_then_one_disc_less(doc)->
  727:     ["Start a disk node and then a disk less one. Distribute some",
  728:      "tables between them."];
  729: start_one_disc_full_then_one_disc_less(suite) -> [];
  730: start_one_disc_full_then_one_disc_less(Config) when is_list(Config) ->
  731:     [N1, N2] = ?init(2, Config),
  732:     ?match(ok, mnesia:create_schema([N1])),
  733:     ?match([], mnesia_test_lib:start_mnesia([N1])),
  734: 
  735:     ?match({atomic, ok}, mnesia:add_table_copy(schema, N2, ram_copies)),
  736: 
  737:     ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
  738: 					     {extra_db_nodes, [N1]}]])),
  739:     mnesia_test_lib:sync_tables([N1, N2], [schema]),
  740: 
  741:     %% Now create some tables
  742:     ?match({atomic,ok},
  743: 	   mnesia:create_table(test_table,
  744: 			       [{ram_copies, [N1, N2]},
  745: 				{attributes,
  746: 				 record_info(fields,test_table)}])),
  747:     
  748:     ?match({atomic,ok},
  749: 	   rpc:call(
  750: 	     N2, mnesia,create_table, [test_table2,
  751: 				      [{ram_copies, [N1, N2]},
  752: 				       {attributes,
  753: 					record_info(fields,test_table2)}]])),
  754: 
  755:     %% Write something on one end ...
  756:     Rec = #test_table{i=55},
  757:     ?match({atomic, ok},
  758: 	   mnesia:transaction(fun() -> mnesia:write(Rec) end)),
  759:     
  760:     %% ... and read it in the other
  761:     ?match({atomic, [Rec]},
  762: 	   rpc:call(N2, mnesia, transaction, 
  763: 		    [fun() -> mnesia:read({test_table, 55}) end])),
  764:     
  765:     
  766:     %% Then do the same but start at the other end
  767:     Rec2 = #test_table2{i=155},
  768:     ?match({atomic, ok},
  769: 	   rpc:call(N2, mnesia, transaction, 
  770: 		    [fun() ->
  771: 			     mnesia:write(Rec2) end
  772: 		    ])),
  773:     
  774:     ?match({atomic, [Rec2]},
  775: 	   mnesia:transaction(fun() -> mnesia:read({test_table2, 155}) end)),
  776:     
  777:     ?verify_mnesia([N1, N2], []),
  778:     ?cleanup(2, Config),
  779:     ok.
  780:     
  781: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  782: start_first_one_disc_less_then_one_disc_full(doc)->
  783:     ["no_doc"];
  784: start_first_one_disc_less_then_one_disc_full(suite) -> [];
  785: start_first_one_disc_less_then_one_disc_full(Config) when is_list(Config) ->
  786:     [N1, N2] = Nodes = ?init(2, Config),
  787:     ?match(ok, mnesia:create_schema([N1])),
  788:     ?match([], mnesia_test_lib:start_mnesia([N1])),
  789: 
  790:     ?match({atomic, ok}, mnesia:add_table_copy(schema, N2, ram_copies)),
  791:     
  792:     ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
  793: 					     {extra_db_nodes, Nodes}]])),
  794: 
  795:     mnesia_test_lib:sync_tables([N1, N2], [schema]),
  796:     
  797:     mnesia_test_lib:kill_mnesia(Nodes),
  798:     receive after 2000 -> ok end,
  799:     ?match([], mnesia_test_lib:start_mnesia(Nodes)),
  800: 
  801:     mnesia_test_lib:sync_tables([N1, N2], [schema]),
  802:     
  803:     %% Now create some tables
  804:     ?match({atomic,ok},
  805: 	   rpc:call(
  806: 	     N1, mnesia,create_table, [test_table,
  807: 				       [%%{disc_copies, [node()]},
  808: 					{ram_copies, [N1, N2]},
  809: 					{attributes,
  810: 					 record_info(fields,test_table)}]])),
  811:     mnesia_test_lib:sync_tables([N1, N2], [test_table]),
  812: 
  813:     ?match({atomic,ok},
  814: 	   rpc:call(
  815: 	     N2, mnesia,create_table, [test_table2,
  816: 				       [%%{disc_copies, [node()]},
  817: 					{ram_copies, [N1, N2]},
  818: 					{attributes,
  819: 					 record_info(fields,test_table2)}]])),
  820:     
  821:     mnesia_test_lib:sync_tables([N1, N2], [test_table, test_table2]),
  822: 
  823:     %% Assure tables loaded
  824:     ?match({[ok, ok], []},
  825: 	   rpc:multicall([N1, N2], mnesia, wait_for_tables,
  826: 			 [[schema, test_table, test_table2], 10000])),
  827:     
  828:     %% Write something on one end ...
  829:     Rec = #test_table{i=55},
  830:     ?match({atomic, ok},
  831: 	   rpc:call(N1, mnesia, transaction, 
  832: 		    [fun() -> mnesia:write(Rec) end])),
  833:     
  834:     %% ... and read it in the other
  835:     ?match({atomic, [Rec]},
  836: 	   rpc:call(N2, mnesia, transaction, 
  837: 		    [fun() -> mnesia:read({test_table, 55}) end])),
  838:     
  839:     %% Then do the same but start at the other end
  840:     Rec2 = #test_table2{i=155},
  841:     ?match({atomic, ok},
  842: 	   rpc:call(N2, mnesia, transaction, 
  843: 		    [fun() ->
  844: 			     mnesia:write(Rec2) end
  845: 		    ])),
  846:     
  847:     ?match({atomic, [Rec2]},
  848: 	   rpc:call(N1, mnesia, transaction, 
  849: 		    [fun() -> mnesia:read({test_table2, 155}) end])),
  850:     
  851:     ?verify_mnesia(Nodes, []),
  852:     ?cleanup(1, Config),
  853:     ok.
  854: 
  855: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  856: start_first_one_disc_less_then_two_more_disc_less(doc)->
  857:     ["no doc"];
  858: start_first_one_disc_less_then_two_more_disc_less(suite) -> [];
  859: start_first_one_disc_less_then_two_more_disc_less(Config) when is_list(Config) ->
  860:     Nodes = [N1, N2, N3] = ?init(3, Config),
  861: 
  862:     ?match(ok, rpc:call(N1, mnesia, start, [[{schema_location, ram}]])),
  863: 
  864:     %% Really should use test_lib:mnesia_start for these ones but ...
  865:     ?match({atomic, ok}, 
  866: 	   rpc:call(N1, mnesia,add_table_copy, [schema, N2, ram_copies])),
  867:     ?match({atomic, ok}, 
  868: 	   rpc:call(N1, mnesia,add_table_copy, [schema, N3, ram_copies])),
  869:     
  870:     ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
  871: 					     {extra_db_nodes, [N1]}]])),
  872:     ?match(ok, rpc:call(N3, mnesia, start, [[{schema_location, ram},
  873: 					     {extra_db_nodes, [N1, N2]}]])),
  874: 
  875:     %% Now create some tables
  876:     ?match({atomic,ok},
  877: 	   rpc:call(
  878: 	     N1, mnesia,create_table, [test_table,
  879: 				      [%%{disc_copies, [node()]},
  880: 				       {ram_copies, [N1, N2, N3]},
  881: 				       {attributes,
  882: 					record_info(fields,test_table)}]])),
  883: 
  884:     %% Assure tables loaded
  885:     ?match({[ok, ok, ok], []},
  886: 	   rpc:multicall([N1, N2, N3], mnesia, wait_for_tables,
  887: 			 [[test_table], 1000])),
  888: 
  889:     %% Write something on one end ...
  890:     ?match({atomic, ok},
  891: 	   rpc:call(N1, mnesia, transaction, 
  892: 		    [fun() -> mnesia:write(#test_table{i=44}) end])),
  893: 
  894:     %% Force synchronicity
  895:     ?match({atomic, ok},
  896: 	   rpc:call(N1, mnesia, transaction, 
  897: 		    [fun() -> mnesia:write_lock_table(test_table) end])),
  898:     
  899:     %% ... and read it in the others
  900:     ?match({[{atomic, [{test_table, 44, _, _, _}]},
  901: 	     {atomic, [{test_table, 44, _, _, _}]}], []},
  902: 	   rpc:multicall([N2, N3], mnesia, transaction, 
  903: 			 [fun() -> mnesia:read({test_table, 44}) end])),
  904:     
  905:     %% Then do the other way around
  906:     ?match({atomic, ok},
  907: 	   rpc:call(N3, mnesia, transaction, 
  908: 		    [fun() -> mnesia:write(#test_table{i=33}) end])),
  909:     %% Force synchronicity
  910:     ?match({atomic, ok},
  911: 	   rpc:call(N3, mnesia, transaction, 
  912: 		    [fun() -> mnesia:write_lock_table(test_table) end])),
  913:     
  914:     ?match({[{atomic, [{test_table, 44, _, _, _}]},
  915: 	     {atomic, [{test_table, 44, _, _, _}]}], []},
  916: 	   rpc:multicall([N1, N2], mnesia, transaction, 
  917: 			 [fun() -> mnesia:read({test_table, 44}) end])),
  918: 
  919:     mnesia_test_lib:reload_appls([mnesia], Nodes),
  920:     ok.
  921: 
  922: 
  923: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  924: schema_location_and_extra_db_nodes_combinations(doc)->
  925:     ["Test schema loaction and extra_db_nodes combinations."];
  926: schema_location_and_extra_db_nodes_combinations(suite) -> [];
  927: schema_location_and_extra_db_nodes_combinations(Config) when is_list(Config) ->
  928:     [N1, N2] = Nodes = ?init(2, Config),
  929:     ?match(ok, mnesia:create_schema([N1])),
  930:     ?match([], mnesia_test_lib:start_mnesia([N1])),
  931:     
  932:     %% Really should use test_lib:mnesia_start for these ones but ...
  933:     ?match({atomic, ok}, 
  934: 	   rpc:call(N1, mnesia,add_table_copy, [schema, N2, ram_copies])),
  935:     
  936:     ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
  937: 					     {extra_db_nodes, [N1]}]])),
  938:     
  939:     %% Assure tables loaded
  940:     ?match({[ok, ok], []},
  941: 	   rpc:multicall([N1, N2], mnesia, wait_for_tables,
  942: 			 [[schema], 10000])),
  943:     
  944:     ?verify_mnesia(Nodes, []),
  945:     ?cleanup(2, Config),
  946:     ok.
  947: 
  948: 
  949: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  950: table_load_to_disc_less_nodes(doc)->
  951:     ["Load tables to disc less nodes"];
  952: table_load_to_disc_less_nodes(suite) -> [];
  953: table_load_to_disc_less_nodes(Config) when is_list(Config) ->
  954:     [N1, N2] = ?init(2, Config),
  955: 
  956:     ?match(ok, rpc:call(N1, mnesia, start, [[{schema_location, ram}]])),
  957: 
  958:     %% Really should use test_lib:mnesia_start for these ones but ...
  959:     ?match({atomic, ok}, 
  960: 	   rpc:call(N1, mnesia,add_table_copy, [schema, N2, ram_copies])),
  961:     
  962:     ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
  963: 					     {extra_db_nodes, [N1]}]])),
  964: 
  965:     %% Now create some tables
  966:     ?match({atomic,ok},
  967: 	   rpc:call(
  968: 	     N1, mnesia,create_table, [test_table,
  969: 				      [%%{disc_copies, [node()]},
  970: 				       {ram_copies, [N1, N2]},
  971: 				       {attributes,
  972: 					record_info(fields,test_table)}]])),
  973: 
  974:     %% Assure tables loaded
  975:     ?match({[ok, ok], []},
  976: 	   rpc:multicall([N1, N2], mnesia, wait_for_tables,
  977: 			 [[test_table], 1000])),
  978: 
  979:     %% Write something on one end ...
  980:     ?match({atomic, ok},
  981: 	   rpc:call(N1, mnesia, transaction, 
  982: 		    [fun() -> mnesia:write(#test_table{i=44}) end])),
  983: 
  984:     %% Force synchronicity
  985:     ?match({atomic, ok},
  986: 	   rpc:call(N1, mnesia, transaction, 
  987: 		    [fun() -> mnesia:write_lock_table(test_table) end])),
  988:     
  989:     %% ... and read it in the others
  990:     ?match({atomic, [{test_table, 44, _, _, _}]},
  991: 	   rpc:call(N2, mnesia, transaction, 
  992: 		    [fun() -> mnesia:read({test_table, 44}) end])),
  993: 
  994:     ?cleanup(2, Config),
  995:     ok.
  996:     
  997: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  998: schema_merge(doc) ->
  999:     ["Provoke various schema merge situations.",
 1000:      "Perform various schema updates while some nodes are down,",
 1001:      "stop the started nodes, start the stopped nodes and perform",
 1002:      "schema updates. Now we have a situation were some of the table",
 1003:      "definitions have been changed on two or more nodes independently",
 1004:      "of each other and when Mnesia on the nodes tries to connect",
 1005:      "to each other at restart the schema will be merged.",
 1006:      "Do also try to provoke schema merge situations were the",
 1007:      "schema cannot be merged."];
 1008: 
 1009: schema_merge(suite) -> [];
 1010: 
 1011: schema_merge(Config) when is_list(Config) ->
 1012:     [N1, N2]=Nodes=?acquire(2,Config),
 1013:     
 1014:     mnesia_test_lib:kill_mnesia([N2]),    
 1015:     receive after 1000 -> ok end,
 1016: 
 1017:     Storage = mnesia_test_lib:storage_type(disc_copies, Config),    
 1018:     ?match({atomic,ok},
 1019: 	   rpc:call(
 1020: 	     N1, mnesia,create_table, 
 1021: 	     [test_table,
 1022: 	      [{Storage, [N1]},
 1023: 	       {attributes,
 1024: 		record_info(fields,test_table)}]])),
 1025:     
 1026:     ?match({atomic, ok},
 1027: 	   rpc:call(N1, mnesia, transaction, 
 1028: 		    [fun() -> mnesia:write(#test_table{i=44}) end])),
 1029: 
 1030:     mnesia_test_lib:kill_mnesia([N1]),
 1031:     receive after 2000 -> ok end,
 1032:     %% Can't use std start because it waits for schema
 1033:     ?match(ok, rpc:call(N2, mnesia, start, [])),
 1034: 
 1035:     ?match({atomic,ok},
 1036: 	   rpc:call(
 1037: 	     N2, mnesia,create_table, 
 1038: 	     [test_table2,
 1039: 	      [{Storage, [N2]},
 1040: 	       {attributes,
 1041: 		record_info(fields,test_table2)}]])),
 1042:     
 1043:     receive after 5000 -> ok end,
 1044: 
 1045:     ?match({atomic, ok},
 1046: 	   rpc:call(N2, mnesia, transaction, 
 1047: 		    [fun() -> mnesia:write(#test_table2{i=33}) end])),
 1048:     
 1049:     %% Can't use std start because it waits for schema
 1050:     ?match(ok, rpc:call(N1, mnesia, start, [])),
 1051: 
 1052:     %% Assure tables loaded
 1053:     ?match({[ok, ok], []},
 1054: 	   rpc:multicall([N1, N2], mnesia, wait_for_tables,
 1055: 			 [[schema, test_table, test_table2], 10000])),
 1056:     
 1057:     %% ... and read it in the others
 1058:     ?match({[{atomic, [{test_table, 44, _, _, _}]},
 1059: 	     {atomic, [{test_table, 44, _, _, _}]}], []},
 1060: 	   rpc:multicall([N1, N2], mnesia, transaction, 
 1061: 			 [fun() -> mnesia:read({test_table, 44}) end])),
 1062:     
 1063:     ?match({[{atomic, [{test_table2, 33, _}]},
 1064: 	     {atomic, [{test_table2, 33, _}]}], []},
 1065: 	   rpc:multicall([N1, N2], mnesia, transaction, 
 1066: 			 [fun() -> mnesia:read({test_table2, 33}) end])),
 1067:     
 1068:     ?verify_mnesia(Nodes, []),
 1069:     ?cleanup(2, Config),
 1070:     ok.
 1071: 
 1072: 
 1073: -define(connect(Nodes), mnesia:change_config(extra_db_nodes, Nodes)).
 1074: -define(rpc_connect(From, Nodes), 
 1075: 	rpc:call(From, mnesia, change_config, [extra_db_nodes, Nodes])).
 1076: 
 1077: 
 1078: sort({ok, NS}) ->
 1079:     {ok, lists:sort(NS)};
 1080: sort(Ns) when is_tuple(Ns) ->
 1081:     Ns;
 1082: sort(NS) when is_list(NS) -> 
 1083:     lists:sort(NS).
 1084: 
 1085: 
 1086: 
 1087: 
 1088: dynamic_basic(suite) -> [];
 1089: dynamic_basic(Config) when is_list(Config) ->
 1090:     Nodes = [N1, N2, N3] = ?acquire_nodes(3, Config),
 1091:     SNs = lists:sort(Nodes),    
 1092: 
 1093:     ?match({atomic, ok}, mnesia:create_table(tab1, [{ram_copies, Nodes--[N1]}, {disc_copies, [N1]}])),
 1094:     ?match({atomic, ok}, mnesia:create_table(tab2, [{disc_copies, Nodes}])),
 1095: 
 1096:     ?match({ok, SNs}, sort(?rpc_connect(N1, Nodes))),     %% What shall happen?
 1097:     ?match({ok, []}, sort(?rpc_connect(N1, [nonode@nothosted]))),  %% What shall happen?
 1098:     
 1099:     ?match([], mnesia_test_lib:kill_mnesia([N2])),
 1100:     ?match(ok, mnesia:delete_schema([N2])),
 1101: 
 1102:     ?match(ok, mnesia:dirty_write({tab1, 1, 1})),
 1103:     ?match(ok, mnesia:dirty_write({tab2, 1, 1})),
 1104:    
 1105:     ?match(ok, rpc:call(N2, mnesia, start, [[{extra_db_nodes, [N1]}]])),
 1106:     ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab1,tab2],5000])),
 1107:     io:format("Here ~p ~n",[?LINE]), 
 1108:     check_storage(N2, N1, [N3]),
 1109:     ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
 1110:     ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
 1111: 
 1112:     ?match([], mnesia_test_lib:kill_mnesia([N3])),
 1113:     ?match(ok, mnesia:delete_schema([N3])),
 1114:     
 1115:     io:format("T1 ~p ~n",[rpc:call(N3,?MODULE,c_nodes,[])]),
 1116:     ?match(ok, rpc:call(N3, mnesia, start, [])),
 1117:     io:format("T2 ~p ~n",[rpc:call(N3,?MODULE,c_nodes,[])]),
 1118:     timer:sleep(2000),
 1119:     io:format("T3 ~p ~n",[rpc:call(N3,?MODULE,c_nodes,[])]),
 1120:     ?match({ok, [N1]}, sort(?rpc_connect(N3, [N1]))),
 1121:     io:format("T4 ~p ~n",[rpc:call(N3,?MODULE,c_nodes,[])]),
 1122:     ?match(ok, rpc:call(N3, mnesia, wait_for_tables, [[tab1,tab2],5000])),
 1123:     io:format("Here ~p ~n",[?LINE]), 
 1124:     check_storage(N3, N1, [N2]),
 1125:     ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
 1126:     ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
 1127:     
 1128:     ?match([], mnesia_test_lib:kill_mnesia([N3])),
 1129:     ?match(ok, mnesia:delete_schema([N3])),
 1130:     
 1131:     ?match(ok, rpc:call(N3, mnesia, start, [])),
 1132:     ?match({ok, [N3]}, sort(?rpc_connect(N1, [N3]))),
 1133:     ?match(ok, rpc:call(N3, mnesia, wait_for_tables, [[tab1,tab2],5000])),
 1134:     io:format("Here ~p ~n",[?LINE]), 
 1135:     check_storage(N3, N1, [N2]),
 1136:     ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
 1137:     ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
 1138: 
 1139:     mnesia_test_lib:kill_mnesia([N2]),
 1140:     ?match(ok, mnesia:delete_schema([N2])),
 1141:     ?match({atomic, ok}, mnesia:del_table_copy(schema, N2)),
 1142: 
 1143:     % Ok, we have now removed references to node N2 from the other nodes
 1144:     % mnesia should come up now.
 1145:     ?match({atomic, ok}, mnesia:add_table_copy(tab1, N2, ram_copies)),
 1146: 
 1147:     ?match(ok, rpc:call(N2, mnesia, start, [])),
 1148:     ?match({ok, _}, sort(?rpc_connect(N2, [N3]))),
 1149:     
 1150:     ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
 1151:     ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
 1152:     ?match(SNs, sort(rpc:call(N3, mnesia, system_info, [running_db_nodes]))),
 1153: 
 1154:     ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab1], 1000])),
 1155:     ?match([{tab1, 1, 1}], rpc:call(N2, mnesia, dirty_read, [tab1, 1])),
 1156:        
 1157:     mnesia_test_lib:kill_mnesia([N2]),
 1158: 
 1159:     %%% SYNC!!!
 1160:     timer:sleep(1000),
 1161: 
 1162:     ?match([N3,N1], sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
 1163:     ?match([N3,N1], sort(rpc:call(N3, mnesia, system_info, [running_db_nodes]))),
 1164:     
 1165:     ?match(ok, rpc:call(N2, mnesia, start, [])),
 1166:     ?match({ok, _}, sort(?rpc_connect(N3, [N2]))),
 1167:     
 1168:     ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
 1169:     ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
 1170:     ?match(SNs, sort(rpc:call(N3, mnesia, system_info, [running_db_nodes]))),
 1171: 
 1172:     ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab1], 1000])),
 1173:     ?match([{tab1, 1, 1}], rpc:call(N2, mnesia, dirty_read, [tab1, 1])),
 1174: 
 1175:     ?verify_mnesia(Nodes, []),
 1176: %%    ?cleanup(3, Config).
 1177:     ok.
 1178: 
 1179: c_nodes() -> 		  						
 1180:     {mnesia_lib:val({current, db_nodes}),mnesia_lib:val(recover_nodes)}.
 1181: 
 1182: 
 1183: dynamic_ext(suite) ->    [];
 1184: dynamic_ext(Config) when is_list(Config) ->
 1185:     Ns = [N1,N2] = ?acquire_nodes(2, Config),
 1186:     SNs = lists:sort([N1,N2]),
 1187:     
 1188:     ?match({atomic, ok}, mnesia:create_table(tab0, [{disc_copies, [N1,N2]}])),
 1189:     ?match({atomic, ok}, mnesia:create_table(tab1, [{ram_copies, [N2]}])),
 1190:     ?match({atomic, ok}, mnesia:create_table(tab2, [{disc_copies, [N2]}])),
 1191:     ?match({atomic, ok}, mnesia:create_table(tab3, [{disc_only_copies, [N2]}])),
 1192:     
 1193:     mnesia_test_lib:kill_mnesia([N2]),
 1194:     ?match(ok, mnesia:delete_schema([N2])),
 1195:     ?match(ok, rpc:call(N2, mnesia, start, [[{extra_db_nodes, [N1]}]])),
 1196:     
 1197:     ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
 1198:     ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
 1199:     
 1200:     ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab0,tab1,tab2,tab3], 2000])),
 1201: 
 1202:     Check = fun({Tab,Storage}) ->
 1203: 		    ?match(Storage, rpc:call(N2, mnesia, table_info, [Tab, storage_type])),
 1204: 		    ?match([{N2,Storage}], 
 1205: 			   lists:sort(rpc:call(N2, mnesia, table_info, [Tab, where_to_commit])))
 1206: 	    end,
 1207:     [Check(Test) || Test <- [{tab1, ram_copies},{tab2, disc_copies},{tab3, disc_only_copies}]],
 1208:     
 1209:     T = now(),
 1210:     ?match(ok, mnesia:dirty_write({tab0, 42, T})),
 1211:     ?match(ok, mnesia:dirty_write({tab1, 42, T})),
 1212:     ?match(ok, mnesia:dirty_write({tab2, 42, T})),
 1213:     ?match(ok, mnesia:dirty_write({tab3, 42, T})),
 1214:     
 1215:     ?match(stopped, rpc:call(N2, mnesia, stop, [])),
 1216:     ?match(ok, rpc:call(N2, mnesia, start, [])),
 1217:     ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
 1218:     ?match(ok, mnesia:wait_for_tables([tab0,tab1,tab2,tab3], 10000)),
 1219:     ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab1,tab2,tab3], 100])),
 1220:     ?match([], mnesia:dirty_read({tab1, 41})),
 1221:     ?match([{tab2,42,T}], mnesia:dirty_read({tab2, 42})),
 1222:     ?match([{tab3,42,T}], mnesia:dirty_read({tab3, 42})),
 1223: 
 1224:     mnesia_test_lib:kill_mnesia([N2]),
 1225:     ?match(ok, mnesia:delete_schema([N2])),
 1226: 
 1227:     ?match(stopped, rpc:call(N1, mnesia, stop, [])),
 1228: 
 1229:     ?match(ok, rpc:call(N2, mnesia, start, [[{extra_db_nodes,[N1,N2]}]])),
 1230:     ?match({timeout,[tab0]}, rpc:call(N2, mnesia, wait_for_tables, [[tab0], 500])),
 1231: 
 1232:     ?match(ok, rpc:call(N1, mnesia, start, [[{extra_db_nodes, [N1,N2]}]])),
 1233:     ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[tab0], 1500])),
 1234:     ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab0], 1500])),
 1235:     ?match([{tab0,42,T}], mnesia:dirty_read({tab0, 42})),
 1236:     ?match([{tab0,42,T}], rpc:call(N2, mnesia,dirty_read,[{tab0,42}])),
 1237: 
 1238:     ?match(stopped, rpc:call(N1, mnesia, stop, [])),
 1239:     mnesia_test_lib:kill_mnesia([N2]),
 1240:     ?match(ok, mnesia:delete_schema([N2])),
 1241:     ?match(ok, rpc:call(N1, mnesia, start, [[{extra_db_nodes, [N1,N2]}]])),   
 1242:     ?match({timeout,[tab0]}, rpc:call(N1, mnesia, wait_for_tables, [[tab0], 500])),
 1243: 
 1244:     ?match(ok, rpc:call(N2, mnesia, start, [[{extra_db_nodes,[N1,N2]}]])),
 1245:     ?match(ok, rpc:call(N1, mnesia, wait_for_tables, [[tab0], 1500])),
 1246:     ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab0], 1500])),
 1247:     ?match([{tab0,42,T}], mnesia:dirty_read({tab0, 42})),
 1248:     ?match([{tab0,42,T}], rpc:call(N2,mnesia,dirty_read,[{tab0,42}])),
 1249: 
 1250:     ?verify_mnesia(Ns, []),
 1251:     ok.
 1252: 
 1253: check_storage(Me, Orig, Other) ->
 1254:     io:format("Nodes ~p ~p ~p~n",[Me,Orig,Other]),
 1255:     rpc:multicall(Other, sys, status, [mnesia_locker]),
 1256:     rpc:call(Me, sys, status, [mnesia_locker]),
 1257:     rpc:call(Orig, sys, status, [mnesia_locker]),
 1258:     rpc:multicall(Other, sys, status, [mnesia_controller]),
 1259:     rpc:call(Me, sys, status, [mnesia_controller]),
 1260:     rpc:call(Orig, sys, status, [mnesia_controller]),
 1261:     %% Verify disc_copies
 1262:     W2C = lists:sort([{Node,disc_copies} || Node <- [Me,Orig|Other]]),
 1263:     W2W = lists:sort([Me,Orig|Other]),
 1264:     ?match(disc_copies, rpc:call(Orig, mnesia, table_info, [schema, storage_type])),
 1265:     ?match(disc_copies, rpc:call(Me, mnesia, table_info, [schema, storage_type])),
 1266:     ?match(W2C, lists:sort(rpc:call(Orig, mnesia, table_info, [schema, where_to_commit]))),
 1267:     ?match(W2C, lists:sort(rpc:call(Me, mnesia, table_info, [schema, where_to_commit]))),
 1268:     
 1269:     ?match(disc_copies, rpc:call(Orig, mnesia, table_info, [tab2, storage_type])),
 1270:     ?match(disc_copies, rpc:call(Me, mnesia, table_info, [tab2, storage_type])),    
 1271:     ?match(W2W, lists:sort(rpc:call(Me, mnesia, table_info, [tab2, where_to_write]))),    
 1272:     ?match(Me, rpc:call(Me, mnesia, table_info, [tab2, where_to_read])),    
 1273:     
 1274:     ?match(W2C, lists:sort(rpc:call(Orig, mnesia, table_info, [tab2, where_to_commit]))),
 1275:     ?match(W2C, lists:sort(rpc:call(Me, mnesia, table_info, [tab2, where_to_commit]))),
 1276:     
 1277:     ?match([{tab1,1,1}], mnesia:dirty_read(tab1,1)),
 1278:     ?match([{tab2,1,1}], mnesia:dirty_read(tab2,1)),
 1279:     ?match([{tab1,1,1}], rpc:call(Me, mnesia, dirty_read, [tab1,1])),
 1280:     ?match([{tab2,1,1}], rpc:call(Me, mnesia, dirty_read, [tab2,1])),
 1281: 
 1282:     ?match(true, rpc:call(Me, mnesia_monitor, use_dir, [])),
 1283:     ?match(disc_copies, rpc:call(Me, mnesia_lib, val, [{schema, storage_type}])),
 1284:     
 1285:     mnesia_test_lib:kill_mnesia([Orig]),
 1286:     mnesia_test_lib:kill_mnesia(Other),
 1287:     T = now(),
 1288:     ?match(ok, rpc:call(Me, mnesia, dirty_write, [{tab2, 42, T}])),
 1289:     ?match(stopped, rpc:call(Me, mnesia, stop, [])),
 1290:     ?match(ok, rpc:call(Me, mnesia, start, [])),   
 1291:     ?match([], mnesia_test_lib:start_mnesia([Orig|Other], [tab1,tab2])),
 1292:     ?match([{tab2,42,T}], rpc:call(Me, mnesia, dirty_read, [{tab2, 42}])),
 1293:     ?match([{tab2,42,T}], rpc:call(Orig, mnesia, dirty_read, [{tab2, 42}])),
 1294:     
 1295:     ?match([{tab1,1,1}], mnesia:dirty_read(tab1,1)),
 1296:     ?match([{tab2,1,1}], mnesia:dirty_read(tab2,1)),
 1297:     ?match([{tab1,1,1}], rpc:call(Me, mnesia, dirty_read, [tab1,1])),
 1298:     ?match([{tab2,1,1}], rpc:call(Me, mnesia, dirty_read, [tab2,1])),    
 1299:     ok.
 1300:     
 1301: 
 1302: dynamic_bad(suite) ->    [];
 1303: dynamic_bad(Config) when is_list(Config) ->
 1304:     Ns = [N1, N2, N3] = ?acquire_nodes(3, Config),
 1305:     SNs = lists:sort([N2,N3]), 
 1306: 
 1307:     ?match({atomic, ok}, mnesia:change_table_copy_type(schema, N2, ram_copies)),
 1308:     ?match({atomic, ok}, mnesia:change_table_copy_type(schema, N3, ram_copies)),
 1309:     ?match({atomic, ok}, mnesia:create_table(tab1, [{ram_copies, Ns -- [N1]},
 1310: 						    {disc_copies, [N1]}])),
 1311:     ?match(ok, mnesia:dirty_write({tab1, 1, 1})),
 1312:     
 1313:     mnesia_test_lib:kill_mnesia(Ns),
 1314:     ?match({[ok, ok], []}, rpc:multicall(Ns -- [N1], mnesia, start, [])),
 1315:     ?match({ok, [N2]}, ?rpc_connect(N3, [N2])),
 1316:     ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
 1317:     ?match(SNs, sort(rpc:call(N3, mnesia, system_info, [running_db_nodes]))),
 1318:     ?match({badrpc, {'EXIT', {aborted, {no_exists, _, _}}}},
 1319: 	   rpc:call(N2, mnesia, table_info, [tab1, where_to_read])),
 1320:     
 1321:     ?match(ok, mnesia:start()),
 1322:     ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab1], 1000])),
 1323:     ?match(N2, rpc:call(N2, mnesia, table_info, [tab1, where_to_read])), 
 1324:     ?match([{tab1, 1, 1}], rpc:call(N2, mnesia, dirty_read, [tab1, 1])),
 1325:     
 1326:     mnesia_test_lib:kill_mnesia(Ns),
 1327:     ?match({[ok, ok], []}, rpc:multicall(Ns -- [N1], mnesia, start, [])),
 1328:     ?match({ok, [N2]}, ?rpc_connect(N3, [N2])),
 1329:     % Make a merge conflict
 1330:     ?match({atomic, ok}, rpc:call(N3, mnesia, create_table, [tab1, []])),
 1331:     
 1332:     io:format("We expect a mnesia crash here~n", []),
 1333:     ?match({error,{_, _}}, mnesia:start()),
 1334: 
 1335:     ?verify_mnesia(Ns -- [N1], []),
 1336:     ok.
 1337: 
 1338: 
 1339: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1340: unknown_config(doc) ->
 1341:     ["Try some unknown configuration parameters and see that expected",
 1342:      "things happens."];
 1343: unknown_config(suite)-> [];
 1344: unknown_config(Config) when is_list(Config) ->
 1345:     ?init(1, Config),
 1346:     %% NOTE: case 1 & 2 below do not respond the same
 1347:     ?match({error, Res} when element(1, Res) == bad_type,
 1348: 	   mnesia:start([{undefined_config,[]}])),
 1349:     %% Below does not work, but the "correct" behaviour would be to have
 1350:     %% case 1 above to behave as the one below.
 1351: 
 1352:     %% in mnesia-1.3 {error,{bad_type,{[],undefined_config}}}
 1353:     ?match({error, Res} when element(1, Res) == bad_type,
 1354: 	   mnesia:start([{[],undefined_config}])),
 1355:     ?cleanup(1, Config),
 1356:     ok.
 1357: 
 1358: 
 1359: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1360: inconsistent_database(doc) ->
 1361:     ["Replace the event module with another module and use it as",
 1362:      "receiver of the various system and table events. Provoke",
 1363:      "coverage of all kinds of events."];
 1364: inconsistent_database(suite) -> [];
 1365: inconsistent_database(Config) when is_list(Config) ->
 1366:     Nodes = mnesia_test_lib:prepare_test_case([{init_test_case, [mnesia]}], 
 1367: 					      2, Config, ?FILE, ?LINE),
 1368:     KillAfter = length(Nodes) * timer:minutes(5),
 1369:     ?acquire_schema(2, Config ++ [{tc_timeout, KillAfter}]),
 1370: 
 1371:     Ok = [ok || _N <- Nodes],
 1372:     StartArgs = [{event_module, mnesia_inconsistent_database_test}],
 1373:     ?match({Ok, []}, rpc:multicall(Nodes, mnesia, start, [StartArgs])),
 1374:     ?match([], mnesia_test_lib:kill_mnesia(Nodes)),
 1375:     
 1376:     ?match(ok, mnesia_meter:go(ram_copies, Nodes)),
 1377: 
 1378:     mnesia_test_lib:reload_appls([mnesia], Nodes),
 1379:     ok.
 1380: