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