1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 1996-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_evil_coverage_test).
   22: -author('hakan@erix.ericsson.se').
   23: -include("mnesia_test_lib.hrl").
   24: 
   25: -compile([export_all]).
   26: 
   27: -define(cleanup(N, Config),
   28: 	mnesia_test_lib:prepare_test_case([{reload_appls, [mnesia]}],
   29: 					  N, Config, ?FILE, ?LINE)).
   30: init_per_testcase(Func, Conf) ->
   31:     mnesia_test_lib:init_per_testcase(Func, Conf).
   32: 
   33: end_per_testcase(Func, Conf) ->
   34:     mnesia_test_lib:end_per_testcase(Func, Conf).
   35: 
   36: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   37: all() -> 
   38:     [system_info, table_info, error_description,
   39:      db_node_lifecycle, evil_delete_db_node, start_and_stop,
   40:      checkpoint, table_lifecycle, storage_options, 
   41:      add_copy_conflict,
   42:      add_copy_when_going_down, replica_management, clear_table_during_load,
   43:      schema_availability, local_content,
   44:      {group, table_access_modifications}, replica_location,
   45:      {group, table_sync}, user_properties, unsupp_user_props,
   46:      {group, record_name}, {group, snmp_access},
   47:      {group, subscriptions}, {group, iteration},
   48:      {group, debug_support}, sorted_ets,
   49:      {mnesia_dirty_access_test, all},
   50:      {mnesia_trans_access_test, all},
   51:      {mnesia_evil_backup, all}].
   52: 
   53: groups() -> 
   54:     [{table_access_modifications, [],
   55:       [change_table_access_mode, change_table_load_order,
   56:        set_master_nodes, offline_set_master_nodes]},
   57:      {table_sync, [],
   58:       [dump_tables, dump_log, wait_for_tables,
   59:        force_load_table]},
   60:      {snmp_access, [],
   61:       [snmp_open_table, snmp_close_table, snmp_get_next_index,
   62:        snmp_get_row, snmp_get_mnesia_key, snmp_update_counter,
   63:        snmp_order]},
   64:      {subscriptions, [],
   65:       [subscribe_standard, subscribe_extended]},
   66:      {iteration, [], [foldl]},
   67:      {debug_support, [],
   68:       [info, schema_0, schema_1, view_0, view_1, view_2,
   69:        lkill, kill]},
   70:      {record_name, [], [{group, record_name_dirty_access}]},
   71:      {record_name_dirty_access, [],
   72:       [record_name_dirty_access_ram,
   73:        record_name_dirty_access_disc,
   74:        record_name_dirty_access_disc_only]}].
   75: 
   76: init_per_group(_GroupName, Config) ->
   77:     Config.
   78: 
   79: end_per_group(_GroupName, Config) ->
   80:     Config.
   81: 
   82: 
   83: 
   84: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   85: %% Get meta info about Mnesia
   86: 
   87: system_info(suite) -> [];
   88: system_info(Config) when is_list(Config) ->
   89:     Nodes = ?acquire_nodes(all, Config),
   90:     Ns = ?sort(Nodes),
   91:     ?match(yes, mnesia:system_info(is_running)),
   92:     ?match(Ns, ?sort(mnesia:system_info(db_nodes))),
   93:     ?match(Ns, ?sort(mnesia:system_info(running_db_nodes))),
   94:     ?match(A when is_atom(A), mnesia:system_info(debug)),
   95:     ?match(L when is_list(L), mnesia:system_info(directory)),
   96:     ?match(L when is_list(L), mnesia:system_info(log_version)),
   97:     ?match({_, _}, mnesia:system_info(schema_version)),
   98:     ?match(L when is_list(L), mnesia:system_info(tables)),
   99:     ?match(L when is_list(L), mnesia:system_info(local_tables)),
  100:     ?match(L when is_list(L), mnesia:system_info(held_locks)),
  101:     ?match(L when is_list(L), mnesia:system_info(lock_queue)),
  102:     ?match(L when is_list(L), mnesia:system_info(transactions)),
  103:     ?match(I when is_integer(I), mnesia:system_info(transaction_failures)),
  104:     ?match(I when is_integer(I), mnesia:system_info(transaction_commits)),
  105:     ?match(I when is_integer(I), mnesia:system_info(transaction_restarts)),
  106:     ?match(L when is_list(L), mnesia:system_info(checkpoints)),
  107:     ?match(A when is_atom(A), mnesia:system_info(backup_module)),
  108:     ?match(true, mnesia:system_info(auto_repair)),
  109:     ?match({_, _}, mnesia:system_info(dump_log_interval)),
  110:     ?match(A when is_atom(A), mnesia:system_info(dump_log_update_in_place)),
  111:     ?match(I when is_integer(I), mnesia:system_info(transaction_log_writes)),
  112:     ?match(I when is_integer(I), mnesia:system_info(send_compressed)),
  113:     ?match(L when is_list(L), mnesia:system_info(all)),
  114:     ?match({'EXIT', {aborted, Reason }} when element(1, Reason) == badarg
  115:            , mnesia:system_info(ali_baba)),
  116:     ?verify_mnesia(Nodes, []).
  117: 
  118: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  119: %% Get meta info about table
  120: 
  121: table_info(suite) -> [];
  122: table_info(Config) when is_list(Config) ->
  123:     [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config),
  124:     
  125:     Tab  = table_info,
  126:     Type = bag,
  127:     ValPos = 3,
  128:     Attrs = [k, v],
  129:     Arity = length(Attrs) +1,
  130: 
  131:     Schema = 
  132: 	case mnesia_test_lib:diskless(Config) of
  133: 	    true -> [{type, Type}, {attributes, Attrs}, {index, [ValPos]},
  134: 		     {ram_copies, Nodes}];
  135: 	    false ->		
  136: 		[{type, Type}, {attributes, Attrs}, {index, [ValPos]},
  137: 		 {disc_only_copies, [Node1]}, {ram_copies, [Node2]}, 
  138: 		 {disc_copies, [Node3]}]
  139: 	end,
  140:     ?match({atomic, ok}, mnesia:create_table(Tab, Schema)),
  141: 
  142:     Size = 10,
  143:     Keys = lists:seq(1, Size),
  144:     Records = [{Tab, A, 7} || A <- Keys],
  145:     lists:foreach(fun(Rec) -> ?match(ok, mnesia:dirty_write(Rec)) end, Records),
  146:     ?match(Mem when is_integer(Mem), mnesia:table_info(Tab, memory)),
  147:     ?match(Size, mnesia:table_info(Tab, size)),
  148:     ?match(Type, mnesia:table_info(Tab, type)),
  149: 
  150:     case mnesia_test_lib:diskless(Config) of
  151: 	true -> 
  152: 	    ?match(Nodes, mnesia:table_info(Tab, ram_copies));
  153: 	false ->              
  154: 	    ?match([Node3], mnesia:table_info(Tab, mnesia_test_lib:storage_type(disc_copies, Config))),
  155: 	    ?match([Node2], mnesia:table_info(Tab, ram_copies)),
  156: 	    ?match([Node1], mnesia:table_info(Tab, mnesia_test_lib:storage_type(disc_only_copies, Config)))
  157:     end,
  158:     Read = [Node1, Node2, Node3],
  159:     ?match(true, lists:member(mnesia:table_info(Tab, where_to_read), Read)),
  160:     Write = ?sort([Node1, Node2, Node3]),
  161:     ?match(Write, ?sort(mnesia:table_info(Tab, where_to_write))),
  162:     ?match([ValPos], mnesia:table_info(Tab, index)),
  163:     ?match(Arity, mnesia:table_info(Tab, arity)),
  164:     ?match(Attrs, mnesia:table_info(Tab, attributes)),
  165:     ?match({Tab, '_', '_'}, mnesia:table_info(Tab, wild_pattern)),
  166:     ?match({atomic, Attrs}, mnesia:transaction(fun() ->
  167: 						       mnesia:table_info(Tab, attributes) end)),
  168: 
  169:     ?match(L when is_list(L), mnesia:table_info(Tab, all)),
  170: 
  171:     %% Table info when table not loaded
  172:     ?match({atomic, ok},
  173: 	   mnesia:create_table(tab_info, Schema)),
  174:     ?match(stopped, mnesia:stop()),
  175:     ?match(stopped, rpc:call(Node2, mnesia, stop, [])),
  176:     ?match(ok, mnesia:start()),
  177:     ?match(ok, mnesia:wait_for_tables([tab_info], 5000)),
  178:     ?match(0, mnesia:table_info(tab_info, size)),
  179:     ?verify_mnesia([Node1, Node3], [Node2]).
  180: 
  181: 
  182: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  183: %% Check the error descriptions
  184: 
  185: error_description(suite) -> [];
  186: error_description(Config) when is_list(Config) ->
  187:     ?acquire_nodes(1, Config),
  188:     Errors = [nested_transaction, badarg, no_transaction, combine_error,
  189:               bad_index, already_exists, index_exists, no_exists, system_limit,
  190:               mnesia_down, not_a_db_node, bad_type, node_not_running, 
  191:               truncated_binary_file, active, illegal
  192:              ],
  193:     ?match(X when is_atom(X), mnesia:error_description({error, bad_error_msg})),
  194:     ?match(X when is_tuple(X), mnesia:error_description({'EXIT', pid, bad})),
  195:     %% This is real error msg
  196:     ?match(X when is_tuple(X), mnesia:error_description(
  197:                               {error, 
  198:                                {"Cannot prepare checkpoint (bad reply)",
  199:                                 {{877,957351,758147},a@legolas},
  200:                                 {error,{node_not_running,a1@legolas}}}})),
  201:     check_errors(error, Errors),
  202:     check_errors(aborted, Errors),
  203:     check_errors('EXIT', Errors).
  204: 
  205: check_errors(_Err, []) -> ok;
  206: check_errors(Err, [Desc|R]) -> 
  207:     ?match(X when is_list(X), mnesia:error_description({Err, Desc})),
  208:     check_errors(Err, R).
  209: 
  210: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  211: %% Add and drop db nodes
  212: 
  213: db_node_lifecycle(suite) -> [];
  214: db_node_lifecycle(Config) when is_list(Config) ->
  215:     [Node1, Node2, Node3] = AllNodes = ?acquire_nodes(3, Config),
  216:     Tab = db_node_lifecycle,
  217: 
  218:     Who = fun(T) -> 
  219: 		  L1 = mnesia:table_info(T, ram_copies),
  220: 		  L2 = mnesia:table_info(T, disc_copies),
  221: 		  L3 = mnesia:table_info(T, disc_only_copies),
  222: 		  L1 ++ L2 ++ L3
  223: 	  end,
  224: 
  225:     SNs = ?sort(AllNodes),
  226: 
  227:     Schema = [{name, Tab}, {ram_copies, [Node1, Node2]}],
  228:     ?match({atomic, ok}, mnesia:create_table(Schema)),
  229: 
  230:     ?match([], mnesia_test_lib:stop_mnesia(AllNodes)),
  231:     ?match(ok, mnesia:delete_schema(AllNodes)),
  232:     ?match({error, _}, mnesia:create_schema(foo)),
  233:     ?match({error, _}, mnesia:create_schema([foo])),
  234:     ?match({error, _}, mnesia:create_schema([foo@bar])),
  235:     ?match(ok, mnesia:start()),
  236:     ?match(false, mnesia:system_info(use_dir)),
  237:     ?match({atomic, ok}, mnesia:create_table(Tab, [])),
  238:     ?match({aborted, {has_no_disc, Node1}}, mnesia:dump_tables([Tab])),
  239:     ?match({aborted, {has_no_disc, Node1}}, mnesia:change_table_copy_type(Tab, node(), disc_copies)),
  240:     ?match({aborted, {has_no_disc, Node1}}, mnesia:change_table_copy_type(Tab, node(), disc_only_copies)),
  241: 
  242:     ?match(stopped, mnesia:stop()),
  243: 
  244:     ?match(ok, mnesia:create_schema(AllNodes)),
  245:     ?match([], mnesia_test_lib:start_mnesia(AllNodes)),
  246: 
  247:     ?match([SNs, SNs, SNs], 
  248: 	   lists:map(fun lists:sort/1,
  249: 		     element(1, rpc:multicall(AllNodes, mnesia, table_info, 
  250: 					      [schema, disc_copies])))),
  251: 
  252:     ?match({aborted, {already_exists, schema, Node2, _}},
  253:            mnesia:change_table_copy_type(schema, Node2, disc_copies)),
  254:     ?match({atomic, ok},
  255:            mnesia:change_table_copy_type(schema, Node2, ram_copies)),
  256:     ?match({aborted, {already_exists, schema, Node2, _}},
  257:            mnesia:change_table_copy_type(schema, Node2, ram_copies)),
  258:     
  259:     ?match({atomic, ok},
  260:            mnesia:change_table_copy_type(schema, Node2, disc_copies)),
  261: 
  262:     ?match([SNs, SNs, SNs], 
  263: 	   lists:map(fun lists:sort/1,
  264: 		     element(1, rpc:multicall(AllNodes, mnesia, table_info, 
  265: 					      [schema, disc_copies])))),
  266: 
  267:     %% Delete the DB 
  268: 
  269:     Tab2 = disk_tab,
  270:     Tab3 = not_local,
  271:     Tab4 = local,
  272:     Tab5 = remote,
  273: 
  274:     Tabs = [Schema,
  275: 	    [{name, Tab2},  {disc_copies, AllNodes}],
  276: 	    [{name, Tab3},  {ram_copies, [Node2, Node3]}],
  277: 	    [{name, Tab4},  {disc_only_copies, [Node1]}],
  278: 	    [{name, Tab5},  {disc_only_copies, [Node2]}]],    
  279: 
  280:     [?match({atomic, ok}, mnesia:create_table(T)) || T <- Tabs ],
  281: 
  282:     ?match({aborted, {active, _, Node2}}, 
  283: 	   mnesia:del_table_copy(schema, Node2)),
  284: 
  285:     ?match([], mnesia_test_lib:stop_mnesia([Node1])),
  286:     ?match({aborted, {node_not_running, Node1}}, 
  287: 	   mnesia:del_table_copy(schema, Node2)),
  288: 
  289:     ?match([], mnesia_test_lib:start_mnesia([Node1],[Tab2,Tab4])),
  290:     ?match([], mnesia_test_lib:stop_mnesia([Node2])),
  291:     ?match({atomic, ok}, 
  292: 	   mnesia:del_table_copy(schema, Node2)),
  293: 
  294:     %% Check     
  295:     RemNodes = AllNodes -- [Node2],
  296: 
  297:     ?match(RemNodes, mnesia:system_info(db_nodes)),     
  298:     ?match([Node1], Who(Tab)),
  299:     ?match(RemNodes, Who(Tab2)),
  300:     ?match([Node3], Who(Tab3)),
  301:     ?match([Node1], Who(Tab4)),
  302:     ?match({'EXIT', {aborted, {no_exists, _, _}}}, Who(Tab5)),
  303: 
  304:     ?match({atomic, ok},
  305:            mnesia:change_table_copy_type(Tab2, Node3, ram_copies)),
  306: 
  307:     ?match({atomic, ok},
  308:            mnesia:change_table_copy_type(schema, Node3, ram_copies)),
  309: 
  310:     ?match([], mnesia_test_lib:stop_mnesia([Node3])),
  311:     ?match({atomic, ok}, 
  312: 	   mnesia:del_table_copy(schema, Node3)),
  313:     ?match([Node1], mnesia:system_info(db_nodes)),     
  314:     ?match([Node1], Who(Tab)),
  315:     ?match([Node1], Who(Tab2)),
  316:     ?match({'EXIT', {aborted, {no_exists, _, _}}}, Who(Tab3)),
  317:     ?match([Node1], Who(Tab4)),
  318:     ?match({'EXIT', {aborted, {no_exists, _, _}}}, Who(Tab5)),
  319: 
  320:     ?verify_mnesia([Node1], []).
  321: 
  322: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  323: %% Drop a db node when several disk resident nodes are down
  324: 
  325: evil_delete_db_node(suite) -> [];
  326: evil_delete_db_node(Config) when is_list(Config) ->
  327:     [Node1, Node2, Node3] = AllNodes = ?acquire_nodes(3, Config),
  328:     Tab = evil_delete_db_node,
  329: 
  330:     ?match({atomic, ok}, mnesia:create_table(Tab, [{disc_copies, AllNodes}])),
  331:     
  332:     ?match([], mnesia_test_lib:stop_mnesia([Node2, Node3])),
  333: 
  334:     ?match({atomic, ok}, mnesia:del_table_copy(schema, Node2)),
  335:     
  336:     RemNodes = AllNodes -- [Node2],
  337:     
  338:     ?match(RemNodes, mnesia:system_info(db_nodes)),
  339:     ?match(RemNodes, mnesia:table_info(Tab, disc_copies)),
  340:     
  341:     ?verify_mnesia([Node1], []).
  342: 
  343: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  344: %% Start and stop the system
  345: 
  346: start_and_stop(suite) -> [];
  347: start_and_stop(Config) when is_list(Config) ->
  348:     [Node1 | _] = Nodes = ?acquire_nodes(all, Config),
  349: 
  350:     ?match(stopped, rpc:call(Node1, mnesia, stop, [])),
  351:     ?match(stopped, rpc:call(Node1, mnesia, stop, [])),
  352:     ?match(ok, rpc:call(Node1, mnesia, start, [])),
  353:     ?match(ok, rpc:call(Node1, mnesia, start, [])),
  354:     ?match(stopped, rpc:call(Node1, mnesia, stop, [])),
  355:     ?verify_mnesia(Nodes -- [Node1], [Node1]),
  356:     ?match([], mnesia_test_lib:start_mnesia(Nodes)),
  357:     ?verify_mnesia(Nodes, []).
  358: 
  359: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  360: %% Checkpoints and backup management
  361: 
  362: checkpoint(suite) -> [];
  363: checkpoint(Config) when is_list(Config) ->
  364:     checkpoint(2, Config),
  365:     checkpoint(3, Config).
  366: 
  367: checkpoint(NodeConfig, Config) ->
  368:     [Node1 | _] = TabNodes = ?acquire_nodes(NodeConfig, Config),
  369:     CreateTab = fun(Type, N, Ns) ->
  370:                         Tab0 = lists:concat(["local_checkpoint_", Type, N]),
  371:                         Tab = list_to_atom(Tab0),
  372:                         catch mnesia:delete_table(Tab),
  373:                         ?match({atomic, ok},
  374:                                mnesia:create_table(Tab, [{Type, Ns}])),
  375:                         Tab
  376:                 end,
  377:     CreateTabs = fun(Type, Acc) ->
  378:                          [CreateTab(Type, 1, [hd(TabNodes)]),
  379:                           CreateTab(Type, 2, TabNodes),
  380:                           CreateTab(Type, 3, [lists:last(TabNodes)])] ++
  381:                              Acc
  382:                  end,
  383:     Types = [ram_copies, disc_copies, disc_only_copies],
  384:     Tabs = lists:foldl(CreateTabs, [], Types),
  385:     Recs = ?sort([{T, N, N} || T <- Tabs, N <- lists:seq(1, 10)]),
  386:     lists:foreach(fun(R) -> ?match(ok, mnesia:dirty_write(R)) end, Recs),
  387: 
  388:     CpName = a_checkpoint_name,
  389:     MinArgs = [{name, CpName}, {min, Tabs}, {allow_remote, false}],
  390:     ?match({error, _}, rpc:call(Node1, mnesia, activate_checkpoint, [MinArgs])),
  391: 
  392:     MaxArgs = [{name, CpName}, {max, Tabs}, {allow_remote, true}],
  393:     ?match({ok, CpName, L} when is_list(L),
  394: 	   rpc:call(Node1, mnesia, activate_checkpoint, [MaxArgs])),
  395:     ?match(ok, rpc:call(Node1, mnesia, deactivate_checkpoint, [CpName])),
  396: 
  397:     Args = [{name, CpName}, {min, Tabs}, {allow_remote, true}],
  398:     ?match({ok, CpName, L} when is_list(L),
  399:            rpc:call(Node1, mnesia, activate_checkpoint, [Args])),
  400:     Recs2 = ?sort([{T, K, 0} || {T, K, _} <- Recs]),
  401:     lists:foreach(fun(R) -> ?match(ok, mnesia:dirty_write(R)) end, Recs2),
  402:     ?match(ok, rpc:call(Node1, mnesia, deactivate_checkpoint, [CpName])),
  403: 
  404:     ?match({error, Reason1 } when element(1, Reason1) == no_exists,
  405:            mnesia:deactivate_checkpoint(CpName)),
  406:     ?match({error, Reason2 } when element(1, Reason2) == badarg,
  407:            mnesia:activate_checkpoint(foo)),
  408:     ?match({error, Reason3 } when element(1, Reason3) == badarg,
  409:            mnesia:activate_checkpoint([{foo, foo}])),
  410:     ?match({error, Reason4 } when element(1, Reason4) == badarg,
  411:            mnesia:activate_checkpoint([{max, foo}])),
  412:     ?match({error, Reason5 } when element(1, Reason5) == badarg,
  413:            mnesia:activate_checkpoint([{min, foo}])),
  414:     ?match({error, _}, mnesia:activate_checkpoint([{min, [foo@bar]}])),
  415:     ?match({error, Reason6 } when element(1, Reason6) == badarg,
  416:            mnesia:activate_checkpoint([{allow_remote, foo}])),
  417: 
  418:     Fun = fun(Tab) -> ?match({atomic, ok}, mnesia:delete_table(Tab)) end,
  419:     lists:foreach(Fun, Tabs),
  420:     ?verify_mnesia(TabNodes, []).
  421: 
  422: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  423: %% Create and delete tables
  424: 
  425: %% Get meta info about table
  426: 
  427: -define(vrl, mnesia_test_lib:verify_replica_location).
  428: 
  429: replica_location(suite) -> [];
  430: replica_location(Config) when is_list(Config) ->
  431:     [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config),
  432:     Tab = replica_location,
  433: 
  434:     %% Create three replicas
  435:     Schema = [{name, Tab}, {disc_only_copies, [Node1]},
  436:               {ram_copies, [Node2]}, {disc_copies, [Node3]}],
  437:     ?match({atomic, ok}, mnesia:create_table(Schema)),
  438:     ?match([], ?vrl(Tab, [Node1], [Node2], [Node3], Nodes)),
  439: 
  440:     %% Delete one replica
  441:     ?match({atomic, ok}, mnesia:del_table_copy(Tab, Node2)),
  442:     ?match([], ?vrl(Tab, [Node1], [], [Node3], Nodes)),
  443: 
  444:     %% Move one replica
  445:     ?match({atomic, ok}, mnesia:move_table_copy(Tab, Node1, Node2)),
  446:     ?match([], ?vrl(Tab, [Node2], [], [Node3], Nodes)),
  447: 
  448:     %% Change replica type
  449:     ?match({atomic, ok}, mnesia:change_table_copy_type(Tab, Node2, ram_copies)),
  450:     ?match([], ?vrl(Tab, [], [Node2], [Node3], Nodes)),
  451: 
  452:     ?verify_mnesia(Nodes, []).
  453: 
  454: table_lifecycle(suite) -> [];
  455: table_lifecycle(Config) when is_list(Config) ->
  456:     [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
  457: 
  458:     ?match({atomic, ok}, mnesia:create_table([{type, bag},
  459: 					      {ram_copies, [Node1]},
  460: 					      {attributes, [rajtan, tajtan]},
  461: 					      {name, order_of_args}])),
  462:     ?match([], mnesia:dirty_read({order_of_args, 4711})),
  463:     ?match({atomic, ok}, mnesia:create_table([{name, already_exists},
  464: 					      {ram_copies, [Node1]}])),
  465:     ?match({aborted, Reason23 } when element(1, Reason23) ==already_exists,
  466: 	   mnesia:create_table([{name, already_exists},
  467: 				{ram_copies, [Node1]}])),
  468:     ?match({aborted, Reason21 } when element(1, Reason21) == bad_type,
  469:            mnesia:create_table([{name, bad_node}, {ram_copies, ["foo"]}])),
  470:     ?match({aborted, Reason2} when element(1, Reason2) == bad_type,
  471:            mnesia:create_table([{name, zero_arity}, {attributes, []}])),
  472:     ?match({aborted, Reason3} when element(1, Reason3) == badarg,
  473:            mnesia:create_table([])),
  474:     ?match({aborted, Reason4} when element(1, Reason4) == badarg,
  475:            mnesia:create_table(atom)),
  476:     ?match({aborted, Reason5} when element(1, Reason5) == badarg,
  477:            mnesia:create_table({cstruct, table_name_as_atom})),
  478:     ?match({aborted, Reason6 } when element(1, Reason6) == bad_type,
  479:            mnesia:create_table([{name, no_host}, {ram_copies, foo}])),
  480:     ?match({aborted, Reason7 } when element(1, Reason7) == bad_type,
  481:            mnesia:create_table([{name, no_host}, {disc_only_copies, foo}])),
  482:     ?match({aborted, Reason8} when element(1, Reason8) == bad_type,
  483:            mnesia:create_table([{name, no_host}, {disc_copies, foo}])),
  484: 
  485:     CreateFun =
  486:         fun() -> ?match({aborted, nested_transaction},
  487:                         mnesia:create_table([{name, nested_trans}])), ok
  488:         end,
  489:     ?match({atomic, ok}, mnesia:transaction(CreateFun)),
  490:     ?match({atomic, ok}, mnesia:create_table([{name, remote_tab},
  491: 					      {ram_copies, [Node2]}])),
  492: 
  493:     ?match({atomic, ok}, mnesia:create_table([{name, a_brand_new_tab},
  494: 					      {ram_copies, [Node1]}])),
  495:     ?match([], mnesia:dirty_read({a_brand_new_tab, 4711})),
  496:     ?match({atomic, ok}, mnesia:delete_table(a_brand_new_tab)),
  497:     ?match({'EXIT', {aborted, Reason31}} when element(1, Reason31) == no_exists,
  498:            mnesia:dirty_read({a_brand_new_tab, 4711})),
  499:     ?match({aborted, Reason41} when element(1, Reason41) == no_exists,
  500:            mnesia:delete_table(a_brand_new_tab)),
  501:     ?match({aborted, Reason9} when element(1, Reason9) == badarg,
  502:            mnesia:create_table([])),
  503: 
  504:     ?match({atomic, ok}, mnesia:create_table([{name, nested_del_trans},
  505: 					      {ram_copies, [Node1]}])),
  506: 
  507:     DeleteFun = fun() -> ?match({aborted, nested_transaction},
  508:                                 mnesia:delete_table(nested_del_trans)), ok end,
  509:     ?match({atomic, ok}, mnesia:transaction(DeleteFun)),
  510: 
  511:     ?match({aborted, Reason10} when element(1, Reason10) == bad_type,
  512:            mnesia:create_table([{name, create_with_index}, {index, 2}])),
  513:     ?match({aborted, Reason32} when element(1, Reason32) == bad_type,
  514:            mnesia:create_table([{name, create_with_index}, {index, [-1]}])),
  515:     ?match({aborted, Reason33} when element(1, Reason33) == bad_type,
  516:            mnesia:create_table([{name, create_with_index}, {index, [0]}])),
  517:     ?match({aborted, Reason34} when element(1, Reason34) == bad_type,
  518:            mnesia:create_table([{name, create_with_index}, {index, [1]}])),
  519:     ?match({aborted, Reason35} when element(1, Reason35) == bad_type,
  520:            mnesia:create_table([{name, create_with_index}, {index, [2]}])),
  521:     ?match({atomic, ok},
  522:            mnesia:create_table([{name, create_with_index}, {index, [3]},
  523:                                 {ram_copies, [Node1]}])),
  524: 
  525:     ets:new(ets_table, [named_table]),
  526:     ?match({aborted, _}, mnesia:create_table(ets_table, [{ram_copies, Nodes}])),
  527:     ?match({aborted, _}, mnesia:create_table(ets_table, [{ram_copies, [Node1]}])),
  528:     ets:delete(ets_table),
  529:     ?match({atomic, ok}, mnesia:create_table(ets_table, [{ram_copies, [Node1]}])),
  530:     ?match(Node1, rpc:call(Node1, mnesia_lib, val, [{ets_table,where_to_read}])),
  531:     ?match(Node1, rpc:call(Node2, mnesia_lib, val, [{ets_table,where_to_read}])),
  532:     ?match({atomic, ok}, mnesia:change_table_copy_type(ets_table, Node1, disc_only_copies)),    
  533:     ?match(Node1, rpc:call(Node2, mnesia_lib, val, [{ets_table,where_to_read}])),
  534:     
  535:     ?verify_mnesia(Nodes, []).
  536: 
  537: 
  538: storage_options(suite) -> [];
  539: storage_options(Config) when is_list(Config) ->
  540:     [N1,N2,N3] = Nodes = ?acquire_nodes(3, Config),
  541: 
  542:     ?match({aborted,_}, mnesia:create_table(a, [{storage_properties, [{ets,foobar}]}])),
  543:     ?match({aborted,_}, mnesia:create_table(a, [{storage_properties, [{ets,[foobar]}]}])),
  544:     ?match({aborted,_}, mnesia:create_table(a, [{storage_properties, [{ets,[duplicate_bag]}]}])),
  545:     ?match({aborted,_}, mnesia:create_table(a, [{storage_properties, [{dets,[{type,bag}]}]}])),
  546: 
  547:     ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, [N1]},
  548: 						 {disc_only_copies, [N2]},
  549: 						 {storage_properties,
  550: 						  [{ets,[compressed]},
  551: 						   {dets, [{auto_save, 5000}]} ]}])),
  552:     ?match(true, ets:info(a, compressed)),
  553:     ?match(5000, rpc:call(N2, dets, info, [a, auto_save])),
  554:     ?match(ok, mnesia:dirty_write({a,1,1})),
  555:     ?match([{a,1,1}], mnesia:dirty_read({a,1})),
  556:     mnesia:dump_log(),
  557:     W2C1 = [{N2, disc_only_copies}, {N1, ram_copies}],
  558:     ?match(W2C1, lists:sort(rpc:call(N2, mnesia_lib, val, [{a, where_to_commit}]))),
  559:     ?match(W2C1, lists:sort(rpc:call(N3, mnesia_lib, val, [{a, where_to_commit}]))),
  560:     ?match({atomic,ok}, mnesia:change_table_copy_type(a, N1, disc_only_copies)),
  561:     W2C2 = [{N2, disc_only_copies}, {N1, disc_only_copies}],
  562:     ?match(W2C2, lists:sort(rpc:call(N2, mnesia_lib, val, [{a, where_to_commit}]))),
  563:     ?match(W2C2, lists:sort(rpc:call(N3, mnesia_lib, val, [{a, where_to_commit}]))),
  564:     ?match(undefined, ets:info(a, compressed)),
  565:     ?match(5000, dets:info(a, auto_save)),
  566:     ?match({atomic,ok}, mnesia:change_table_copy_type(a, N1, disc_copies)),
  567:     ?match(true, ets:info(a, compressed)),
  568: 
  569:     ?verify_mnesia(Nodes, []).
  570: 
  571: 
  572: clear_table_during_load(suite) -> [];
  573: clear_table_during_load(doc) ->
  574:     ["Clear table caused during load caused a schema entry in the actual tab"];
  575: clear_table_during_load(Config) when is_list(Config) ->
  576:     Nodes = [_, Node2] = ?acquire_nodes(2, Config ++ [{tc_timeout, timer:minutes(2)}]),
  577:     ?match({atomic,ok}, mnesia:create_table(cleartab, [{ram_copies, Nodes}])),
  578:     Tester = self(),
  579:     Bin = <<"Testingasdasd", 0:32000>>,
  580:     Fill =  fun() -> [mnesia:write({cleartab, N, Bin}) || N <- lists:seq(1, 3000)], ok end,
  581:     ?match({atomic, ok}, mnesia:sync_transaction(Fill)),
  582: 
  583:     StopAndStart = fun() ->
  584: 			   stopped = mnesia:stop(),
  585: 			   Tester ! {self(), stopped},
  586: 			   receive start_node -> ok end,
  587: 			   ok = mnesia:start(),
  588: 			   ok = mnesia:wait_for_tables([cleartab], 2000),
  589: 			   lists:foreach(fun({cleartab,_,_}) -> ok;
  590: 					    (What) -> Tester ! {failed, What},
  591: 						      unlink(Tester),
  592: 						      exit(foo)
  593: 					 end,
  594: 					 ets:tab2list(cleartab)),
  595: 			   Tester ! {self(), ok},
  596: 			   normal
  597: 		   end,
  598: 
  599:     Test = fun(N) ->
  600: 		   Pid = spawn_link(Node2, StopAndStart),
  601: 		   receive {Pid, stopped} -> ok end,
  602: 		   Pid ! start_node,
  603: 		   timer:sleep(N*10),
  604: 		   {atomic, ok} = mnesia:clear_table(cleartab),
  605: 		   receive
  606: 		       {Pid, ok} -> ok;
  607: 		       {failed, What} ->
  608: 			   io:format("Failed in ~p tries, with ~p~n",[N, What]),
  609: 			   exit({error, What});
  610: 		       {'EXIT', Pid, Reason} ->
  611: 			   exit({died, Reason})
  612: 		   end
  613: 	   end,
  614:     [Test(N) || N <- lists:seq(1, 10)],
  615:     ?verify_mnesia(Nodes, []).
  616: 
  617: 
  618: add_copy_conflict(suite) -> [];
  619: add_copy_conflict(doc) -> 
  620:     ["Verify that OTP-5065 doesn't happen again, whitebox testing"];
  621: add_copy_conflict(Config) when is_list(Config) ->
  622:     Nodes = [Node1, Node2] = 
  623: 	?acquire_nodes(2, Config ++ [{tc_timeout, timer:minutes(2)}]),
  624:     
  625:     ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, Nodes}])),
  626:     ?match({atomic, ok}, mnesia:create_table(b, [{ram_copies, Nodes}])),
  627:     ?match({atomic, ok}, mnesia:create_table(test, [{ram_copies, [Node2]}])),            
  628:     mnesia:stop(),
  629:     ?match(ok,mnesia:start([{no_table_loaders, 1}])),
  630: 
  631:     verify_ll_queue(10),
  632: 
  633:     Self = self(),
  634:     Test = fun() ->
  635: 		   Res = mnesia:add_table_copy(test, Node1, ram_copies),
  636: 		   Self ! {test, Res}
  637: 	   end,
  638:     %% Create conflict with loader queue.
  639:     spawn_link(Test),
  640:     ?match_receive(timeout),
  641:     %% Conflict ok
  642:     mnesia_controller:unblock_controller(),
  643:     
  644:     ?match_receive({test, {atomic,ok}}),
  645:     ?match(ok, mnesia:wait_for_tables([a,b], 3000)),
  646:     ?verify_mnesia(Nodes, []),
  647:     ?cleanup(1, Config).
  648: 
  649: verify_ll_queue(0) ->
  650:     ?error("Couldn't find anything in queue~n",[]);
  651: verify_ll_queue(N) ->
  652:     ?match(granted,mnesia_controller:block_controller()),
  653:     case mnesia_controller:get_info(1000) of
  654: 	{info,{state,_,true,[],_Loader,[],[],[],_,_,_,_,_,_}} ->
  655: 	    %% Very slow SMP machines havn't loaded it yet..
  656: 	    mnesia_controller:unblock_controller(),
  657: 	    timer:sleep(10),
  658: 	    verify_ll_queue(N-1);
  659: 	{info,{state,_,true,[],Loader,LL,[],[],_,_,_,_,_,_}} ->
  660: 	    io:format("~p~n", [{Loader,LL}]),
  661: 	    ?match([_], LL);  %% Verify that something is in the loader queue
  662: 	Else ->
  663: 	    ?error("No match ~p maybe the internal format has changed~n",[Else])
  664:     end.
  665: 
  666: add_copy_when_going_down(suite) -> [];
  667: add_copy_when_going_down(doc) -> 
  668:     ["Tests abort when node we load from goes down"];
  669: add_copy_when_going_down(Config) -> 
  670:     [Node1, Node2] = 
  671: 	?acquire_nodes(2, Config ++ [{tc_timeout, timer:minutes(2)}]),
  672:     ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, [Node1]}])),
  673:     %% Grab a write lock 
  674:     WriteAndWait = fun() -> 
  675: 			   mnesia:write({a,1,1}),
  676: 			   receive continue -> ok 
  677: 			   end
  678: 		   end,
  679:     _Lock = spawn(fun() -> mnesia:transaction(WriteAndWait) end),
  680:     Tester = self(),
  681:     spawn_link(fun() -> Res = rpc:call(Node2, mnesia, add_table_copy,
  682: 				       [a, Node2, ram_copies]),
  683: 			Tester ! {test, Res}
  684: 	       end),
  685:     %% We have a lock here we should get a timeout
  686:     ?match_receive(timeout),
  687:     mnesia_test_lib:kill_mnesia([Node1]),
  688:     ?match_receive({test,{aborted,_}}),
  689:     ?verify_mnesia([Node2], []).
  690: 
  691: 
  692: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  693: %% Add, drop and move replicas, change storage types
  694: %% Change table layout (only arity change supported)
  695: 
  696: -record(replica_management, {k, v}).
  697: -record(new_replica_management, {k, v, extra}).
  698: 
  699: -define(SS(R), lists:sort(element(1,R))).
  700: 
  701: replica_management(doc) ->
  702:     "Add, drop and move replicas, change storage types.";
  703: replica_management(suite) ->
  704:     [];
  705: replica_management(Config) when is_list(Config) ->
  706:     %% add_table_copy/3, del_table_copy/2, move_table_copy/3,
  707:     %% change_table_copy_type/3, transform_table/3
  708: 
  709:     Nodes = [Node1, Node2, Node3] = ?acquire_nodes(3, Config),
  710: 
  711:     Tab = replica_management,
  712:     Attrs = record_info(fields, replica_management),
  713: 
  714:     %%
  715:     %% Add, delete and change replicas
  716:     %%
  717:     ?match({atomic, ok},
  718:            mnesia:create_table([{name, Tab}, {attributes, Attrs},
  719:                                 {ram_copies, [Node1, Node3]}])),
  720:     [?match(ok, mnesia:dirty_write({Tab, K, K + 2})) || K <-lists:seq(1, 10)],
  721:     ?match([], ?vrl(Tab, [], [Node1, Node3], [], Nodes)),
  722:     %% R - -
  723:     ?match({atomic, ok}, mnesia:dump_tables([Tab])),
  724:     ?match({aborted,  Reason50 } when element(1, Reason50) == combine_error,
  725: 	   mnesia:add_table_copy(Tab, Node2, disc_copies)),
  726:     ?match({aborted,  Reason51 } when element(1, Reason51) == combine_error,
  727:            mnesia:change_table_copy_type(Tab, Node1, disc_copies)),
  728:     ?match({atomic, ok}, mnesia:clear_table(Tab)),
  729:     SyncedCheck = fun() ->
  730: 			  mnesia:lock({record,Tab,0}, write),
  731: 			  ?match([0,0,0], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size])))
  732: 		  end,
  733:     mnesia:transaction(SyncedCheck),
  734: 
  735:     ?match({[0,0,0], []}, rpc:multicall(Nodes, mnesia, table_info, [Tab, size])),
  736:     ?match({atomic, ok}, mnesia:del_table_copy(Tab, Node1)),
  737:     ?match({atomic, ok}, mnesia:del_table_copy(Tab, Node3)),
  738:     ?match([], ?vrl(Tab, [], [], [], Nodes)),
  739:     %% - - -
  740:     ?match({aborted,Reason52} when element(1, Reason52) ==  no_exists,
  741:            mnesia:add_table_copy(Tab, Node3, ram_copies)),
  742: 
  743:     ?match({atomic, ok}, mnesia:create_table([{name, Tab},
  744: 					      {attributes, Attrs},
  745: 					      {disc_copies, [Node1]}])),
  746:     ?match([], ?vrl(Tab, [], [], [Node1], Nodes)),
  747:     %% D - -
  748:     [?match(ok, mnesia:dirty_write({Tab, K, K + 2})) || K <-lists:seq(1, 10)],
  749: 
  750:     ?match({aborted,  Reason53} when element(1, Reason53) == badarg,
  751:            mnesia:add_table_copy(Tab, Node2, bad_storage_type)),
  752:     ?match({atomic, ok}, mnesia:add_table_copy(Tab, Node2, disc_only_copies)),
  753:     ?match([], ?vrl(Tab, [Node2], [], [Node1], Nodes)),
  754:     ?match([0,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  755:     %% D DO -
  756:     ?match({atomic, ok}, mnesia:add_table_copy(Tab, Node3, ram_copies)),
  757:     ?match([], ?vrl(Tab, [Node2], [Node3], [Node1], Nodes)),
  758:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  759:     %% D DO R
  760:     ?match({atomic, ok},
  761:            mnesia:change_table_copy_type(Tab, Node1, disc_only_copies)),
  762:     ?match([], ?vrl(Tab, [Node1, Node2], [Node3], [], Nodes)),
  763:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  764:     %% DO DO R
  765:     ?match({aborted,  Reason54} when element(1, Reason54) == already_exists,
  766:            mnesia:add_table_copy(Tab, Node3, ram_copies)),
  767:     ?match({atomic, ok}, mnesia:del_table_copy(Tab, Node1)),
  768:     ?match([], ?vrl(Tab, [Node2], [Node3], [], Nodes)),
  769:     %% - DO R
  770:     ?match({aborted, _}, mnesia:del_table_copy(Tab, Node1)),
  771:     ?match(Tab, ets:new(Tab, [named_table])),
  772:     ?match({aborted, _}, mnesia:add_table_copy(Tab, Node1, disc_copies)),
  773:     ?match(true, ets:delete(Tab)),
  774:     ?match({atomic, ok}, mnesia:add_table_copy(Tab, Node1, disc_copies)),
  775:     ?match([], ?vrl(Tab, [Node2], [Node3], [Node1], Nodes)),
  776:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  777:     %% D DO R
  778:     ?match({atomic, ok},mnesia:change_table_copy_type(Tab, Node3, disc_only_copies)),
  779:     ?match([], ?vrl(Tab, [Node2, Node3], [], [Node1], Nodes)),
  780:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  781: 
  782:     %% D DO D0
  783:     ?match({atomic, ok}, mnesia:change_table_copy_type(Tab, Node3, ram_copies)),
  784:     ?match([], ?vrl(Tab, [Node2], [Node3], [Node1], Nodes)),
  785:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  786:     %% D DO R
  787:     ?match({atomic, ok},
  788:            mnesia:change_table_copy_type(Tab, Node2, disc_copies)),
  789:     ?match([], ?vrl(Tab, [], [Node3], [Node1,Node2], Nodes)),
  790:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  791: 
  792:     %% D D R
  793:     ?match({atomic, ok}, mnesia:change_table_copy_type(Tab, Node1, disc_only_copies)),
  794:     ?match([], ?vrl(Tab, [Node1], [Node3], [Node2], Nodes)),
  795:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  796: 
  797:     %% DO D R
  798:     ?match(Tab, ets:new(Tab, [named_table])),
  799:     ?match({aborted, _}, mnesia:change_table_copy_type(Tab, Node1, ram_copies)),
  800:     ?match(true, ets:delete(Tab)),
  801:     ?match({atomic, ok}, mnesia:change_table_copy_type(Tab, Node1, ram_copies)),
  802:     ?match([], ?vrl(Tab, [], [Node3,Node1], [Node2], Nodes)),
  803:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  804:     %% R D R
  805:     ?match({atomic, ok}, mnesia:change_table_copy_type(Tab, Node1, disc_copies)),
  806:     ?match([], ?vrl(Tab, [], [Node3], [Node2,Node1], Nodes)),
  807:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  808: 
  809:     %% D D R
  810:     ?match({atomic, ok}, mnesia:change_table_copy_type(Tab, Node2, disc_only_copies)),
  811:     ?match([], ?vrl(Tab, [Node2], [Node3], [Node1], Nodes)),
  812:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  813: 
  814:     %% D DO R
  815:     ?match({atomic, ok}, mnesia:change_table_copy_type(Tab, Node3, disc_only_copies)),
  816:     ?match([], ?vrl(Tab, [Node2, Node3], [], [Node1], Nodes)),
  817:     ?match([10,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  818:     %% D DO DO
  819:     %% test clear
  820:     ?match({atomic, ok}, mnesia:clear_table(Tab)),
  821:     mnesia:transaction(SyncedCheck),
  822: 
  823:     %% rewrite for rest of testcase
  824:     [?match(ok, mnesia:dirty_write({Tab, K, K + 2})) || K <-lists:seq(1, 10)],
  825: 
  826:     %% D DO DO
  827:     ?match({atomic, ok}, mnesia:del_table_copy(Tab, Node2)),
  828:     ?match([], ?vrl(Tab, [Node3], [], [Node1], Nodes)),
  829:     %% D - DO
  830:     ?match({aborted,  Reason55} when element(1, Reason55) == already_exists,
  831:            mnesia:change_table_copy_type(Tab, Node1, disc_copies)),
  832: 
  833:     %%
  834:     %% Move replica
  835:     %%
  836:     ?match({atomic, ok}, mnesia:move_table_copy(Tab, Node1, Node2)),
  837:     ?match([], ?vrl(Tab, [Node3], [], [Node2], Nodes)),
  838:     ?match([0,10,10], ?SS(rpc:multicall(Nodes, mnesia, table_info, [Tab, size]))),
  839:     %% - D DO
  840:     ?match({aborted, _}, mnesia:move_table_copy(Tab, Node1, Node2)),
  841:     ?match([], mnesia_test_lib:stop_mnesia([Node3])),
  842:     ?match({atomic,ok}, mnesia:transaction(fun() -> mnesia:write({Tab, 43, sync_me}) end)),
  843:     ?match([], ?vrl(Tab, [Node3], [], [Node2],Nodes -- [Node3])),
  844:     %% - D DO
  845:     ?match({aborted,Reason56} when element(1, Reason56) == not_active,
  846: 	   mnesia:move_table_copy(Tab, Node3, Node1)),
  847:     ?match([], ?vrl(Tab, [Node3], [], [Node2],Nodes -- [Node3])),
  848:     %% DO D -
  849:     ?match([], mnesia_test_lib:start_mnesia([Node3])),
  850:     ?match([], ?vrl(Tab, [Node3], [], [Node2], Nodes)),
  851:     %% DO D -
  852:     
  853:     %%
  854:     %% Transformer
  855:     %%
  856: 
  857:     NewAttrs = record_info(fields, new_replica_management),
  858:     Transformer =
  859:         fun(Rec) when is_record(Rec, replica_management) -> 
  860: 		#new_replica_management{k = Rec#replica_management.k,
  861: 					v = Rec#replica_management.v,
  862: 					extra = Rec#replica_management.k * 2}
  863:         end,
  864:     ?match({atomic, ok}, mnesia:transform_table(Tab, fun(R) -> R end, Attrs)),
  865:     ?match({atomic, ok}, mnesia:transform_table(Tab, Transformer, NewAttrs, new_replica_management)),
  866: 
  867:     ERlist = [#new_replica_management{k = K, v = K+2, extra = K*2} || K <- lists:seq(1, 10)],
  868:     ARlist = [hd(mnesia:dirty_read(Tab, K)) || K <- lists:seq(1, 10)],
  869: 
  870:     ?match(ERlist, ARlist),
  871: 
  872:     ?match({aborted,  Reason56} when element(1, Reason56) == bad_type,
  873:            mnesia:transform_table(Tab, Transformer, 0)),
  874:     ?match({aborted, Reason57} when element(1, Reason57) ==  bad_type,
  875:            mnesia:transform_table(Tab, Transformer, -1)),
  876:     ?match({aborted, Reason58} when element(1, Reason58) ==  bad_type,
  877:            mnesia:transform_table(Tab, Transformer, [])),
  878:     ?match({aborted,  Reason59} when element(1, Reason59) == bad_type,
  879:            mnesia:transform_table(Tab, no_fun, NewAttrs)),
  880:     ?match({aborted,  Reason59} when element(1, Reason59) == bad_type,
  881:            mnesia:transform_table(Tab, fun(X) -> X end, NewAttrs, {tuple})),
  882: 
  883:     %% OTP-3878 
  884:     ?match({atomic, ok}, mnesia:transform_table(Tab, ignore, 
  885:                                                 NewAttrs ++ [dummy])),
  886:     ?match({atomic, ok}, mnesia:transform_table(Tab, ignore, 
  887:                                                 NewAttrs ++ [dummy], last_rec)),
  888: 
  889:     ARlist = [hd(mnesia:dirty_read(Tab, K)) || K <- lists:seq(1, 10)],
  890:     ?match({'EXIT',{aborted,{bad_type,_}}},
  891:            mnesia:dirty_write(Tab, #new_replica_management{})),
  892:     ?match(ok, mnesia:dirty_write(Tab, {last_rec, k, v, e, dummy})),
  893: 
  894:     ?verify_mnesia(Nodes, []).
  895: 
  896: schema_availability(doc) ->
  897:     ["Test that schema succeeds (or fails) as intended when some db nodes are down."];
  898: schema_availability(suite) ->
  899:     [];
  900: schema_availability(Config) when is_list(Config) ->
  901:     [N1, _N2, N3] = Nodes = ?acquire_nodes(3, Config),
  902:     Tab = schema_availability,
  903:     Storage = mnesia_test_lib:storage_type(ram_copies, Config),
  904:     Def1 = [{Storage, [N1, N3]}],
  905:     ?match({atomic, ok}, mnesia:create_table(Tab, Def1)),
  906: 
  907:     N = 10,
  908:     ?match(ok, mnesia:sync_dirty(fun() -> [mnesia:write({Tab, K, K + 2}) || K <- lists:seq(1, N)], ok end)),
  909:     ?match({[N,0,N], []}, rpc:multicall(Nodes, mnesia, table_info, [Tab, size])),
  910:     ?match([], mnesia_test_lib:kill_mnesia([N3])),
  911:     ?match({[N,0,0], []}, rpc:multicall(Nodes, mnesia, table_info, [Tab, size])),
  912: 
  913:     ?match([], mnesia_test_lib:start_mnesia([N3], [Tab])),
  914:     ?match({[N,0,N], []}, rpc:multicall(Nodes, mnesia, table_info, [Tab, size])),
  915:     ?match([], mnesia_test_lib:kill_mnesia([N3])),
  916: 
  917:     ?match({atomic, ok}, mnesia:clear_table(Tab)),
  918:     ?match({[0,0,0], []}, rpc:multicall(Nodes, mnesia, table_info, [Tab, size])),
  919: 
  920:     ?match([], mnesia_test_lib:start_mnesia([N3], [Tab])),
  921:     ?match({[0,0,0], []}, rpc:multicall(Nodes, mnesia, table_info, [Tab, size])),
  922: 
  923:     ?verify_mnesia(Nodes, []).
  924: 
  925: -define(badrpc(Tab), {badrpc, {'EXIT', {aborted,{no_exists,Tab}}}}).
  926: 
  927: local_content(doc) ->
  928:     ["Test local_content functionality, we want to see that correct"
  929:      " properties gets propageted correctly between nodes"];
  930: local_content(suite) -> [];
  931: local_content(Config) when is_list(Config) ->
  932:     [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config), 
  933:     Tab1 = local1,
  934:     Def1 = [{local_content, true}, {ram_copies, Nodes}],
  935:     Tab2 = local2,
  936:     Def2 = [{local_content, true}, {disc_copies, [Node1]}],
  937:     Tab3 = local3,
  938:     Def3 = [{local_content, true}, {disc_only_copies, [Node1]}],
  939:     Tab4 = local4,
  940:     Def4 = [{local_content, true}, {ram_copies, [Node1]}],
  941: 
  942:     ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
  943:     ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
  944:     ?match({atomic, ok}, mnesia:create_table(Tab3, Def3)),
  945:     ?match({atomic, ok}, mnesia:create_table(Tab4, Def4)),
  946: 
  947:     ?match(ok, rpc:call(Node1, mnesia, dirty_write, [{Tab1, 1, Node1}])),
  948:     ?match(ok, rpc:call(Node2, mnesia, dirty_write, [{Tab1, 1, Node2}])),
  949:     ?match(ok, rpc:call(Node3, mnesia, dirty_write, [{Tab1, 1, Node3}])),
  950:     ?match(ok, rpc:call(Node1, mnesia, dirty_write, [{Tab2, 1, Node1}])),
  951:     ?match(ok, rpc:call(Node1, mnesia, dirty_write, [{Tab3, 1, Node1}])),
  952:     ?match(ok, rpc:call(Node1, mnesia, dirty_write, [{Tab4, 1, Node1}])),
  953: 
  954:     ?match(?badrpc(Tab2), rpc:call(Node2, mnesia, dirty_write, [{Tab2, 1, Node2}])),
  955:     ?match(?badrpc(Tab3), rpc:call(Node2, mnesia, dirty_write, [{Tab3, 1, Node2}])),
  956:     ?match(?badrpc(Tab4), rpc:call(Node2, mnesia, dirty_write, [{Tab4, 1, Node2}])),
  957: 
  958:     ?match({atomic, ok}, rpc:call(Node1, mnesia, add_table_copy, [Tab2, Node2, ram_copies])),    
  959:     ?match({atomic, ok}, rpc:call(Node2, mnesia, add_table_copy, [Tab3, Node2, disc_copies])),
  960:     ?match({atomic, ok}, rpc:call(Node3, mnesia, add_table_copy, [Tab4, Node2, disc_only_copies])),
  961:     ?match([], rpc:call(Node2, mnesia, dirty_read, [{Tab2, 1}])),
  962:     ?match([], rpc:call(Node2, mnesia, dirty_read, [{Tab3, 1}])),
  963:     ?match([], rpc:call(Node2, mnesia, dirty_read, [{Tab4, 1}])),
  964: 
  965:     ?match(ok, rpc:call(Node2, mnesia, dirty_write, [{Tab2, 1, Node2}])),
  966:     ?match(ok, rpc:call(Node2, mnesia, dirty_write, [{Tab3, 1, Node2}])),
  967:     ?match(ok, rpc:call(Node2, mnesia, dirty_write, [{Tab4, 1, Node2}])),
  968: 
  969:     ?match([{Tab1, 1, Node1}], rpc:call(Node1, mnesia, dirty_read, [{Tab1, 1}])),
  970:     ?match([{Tab2, 1, Node1}], rpc:call(Node1, mnesia, dirty_read, [{Tab2, 1}])),
  971:     ?match([{Tab3, 1, Node1}], rpc:call(Node1, mnesia, dirty_read, [{Tab3, 1}])),
  972:     ?match([{Tab4, 1, Node1}], rpc:call(Node1, mnesia, dirty_read, [{Tab4, 1}])),
  973: 
  974:     ?match([{Tab1, 1, Node2}], rpc:call(Node2, mnesia, dirty_read, [{Tab1, 1}])),
  975:     ?match([{Tab2, 1, Node2}], rpc:call(Node2, mnesia, dirty_read, [{Tab2, 1}])),
  976:     ?match([{Tab3, 1, Node2}], rpc:call(Node2, mnesia, dirty_read, [{Tab3, 1}])),
  977:     ?match([{Tab4, 1, Node2}], rpc:call(Node2, mnesia, dirty_read, [{Tab4, 1}])),
  978: 
  979:     ?match([{Tab1, 1, Node3}], rpc:call(Node3, mnesia, dirty_read, [{Tab1, 1}])),
  980:     ?match(?badrpc([_Tab2, 1]), rpc:call(Node3, mnesia, dirty_read, [{Tab2, 1}])),
  981:     ?match(?badrpc([_Tab3, 1]), rpc:call(Node3, mnesia, dirty_read, [{Tab3, 1}])),
  982:     ?match(?badrpc([_Tab4, 1]), rpc:call(Node3, mnesia, dirty_read, [{Tab4, 1}])),
  983: 
  984:     ?match({atomic, ok}, 
  985: 	   mnesia:change_table_copy_type(schema, Node3, ram_copies)),
  986:     ?match([], mnesia_test_lib:stop_mnesia([Node3])),
  987: 
  988:     %% Added for OTP-44306
  989:     ?match(ok, rpc:call(Node3, mnesia, start, [])),
  990:     ?match({ok, _}, mnesia:change_config(extra_db_nodes, [Node3])),
  991: 
  992:     mnesia_test_lib:sync_tables([Node3], [Tab1]),
  993: 
  994:     ?match([], rpc:call(Node3, mnesia, dirty_read, [{Tab1, 1}])),
  995: 
  996:     ?match({atomic, ok}, rpc:call(Node1, mnesia, clear_table, [Tab1])),
  997:     
  998:     SyncedCheck = fun(Tab) ->
  999: 			  mnesia:lock({record,Tab,0}, write),
 1000: 			  {OK, []} = rpc:multicall(Nodes, mnesia, table_info, [Tab, size]),
 1001: 			  OK
 1002: 		  end,
 1003:     ?match({atomic, [0,1,0]}, mnesia:transaction(SyncedCheck, [Tab1])),
 1004:     ?match({atomic, ok}, rpc:call(Node2, mnesia, clear_table, [Tab2])),    
 1005:     ?match({atomic, [1,0,0]}, mnesia:transaction(SyncedCheck, [Tab2])),
 1006:     ?match({atomic, ok}, rpc:call(Node2, mnesia, clear_table, [Tab3])),    
 1007:     ?match({atomic, [1,0,0]}, mnesia:transaction(SyncedCheck, [Tab3])),
 1008: 
 1009:     ?verify_mnesia(Nodes, []).
 1010: 
 1011: 
 1012: change_table_access_mode(suite) -> [];
 1013: change_table_access_mode(Config) when is_list(Config) -> 
 1014:     [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config),
 1015:     Tab = test_access_mode_tab,
 1016: 
 1017:     Def = case  mnesia_test_lib:diskless(Config) of
 1018: 	      true -> [{name, Tab}, {ram_copies, Nodes}];
 1019: 	      false -> [{name, Tab}, {ram_copies, [Node1]}, 
 1020: 			{disc_copies, [Node2]},
 1021: 			{disc_only_copies, [Node3]}]
 1022: 	  end,
 1023:     ?match({atomic, ok}, mnesia:create_table(Def)),
 1024: 
 1025:     Write = fun(What) -> mnesia:write({Tab, 1, What}) end,
 1026:     Read = fun() -> mnesia:read({Tab, 1}) end,
 1027: 
 1028:     ?match({atomic, ok}, mnesia:transaction(Write, [test_ok])),
 1029:     %% test read_only
 1030:     ?match({atomic, ok}, mnesia:change_table_access_mode(Tab, read_only)),
 1031:     ?match({aborted, _}, mnesia:transaction(Write, [nok])),
 1032:     ?match({'EXIT', {aborted, _}}, mnesia:dirty_write({Tab, 1, [nok]})),
 1033:     ?match({aborted, _}, rpc:call(Node2, mnesia, transaction, [Write, [nok]])),
 1034:     ?match({aborted, _}, rpc:call(Node3, mnesia, transaction, [Write, [nok]])),
 1035:     ?match({atomic, [{Tab, 1, test_ok}]}, mnesia:transaction(Read)),
 1036:     %% test read_write
 1037:     ?match({atomic, ok}, mnesia:change_table_access_mode(Tab, read_write)),
 1038:     ?match({atomic, ok}, mnesia:transaction(Write, [test_ok1])),
 1039:     ?match({atomic, [{Tab, 1, test_ok1}]}, mnesia:transaction(Read)),
 1040:     ?match({atomic, ok}, rpc:call(Node2, mnesia, transaction, [Write, [test_ok2]])),
 1041:     ?match({atomic, [{Tab, 1, test_ok2}]}, mnesia:transaction(Read)),
 1042:     ?match({atomic, ok}, rpc:call(Node3, mnesia, transaction, [Write, [test_ok3]])),
 1043:     ?match({atomic, [{Tab, 1, test_ok3}]}, mnesia:transaction(Read)),
 1044: 
 1045:     ?match({atomic, ok}, mnesia:delete_table(Tab)),
 1046: 
 1047:     Def4 = [{name, Tab}, {access_mode, read_only_bad}],
 1048:     ?match({aborted, {bad_type, _, _}}, mnesia:create_table(Def4)),
 1049: 
 1050:     Def2 = [{name, Tab}, {access_mode, read_only}],
 1051:     ?match({atomic, ok}, mnesia:create_table(Def2)),
 1052:     ?match({aborted, _}, mnesia:transaction(Write, [nok])),
 1053: 
 1054:     ?match({atomic, ok}, mnesia:change_table_access_mode(Tab, read_write)),
 1055:     ?match({atomic, ok}, mnesia:delete_table(Tab)),
 1056: 
 1057:     Def3 = [{name, Tab}, {mnesia_test_lib:storage_type(disc_copies, Config),
 1058: 			  [Node1, Node2]},
 1059: 	    {access_mode, read_write}],
 1060:     ?match({atomic, ok}, mnesia:create_table(Def3)),
 1061:     ?match({atomic, ok}, mnesia:transaction(Write, [ok])),
 1062:     ?match({atomic, ok}, mnesia:change_table_access_mode(Tab, read_only)),
 1063:     ?match({aborted, _}, mnesia:del_table_copy(Tab, Node2)),
 1064:     ?match({aborted, _}, mnesia:del_table_copy(Tab, Node1)),
 1065:     ?match({aborted, _}, mnesia:delete_table(Tab)),
 1066:     ?match({atomic, ok}, mnesia:change_table_access_mode(Tab, read_write)),
 1067: 
 1068:     ?match({aborted, {bad_type, _, _}},
 1069: 	   mnesia:change_table_access_mode(Tab, strange_atom)),
 1070:     ?match({atomic, ok}, mnesia:delete_table(Tab)),
 1071: 
 1072:     ?match({aborted, {no_exists, _}}, 
 1073: 	   mnesia:change_table_access_mode(err_tab, read_only)),
 1074:     ?match({aborted, {no_exists, _}}, 
 1075: 	   mnesia:change_table_access_mode([Tab], read_only)),
 1076:     ?verify_mnesia(Nodes, []).
 1077: 
 1078: change_table_load_order(suite) -> [];
 1079: change_table_load_order(Config) when is_list(Config) ->
 1080:     [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config),
 1081:     Tab1 = load_order_tab1,
 1082:     Tab2 = load_order_tab2,
 1083:     Tab3 = load_order_tab3,
 1084: 
 1085:     Def = case mnesia_test_lib:diskless(Config) of
 1086: 	      true -> [{ram_copies, Nodes}]; 
 1087: 	      false ->		  
 1088: 		  [{ram_copies, [Node1]}, 
 1089: 		   {disc_copies, [Node2]},
 1090: 		   {disc_only_copies, [Node3]}]
 1091: 	  end,
 1092:     ?match({atomic, ok}, mnesia:create_table(Tab1, Def)),
 1093:     ?match({atomic, ok}, mnesia:create_table(Tab2, Def)),
 1094:     ?match({atomic, ok}, mnesia:create_table(Tab3, Def)),
 1095: 
 1096:     ?match({aborted, _}, mnesia:change_table_load_order(Tab1, should_be_integer)),       
 1097:     ?match({aborted, _}, mnesia:change_table_load_order(err_tab, 5)),       
 1098:     ?match({aborted, _}, mnesia:change_table_load_order([err_tab], 5)),       
 1099:     ?match({atomic, ok}, mnesia:change_table_load_order(Tab1, 5)),       
 1100:     ?match({atomic, ok}, mnesia:change_table_load_order(Tab2, 4)),    
 1101:     ?match({atomic, ok}, mnesia:change_table_load_order(Tab3, 73)),
 1102: 
 1103:     ?match({aborted, _}, mnesia:change_table_load_order(schema, -32)),   
 1104: 
 1105:     ?verify_mnesia(Nodes, []).
 1106: 
 1107: set_master_nodes(suite) -> [];
 1108: set_master_nodes(Config) when is_list(Config) ->
 1109:     [Node1, Node2, Node3] = Nodes = ?acquire_nodes(3, Config),
 1110:     Tab1 = master_node_tab1,
 1111:     Tab2 = master_node_tab2,
 1112:     Tab3 = master_node_tab3,
 1113:     Def1 = [{ram_copies, [Node1, Node2]}],
 1114:     Def2 = [{disc_copies, [Node2, Node3]}],
 1115:     Def3 = [{disc_only_copies, [Node3, Node1]}],
 1116:     ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 1117:     ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 1118:     ?match({atomic, ok}, mnesia:create_table(Tab3, Def3)),
 1119: 
 1120:     ?match({error, _}, mnesia:set_master_nodes(schema, ['hopefully@non.existing.node'])),
 1121:     ?match({error, _}, mnesia:set_master_nodes(badtab, [Node2, Node3])),
 1122:     ?match({error, _}, mnesia:set_master_nodes(Tab1, [Node3])),
 1123:     ?match([], mnesia:table_info(Tab1, master_nodes)),
 1124: 
 1125:     ?match(ok, mnesia:set_master_nodes(schema, [Node3, Node1])),
 1126:     ?match([Node3, Node1], mnesia:table_info(schema, master_nodes)),
 1127:     ?match(ok, mnesia:set_master_nodes(Tab1, [Node2])),
 1128:     ?match([Node2], mnesia:table_info(Tab1, master_nodes)),
 1129:     ?match(ok, mnesia:set_master_nodes(Tab1, [Node2, Node1])),
 1130:     ?match([Node2, Node1], mnesia:table_info(Tab1, master_nodes)),
 1131:     ?match(ok, mnesia:set_master_nodes(Tab2, [Node2])),  % Should set where_to_read to Node2!
 1132:     ?match([Node2], mnesia:table_info(Tab2, master_nodes)),
 1133:     ?match(ok, mnesia:set_master_nodes(Tab3, [Node3])),
 1134:     ?match([Node3], mnesia:table_info(Tab3, master_nodes)),
 1135:     ?match(ok, mnesia:set_master_nodes(Tab3, [])),
 1136:     ?match([], mnesia:table_info(Tab3, master_nodes)),
 1137: 
 1138:     ?match(ok, mnesia:set_master_nodes([Node1])),
 1139:     ?match([Node1], mnesia:table_info(schema, master_nodes)),
 1140:     ?match([Node1], mnesia:table_info(Tab1, master_nodes)),
 1141:     ?match([], mnesia:table_info(Tab2, master_nodes)),
 1142:     ?match([Node1], mnesia:table_info(Tab3, master_nodes)),
 1143: 
 1144:     ?match(ok, mnesia:set_master_nodes([Node1, Node2])),
 1145:     ?match([Node1, Node2], mnesia:table_info(schema, master_nodes)),
 1146:     ?match([Node1, Node2], mnesia:table_info(Tab1, master_nodes)),
 1147:     ?match([Node2], mnesia:table_info(Tab2, master_nodes)),
 1148:     ?match([Node1], mnesia:table_info(Tab3, master_nodes)),
 1149: 
 1150:     ?verify_mnesia(Nodes, []).
 1151: 
 1152: offline_set_master_nodes(suite) -> [];
 1153: offline_set_master_nodes(Config) when is_list(Config) ->
 1154:     [Node] = Nodes = ?acquire_nodes(1, Config),
 1155:     Tab1 = offline_master_node_tab1,
 1156:     Tab2 = offline_master_node_tab2,
 1157:     Tab3 = offline_master_node_tab3,
 1158:     Tabs = ?sort([Tab1, Tab2, Tab3]),
 1159:     Def1 = [{ram_copies, [Node]}],
 1160:     Def2 = [{disc_copies, [Node]}],
 1161:     Def3 = [{disc_only_copies, [Node]}],
 1162:     ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 1163:     ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 1164:     ?match({atomic, ok}, mnesia:create_table(Tab3, Def3)),
 1165:     ?match([], mnesia:system_info(master_node_tables)),
 1166:     ?match([], mnesia_test_lib:stop_mnesia([Node])),
 1167: 
 1168:     ?match(ok, mnesia:set_master_nodes(Tab1, [Node])),
 1169:     ?match(ok, mnesia:set_master_nodes(Tab2, [Node])),
 1170:     ?match(ok, mnesia:set_master_nodes(Tab3, [Node])),
 1171:     ?match([], mnesia_test_lib:start_mnesia([Node])),
 1172:     ?match(Tabs, ?sort(mnesia:system_info(master_node_tables))),
 1173: 
 1174:     ?match([], mnesia_test_lib:stop_mnesia([Node])),
 1175:     ?match(ok, mnesia:set_master_nodes(Tab1, [])),
 1176:     ?match(ok, mnesia:set_master_nodes(Tab2, [])),
 1177:     ?match(ok, mnesia:set_master_nodes(Tab3, [])),
 1178:     ?match([], mnesia_test_lib:start_mnesia([Node])),
 1179:     ?match([], mnesia:system_info(master_node_tables)),
 1180: 
 1181:     ?match([], mnesia_test_lib:stop_mnesia([Node])),
 1182:     ?match(ok, mnesia:set_master_nodes([Node])),
 1183:     ?match([], mnesia_test_lib:start_mnesia([Node])),
 1184:     AllTabs = ?sort([schema | Tabs]),
 1185:     ?match(AllTabs, ?sort(mnesia:system_info(master_node_tables))),
 1186: 
 1187:     ?match([], mnesia_test_lib:stop_mnesia([Node])),
 1188:     ?match(ok, mnesia:set_master_nodes([])),
 1189:     ?match([], mnesia_test_lib:start_mnesia([Node])),
 1190:     ?match([], mnesia:system_info(master_node_tables)),
 1191: 
 1192:     ?verify_mnesia(Nodes, []).
 1193: 
 1194: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1195: %% Syncronize table with log or disc
 1196: %%
 1197: 
 1198: %% Dump ram tables on disc
 1199: dump_tables(suite) -> [];
 1200: dump_tables(Config) when is_list(Config) ->
 1201:     [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 1202:     Tab = dump_tables,
 1203:     Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node2]}],
 1204:     ?match({atomic, ok}, mnesia:create_table(Schema)),
 1205: 
 1206:     %% Dump 10 records
 1207:     Size = 10,
 1208:     Keys = lists:seq(1, Size),
 1209:     Records = [{Tab, A, 7} || A <- Keys],
 1210:     lists:foreach(fun(Rec) -> ?match(ok, mnesia:dirty_write(Rec)) end, Records),
 1211: 
 1212:     AllKeys = fun() -> ?sort(mnesia:all_keys(Tab)) end,
 1213: 
 1214:     ?match({atomic, Keys}, mnesia:transaction(AllKeys)),
 1215:     ?match({atomic, ok}, mnesia:dump_tables([Tab])),
 1216: 
 1217:     %% Delete one record
 1218:     ?match(ok, mnesia:dirty_delete({Tab, 5})),
 1219:     Keys2 = lists:delete(5, Keys),
 1220: 
 1221:     ?match({atomic, Keys2}, mnesia:transaction(AllKeys)),
 1222: 
 1223:     %% Check that all 10 is restored after a stop
 1224:     ?match([], mnesia_test_lib:stop_mnesia([Node1, Node2])),
 1225:     ?match([], mnesia_test_lib:start_mnesia([Node1, Node2])),
 1226:     ?match(ok, mnesia:wait_for_tables([Tab], infinity)),
 1227: 
 1228:     ?match({atomic, Keys}, mnesia:transaction(AllKeys)),
 1229: 
 1230:     ?match({aborted,Reason} when element(1, Reason) == no_exists,
 1231:            mnesia:dump_tables([foo])),
 1232:     ?verify_mnesia(Nodes, []).
 1233: 
 1234: dump_log(suite) -> [];
 1235: dump_log(Config) when is_list(Config) ->
 1236:     [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 1237:     Tab = dump_log,
 1238:     Schema = [{name, Tab}, {attributes, [k, v]}, {ram_copies, [Node1, Node2]}],
 1239:     ?match({atomic, ok}, mnesia:create_table(Schema)),
 1240:     Tab1 = dump_log1,
 1241:     Schema1 = [{name, Tab1}, {attributes, [k, v]}, {disc_copies, [Node1]}],
 1242:     ?match({atomic, ok}, mnesia:create_table(Schema1)),
 1243:     Tab2 = dump_log2,
 1244:     Schema2 = [{name, Tab2}, {attributes, [k, v]}, {disc_only_copies, [Node1]}],
 1245:     ?match({atomic, ok}, mnesia:create_table(Schema2)),
 1246: 
 1247:     ?match(ok, mnesia:dirty_write({Tab, 1, ok})),
 1248:     ?match(ok, mnesia:dirty_write({Tab1, 1, ok})),
 1249:     ?match(ok, mnesia:dirty_write({Tab2, 1, ok})),
 1250: 
 1251:     ?match(dumped, mnesia:dump_log()),
 1252:     ?match(dumped, rpc:call(Node2, mnesia, dump_log, [])),
 1253: 
 1254:     ?match({atomic, ok}, mnesia:change_table_copy_type(schema, Node2, ram_copies)),
 1255:     ?match(dumped, rpc:call(Node2, mnesia, dump_log, [])),
 1256: 
 1257:     Self = self(),
 1258:     spawn(fun() -> dump_log(100, Self) end),
 1259:     spawn(fun() -> dump_log(100, Self) end),
 1260: 
 1261:     ?match(ok, receive finished -> ok after 3000 -> timeout end),
 1262:     ?match(ok, receive finished -> ok after 3000 -> timeout end),
 1263:     
 1264:     ?verify_mnesia(Nodes, []).
 1265: 
 1266: dump_log(N, Tester) when N > 0 ->
 1267:     mnesia:dump_log(),
 1268:     dump_log(N-1, Tester);
 1269: dump_log(_, Tester) ->
 1270:     Tester ! finished.
 1271: 
 1272: 
 1273: wait_for_tables(doc) -> 
 1274:     ["Intf. test of wait_for_tables, see also force_load_table"];
 1275: wait_for_tables(suite) -> [];
 1276: wait_for_tables(Config) when is_list(Config) ->
 1277:     [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 1278:     Tab = wf_tab,
 1279:     Schema = [{name, Tab}, {ram_copies, [Node1, Node2]}],
 1280:     ?match({atomic, ok}, mnesia:create_table(Schema)),
 1281:     ?match(ok, mnesia:wait_for_tables([wf_tab], infinity)),
 1282:     ?match(ok, mnesia:wait_for_tables([], timer:seconds(5))),
 1283:     ?match({timeout, [bad_tab]}, mnesia:wait_for_tables([bad_tab], timer:seconds(5))),
 1284:     ?match(ok, mnesia:wait_for_tables([wf_tab], 0)),
 1285:     ?match({error,_}, mnesia:wait_for_tables([wf_tab], -1)),
 1286:     ?verify_mnesia(Nodes, []).
 1287: 
 1288: force_load_table(suite) -> [];
 1289: force_load_table(Config) when is_list(Config) ->
 1290:     [Node1, Node2] = ?acquire_nodes(2, Config),
 1291:     Tab = wf_tab,
 1292: 
 1293:     Schema = [{name, Tab}, {disc_copies, [Node1, Node2]}],
 1294:     ?match({atomic, ok}, mnesia:create_table(Schema)),
 1295:     ?match(ok, mnesia:dirty_write({Tab, 1, test_ok})),
 1296:     mnesia_test_lib:kill_mnesia([Node1]),
 1297:     ?match(ok, rpc:call(Node2, mnesia, dirty_write, [{Tab, 1, test_nok}])),
 1298:     mnesia_test_lib:kill_mnesia([Node2]),
 1299:     %%    timer:sleep(timer:seconds(5)),
 1300:     ?match(ok, mnesia:start()),
 1301:     ?match({timeout, [Tab]}, mnesia:wait_for_tables([Tab], 5)),
 1302:     ?match({'EXIT', _}, mnesia:dirty_read({Tab, 1})),
 1303:     ?match(yes, mnesia:force_load_table(Tab)),
 1304:     ?match([{Tab, 1, test_ok}], mnesia:dirty_read({Tab, 1})),
 1305: 
 1306:     ?match({error, _}, mnesia:force_load_table(error_tab)),
 1307:     ?verify_mnesia([Node1], [Node2]).
 1308: 
 1309: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1310: 
 1311: user_properties(doc) ->
 1312:     ["Test of reading, writing and deletion of user properties",
 1313:      "Plus initialization of user properties when a table is created",
 1314:      "Do also test mnesia:table_info(Tab, user_properties)"];
 1315: user_properties(suite) -> [];
 1316: user_properties(Config) when is_list(Config) ->
 1317:     [Node] = Nodes = ?acquire_nodes(1, Config),
 1318:     Tab1 = user_properties_1,
 1319:     Tab2 = user_properties_2,
 1320:     Tab3 = user_properties_3,
 1321:     Def1 = [{ram_copies, [Node]}, {user_properties, []}],
 1322:     Def2 = [{mnesia_test_lib:storage_type(disc_copies, Config), [Node]}],
 1323:     Def3 = [{mnesia_test_lib:storage_type(disc_only_copies, Config), [Node]}, 
 1324: 	    {user_properties, []}],
 1325: 
 1326:     PropKey = my_prop,
 1327:     Prop = {PropKey, some, elements},
 1328:     Prop2 = {PropKey, some, other, elements},
 1329:     YourProp= {your_prop},
 1330:     ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 1331:     ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 1332:     ?match({atomic, ok}, mnesia:create_table(Tab3, Def3)),
 1333: 
 1334:     ?match([], mnesia:table_info(Tab1, user_properties)),
 1335:     ?match([], mnesia:table_info(Tab2, user_properties)),
 1336:     ?match([], mnesia:table_info(Tab3, user_properties)),
 1337: 
 1338:     ?match({'EXIT', {no_exists, {Tab1, user_property, PropKey}}},
 1339: 	   mnesia:read_table_property(Tab1, PropKey)),
 1340:     ?match({'EXIT', {no_exists, {Tab2, user_property, PropKey}}},
 1341: 	   mnesia:read_table_property(Tab2, PropKey)),
 1342:     ?match({'EXIT', {no_exists, {Tab3, user_property, PropKey}}},
 1343: 	   mnesia:read_table_property(Tab3, PropKey)),
 1344: 
 1345:     ?match({atomic, ok}, mnesia:write_table_property(Tab1, Prop)),
 1346:     ?match({atomic, ok}, mnesia:write_table_property(Tab2, Prop)),
 1347:     ?match({atomic, ok}, mnesia:write_table_property(Tab3, Prop)),
 1348:     ?match({atomic, ok}, mnesia:write_table_property(Tab1, YourProp)),
 1349:     ?match({atomic, ok}, mnesia:write_table_property(Tab2, YourProp)),
 1350:     ?match({atomic, ok}, mnesia:write_table_property(Tab3, YourProp)),
 1351: 
 1352:     ?match(Prop, mnesia:read_table_property(Tab1, PropKey)),
 1353:     ?match(Prop, mnesia:read_table_property(Tab2, PropKey)),
 1354:     ?match(Prop, mnesia:read_table_property(Tab3, PropKey)),
 1355: 
 1356:     ?match({atomic, ok}, mnesia:write_table_property(Tab1, Prop2)),
 1357:     ?match({atomic, ok}, mnesia:write_table_property(Tab2, Prop2)),
 1358:     ?match({atomic, ok}, mnesia:write_table_property(Tab3, Prop2)),
 1359:     ?match(Prop2, mnesia:read_table_property(Tab1, PropKey)),
 1360:     ?match(Prop2, mnesia:read_table_property(Tab2, PropKey)),
 1361:     ?match(Prop2, mnesia:read_table_property(Tab3, PropKey)),
 1362: 
 1363:     ?match({atomic, ok}, mnesia:delete_table_property(Tab1, PropKey)),
 1364:     ?match({atomic, ok}, mnesia:delete_table_property(Tab2, PropKey)),
 1365:     ?match({atomic, ok}, mnesia:delete_table_property(Tab3, PropKey)),
 1366: 
 1367:     ?match([YourProp], mnesia:table_info(Tab1, user_properties)),
 1368:     ?match([YourProp], mnesia:table_info(Tab2, user_properties)),
 1369:     ?match([YourProp], mnesia:table_info(Tab3, user_properties)),
 1370: 
 1371:     Tab4 = user_properties_4,
 1372:     ?match({atomic, ok}, 
 1373: 	   mnesia:create_table(Tab4, [{user_properties, [Prop]}])),
 1374: 
 1375:     ?match([Prop], mnesia:table_info(Tab4, user_properties)),
 1376: 
 1377:     %% Some error cases
 1378: 
 1379:     ?match({aborted, {bad_type, Tab1, {}}},
 1380: 	   mnesia:write_table_property(Tab1, {})),
 1381:     ?match({aborted, {bad_type, Tab1, ali}},
 1382: 	   mnesia:write_table_property(Tab1, ali)),
 1383: 
 1384:     Tab5 = user_properties_5,
 1385:     ?match({aborted, {bad_type, Tab5, {user_properties, {}}}}, 
 1386: 	   mnesia:create_table(Tab5, [{user_properties, {}}])),
 1387:     ?match({aborted, {bad_type, Tab5, {user_properties, ali}}}, 
 1388: 	   mnesia:create_table(Tab5, [{user_properties, ali}])),
 1389:     ?match({aborted, {bad_type, Tab5, {user_properties, [{}]}}}, 
 1390: 	   mnesia:create_table(Tab5, [{user_properties, [{}]}])),
 1391:     ?match({aborted, {bad_type, Tab5, {user_properties, [ali]}}}, 
 1392: 	   mnesia:create_table(Tab5, [{user_properties, [ali]}])),
 1393: 
 1394:     ?verify_mnesia(Nodes, []).
 1395: 
 1396: 
 1397: unsupp_user_props(doc) ->
 1398:     ["Simple test of adding user props in a schema_transaction"];
 1399: unsupp_user_props(suite) -> [];
 1400: unsupp_user_props(Config) when is_list(Config) ->
 1401:     [Node1] = ?acquire_nodes(1, Config),
 1402:     Tab1 = silly1,
 1403:     Tab2 = silly2,
 1404:     Storage = mnesia_test_lib:storage_type(ram_copies, Config),
 1405: 
 1406:     ?match({atomic, ok}, rpc:call(Node1, mnesia,
 1407: 				  create_table, [Tab1, [{Storage, [Node1]}]])),
 1408:     ?match({atomic, ok}, rpc:call(Node1, mnesia,
 1409: 				  create_table, [Tab2, [{Storage, [Node1]}]])),
 1410: 
 1411:     F1 = fun() ->
 1412: 		 mnesia_schema:do_write_table_property(
 1413: 		   silly1, {prop, propval1}),
 1414: 		 mnesia_schema:do_write_table_property(
 1415: 		   silly2, {prop, propval2}), % same key as above
 1416: 		 mnesia_schema:do_write_table_property(
 1417: 		   schema, {prop, propval3})  % same key as above
 1418: 	 end,
 1419:     ?match({atomic, ok}, rpc:call(Node1, mnesia_schema,
 1420: 				  schema_transaction, [F1])),
 1421: 
 1422:     ?match([{prop,propval1}], rpc:call(Node1, mnesia,
 1423: 				       table_info, [silly1, user_properties])),
 1424:     ?match([{prop,propval2}], rpc:call(Node1, mnesia,
 1425: 				       table_info, [silly2, user_properties])),
 1426:     ?match([{prop,propval3}], rpc:call(Node1, mnesia,
 1427: 				       table_info, [schema, user_properties])),
 1428: 
 1429:     F2 = fun() ->
 1430: 		 mnesia_schema:do_write_table_property(
 1431: 		   silly1, {prop, propval1a}),
 1432: 		 mnesia_schema:do_write_table_property(
 1433: 		   silly1, {prop, propval1b})  % same key as above
 1434: 	 end,
 1435:     ?match({atomic, ok}, rpc:call(Node1, mnesia_schema,
 1436: 				  schema_transaction, [F2])),
 1437: 
 1438:     ?match([{prop,propval1b}], rpc:call(Node1, mnesia,
 1439: 					table_info,
 1440: 					[silly1, user_properties])),
 1441:     ?verify_mnesia([Node1], []).
 1442: 
 1443: 
 1444: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1445: 
 1446: 
 1447: snmp_open_table(suite) -> [];
 1448: snmp_open_table(Config) when is_list(Config) -> 
 1449:     [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 1450:     Tab1 = local_snmp_table,
 1451: 
 1452:     Storage = mnesia_test_lib:storage_type(disc_copies, Config),
 1453:     Def1 = 
 1454: 	case mnesia_test_lib:diskless(Config) of
 1455: 	    true -> [{ram_copies, Nodes}];
 1456: 	    false ->		
 1457: 		[{disc_copies, [Node1]}, {ram_copies, [Node2]}]
 1458: 	end,
 1459: 
 1460:     Tab2 = ext_snmp_table,
 1461:     Def2 = [{Storage, [Node2]}],
 1462:     ErrTab = non_existing_tab,
 1463:     ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 1464:     ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 1465:     ?match({atomic, ok}, mnesia:snmp_open_table(Tab1, [{key, integer}])),
 1466:     ?match({atomic, ok}, mnesia:snmp_open_table(Tab2, [{key, integer}])),
 1467:     ?match({aborted, _}, mnesia:snmp_open_table(ErrTab, [{key, integer}])),
 1468:     ?verify_mnesia(Nodes, []).
 1469: 
 1470: snmp_close_table(suite) -> [];
 1471: snmp_close_table(Config) when is_list(Config) -> 
 1472:     [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 1473:     Tab1 = local_snmp_table,
 1474:     Storage = mnesia_test_lib:storage_type(disc_copies, Config),
 1475:     Def1 = 
 1476: 	case mnesia_test_lib:diskless(Config) of
 1477: 	    true -> [{ram_copies, Nodes}];
 1478: 	    false ->		
 1479: 		[{disc_copies, [Node1]}, {ram_copies, [Node2]}]
 1480: 	end,
 1481: 
 1482:     Tab2 = ext_snmp_table,
 1483:     Def2 = [{snmp, [{key, integer}]}, {Storage, [Node2]}],
 1484:     ErrTab = non_existing_tab,
 1485:     ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 1486:     ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 1487:     ?match({atomic, ok}, mnesia:create_table(no_snmp_tab, [])),
 1488:     add_some_records(Tab1, Tab2, 3),    
 1489:     ?match({atomic, ok}, mnesia:snmp_open_table(Tab1, [{key, integer}])),    
 1490:     add_some_records(Tab1, Tab2, 5),    
 1491:     ?match({atomic, ok}, mnesia:snmp_close_table(Tab1)),
 1492: 
 1493:     Transform = fun(Tab, Key) ->
 1494: 			[{T,K,V}] = mnesia:read(Tab, Key, write),
 1495: 			mnesia:delete(T,K, write),
 1496: 			mnesia:write({T, {K,K}, V, 43+V})
 1497: 		end,
 1498:     
 1499:     ?match({atomic, ok}, mnesia:transform_table(Tab1, ignore, [key,val,new])),
 1500:     ?match({atomic, ok},
 1501: 	   mnesia:transaction(fun() ->
 1502: 				      mnesia:write_lock_table(Tab1),
 1503: 				      Keys = mnesia:select(Tab1, [{{'_','$1','_'}, [],
 1504: 								   ['$1']}]),
 1505: 				      [Transform(Tab1, Key) || Key <- Keys],
 1506: 				      ok
 1507: 			      end)),
 1508:     ?match([{Tab1, {1, 1}, 1, 44}], mnesia:dirty_read(Tab1, {1, 1})),
 1509:     ?match({atomic, ok}, mnesia:snmp_open_table(Tab1, [{key,{integer,integer}}])),
 1510: 
 1511:     ?match({atomic, ok}, mnesia:snmp_close_table(Tab2)),
 1512:     ?match({atomic, ok}, mnesia:transform_table(Tab2, ignore, [key,val,new])),
 1513:     ?match({atomic, ok},
 1514: 	   mnesia:transaction(fun() ->
 1515: 				      mnesia:write_lock_table(Tab2),
 1516: 				      Keys = mnesia:select(Tab2, [{{'_','$1','_'}, [],
 1517: 								   ['$1']}]),
 1518: 				      [Transform(Tab2, Key) || Key <- Keys],
 1519: 				      ok
 1520: 			      end)),
 1521:     
 1522:     ?match({atomic, ok}, mnesia:snmp_open_table(Tab2, [{key,{integer,integer}}])), 
 1523:     
 1524:     %% Should be aborted ????
 1525:     ?match({atomic, ok}, mnesia:snmp_close_table(no_snmp_tab)),
 1526:     ?match({aborted, _}, mnesia:snmp_close_table(ErrTab)),
 1527:     ?verify_mnesia(Nodes, []).
 1528: 
 1529: snmp_get_next_index(suite) -> [];
 1530: snmp_get_next_index(Config) when is_list(Config) ->
 1531:     [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 1532:     Tab1 = local_snmp_table,
 1533:     Storage = mnesia_test_lib:storage_type(disc_copies, Config),
 1534:     Def1 = 
 1535: 	case mnesia_test_lib:diskless(Config) of
 1536: 	    true -> [{ram_copies, Nodes}];
 1537: 	    false ->		
 1538: 		[{disc_copies, [Node1]}, {ram_copies, [Node2]}]
 1539: 	end,
 1540: 
 1541:     Tab2 = ext_snmp_table,
 1542:     Def2 = [{Storage, [Node2]}],
 1543:     ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 1544:     ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 1545:     ?match({atomic, ok}, mnesia:snmp_open_table(Tab1, [{key, integer}])),
 1546:     ?match({atomic, ok}, mnesia:snmp_open_table(Tab2, [{key, integer}])),
 1547:     add_some_records(Tab1, Tab2, 1),
 1548:     Test = 
 1549: 	fun() ->
 1550: 		%% Test local tables
 1551: 		{success, Res11} = ?match({ok, _}, mnesia:snmp_get_next_index(Tab1,[])),
 1552: 		{ok, Index11} = Res11,
 1553: 		{success, _Res12} = 
 1554: 		    ?match(endOfTable, mnesia:snmp_get_next_index(Tab1, Index11)),
 1555: 		?match({'EXIT',_}, mnesia:snmp_get_next_index(Tab1, endOfTable)),
 1556: 
 1557: 		%% Test external table
 1558: 		{success, Res21} =
 1559: 		    ?match({ok, _}, mnesia:snmp_get_next_index(Tab2, [])),
 1560: 		{ok, Index21} = Res21,
 1561: 		{success, _Res22} = 
 1562: 		    ?match(endOfTable, mnesia:snmp_get_next_index(Tab2, Index21)),
 1563: 
 1564: 		{ok, Row} = mnesia:snmp_get_row(Tab1, Index11),		
 1565: 		?match(ok, mnesia:dirty_delete(Tab1, hd(Index11))),
 1566: 
 1567: 		?match(endOfTable, mnesia:snmp_get_next_index(Tab1,[])),
 1568: 
 1569: 		ok = mnesia:dirty_write(Row), %% Reset to coming tests
 1570: 
 1571: 		%% Test of non existing table
 1572: 		%%?match(endOfTable, mnesia:snmp_get_next_index(ErrTab, [])),
 1573: 		ok
 1574: 	end,
 1575:     ?match(ok, Test()),
 1576:     ?match({atomic,ok}, mnesia:transaction(Test)),
 1577:     ?match(ok, mnesia:sync_dirty(Test)),
 1578:     ?match(ok, mnesia:activity(transaction,Test,mnesia)),
 1579: 
 1580:     %%io:format("**********Before ~p~n", [mnesia_lib:val({Tab1,snmp})]),
 1581:     %%io:format(" ~p ~n", [ets:tab2list(mnesia_lib:val({local_snmp_table,{index,snmp}}))]),
 1582:     ?match([], mnesia_test_lib:stop_mnesia(Nodes)),
 1583:     ?match([], mnesia_test_lib:start_mnesia(Nodes, [Tab1, Tab2])),
 1584:     %%io:format("**********After ~p~n", [mnesia_lib:val({Tab1,snmp})]),
 1585:     %%io:format(" ~p ~n", [ets:tab2list(mnesia_lib:val({local_snmp_table,{index,snmp}}))]),
 1586: 
 1587:     ?match(ok, Test()),
 1588:     ?match({atomic,ok}, mnesia:transaction(Test)),
 1589:     ?match(ok, mnesia:sync_dirty(Test)),
 1590:     ?match(ok, mnesia:activity(transaction,Test,mnesia)),
 1591: 
 1592:     ?verify_mnesia(Nodes, []).
 1593: 
 1594: add_some_records(Tab1, Tab2, N) ->
 1595:     Recs1 = [{Tab1, I, I} || I <- lists:reverse(lists:seq(1, N))],
 1596:     Recs2 = [{Tab2, I, I} || I <- lists:reverse(lists:seq(20, 20+N-1))],
 1597:     lists:foreach(fun(R) -> mnesia:dirty_write(R) end, Recs1),
 1598:     Fun = fun(R) -> mnesia:write(R) end,
 1599:     Trans = fun() -> lists:foreach(Fun, Recs2) end, 
 1600:     {atomic, ok} = mnesia:transaction(Trans),
 1601:     %% Sync things, so everything gets everywhere!
 1602:     {atomic, ok} = mnesia:sync_transaction(fun() -> mnesia:write(lists:last(Recs1)) end),
 1603:     {atomic, ok} = mnesia:sync_transaction(fun() -> mnesia:write(lists:last(Recs2)) end),
 1604:     ?sort(Recs1 ++ Recs2).
 1605: 
 1606: snmp_get_row(suite) -> [];
 1607: snmp_get_row(Config) when is_list(Config) -> 
 1608:     [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 1609:     Tab1 = local_snmp_table,
 1610:     Storage = mnesia_test_lib:storage_type(disc_copies, Config),
 1611:     Def1 = 
 1612: 	case mnesia_test_lib:diskless(Config) of
 1613: 	    true -> [{ram_copies, Nodes}];
 1614: 	    false ->		
 1615: 		[{disc_copies, [Node1]}, {ram_copies, [Node2]}]
 1616: 	end,
 1617:     Tab2 = ext_snmp_table,
 1618:     Def2 = [{Storage, [Node2]}],
 1619:     Tab3 = snmp_table,
 1620:     Def3 = [{Storage, [Node1]}, 
 1621:             {attributes, [key, data1, data2]}],    
 1622: 
 1623:     Setup = fun() ->
 1624: 		    ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 1625: 		    ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 1626: 		    ?match({atomic, ok}, mnesia:create_table(Tab3, Def3)),
 1627: 		    ?match({atomic, ok}, mnesia:snmp_open_table(Tab1, [{key, integer}])),
 1628: 		    ?match({atomic, ok}, mnesia:snmp_open_table(Tab2, [{key, integer}])),
 1629: 		    ?match({atomic, ok}, mnesia:snmp_open_table(
 1630: 					   Tab3, [{key, {fix_string,integer}}])),
 1631: 		    add_some_records(Tab1, Tab2, 1)
 1632: 	    end,
 1633:     Clear = fun() ->
 1634: 		    ?match({atomic, ok}, mnesia:delete_table(Tab1)),
 1635: 		    ?match({atomic, ok}, mnesia:delete_table(Tab2)),
 1636: 		    ?match({atomic, ok}, mnesia:delete_table(Tab3))
 1637: 	    end,
 1638:     Test = 
 1639: 	fun() ->
 1640: 		%% Test local tables
 1641: 		{success, Res11} = 
 1642: 		    ?match({ok, [1]}, mnesia:snmp_get_next_index(Tab1,[])),
 1643: 		{ok, Index11} = Res11,
 1644: 		?match({ok, {Tab1,1,1}}, mnesia:snmp_get_row(Tab1, Index11)),    
 1645: 		?match(endOfTable, mnesia:snmp_get_next_index(Tab1, Index11)),
 1646: 		?match({'EXIT',_}, mnesia:snmp_get_row(Tab1, endOfTable)),
 1647: 		?match(undefined, mnesia:snmp_get_row(Tab1, [73])),
 1648: 		
 1649: 		Add = fun() ->  mnesia:write({Tab3, {"f_string", 3}, data1, data2}) end,
 1650: 		?match({atomic, ok}, mnesia:transaction(Add)),
 1651:                 {success, {ok, Index31}} = ?match({ok, RowIndex31} when is_list(RowIndex31), 
 1652: 						 mnesia:snmp_get_next_index(Tab3,[])),
 1653: 		?match({ok, Row31} when is_tuple(Row31), 
 1654: 					mnesia:snmp_get_row(Tab3, Index31)),
 1655: 		?match(endOfTable, mnesia:snmp_get_next_index(Tab3, Index31)),
 1656: 		Del = fun() -> mnesia:delete({Tab3,{"f_string",3}}) end,
 1657: 		?match({atomic, ok}, mnesia:transaction(Del)),
 1658: 		?match(undefined, mnesia:snmp_get_row(Tab3, "f_string" ++ [3])),
 1659: 		?match(undefined, mnesia:snmp_get_row(Tab3, "f_string" ++ [73])),
 1660: 
 1661:                 %% Test external table
 1662:                 {success, Res21} = ?match({ok,[20]}, mnesia:snmp_get_next_index(Tab2, [])),
 1663: 		{ok, Index21} = Res21,
 1664:                 ?match({ok, Row2} when is_tuple(Row2), mnesia:snmp_get_row(Tab2, Index21)), 
 1665:                 ?match(endOfTable, mnesia:snmp_get_next_index(Tab2, Index21)),
 1666:                 %% Test of non existing table
 1667:                 %% ?match(endOfTable, mnesia:snmp_get_next_index(ErrTab, [])),
 1668:                 ok
 1669: 	end,
 1670:     Setup(),
 1671:     ?match(ok, Test()),
 1672:     Clear(), Setup(),
 1673:     ?match({atomic,ok}, mnesia:transaction(Test)),
 1674:     Clear(), Setup(),
 1675:     ?match(ok, mnesia:sync_dirty(Test)),
 1676:     Clear(), Setup(),
 1677:     ?match(ok, mnesia:activity(transaction,Test,mnesia)),
 1678: 
 1679:     Clear(), Setup(),
 1680:     ?match([], mnesia_test_lib:stop_mnesia(Nodes)),
 1681:     ?match([], mnesia_test_lib:start_mnesia(Nodes, [Tab1, Tab2])),
 1682:     ?match(ok, Test()),
 1683:     Clear(), Setup(),
 1684:     ?match([], mnesia_test_lib:stop_mnesia(Nodes)),
 1685:     ?match([], mnesia_test_lib:start_mnesia(Nodes, [Tab1, Tab2])),
 1686:     ?match({atomic,ok}, mnesia:transaction(Test)),
 1687: 
 1688:     ?verify_mnesia(Nodes, []).
 1689: 
 1690: snmp_get_mnesia_key(suite) -> [];
 1691: snmp_get_mnesia_key(Config) when is_list(Config) ->
 1692:     [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 1693:     Tab1 = local_snmp_table,
 1694:     Storage = mnesia_test_lib:storage_type(disc_copies, Config),
 1695:     Def1 = 
 1696: 	case mnesia_test_lib:diskless(Config) of
 1697: 	    true -> [{ram_copies, Nodes}];
 1698: 	    false ->		
 1699: 		[{disc_copies, [Node1]}, {ram_copies, [Node2]}]
 1700: 	end,
 1701: 
 1702:     Tab2 = ext_snmp_table,
 1703:     Def2 = [{Storage, [Node2]}],
 1704: 
 1705:     Tab3 = fix_string,    
 1706:     Setup = fun() -> 
 1707: 		    ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 1708: 		    ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 1709: 		    ?match({atomic, ok}, mnesia:create_table(Tab3, Def1)),
 1710: 		    ?match({atomic, ok}, mnesia:snmp_open_table(Tab1, [{key, integer}])),
 1711: 		    ?match({atomic, ok}, mnesia:snmp_open_table(Tab2, [{key, integer}])),
 1712: 		    ?match({atomic, ok}, mnesia:snmp_open_table(Tab3, [{key, {fix_string,integer}}])),
 1713: 
 1714: 		    add_some_records(Tab1, Tab2, 1)	    
 1715: 	    end,
 1716:     Clear = fun() ->
 1717: 		    ?match({atomic, ok}, mnesia:delete_table(Tab1)),
 1718: 		    ?match({atomic, ok}, mnesia:delete_table(Tab2)),
 1719: 		    ?match({atomic, ok}, mnesia:delete_table(Tab3))
 1720: 	    end,
 1721:     Test = 
 1722: 	fun() ->
 1723: 		%% Test local tables
 1724: 		{success, Res11} = 
 1725: 		    ?match({ok, [1]}, mnesia:snmp_get_next_index(Tab1,[])),
 1726: 		{ok, Index11} = Res11,
 1727: 		?match({ok, 1}, mnesia:snmp_get_mnesia_key(Tab1, Index11)),    
 1728: 		%% Test external tables
 1729: 		{success, Res21} =
 1730: 		    ?match({ok, [20]}, mnesia:snmp_get_next_index(Tab2, [])),
 1731: 		{ok, Index21} = Res21,
 1732: 		?match({ok, 20}, mnesia:snmp_get_mnesia_key(Tab2, Index21)),
 1733: 		?match(undefined, mnesia:snmp_get_mnesia_key(Tab2, [97])),
 1734: 		?match({'EXIT', _}, mnesia:snmp_get_mnesia_key(Tab2, 97)),
 1735: 
 1736: 		?match({atomic,ok}, mnesia:transaction(fun() -> mnesia:delete({Tab1,1}) end)),
 1737: 		?match(undefined, mnesia:snmp_get_mnesia_key(Tab1, Index11)),
 1738: 		
 1739: 		?match({atomic,ok},mnesia:transaction(fun() -> mnesia:write({Tab1,73,7}) end)),
 1740: 		?match({ok, 73}, mnesia:snmp_get_mnesia_key(Tab1, [73])),
 1741: 		?match({atomic,ok}, mnesia:transaction(fun() -> mnesia:delete({Tab1,73}) end)),
 1742: 		?match(undefined, mnesia:snmp_get_mnesia_key(Tab1, [73])),
 1743: 
 1744: 		?match({atomic,ok},mnesia:transaction(fun() -> mnesia:write({Tab3,{"S",5},7}) end)),
 1745: 		?match({ok,{"S",5}}, mnesia:snmp_get_mnesia_key(Tab3, [$S,5])),
 1746: 		?match({atomic,ok},mnesia:transaction(fun() -> mnesia:delete({Tab3,{"S",5}}) end)),
 1747: 		?match(undefined, mnesia:snmp_get_mnesia_key(Tab3, [$S,5])),
 1748: 
 1749: 		ok
 1750: 	end,
 1751:     Setup(),
 1752:     ?match(ok, Test()),
 1753:     Clear(), Setup(),
 1754:     ?match({atomic,ok}, mnesia:transaction(Test)),
 1755:     Clear(), Setup(),
 1756:     ?match(ok, mnesia:sync_dirty(Test)),
 1757:     Clear(), Setup(),
 1758:     ?match(ok, mnesia:activity(transaction,Test,mnesia)),
 1759:     ?verify_mnesia(Nodes, []).
 1760: 
 1761: snmp_update_counter(doc) ->
 1762:     ["Verify that counters may be updated for tables with SNMP property"];
 1763: snmp_update_counter(suite) -> [];
 1764: snmp_update_counter(Config) when is_list(Config) ->
 1765:     [Node1] = Nodes = ?acquire_nodes(1, Config),
 1766:     Tab = snmp_update_counter,
 1767:     Def = [{attributes, [key, value]},
 1768:            {snmp, [{key, integer}]},
 1769:            {ram_copies, [Node1]}
 1770:           ],
 1771:     ?match({atomic, ok}, mnesia:create_table(Tab, Def)),
 1772:     Oid = {Tab, 1},
 1773:     ?match([], mnesia:dirty_read(Oid)),
 1774:     ?match(ok, mnesia:dirty_write({Tab, 1, 1})),
 1775:     ?match([{Tab, _Key, 1}], mnesia:dirty_read(Oid)),
 1776:     ?match(3, mnesia:dirty_update_counter(Oid, 2)),
 1777:     ?match([{Tab, _Key, 3}], mnesia:dirty_read(Oid)),
 1778:     ?verify_mnesia(Nodes, []).
 1779: 
 1780: snmp_order(doc) ->
 1781:     ["Verify that sort order is correct in transactions and dirty variants"];
 1782: snmp_order(suite) -> [];
 1783: snmp_order(Config) when is_list(Config) ->
 1784:     [Node1] = Nodes = ?acquire_nodes(1, Config),
 1785:     Tab = snmp_order,
 1786:     Def = [{attributes, [key, value]},
 1787:            {snmp, [{key, {integer, integer, integer}}]},
 1788:            {ram_copies, [Node1]}
 1789:           ],
 1790:     ?match({atomic, ok}, mnesia:create_table(Tab, Def)),
 1791:     Oid = {Tab, 1},
 1792:     ?match([], mnesia:dirty_read(Oid)),
 1793:     ?match({'EXIT', {aborted, _}}, mnesia:dirty_write({Tab, 1, 1})),
 1794:     [mnesia:dirty_write({Tab, {A,B,2}, default}) ||
 1795: 	A <- lists:seq(1, 9, 2),
 1796: 	B <- lists:seq(2, 8, 2)],
 1797:     
 1798:     Test1 = fun() ->
 1799: 		    Keys0 = get_keys(Tab, []),
 1800: 		    ?match(Keys0, lists:sort(Keys0)),
 1801: 		    ?match([[1,2,2]|_], Keys0),
 1802: 		    Keys1 = get_keys(Tab, [5]),
 1803: 		    ?match(Keys1, lists:sort(Keys1)),
 1804: 		    ?match([[5,2,2]|_], Keys1),
 1805: 		    Keys2 = get_keys(Tab, [7, 4]),
 1806: 		    ?match(Keys2, lists:sort(Keys2)),
 1807: 		    ?match([[7,4,2]|_], Keys2),
 1808: 		    ok
 1809: 	    end,
 1810:     ?match(ok, Test1()),
 1811:     ?match({atomic, ok},mnesia:transaction(Test1)),
 1812:     ?match(ok,mnesia:sync_dirty(Test1)),
 1813:    
 1814:     Test2 = fun() ->
 1815: 		    mnesia:write(Tab, {Tab,{0,0,2},updated}, write),
 1816: 		    mnesia:write(Tab, {Tab,{5,3,2},updated}, write),
 1817: 		    mnesia:write(Tab, {Tab,{10,10,2},updated}, write),
 1818: 		    Keys0 = get_keys(Tab, []),
 1819: 		    ?match([[0,0,2],[1,2,2]|_], Keys0),
 1820: 		    ?match(Keys0, lists:sort(Keys0)),
 1821: 		    
 1822: 		    Keys1 = get_keys(Tab, [5]),
 1823: 		    ?match([[5,2,2],[5,3,2]|_], Keys1),
 1824: 		    ?match(Keys1, lists:sort(Keys1)),
 1825: 		    
 1826: 		    Keys2 = get_keys(Tab, [7,4]),
 1827: 		    ?match([[7,4,2]|_], Keys2),
 1828: 		    ?match(Keys2, lists:sort(Keys2)),
 1829: 		    ?match([10,10,2], lists:last(Keys0)),
 1830: 		    ?match([10,10,2], lists:last(Keys1)),
 1831: 		    ?match([10,10,2], lists:last(Keys2)),
 1832: 		    
 1833: 		    ?match([[10,10,2]], get_keys(Tab, [10])),
 1834: 		    ok
 1835: 	    end,
 1836: 
 1837:     ?match({atomic, ok},mnesia:transaction(Test2)),
 1838: 
 1839:     ?verify_mnesia(Nodes, []).
 1840: 
 1841: get_keys(Tab, Key) ->
 1842:     case mnesia:snmp_get_next_index(Tab, Key) of
 1843: 	endOfTable -> [];
 1844: 	{ok, Next} ->
 1845: 	    [Next|get_keys(Tab, Next)]
 1846:     end.
 1847: 
 1848: 
 1849: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 1850: 
 1851: -record(tab, {i, e1, e2}).			% Simple test table
 1852: 
 1853: 
 1854: subscribe_extended(doc) ->
 1855:     ["Test the extended set of events, test with and without checkpoints. "];
 1856: subscribe_extended(suite) ->
 1857:     [];
 1858: subscribe_extended(Config) when is_list(Config) ->
 1859:     [N1, N2]=Nodes=?acquire_nodes(2, Config),
 1860:     Tab1 = etab,
 1861:     Storage = mnesia_test_lib:storage_type(ram_copies, Config),
 1862:     Def1 = [{Storage, [N1, N2]}, {attributes, record_info(fields, tab)}],
 1863:     ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 1864: 
 1865:     Tab2 = bag,
 1866:     Def2 = [{Storage, [N1, N2]}, 
 1867: 	    {type, bag},
 1868: 	    {record_name, Tab1},
 1869: 	    {attributes, record_info(fields, tab)}],
 1870:     ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 1871: 
 1872:     Tab3 = ctab,
 1873:     Def3 = [{Storage, [N1, N2]}],
 1874:     ?match({atomic, ok}, mnesia:create_table(Tab3, Def3)),
 1875: 
 1876:     ?match({ok, N1}, mnesia:subscribe({table, Tab1, detailed})),
 1877:     ?match({ok, N1}, mnesia:subscribe({table, Tab2, detailed})),
 1878:     ?match({ok, N1}, mnesia:subscribe({table, Tab3, detailed})),
 1879: 
 1880:     ?match({error, {already_exists, _}}, mnesia:subscribe({table, Tab1, simple})),
 1881:     ?match({error, {badarg, {table, Tab1, bad}}}, mnesia:subscribe({table, Tab1, bad})),
 1882: 
 1883:     ?match({ok, N1}, mnesia:subscribe(activity)),
 1884:     test_ext_sub(Tab1, Tab2, Tab3),
 1885:     
 1886:     ?match({ok, N1}, mnesia:unsubscribe(activity)),
 1887:     ?match({ok, N1}, mnesia:subscribe({table, Tab1, detailed})),
 1888:     ?match({atomic, ok}, mnesia:clear_table(Tab1)),
 1889:     ?match({mnesia_table_event, {delete, schema, {schema, Tab1}, [{schema, Tab1, _}],_}}, recv_event()),
 1890:     ?match({mnesia_table_event, {write, schema, {schema, Tab1, _}, [], _}}, recv_event()),
 1891: 
 1892:     ?match({atomic, ok}, mnesia:clear_table(Tab2)),
 1893:     ?match({mnesia_table_event, {delete, schema, {schema, Tab2}, [{schema, Tab2, _}],_}}, 
 1894: 	   recv_event()),
 1895:     ?match({mnesia_table_event, {write, schema, {schema, Tab2, _}, [], _}}, recv_event()),
 1896: 
 1897:     ?match({ok, N1}, mnesia:unsubscribe({table, Tab2, detailed})),    
 1898:     {ok, _, _} = mnesia:activate_checkpoint([{name, testing}, 
 1899: 					     {ram_overrides_dump, true}, 
 1900: 					     {max, [Tab1, Tab2]}]),
 1901:     ?match({ok, N1}, mnesia:subscribe({table, Tab2, detailed})),
 1902:     ?match({ok, N1}, mnesia:subscribe(activity)),
 1903:     test_ext_sub(Tab1, Tab2, Tab3),
 1904: 
 1905:     ?verify_mnesia(Nodes, []).
 1906: 
 1907: test_ext_sub(Tab1, Tab2, Tab3) ->
 1908:     %% The basics 
 1909:     Rec1 = {Tab1, 1, 0, 0},
 1910:     Rec2 = {Tab1, 1, 1, 0},
 1911:     Rec3 = {Tab1, 2, 1, 0},
 1912:     Rec4 = {Tab1, 2, 2, 0},
 1913: 
 1914:     Write  = fun(Tab, Rec) -> 
 1915: 		     mnesia:transaction(fun() -> mnesia:write(Tab, Rec, write) 
 1916: 					end) 
 1917: 	     end,
 1918:     Delete = fun(Tab, Rec) -> 
 1919: 		     mnesia:transaction(fun() -> mnesia:delete(Tab, Rec, write) 
 1920: 					end) 
 1921: 	     end,
 1922:     DelObj = fun(Tab, Rec) -> 
 1923: 		     mnesia:transaction(fun() -> mnesia:delete_object(Tab, Rec, write) 
 1924: 					end) 
 1925: 	     end,
 1926: 
 1927:     S = self(),
 1928:     D = {dirty, self()},
 1929:     %% SET 
 1930:     ?match(ok, mnesia:dirty_write(Rec1)),
 1931:     ?match({mnesia_table_event, {write, Tab1, Rec1, [], D}}, recv_event()), 
 1932:     ?match(ok, mnesia:dirty_write(Rec3)),
 1933:     ?match({mnesia_table_event, {write, Tab1, Rec3, [], D}}, recv_event()),    
 1934:     ?match(ok, mnesia:dirty_write(Rec1)),
 1935:     ?match({mnesia_table_event, {write, Tab1, Rec1, [Rec1], D}}, recv_event()),
 1936:     ?match({atomic, ok}, Write(Tab1, Rec2)),
 1937:     ?match({mnesia_table_event, {write, Tab1, Rec2, [Rec1], {tid,_,S}}}, recv_event()),    
 1938:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1939:     ?match(ok, mnesia:dirty_delete({Tab1, 2})),
 1940:     ?match({mnesia_table_event, {delete, Tab1, {Tab1, 2}, [Rec3], D}}, recv_event()),
 1941:     ?match({atomic, ok}, DelObj(Tab1, Rec2)),
 1942:     ?match({mnesia_table_event, {delete, Tab1, Rec2, [Rec2], {tid,_,S}}}, recv_event()),
 1943:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1944: 
 1945:     ?match({atomic, ok}, Delete(Tab1, 1)),
 1946:     ?match({mnesia_table_event, {delete, Tab1, {Tab1, 1}, [], {tid,_,S}}}, recv_event()),
 1947:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1948:     ?match({ok, _N1}, mnesia:unsubscribe({table, Tab1, detailed})),
 1949: 
 1950:     %% BAG 
 1951: 
 1952:     ?match({atomic, ok}, Write(Tab2, Rec1)),
 1953:     ?match({mnesia_table_event, {write, Tab2, Rec1, [], {tid,_,S}}}, recv_event()),
 1954:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1955:     ?match({atomic, ok}, Write(Tab2, Rec4)),
 1956:     ?match({mnesia_table_event, {write, Tab2, Rec4, [], {tid,_,S}}}, recv_event()),    
 1957:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1958:     ?match({atomic, ok}, Write(Tab2, Rec3)),
 1959:     ?match({mnesia_table_event, {write, Tab2, Rec3, [Rec4], {tid,_,S}}}, recv_event()),    
 1960:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1961:     ?match({atomic, ok}, Write(Tab2, Rec2)),
 1962:     ?match({mnesia_table_event, {write, Tab2, Rec2, [Rec1], {tid,_,S}}}, recv_event()),    
 1963:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1964:     ?match({atomic, ok}, Write(Tab2, Rec1)),
 1965:     ?match({mnesia_table_event, {write, Tab2, Rec1, [Rec1, Rec2], {tid,_,S}}}, recv_event()),
 1966:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1967:     ?match({atomic, ok}, DelObj(Tab2, Rec2)),
 1968:     ?match({mnesia_table_event, {delete, Tab2, Rec2, [Rec2], {tid,_,S}}}, recv_event()),
 1969:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1970:     ?match({atomic, ok}, Delete(Tab2, 1)),
 1971:     ?match({mnesia_table_event, {delete, Tab2, {Tab2, 1}, [Rec1], {tid,_,S}}}, recv_event()),
 1972:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1973:     ?match({atomic, ok}, Delete(Tab2, 2)),
 1974:     ?match({mnesia_table_event, {delete, Tab2, {Tab2, 2}, [Rec4, Rec3], {tid,_,S}}}, recv_event()),
 1975:     ?match({mnesia_activity_event, {complete, {tid,_,S}}}, recv_event()),
 1976: 
 1977:     %% COUNTERS
 1978: 
 1979:     Rec5 = {Tab3, counter, 0},
 1980:     ?match(ok, mnesia:dirty_write(Rec5)),
 1981:     ?match({mnesia_table_event, {write, Tab3, Rec5, [], D}}, recv_event()),
 1982:     ?match(1, mnesia:dirty_update_counter({Tab3, counter}, 1)),
 1983:     ?match({mnesia_table_event, {write, Tab3, {Tab3,counter,1}, [Rec5], D}}, recv_event()),
 1984:     ?match(ok, mnesia:dirty_delete({Tab3, counter})),
 1985:     ?match({mnesia_table_event, {delete, Tab3, {Tab3,counter},
 1986: 				 [{Tab3,counter,1}], D}}, recv_event()),
 1987:     ok.
 1988: 
 1989: 
 1990: subscribe_standard(doc) ->
 1991:     ["Tests system events and the orignal table events"];
 1992: subscribe_standard(suite) -> [];
 1993: subscribe_standard(Config) when is_list(Config)-> 
 1994:     [N1, N2]=?acquire_nodes(2, Config),
 1995:     Tab = tab,
 1996: 
 1997:     Storage = mnesia_test_lib:storage_type(disc_copies, Config),
 1998:     Def = [{Storage, [N1, N2]}, {attributes, record_info(fields, tab)}],
 1999: 
 2000:     ?match({atomic, ok}, mnesia:create_table(Tab, Def)),
 2001: 
 2002:     %% Check system events
 2003:     ?match({error, {badarg, foo}}, mnesia:unsubscribe(foo)),
 2004:     ?match({error, badarg}, mnesia:unsubscribe({table, foo})),
 2005:     mnesia:unsubscribe(activity),
 2006: 
 2007:     ?match({ok, N1}, mnesia:subscribe(system)),
 2008:     ?match({ok, N1}, mnesia:subscribe(activity)),
 2009: 
 2010:     ?match([], mnesia_test_lib:kill_mnesia([N2])),
 2011:     ?match({mnesia_system_event, {mnesia_down, N2}}, recv_event()),
 2012:     ?match(timeout, recv_event()),
 2013: 
 2014:     ?match([], mnesia_test_lib:start_mnesia([N2], [Tab])),
 2015:     ?match({mnesia_activity_event, _}, recv_event()),
 2016:     ?match({mnesia_system_event,{mnesia_up, N2}}, recv_event()),
 2017: 
 2018:     ?match(true, lists:member(self(), mnesia:system_info(subscribers))),
 2019:     ?match([], mnesia_test_lib:kill_mnesia([N1])),
 2020:     timer:sleep(500),
 2021:     mnesia_test_lib:flush(),
 2022:     ?match([], mnesia_test_lib:start_mnesia([N1], [Tab])),
 2023:     ?match(timeout, recv_event()),
 2024: 
 2025:     ?match({ok, N1}, mnesia:subscribe(system)),
 2026:     ?match({error, {already_exists, system}}, mnesia:subscribe(system)),
 2027:     ?match(stopped, mnesia:stop()),
 2028:     ?match({mnesia_system_event, {mnesia_down, N1}}, recv_event()),
 2029:     ?match({error, {node_not_running, N1}}, mnesia:subscribe(system)),
 2030:     ?match([], mnesia_test_lib:start_mnesia([N1, N2], [Tab])),
 2031: 
 2032:     %% Check table events
 2033:     ?match({ok, N1}, mnesia:subscribe(activity)),
 2034:     Old_Level = mnesia:set_debug_level(trace),
 2035:     ?match({ok, N1}, mnesia:subscribe({table,Tab})),
 2036: 
 2037:     ?match({atomic, ok},
 2038: 	   mnesia:transaction(fun() -> mnesia:write(#tab{i=155}) end)),
 2039:     Self = self(),
 2040:     ?match({mnesia_table_event, {write, _, _}}, recv_event()),
 2041:     ?match({mnesia_activity_event, {complete, {tid, _, Self}}}, recv_event()),
 2042: 
 2043:     ?match({ok, N1}, mnesia:unsubscribe({table,Tab})),
 2044:     ?match({ok, N1}, mnesia:unsubscribe(activity)),
 2045: 
 2046:     ?match({atomic, ok},
 2047: 	   mnesia:transaction(fun() -> mnesia:write(#tab{i=255}) end)),
 2048:     
 2049:     ?match(timeout, recv_event()),
 2050:     mnesia:set_debug_level(Old_Level),
 2051: 
 2052:     %% Check deletion of replica
 2053: 
 2054:     ?match({ok, N1}, mnesia:subscribe({table,Tab})),
 2055:     ?match({ok, N1}, mnesia:subscribe(activity)),
 2056:     ?match(ok, mnesia:dirty_write(#tab{i=355})),
 2057:     ?match({mnesia_table_event, {write, _, _}}, recv_event()),
 2058:     ?match({atomic, ok}, mnesia:del_table_copy(Tab, N1)),
 2059:     ?match({mnesia_activity_event, _}, recv_event()),
 2060:     ?match(ok, mnesia:dirty_write(#tab{i=455})),
 2061:     ?match(timeout, recv_event()),
 2062: 
 2063:     ?match({atomic, ok}, mnesia:move_table_copy(Tab, N2, N1)),
 2064:     ?match({mnesia_activity_event, _}, recv_event()),
 2065:     ?match({ok, N1}, mnesia:subscribe({table,Tab})),
 2066:     ?match(ok, mnesia:dirty_write(#tab{i=555})),
 2067:     ?match({mnesia_table_event, {write, _, _}}, recv_event()),
 2068:     ?match({atomic, ok}, mnesia:move_table_copy(Tab, N1, N2)),
 2069:     ?match({mnesia_activity_event, _}, recv_event()),
 2070:     ?match(ok, mnesia:dirty_write(#tab{i=655})),
 2071:     ?match(timeout, recv_event()),
 2072: 
 2073:     ?match({atomic, ok}, mnesia:add_table_copy(Tab, N1, ram_copies)),
 2074:     ?match({mnesia_activity_event, _}, recv_event()),
 2075:     ?match({ok, N1}, mnesia:subscribe({table,Tab})),
 2076:     ?match({error, {already_exists, {table,Tab, simple}}}, 
 2077: 	   mnesia:subscribe({table,Tab})),
 2078:     ?match(ok, mnesia:dirty_write(#tab{i=755})),
 2079:     ?match({mnesia_table_event, {write, _, _}}, recv_event()),
 2080: 
 2081:     ?match({atomic, ok}, mnesia:delete_table(Tab)),
 2082:     ?match({mnesia_activity_event, _}, recv_event()),
 2083:     ?match(timeout, recv_event()),
 2084: 
 2085:     mnesia_test_lib:kill_mnesia([N1]),
 2086: 
 2087:     ?verify_mnesia([N2], [N1]).
 2088: 
 2089: recv_event() ->
 2090:     receive
 2091: 	Event -> Event
 2092:     after 1000 -> 
 2093: 	    timeout
 2094:     end.
 2095: 
 2096: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 2097: 
 2098: 
 2099: foldl(suite) ->
 2100:     [];
 2101: foldl(doc) ->
 2102:     [""];
 2103: foldl(Config) when is_list(Config) ->
 2104:     Nodes = [_N1, N2] = ?acquire_nodes(2, Config),
 2105:     Tab1 = fold_local,
 2106:     Tab2 = fold_remote,
 2107:     Tab3 = fold_ordered, 
 2108:     ?match({atomic, ok}, mnesia:create_table(Tab1, [{ram_copies, Nodes}])),
 2109:     ?match({atomic, ok}, mnesia:create_table(Tab2, [{ram_copies, [N2]}, {type, bag}])),
 2110:     ?match({atomic, ok}, mnesia:create_table(Tab3, [{ram_copies, Nodes}, 
 2111: 						    {type, ordered_set}])),    
 2112: 
 2113:     Tab1Els = [{Tab1, N, N} || N <- lists:seq(1, 10)],
 2114:     Tab2Els = ?sort([{Tab2, 1, 2} | [{Tab2, N, N} || N <- lists:seq(1, 10)]]),
 2115:     Tab3Els = [{Tab3, N, N} || N <- lists:seq(1, 10)],
 2116: 
 2117:     [mnesia:sync_transaction(fun() -> mnesia:write(E) end) || E <- Tab1Els],
 2118:     [mnesia:sync_transaction(fun() -> mnesia:write(E) end) || E <- Tab2Els],
 2119:     [mnesia:sync_transaction(fun() -> mnesia:write(E) end) || E <- Tab3Els],
 2120: 
 2121:     Fold = fun(Tab) ->
 2122: 		   lists:reverse(mnesia:foldl(fun(E, A) -> [E | A] end, [], Tab))
 2123: 	   end,
 2124:     Fold2 = fun(Tab, Lock) ->
 2125: 		    lists:reverse(mnesia:foldl(fun(E, A) -> [E | A] end, [], Tab, Lock))
 2126: 	    end,    
 2127:     Exit = fun(Tab) ->
 2128: 		   lists:reverse(mnesia:foldl(fun(_E, _A) -> exit(testing) end, [], Tab))
 2129: 	   end,
 2130:     %% Errors 
 2131:     ?match({aborted, _}, mnesia:transaction(Fold, [error])),
 2132:     ?match({aborted, _}, mnesia:transaction(fun(Tab) -> mnesia:foldl(badfun,[],Tab) end,
 2133: 					    [Tab1])),    
 2134:     ?match({aborted, testing}, mnesia:transaction(Exit, [Tab1])), 
 2135:     ?match({aborted, _}, mnesia:transaction(Fold2, [Tab1, read_lock])),
 2136: 
 2137:     %% Success
 2138:     ?match({atomic, Tab1Els}, sort_res(mnesia:transaction(Fold, [Tab1]))),
 2139:     ?match({atomic, Tab2Els}, sort_res(mnesia:transaction(Fold, [Tab2]))),
 2140:     ?match({atomic, Tab3Els}, mnesia:transaction(Fold, [Tab3])),        
 2141: 
 2142:     ?match({atomic, Tab1Els}, sort_res(mnesia:transaction(Fold2, [Tab1, read]))),
 2143:     ?match({atomic, Tab1Els}, sort_res(mnesia:transaction(Fold2, [Tab1, write]))),
 2144: 
 2145:     ?match(Tab1Els, sort_res(mnesia:sync_dirty(Fold, [Tab1]))),
 2146:     ?match(Tab2Els, sort_res(mnesia:async_dirty(Fold, [Tab2]))),
 2147: 
 2148:     ?verify_mnesia(Nodes, []).	   
 2149: 
 2150: sort_res({atomic, List}) ->
 2151:     {atomic, ?sort(List)};
 2152: sort_res(Else) when is_list(Else) ->
 2153:     ?sort(Else);
 2154: sort_res(Else) ->
 2155:     Else.
 2156: 
 2157: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 2158: 
 2159: info(suite) -> [];
 2160: info(Config) when is_list(Config) ->
 2161:     Nodes = ?acquire_nodes(1, Config),
 2162:     ?match(ok, mnesia:info()),
 2163:     ?verify_mnesia(Nodes, []).
 2164: 
 2165: schema_0(suite) -> [];
 2166: schema_0(Config) when is_list(Config) ->
 2167:     Nodes = ?acquire_nodes(1, Config),
 2168:     ?match(ok, mnesia:schema()),
 2169:     ?verify_mnesia(Nodes, []).
 2170: 
 2171: schema_1(suite) -> [];
 2172: schema_1(Config) when is_list(Config) ->
 2173:     Nodes = ?acquire_nodes(1, Config),
 2174:     Tab = schema_1,
 2175:     ?match({atomic, ok}, mnesia:create_table(Tab, [])),
 2176:     ?match(ok, mnesia:schema(Tab)),
 2177:     ?verify_mnesia(Nodes, []).
 2178: 
 2179: view_0(suite) -> [];
 2180: view_0(Config) when is_list(Config) ->
 2181:     Nodes = ?acquire_nodes(1, Config),
 2182:     ?match(ok, mnesia_lib:view()),
 2183:     ?verify_mnesia(Nodes, []).
 2184: 
 2185: view_1(suite) -> [];
 2186: view_1(Config) when is_list(Config) ->
 2187:     Nodes = ?acquire_nodes(1, Config),
 2188:     BinCore = mnesia_lib:mkcore({crashinfo, "Just testing..."}),
 2189:     CoreFile = lists:concat(["MnesiaCore.", node(), ".view_1.", ?MODULE]),
 2190:     ?match(ok, file:write_file(CoreFile, BinCore)),
 2191:     ?match(ok, mnesia_lib:view(CoreFile)),
 2192:     ?match(ok, file:delete(CoreFile)),
 2193: 
 2194:     ?match(stopped, mnesia:stop()),
 2195:     Dir = mnesia:system_info(directory),
 2196:     ?match(eof, mnesia_lib:view(filename:join(Dir, "LATEST.LOG"))),
 2197:     ?match(ok, mnesia_lib:view(filename:join(Dir, "schema.DAT"))),
 2198:     ?verify_mnesia([], Nodes).
 2199: 
 2200: view_2(suite) -> [];
 2201: view_2(Config) when is_list(Config) ->
 2202:     Nodes = ?acquire_nodes(1, Config),
 2203:     BinCore = mnesia_lib:mkcore({crashinfo, "More testing..."}),
 2204:     File = lists:concat([?MODULE, "view_2.", node()]),
 2205:     ?match(ok, file:write_file(File, BinCore)),
 2206:     ?match(ok, mnesia_lib:view(File, core)),
 2207:     ?match(ok, file:delete(File)),
 2208: 
 2209:     ?match(stopped, mnesia:stop()),
 2210:     Dir = mnesia:system_info(directory),
 2211:     ?match(ok, file:rename(filename:join(Dir, "LATEST.LOG"), File)),
 2212:     ?match(eof, mnesia_lib:view(File, log)),
 2213:     ?match(ok, file:delete(File)),
 2214: 
 2215:     ?match(ok, file:rename(filename:join(Dir, "schema.DAT"), File)),
 2216:     ?match(ok, mnesia_lib:view(File, dat)),
 2217:     ?match(ok, file:delete(File)),
 2218:     ?verify_mnesia([], Nodes).
 2219: 
 2220: lkill(suite) -> [];
 2221: lkill(Config) when is_list(Config) ->
 2222:     [Node1, Node2] = ?acquire_nodes(2, Config),
 2223: 
 2224:     ?match(yes, rpc:call(Node1, mnesia, system_info, [is_running])),
 2225:     ?match(yes, rpc:call(Node2, mnesia, system_info, [is_running])),
 2226:     ?match(ok, rpc:call(Node2, mnesia, lkill, [])),
 2227:     ?match(yes, rpc:call(Node1, mnesia, system_info, [is_running])),
 2228:     ?match(no, rpc:call(Node2, mnesia, system_info, [is_running])),
 2229:     ?verify_mnesia([Node1], [Node2]).
 2230: 
 2231: kill(suite) -> [];
 2232: kill(Config) when is_list(Config) ->
 2233:     [Node1, Node2] = ?acquire_nodes(2, Config),
 2234: 
 2235:     ?match(yes, rpc:call(Node1, mnesia, system_info, [is_running])),
 2236:     ?match(yes, rpc:call(Node2, mnesia, system_info, [is_running])),
 2237:     ?match({_, []}, rpc:call(Node2, mnesia, kill, [])),
 2238:     ?match(no, rpc:call(Node1, mnesia, system_info, [is_running])),
 2239:     ?match(no, rpc:call(Node2, mnesia, system_info, [is_running])),
 2240:     ?verify_mnesia([], [Node1, Node2]).
 2241: 
 2242: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 2243: 
 2244: 
 2245: 
 2246: record_name_dirty_access_ram(suite) ->
 2247:     [];
 2248: record_name_dirty_access_ram(Config) when is_list(Config) ->
 2249:     record_name_dirty_access(ram_copies, Config).
 2250: 
 2251: record_name_dirty_access_disc(suite) ->
 2252:     [];
 2253: record_name_dirty_access_disc(Config) when is_list(Config) ->
 2254:     record_name_dirty_access(disc_copies, Config).
 2255: 
 2256: record_name_dirty_access_disc_only(suite) ->
 2257:     [];
 2258: record_name_dirty_access_disc_only(Config) when is_list(Config) ->
 2259:     record_name_dirty_access(disc_only_copies, Config).
 2260: 
 2261: record_name_dirty_access(Storage, Config) ->
 2262:     [Node1, _Node2] = Nodes = ?acquire_nodes(2, Config),
 2263: 
 2264:     List = lists:concat([record_name_dirty_access_, Storage]),
 2265:     Tab = list_to_atom(List),
 2266:     RecName = some_record,
 2267:     Attr = val,
 2268:     TabDef = [{type, bag},
 2269: 	      {record_name, RecName},
 2270: 	      {index, [Attr]},
 2271: 	      {Storage, Nodes}],
 2272:     ?match({atomic, ok}, mnesia:create_table(Tab, TabDef)),
 2273: 
 2274:     ?match(RecName, mnesia:table_info(Tab, record_name)),
 2275: 
 2276:     ?match(ok, mnesia:dirty_write(Tab, {RecName, 2, 20})),
 2277:     ?match(ok, mnesia:dirty_write(Tab, {RecName, 2, 21})),
 2278:     ?match(ok, mnesia:dirty_write(Tab, {RecName, 2, 22})),
 2279: 
 2280:     %% Backup test
 2281:     BupFile = List ++ ".BUP",
 2282:     CpName = cpname,
 2283:     CpArgs = [{name, CpName}, {min, [Tab]}, {ram_overrides_dump, true}],
 2284:     ?match({ok, CpName, _}, mnesia:activate_checkpoint(CpArgs)),
 2285:     ?match(ok, mnesia:backup_checkpoint(CpName, BupFile)),
 2286:     ?match(ok, mnesia:deactivate_checkpoint(CpName)),
 2287: 
 2288:     ?match(ok, mnesia:dirty_write(Tab, {RecName, 1, 10})),
 2289:     ?match({ok, Node1}, mnesia:subscribe({table, Tab})),
 2290:     ?match(ok, mnesia:dirty_write(Tab, {RecName, 3, 10})),
 2291: 
 2292:     Twos =?sort( [{RecName, 2, 20}, {RecName, 2, 21}, {RecName, 2, 22}]),
 2293:     ?match(Twos, ?sort(mnesia:dirty_read(Tab, 2))),
 2294: 
 2295:     ?match(ok, mnesia:dirty_delete_object(Tab, {RecName, 2, 21})),
 2296: 
 2297:     Tens = ?sort([{RecName, 1, 10}, {RecName, 3, 10}]),
 2298:     TenPat = {RecName, '_', 10},
 2299:     ?match(Tens, ?sort(mnesia:dirty_match_object(Tab, TenPat))),
 2300:     ?match(Tens, ?sort(mnesia:dirty_select(Tab, [{TenPat, [], ['$_']}]))),
 2301: 
 2302:     %% Subscription test
 2303:     E = mnesia_table_event,
 2304:     ?match_receive({E, {write, {Tab, 3, 10}, _}}),
 2305:     ?match_receive({E, {delete_object, {Tab, 2, 21}, _}}),
 2306:     ?match({ok, Node1}, mnesia:unsubscribe({table, Tab})),
 2307: 
 2308:     ?match([], mnesia_test_lib:stop_mnesia([Node1])),
 2309:     ?match([], mnesia_test_lib:start_mnesia(Nodes, [Tab])),
 2310: 
 2311:     ?match(Tens, ?sort(mnesia:dirty_index_match_object(Tab, TenPat, Attr) )),
 2312:     ?match(Tens, ?sort(mnesia:dirty_index_read(Tab, 10, Attr))),
 2313: 
 2314:     ?match([1, 2, 3], ?sort(mnesia:dirty_all_keys(Tab))),
 2315: 
 2316:     ?match({ok, Node1}, mnesia:subscribe({table, Tab})),
 2317:     ?match(ok, mnesia:dirty_delete(Tab, 2)),
 2318:     ?match([], mnesia:dirty_read(Tab, 2)),
 2319: 
 2320:     ?match_receive({E, {delete, {Tab, 2}, _}}),
 2321:     ?match([], mnesia_test_lib:flush()),
 2322:     ?match({ok, Node1}, mnesia:unsubscribe({table, Tab})),
 2323: 
 2324:     %% Restore test
 2325:     ?match({atomic, [Tab]}, mnesia:restore(BupFile, [{recreate_tables, [Tab]}])),
 2326:     ?match(RecName, mnesia:table_info(Tab, record_name)),
 2327: 
 2328:     ?match(Twos, ?sort(mnesia:dirty_match_object(Tab, mnesia:table_info(Tab, wild_pattern)))),
 2329:     ?match(Twos, ?sort(mnesia:dirty_select(Tab, 
 2330: 					   [{mnesia:table_info(Tab, wild_pattern),
 2331: 					     [],['$_']}]))),
 2332: 
 2333:     %% Traverse backup test
 2334: 
 2335:     Fun = fun(Rec, {Good, Bad}) ->
 2336: 		  ?verbose("BUP: ~p~n", [Rec]),
 2337: 		  case Rec of
 2338: 		      {T, K, V} when T == Tab ->
 2339: 			  Good2 = Good ++ [{RecName, K, V}],
 2340: 			  {[Rec], {?sort(Good2), Bad}};
 2341: 		      {T, K} when T == Tab ->
 2342: 			  Good2 = [G || G <- Good, element(2, G) /= K],
 2343: 			  {[Rec], {?sort(Good2), Bad}};
 2344: 		      _ when element(1, Rec) == schema ->
 2345: 			  {[Rec], {Good, Bad}};
 2346: 		      _ ->
 2347: 			  Bad2 = Bad ++ [Rec],
 2348: 			  {[Rec], {Good, ?sort(Bad2)}}
 2349: 		  end
 2350:           end,
 2351: 
 2352:     ?match({ok, {Twos, []}}, mnesia:traverse_backup(BupFile, mnesia_backup, 
 2353: 						    dummy, read_only, 
 2354: 						    Fun, {[], []})),
 2355:     ?match(ok, file:delete(BupFile)),
 2356: 
 2357:     %% Update counter test
 2358: 
 2359:     CounterTab = list_to_atom(lists:concat([Tab, "_counter"])),
 2360:     CounterTabDef = [{record_name, some_counter}],
 2361:     C = my_counter,
 2362:     ?match({atomic, ok}, mnesia:create_table(CounterTab, CounterTabDef)),
 2363:     ?match(some_counter, mnesia:table_info(CounterTab, record_name)),
 2364:     ?match(0, mnesia:dirty_update_counter(CounterTab, gurka, -10)),
 2365:     ?match(10, mnesia:dirty_update_counter(CounterTab, C, 10)),
 2366:     ?match(11, mnesia:dirty_update_counter(CounterTab, C, 1)),
 2367:     ?match(4711, mnesia:dirty_update_counter(CounterTab, C, 4700)),
 2368:     ?match([{some_counter, C, 4711}], mnesia:dirty_read(CounterTab, C)),
 2369:     ?match(0, mnesia:dirty_update_counter(CounterTab, C, -4747)),
 2370: 
 2371:     %% Registry tests
 2372: 
 2373:     RegTab = list_to_atom(lists:concat([Tab, "_registry"])),
 2374:     RegTabDef = [{record_name, some_reg}],
 2375:     ?match(ok, mnesia_registry:create_table(RegTab, RegTabDef)),
 2376:     ?match(some_reg, mnesia:table_info(RegTab, record_name)),
 2377:     {success, RegRecs} =
 2378: 	?match([_ | _], mnesia_registry_test:dump_registry(node(), RegTab)),
 2379: 
 2380:     R = ?sort(RegRecs),
 2381:     ?match(R, ?sort(mnesia_registry_test:restore_registry(node(), RegTab))),
 2382: 
 2383:     ?verify_mnesia(Nodes, []).
 2384: 
 2385: sorted_ets(suite) ->
 2386:     [];
 2387: sorted_ets(Config) when is_list(Config) ->
 2388:     [N1, N2, N3] = All = ?acquire_nodes(3, Config),
 2389: 
 2390:     Tab = sorted_tab,    
 2391:     Def = case  mnesia_test_lib:diskless(Config) of
 2392: 	      true ->  [{name, Tab}, {type, ordered_set}, {ram_copies, All}];
 2393: 	      false -> [{name, Tab}, {type, ordered_set},
 2394: 			{ram_copies, [N1]}, 
 2395: 			{disc_copies,[N2, N3]}]
 2396: 	  end,
 2397: 
 2398:     ?match({atomic, ok}, mnesia:create_table(Def)),
 2399:     ?match({aborted, _}, mnesia:create_table(fel, [{disc_only_copies, N1}])),
 2400: 
 2401:     ?match([ok | _], 
 2402: 	   [mnesia:dirty_write({Tab, {dirty, N}, N}) || N <- lists:seq(1, 10)]),    
 2403:     ?match({atomic, _}, 
 2404: 	   mnesia:sync_transaction(fun() ->
 2405: 					   [mnesia:write({Tab, {trans, N}, N}) || 
 2406: 					       N <- lists:seq(1, 10)]
 2407: 				   end)),
 2408: 
 2409:     List = mnesia:dirty_match_object({Tab, '_', '_'}),
 2410:     ?match(List, ?sort(List)),
 2411:     ?match(List, rpc:call(N2, mnesia, dirty_match_object, [{Tab, '_', '_'}])),
 2412:     ?match(List, rpc:call(N3, mnesia, dirty_match_object, [{Tab, '_', '_'}])),
 2413: 
 2414:     mnesia_test_lib:stop_mnesia(All),
 2415:     mnesia_test_lib:start_mnesia(All, [sorted_tab]),
 2416: 
 2417:     List = mnesia:dirty_match_object({Tab, '_', '_'}),
 2418:     ?match(List, ?sort(List)),
 2419:     ?match(List, rpc:call(N2, mnesia, dirty_match_object, [{Tab, '_', '_'}])),
 2420:     ?match(List, rpc:call(N3, mnesia, dirty_match_object, [{Tab, '_', '_'}])),
 2421: 
 2422:     ?match(List, rpc:call(N3, mnesia, dirty_select, [Tab, [{{Tab, '_', '_'},[],['$_']}]])),
 2423: 
 2424:     TransMatch = fun() ->
 2425: 			 mnesia:write({Tab, {trans, 0}, 0}),
 2426: 			 mnesia:write({Tab, {trans, 11}, 11}),
 2427: 			 mnesia:match_object({Tab, '_', '_'})
 2428: 		 end,
 2429:     TransSelect = fun() ->
 2430: 			  mnesia:write({Tab, {trans, 0}, 0}),
 2431: 			  mnesia:write({Tab, {trans, 11}, 11}),
 2432: 			  mnesia:select(Tab, [{{Tab, '_', '_'},[],['$_']}])
 2433: 		  end,
 2434: 
 2435:     TList = mnesia:transaction(TransMatch),
 2436:     STList = ?sort(TList),
 2437:     ?match(STList, TList),
 2438:     ?match(STList, rpc:call(N2, mnesia, transaction, [TransMatch])),
 2439:     ?match(STList, rpc:call(N3, mnesia, transaction, [TransMatch])),
 2440: 
 2441:     TSel = mnesia:transaction(TransSelect),
 2442:     ?match(STList, TSel),
 2443:     ?match(STList, rpc:call(N2, mnesia, transaction, [TransSelect])),
 2444:     ?match(STList, rpc:call(N3, mnesia, transaction, [TransSelect])),
 2445: 
 2446:     ?match({atomic, ok}, mnesia:create_table(rec, [{type, ordered_set}])),
 2447:     [ok = mnesia:dirty_write(R) || R <- [{rec,1,1}, {rec,2,1}]],
 2448:     ?match({atomic, ok}, mnesia:add_table_index(rec, 3)),    
 2449:     TestIt = fun() ->
 2450: 		     ok = mnesia:write({rec,1,1}),
 2451: 		     mnesia:index_read(rec, 1, 3)
 2452: 	     end,
 2453:     ?match({atomic, [{rec,1,1}, {rec,2,1}]}, mnesia:transaction(TestIt)).
 2454: 
 2455: