1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1996-2011. 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_install_test). 22: -author('hakan@erix.ericsson.se'). 23: 24: -compile([export_all]). 25: -include("mnesia_test_lib.hrl"). 26: 27: init_per_testcase(Func, Conf) -> 28: mnesia_test_lib:init_per_testcase(Func, Conf). 29: 30: end_per_testcase(Func, Conf) -> 31: mnesia_test_lib:end_per_testcase(Func, Conf). 32: 33: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34: all() -> 35: [silly_durability, silly_move, silly_upgrade]. 36: 37: groups() -> 38: [{stress, [], stress_cases()}]. 39: 40: init_per_group(_GroupName, Config) -> 41: Config. 42: 43: end_per_group(_GroupName, Config) -> 44: Config. 45: 46: 47: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 48: %% Stepwise of more and more advanced features 49: silly() -> 50: Nodes = [node()] ++ nodes(), 51: mnesia_test_lib:kill_mnesia(Nodes), 52: Config = [{nodes, Nodes}], 53: mnesia_test_lib:eval_test_case(?MODULE, silly2, Config). 54: 55: silly2(Config) when is_list(Config) -> 56: [Node1 | _] = Nodes = ?acquire_nodes(3, Config), 57: mnesia_test_lib:kill_mnesia(Nodes), 58: ?ignore([mnesia:delete_schema([N]) || N <- Nodes]), 59: ?match(ok, mnesia:create_schema([Node1])), 60: ?match(ok, rpc:call(Node1, mnesia, start, [])), 61: ?match(ok, rpc:call(Node1, mnesia, wait_for_tables, 62: [[schema], infinity])), 63: Res = silly_durability(Config), 64: StressFun = fun(F) -> apply(?MODULE, F, [Config]) end, 65: R = 66: case length(Nodes) of 67: L when L > 1 -> 68: Node2 = lists:nth(2, Nodes), 69: AddDb = [schema, Node2, ram_copies], 70: ?match({atomic, ok}, 71: rpc:call(Node1, mnesia, add_table_copy, AddDb)), 72: Args = [[{extra_db_nodes, [Node1]}]], 73: ?match(ok, rpc:call(Node2, mnesia, start, Args)), 74: ChangeDb = [schema, Node2, disc_copies], 75: ?match({atomic, ok}, 76: rpc:call(Node1, mnesia, change_table_copy_type, 77: ChangeDb)), 78: ?match([], mnesia_test_lib:sync_tables([Node1, Node2], 79: [schema])), 80: MoveRes = silly_move(Config), 81: UpgradeRes = silly_upgrade(Config), 82: StressRes = [StressFun(F) || F <- stress_cases()], 83: ?verify_mnesia([Node2], []), 84: [Res, MoveRes, UpgradeRes] ++ StressRes; 85: _ -> 86: StressRes = [StressFun(F) || F <- stress_cases()], 87: ?warning("Too few nodes. Perform net_adm:ping(OtherNode) " 88: "and rerun!!!~n", []), 89: [Res | StressRes] 90: end, 91: ?verify_mnesia([Node1], []), 92: R. 93: 94: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 95: silly_durability(doc) -> 96: ["Simple test of durability"]; 97: silly_durability(suite) -> []; 98: silly_durability(Config) when is_list(Config) -> 99: [Node1] = ?acquire_nodes(1, Config), 100: Tab = silly, 101: Storage = mnesia_test_lib:storage_type(disc_copies, Config), 102: 103: ?match({atomic, ok}, rpc:call(Node1, mnesia, 104: create_table, [Tab, [{Storage, [Node1]}]])), 105: 106: Read = fun() -> mnesia:read({Tab, a}) end, 107: Write = fun() -> mnesia:write({Tab, a, b}) end, 108: 109: ?match({atomic, []}, 110: rpc:call(Node1, mnesia, transaction, [Read])), 111: ?match({atomic, ok}, 112: rpc:call(Node1, mnesia, transaction, [Write])), 113: ?match({atomic, [{Tab, a, b}]}, 114: rpc:call(Node1, mnesia, transaction, [Read])), 115: 116: ?match(stopped, rpc:call(Node1, mnesia, stop, [])), 117: ?match(ok, rpc:call(Node1, mnesia, start, [])), 118: case mnesia_test_lib:diskless(Config) of 119: true -> 120: skip; 121: false -> 122: ?match(ok, rpc:call(Node1, mnesia, wait_for_tables, [[Tab], infinity])), 123: ?match({atomic, [{Tab, a, b}]}, 124: rpc:call(Node1, mnesia, transaction, [Read])) 125: end, 126: ?verify_mnesia([Node1], []). 127: 128: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 129: silly_move(doc) -> 130: ["Simple test of movement of a replica from one node to another"]; 131: silly_move(suite) -> []; 132: silly_move(Config) when is_list(Config) -> 133: [Node1, Node2] = ?acquire_nodes(2, Config), 134: Tab = silly_move, 135: ?match({atomic, ok}, 136: rpc:call(Node1, mnesia, 137: create_table, [Tab, [{ram_copies, [Node2]}]])), 138: ?match([], mnesia_test_lib:sync_tables([Node1, Node2], [Tab])), 139: 140: Read = fun() -> mnesia:read({Tab, a}) end, 141: Write = fun() -> mnesia:write({Tab, a, b}) end, 142: 143: ?match({atomic, []}, 144: rpc:call(Node1, mnesia, transaction, [Read])), 145: ?match({atomic, ok}, 146: rpc:call(Node1, mnesia, transaction, [Write])), 147: ?match({atomic, [{Tab, a, b}]}, 148: rpc:call(Node1, mnesia, transaction, [Read])), 149: 150: case mnesia_test_lib:diskless(Config) of 151: true -> skip; 152: false -> 153: ?match({atomic, ok}, 154: rpc:call(Node1, mnesia, 155: change_table_copy_type, [Tab, Node2, disc_only_copies])), 156: ?match([], mnesia_test_lib:sync_tables([Node1, Node2], [Tab])) 157: end, 158: ?match({atomic, [{Tab, a, b}]}, rpc:call(Node1, mnesia, transaction, [Read])), 159: 160: ?match({atomic, ok}, 161: rpc:call(Node1, mnesia, 162: move_table_copy, [Tab, Node2, Node1])), 163: ?match([], mnesia_test_lib:sync_tables([Node1, Node2], [Tab])), 164: ?match({atomic, [{Tab, a, b}]}, 165: rpc:call(Node1, mnesia, transaction, [Read])), 166: ?verify_mnesia([Node1], []). 167: 168: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 169: silly_upgrade(doc) -> 170: ["Simple test of a schema upgrade and restore from backup"]; 171: silly_upgrade(suite) -> []; 172: silly_upgrade(Config) when is_list(Config) -> 173: [Node1, Node2] = Nodes = ?acquire_nodes(2, Config), 174: Name = silly_upgrade, 175: Tab1 = silly_upgrade1, 176: Tab2 = silly_upgrade2, 177: Bup = "silly_upgrade.BUP", 178: Bup2 = "silly_upgrade_part.BUP", 179: ?match({atomic, ok}, mnesia:create_table(Tab1, [{ram_copies, Nodes}])), 180: ?match({atomic, ok}, mnesia:create_table(Tab2, [{disc_only_copies, Nodes}])), 181: 182: CpState = add_some_records(Tab1, Tab2, []), 183: ?match(match, verify_state(Tab1, Tab2, CpState)), 184: file:delete(Bup), 185: ?match(ok, mnesia:backup(Bup)), 186: Args = [{name, Name}, {ram_overrides_dump, true}, 187: {min, [Tab1, schema]}, {max, [Tab2]}], 188: ?match({ok, Name, _}, mnesia:activate_checkpoint(Args)), 189: 190: IgnoreState = add_more_records(Tab1, Tab2, CpState), 191: ?match(match, verify_state(Tab1, Tab2, IgnoreState)), 192: ?match({mismatch, _, _}, verify_state(Tab1, Tab2, CpState)), 193: ?match({atomic, ok}, mnesia:del_table_copy(Tab2, Node1)), 194: file:delete(Bup2), 195: ?match(ok, mnesia:backup_checkpoint(Name, Bup2)), 196: 197: UpgradeState = transform_some_records(Tab1, Tab2, IgnoreState), 198: ?match({mismatch, _, _}, verify_state(Tab1, Tab2, CpState)), 199: ?match({mismatch, _, _}, verify_state(Tab1, Tab2, IgnoreState)), 200: ?match(match, verify_state(Tab1, Tab2, UpgradeState)), 201: 202: ?match(ok, mnesia:deactivate_checkpoint(Name)), 203: ?match(match, verify_state(Tab1, Tab2, UpgradeState)), 204: 205: ?match(ok, mnesia:install_fallback(Bup2)), 206: file:delete(Bup2), 207: %% Will generate intentional crash, fatal error 208: ?match([], mnesia_test_lib:stop_mnesia([Node2])), 209: wait_till_dead([Node1, Node2]), 210: ?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab1, Tab2])), 211: ?match(match, verify_state(Tab1, Tab2, CpState)), 212: 213: ?match(ok, mnesia:install_fallback(Bup)), 214: file:delete(Bup), 215: %% Will generate intentional crash, fatal error 216: ?match([], mnesia_test_lib:stop_mnesia([Node1, Node2])), 217: wait_till_dead([Node1, Node2]), 218: ?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab1, Tab2])), 219: CpState2 = [X || X <- CpState, element(1, X) /= Tab1], 220: ?match(match, verify_state(Tab1, Tab2, CpState2)), 221: ?verify_mnesia(Nodes, []). 222: 223: wait_till_dead([]) -> 224: ok; %% timer:sleep(5); 225: wait_till_dead(Repeat = [N|Ns]) -> 226: Apps = rpc:call(N, application, which_applications, []), 227: case lists:keymember(mnesia, 1, Apps) of 228: true -> 229: timer:sleep(10), 230: wait_till_dead(Repeat); 231: false -> 232: case rpc:call(N, erlang, whereis, [mnesia_monitor]) of 233: undefined -> 234: wait_till_dead(Ns); 235: _ -> 236: timer:sleep(10), 237: wait_till_dead(Repeat) 238: end 239: end. 240: 241: add_some_records(Tab1, Tab2, Old) -> 242: Recs1 = [{Tab1, I, I} || I <- lists:seq(1, 30)], 243: Recs2 = [{Tab2, I, I} || I <- lists:seq(20, 40)], 244: lists:foreach(fun(R) -> mnesia:dirty_write(R) end, Recs1), 245: Fun = fun(R) -> mnesia:write(R) end, 246: Trans = fun() -> lists:foreach(Fun, Recs2) end, 247: ?match({atomic, _}, mnesia:transaction(Trans)), 248: lists:sort(Old ++ Recs1 ++ Recs2). 249: 250: add_more_records(Tab1, Tab2, Old) -> 251: Change1 = [{T, K, V+100} || {T, K, V} <- Old, K==23], 252: Change2 = [{T, K, V+100} || {T, K, V} <- Old, K==24], 253: Del = [{T, K} || {T, K, _V} <- Old, K>=25], 254: New = [{Tab1, 50, 50}, {Tab2, 50, 50}], 255: lists:foreach(fun(R) -> mnesia:dirty_write(R) end, Change1), 256: lists:foreach(fun(R) -> mnesia:dirty_delete(R) end, Del), 257: Fun = fun(R) -> mnesia:write(R) end, 258: Trans = fun() -> lists:foreach(Fun, Change2 ++ New) end, 259: ?match({atomic, ok}, mnesia:transaction(Trans)), 260: Recs = [{T, K, V} || {T, K, V} <- Old, K<23] ++ Change1 ++ Change2 ++ New, 261: lists:sort(Recs). 262: 263: 264: verify_state(Tab1, Tab2, Exp) -> 265: Fun = fun() -> 266: Act1 = [mnesia:read({Tab1, K}) || K <- mnesia:all_keys(Tab1)], 267: Act2 = [mnesia:read({Tab2, K}) || K <- mnesia:all_keys(Tab2)], 268: Act = lists:append(Act1) ++ lists:append(Act2), 269: {ok, Act -- Exp, Exp -- Act} 270: end, 271: case mnesia:transaction(Fun) of 272: {atomic, {ok, [], []}} -> match; 273: {atomic, {ok, More, Less}} -> {mismatch, More, Less}; 274: {aborted, Reason} -> {error, Reason} 275: end. 276: 277: transform_some_records(Tab1, _Tab2, Old) -> 278: Fun = fun(Rec) -> 279: list_to_tuple(tuple_to_list(Rec) ++ [4711]) 280: end, 281: ?match({atomic, ok}, 282: mnesia:transform_table(Tab1, Fun, [key, val, extra])), 283: Filter = fun(Rec) when element(1, Rec) == Tab1 -> {true, Fun(Rec)}; 284: (_) -> true 285: end, 286: lists:sort(lists:zf(Filter, Old)). 287: 288: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 289: 290: stress_cases() -> 291: [conflict, dist]. 292: 293: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 294: dist(doc) -> 295: ["Avoid lock conflicts in order to maximize thruput", 296: "Ten drivers per node, tables replicated to all nodes, lots of branches"]; 297: dist(suite) -> []; 298: dist(Config) when is_list(Config) -> 299: Nodes = ?acquire_nodes(3, Config ++ [{tc_timeout, 10 * 60000}]), 300: Storage = mnesia_test_lib:storage_type(disc_copies, Config), 301: ?match({ok, _}, mnesia_tpcb:start(dist_args(Nodes, Storage))). 302: 303: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 304: conflict(doc) -> 305: ["Provoke a lot of lock conflicts.", 306: "Ten drivers per node, tables replicated to all nodes, single branch"]; 307: conflict(suite) -> []; 308: conflict(Config) when is_list(Config) -> 309: Nodes = ?acquire_nodes(3, Config ++ [{tc_timeout, 10 * 60000}]), 310: Storage = mnesia_test_lib:storage_type(disc_copies, Config), 311: ?match({ok, _}, mnesia_tpcb:start(conflict_args(Nodes, Storage))). 312: 313: conflict_args(Nodes, ReplicaType) -> 314: [{db_nodes, Nodes}, 315: {driver_nodes, Nodes}, 316: {replica_nodes, Nodes}, 317: {n_drivers_per_node, 10}, 318: {n_branches, 1}, 319: {n_accounts_per_branch, 10}, 320: {replica_type, ReplicaType}, 321: {stop_after, timer:minutes(5)}, 322: {report_interval, timer:seconds(10)}, 323: {use_running_mnesia, true}, 324: {reuse_history_id, true}]. 325: 326: dist_args(Nodes, ReplicaType) -> 327: [{db_nodes, Nodes}, 328: {driver_nodes, Nodes}, 329: {replica_nodes, Nodes}, 330: {n_drivers_per_node, 10}, 331: {n_branches, length(Nodes) * 100}, 332: {n_accounts_per_branch, 10}, 333: {replica_type, ReplicaType}, 334: {stop_after, timer:minutes(5)}, 335: {report_interval, timer:seconds(10)}, 336: {use_running_mnesia, true}, 337: {reuse_history_id, true}]. 338: