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