1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-2016. 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_config_test).
23-author('hakan@erix.ericsson.se').
24
25-include("mnesia_test_lib.hrl").
26
27-record(test_table,{i,a1,a2,a3}).
28-record(test_table2,{i, b}).
29
30-export([
31	all/0,groups/0,init_per_group/2,end_per_group/2,
32	 access_module/1,
33	 auto_repair/1,
34	 backup_module/1,
35	 debug/1,
36	 dir/1,
37	 dump_log_load_regulation/1,
38
39	 dump_log_update_in_place/1,
40	 event_module/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
94init_per_testcase(Func, Conf) ->
95    mnesia_test_lib:init_per_testcase(Func, Conf).
96
97end_per_testcase(Func, Conf) ->
98    mnesia_test_lib:end_per_testcase(Func, Conf).
99
100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101
102
103all() ->
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,
108     inconsistent_database, max_wait_for_decision,
109     send_compressed, app_test, {group, schema_config},
110     unknown_config].
111
112groups() ->
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
125init_per_group(_GroupName, Config) ->
126    Config.
127
128end_per_group(_GroupName, Config) ->
129    Config.
130
131
132
133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134
135access_module(doc) ->
136    ["Replace the activity access module with another module and ",
137     "use it to read and write to some alternate table storage"];
138access_module(suite) -> [];
139access_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
156access_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
191do_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%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248auto_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    ];
256auto_repair(suite) -> [];
257auto_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
277backup_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."];
281backup_module(suite) -> [];
282backup_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    %% Test some error cases
326    mnesia:set_debug_level(debug),
327    ?match({error, _}, mnesia:install_fallback("NonExisting.FILE")),
328    ?match({error, _}, mnesia:install_fallback(filename:join(mnesia_lib:dir(), "LATEST.LOG"))),
329
330    %% Cleanup
331    file:delete(File),
332    ?verify_mnesia(Nodes, []),
333    ?cleanup(1, Config),
334    ok.
335
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337debug(doc) ->
338    ["Try out the four debug levels and ensure that the",
339    "expected events are generated."];
340debug(suite) -> [];
341debug(Config) when is_list(Config) ->
342    Nodes = ?init(1, Config),
343    case application:get_env(mnesia,debug) of
344	undefined ->
345	    ?match(none, mnesia:system_info(debug));
346	{ok, false} ->
347	    ?match(none, mnesia:system_info(debug));
348	{ok, true} ->
349	    ?match(debug, mnesia:system_info(debug));
350	{ok, Env} ->
351	    ?match(Env, mnesia:system_info(debug))
352    end,
353
354    ?match(ok, mnesia:start([{debug, verbose}])),
355    ?match(verbose, mnesia:system_info(debug)),
356    mnesia_test_lib:kill_mnesia(Nodes),
357    receive after 2000 -> ok end,
358
359    ?match(ok, mnesia:start([{debug, debug}])),
360    ?match(debug, mnesia:system_info(debug)),
361    mnesia_test_lib:kill_mnesia(Nodes),
362    receive after 2000 -> ok end,
363
364    ?match(ok, mnesia:start([{debug, trace}])),
365    ?match(trace, mnesia:system_info(debug)),
366    mnesia_test_lib:kill_mnesia(Nodes),
367    receive after 2000 -> ok end,
368
369    ?match(ok, mnesia:start([{debug, true}])),
370    ?match(debug, mnesia:system_info(debug)),
371    mnesia_test_lib:kill_mnesia(Nodes),
372    receive after 2000 -> ok end,
373
374    ?match(ok, mnesia:start([{debug, false}])),
375    ?match(none, mnesia:system_info(debug)),
376
377    ?verify_mnesia(Nodes, []),
378    ?cleanup(1, Config),
379    ok.
380
381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382dir(doc) ->
383    ["Try to use alternate Mnesia directories"];
384dir(suite) -> [];
385dir(Config) when is_list(Config) ->
386    Nodes = ?init(1, Config),
387
388    ?match(ok, mnesia:start([{dir, tuff}])),
389    Dir = filename:join([element(2, file:get_cwd()), "tuff"]),
390    ?match(Dir, mnesia:system_info(directory)),
391    mnesia_test_lib:kill_mnesia(Nodes),
392
393    ?cleanup(1, Config),
394    ok.
395
396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397dump_log_update_in_place(doc) ->
398    ["Change the update in place policy for the transaction log dumper."];
399dump_log_update_in_place(suite) -> [];
400dump_log_update_in_place(Config) when is_list(Config) ->
401    Nodes = ?acquire(1, Config),
402    ?match(true, mnesia:system_info(dump_log_update_in_place)),
403    ?match({atomic,ok},
404	   mnesia:create_table(test_table,
405			       [{disc_copies, Nodes},
406				{attributes,
407				 record_info(fields,test_table)}])),
408
409    mnesia_test_lib:kill_mnesia(Nodes),
410    receive after 2000 -> ok end,
411
412    ?match(ok, mnesia:start([{dump_log_update_in_place, false}])),
413    ?match(false, mnesia:system_info(dump_log_update_in_place)),
414
415    mnesia_test_lib:sync_tables(Nodes, [schema, test_table]),
416
417    %% Now provoke some log dumps
418
419    L = lists:map(
420	  fun(Num) ->
421		  %% Write something on one end ...
422		  mnesia:transaction(
423		    fun() ->
424			    mnesia:write(#test_table{i=Num}) end
425		   ) end,
426	  lists:seq(1, 110)),
427
428    L2 = lists:duplicate(110, {atomic, ok}),
429
430    %% If this fails then some of the 110 writes above failed
431    ?match(true, L==L2),
432    if  L==L2 -> ok;
433	true ->
434	    ?verbose("***** List1 len: ~p, List2 len: ~p~n",
435		      [length(L), length(L2)]),
436	    ?verbose("L: ~p~nL2:~p~n", [L, L2])
437    end,
438
439    %% If we still can write, then Mnesia is probably alive
440    ?trans(fun() -> mnesia:write(#test_table{i=115}) end),
441
442    ?verify_mnesia(Nodes, []),
443    ?cleanup(1, Config),
444    ok.
445
446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
447
448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
449dump_log_write_threshold(doc)->
450    ["This test case must be rewritten.",
451     "Dump logs are tested by doing transactions, then killing Mnesia and ",
452     "then examining the table data files and see if they are correct.",
453     "The test_table is used as a counter, test_table. is stepped once ",
454     "for each transaction."];
455dump_log_write_threshold(suite)->[];
456dump_log_write_threshold(Config) when is_list(Config) ->
457    [N1] = ?acquire_schema(1, Config),
458
459    Threshold = 3,
460    ?match(ok,mnesia:start([{dump_log_write_threshold, Threshold}])),
461
462    ?match({atomic,ok},
463	   mnesia:create_table(test_table,
464			       [{disc_copies, [N1]},
465				{attributes,
466				 record_info(fields,test_table)}])),
467    ?match(dumped, mnesia:dump_log()),
468
469    ?match(ok, do_trans(2)),				% Shall not have dumped
470    check_logs(0),
471
472    ?match(ok, do_trans(Threshold - 2)),			% Trigger a dump
473    receive after 1000 -> ok end,
474    check_logs(Threshold),
475
476
477    ?match(ok, do_trans(Threshold - 1)),
478    ?match(dumped, mnesia:dump_log()),   %% This should trigger ets2dcd dump
479    check_logs(0),                       %% and leave no dcl file
480
481    ?match(stopped, mnesia:stop()),
482
483    %% Check bad threshold value
484    ?match({error,{bad_type,dump_log_write_threshold,0}},
485	   mnesia:start([{dump_log_write_threshold,0}])),
486
487    ?verify_mnesia([], [N1]),
488    ?cleanup(1, Config),
489    ok.
490
491
492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493dump_log_time_threshold(doc)->
494    ["See doc on above."];
495dump_log_time_threshold(suite)->[];
496dump_log_time_threshold(Config) when is_list(Config) ->
497    Nodes = ?acquire_schema(1, Config),
498    Time = 4000,
499
500    %% Check bad threshold value
501    ?match({error,{bad_type,dump_log_time_threshold,0}},
502	   mnesia:start([{dump_log_time_threshold,0}])),
503
504
505    ?match(ok,mnesia:start([{dump_log_write_threshold,100},
506			    {dump_log_time_threshold, Time}])),
507
508    ?match({atomic,ok},mnesia:create_table(test_table,
509					   [{disc_copies, Nodes},
510					    {attributes,
511					     record_info(fields,
512							 test_table)}])),
513
514    %% Check that nothing is dumped when within time threshold
515    ?match(ok, do_trans(1)),
516    check_logs(0),
517
518    ?match(Time, mnesia:system_info(dump_log_time_threshold)),
519
520    %% Check that things get dumped when time threshold exceeded
521    ?match(ok, do_trans(5)),
522    receive after Time+2000 -> ok end,
523    check_logs(6),
524
525    ?verify_mnesia([node()], []),
526    ?cleanup(1, Config),
527    ok.
528
529%%%%%%%%
530%%
531%% Help functions for dump log
532
533%% Do a transaction N times
534do_trans(0) -> ok;
535do_trans(N) ->
536    Fun = fun() ->
537		  XX=incr(),
538		  mnesia:write(#test_table{i=XX})
539	  end,
540    {atomic, ok} = mnesia:transaction(Fun),
541    do_trans(N-1).
542
543%% An increasing number
544incr() ->
545    case get(bloody_counter) of
546	undefined -> put(bloody_counter, 2), 1;
547	Num -> put(bloody_counter, Num+1)
548    end.
549
550%%
551%% Check that the correct number of transactions have been recorded.
552%%-record(test_table,{i,a1,a2,a3}).
553check_logs(N) ->
554    File = mnesia_lib:tab2dcl(test_table),
555    Args = [{file, File}, {name, testing}, {repair, true}, {mode, read_only}],
556
557    if N == 0 ->
558	    ?match(false, mnesia_lib:exists(File));
559       true ->
560	    ?match(true, mnesia_lib:exists(File)),
561	    ?match({ok, _Log}, disk_log:open(Args)),
562
563	    {Cont, Terms} = disk_log:chunk(testing, start),
564	    ?match(eof, disk_log:chunk(testing, Cont)),
565	    %%?verbose("N: ~p, L: ~p~n", [N, L]),
566	    disk_log:close(testing),
567
568	    %% Correct number of records in file
569	    ?match({N, N}, {N, length(Terms) -1 })  %% Ignore Header
570    end.
571
572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
573
574dump_log_load_regulation(doc) ->
575    ["Test the load regulation of the dumper"];
576dump_log_load_regulation(suite) ->
577    [];
578dump_log_load_regulation(Config) when is_list(Config) ->
579    Nodes = ?acquire_nodes(1, Config),
580    Param = dump_log_load_regulation,
581
582    %% Normal
583    NoReg = false,
584    ?match(NoReg, mnesia:system_info(Param)),
585    ?match([], mnesia_test_lib:stop_mnesia(Nodes)),
586
587    %% Bad
588    Bad = arne_anka,
589    ?match({error, {bad_type, Param, Bad}},
590	   mnesia:start([{Param, Bad}])),
591
592    %% Regulation activated
593    Reg = true,
594    ?match(ok,mnesia:start([{Param, Reg}])),
595    ?match(Reg, mnesia:system_info(Param)),
596
597    Args =
598	[{db_nodes, Nodes},
599	 {driver_nodes, Nodes},
600	 {replica_nodes, Nodes},
601	 {n_drivers_per_node, 5},
602	 {n_branches, length(Nodes) * 10},
603	 {n_accounts_per_branch, 5},
604	 {replica_type, disc_copies},
605	 {stop_after, timer:seconds(15)},
606	 {report_interval, timer:seconds(3)},
607	 {use_running_mnesia, true},
608	 {reuse_history_id, true}],
609
610    ?match({ok, _}, mnesia_tpcb:start(Args)),
611
612    ?verify_mnesia(Nodes, []),
613    ?cleanup(1, Config),
614    ok.
615
616%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
617
618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
619
620max_wait_for_decision(doc) ->
621    ["Provoke Mnesia to make a forced decision of the outome",
622     "of a heavy weight transaction."].
623
624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625
626send_compressed(doc) -> [];
627send_compressed(suite) -> [];
628send_compressed(Config) ->
629    [N1,N2] = Nodes = ?acquire_nodes(2, Config),
630    ?match({atomic,ok}, mnesia:create_table(t0, [{ram_copies,[N1,N2]}])),
631    ?match({atomic,ok}, mnesia:create_table(t1, [{disc_copies,[N1,N2]}])),
632    ?match({atomic,ok}, mnesia:create_table(t2, [{disc_only_copies,[N1,N2]}])),
633
634    Max = 1000,
635    Create = fun(Tab) -> [mnesia:write({Tab, N, {N, "FILLER-123490878345asdasd"}})
636			  || N <- lists:seq(1, Max)],
637			 ok
638	     end,
639
640    ?match([], mnesia_test_lib:kill_mnesia([N2])),
641    sys:get_status(mnesia_monitor), %% sync N1
642    ?match([], mnesia_test_lib:kill_mnesia([N1])),
643    ?match(ok, mnesia:start([{send_compressed, 9}])),
644    ?match(ok, mnesia:wait_for_tables([t0,t1,t2], 25000)),
645
646    ?match({atomic, ok}, mnesia:transaction(Create, [t0])),
647    ?match({atomic, ok}, mnesia:transaction(Create, [t1])),
648    ?match({atomic, ok}, mnesia:transaction(Create, [t2])),
649
650    ?match([], mnesia_test_lib:start_mnesia([N2], [t0,t1,t2])),
651
652    Verify = fun(Tab) ->
653		     [ [{Tab,N,{N,_}}] = mnesia:read(Tab, N) || N <- lists:seq(1, Max)],
654		     ok
655	     end,
656    ?match({atomic, ok}, rpc:call(N1, mnesia, transaction, [Verify, [t0]])),
657    ?match({atomic, ok}, rpc:call(N1, mnesia, transaction, [Verify, [t1]])),
658    ?match({atomic, ok}, rpc:call(N1, mnesia, transaction, [Verify, [t2]])),
659
660    ?match({atomic, ok}, rpc:call(N2, mnesia, transaction, [Verify, [t0]])),
661    ?match({atomic, ok}, rpc:call(N2, mnesia, transaction, [Verify, [t1]])),
662    ?match({atomic, ok}, rpc:call(N2, mnesia, transaction, [Verify, [t2]])),
663
664    ?verify_mnesia(Nodes, []),
665    ?cleanup(1, Config),
666    ok.
667
668app_test(doc) -> [];
669app_test(suite) -> [];
670app_test(_Config) ->
671    ?match(ok,test_server:app_test(mnesia)),
672    ok.
673
674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675
676event_module(doc) ->
677    ["Replace the event module with another module and use it as",
678     "receiver of the various system and table events. Provoke",
679     "coverage of all kinds of events."];
680event_module(suite) -> [];
681event_module(Config) when is_list(Config) ->
682    Filter = fun({mnesia_system_event,{mnesia_info, _, _}}) -> false;
683		(_) -> true
684	     end,
685
686    [_N1, N2]=Nodes=?acquire_schema(2, Config),
687
688    Def = case mnesia_test_lib:diskless(Config) of
689	      true -> [{event_module, mnesia_config_event},
690		       {extra_db_nodes, Nodes}];
691	      false  ->
692		  [{event_module, mnesia_config_event}]
693	  end,
694
695    ?match({[ok, ok], []}, rpc:multicall(Nodes, mnesia, start, [Def])),
696    receive after 2000 -> ok end,
697    mnesia_event ! {get_log, self()},
698    DebugLog1 = receive
699		    {log, L1} -> L1
700		after 10000 -> [timeout]
701		end,
702    ?match([{mnesia_system_event,{mnesia_up,N2}}],
703	   lists:filter(Filter, DebugLog1)),
704    mnesia_test_lib:kill_mnesia([N2]),
705    receive after 2000 -> ok end,
706
707    ?match({[ok], []}, rpc:multicall([N2], mnesia, start, [])),
708
709    receive after 2000 -> ok end,
710    mnesia_event ! {get_log, self()},
711    DebugLog = receive
712		   {log, L} -> L
713	       after 10000 -> [timeout]
714	       end,
715    ?match([{mnesia_system_event,{mnesia_up,N2}},
716	    {mnesia_system_event,{mnesia_down,N2}},
717	    {mnesia_system_event,{mnesia_up, N2}}],
718	   lists:filter(Filter, DebugLog)),
719    ?verify_mnesia(Nodes, []),
720    ?cleanup(1, Config),
721    ok.
722
723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725start_one_disc_full_then_one_disc_less(doc)->
726    ["Start a disk node and then a disk less one. Distribute some",
727     "tables between them."];
728start_one_disc_full_then_one_disc_less(suite) -> [];
729start_one_disc_full_then_one_disc_less(Config) when is_list(Config) ->
730    [N1, N2] = ?init(2, Config),
731    ?match(ok, mnesia:create_schema([N1])),
732    ?match([], mnesia_test_lib:start_mnesia([N1])),
733
734    ?match({atomic, ok}, mnesia:add_table_copy(schema, N2, ram_copies)),
735
736    ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
737					     {extra_db_nodes, [N1]}]])),
738    mnesia_test_lib:sync_tables([N1, N2], [schema]),
739
740    %% Now create some tables
741    ?match({atomic,ok},
742	   mnesia:create_table(test_table,
743			       [{ram_copies, [N1, N2]},
744				{attributes,
745				 record_info(fields,test_table)}])),
746
747    ?match({atomic,ok},
748	   rpc:call(
749	     N2, mnesia,create_table, [test_table2,
750				      [{ram_copies, [N1, N2]},
751				       {attributes,
752					record_info(fields,test_table2)}]])),
753
754    %% Write something on one end ...
755    Rec = #test_table{i=55},
756    ?match({atomic, ok},
757	   mnesia:transaction(fun() -> mnesia:write(Rec) end)),
758
759    %% ... and read it in the other
760    ?match({atomic, [Rec]},
761	   rpc:call(N2, mnesia, transaction,
762		    [fun() -> mnesia:read({test_table, 55}) end])),
763
764
765    %% Then do the same but start at the other end
766    Rec2 = #test_table2{i=155},
767    ?match({atomic, ok},
768	   rpc:call(N2, mnesia, transaction,
769		    [fun() ->
770			     mnesia:write(Rec2) end
771		    ])),
772
773    ?match({atomic, [Rec2]},
774	   mnesia:transaction(fun() -> mnesia:read({test_table2, 155}) end)),
775
776    ?verify_mnesia([N1, N2], []),
777    ?cleanup(2, Config),
778    ok.
779
780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
781start_first_one_disc_less_then_one_disc_full(doc)->
782    ["no_doc"];
783start_first_one_disc_less_then_one_disc_full(suite) -> [];
784start_first_one_disc_less_then_one_disc_full(Config) when is_list(Config) ->
785    [N1, N2] = Nodes = ?init(2, Config),
786    ?match(ok, mnesia:create_schema([N1])),
787    ?match([], mnesia_test_lib:start_mnesia([N1])),
788
789    ?match({atomic, ok}, mnesia:add_table_copy(schema, N2, ram_copies)),
790
791    ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
792					     {extra_db_nodes, Nodes}]])),
793
794    mnesia_test_lib:sync_tables([N1, N2], [schema]),
795
796    mnesia_test_lib:kill_mnesia(Nodes),
797    receive after 2000 -> ok end,
798    ?match([], mnesia_test_lib:start_mnesia(Nodes)),
799
800    mnesia_test_lib:sync_tables([N1, N2], [schema]),
801
802    %% Now create some tables
803    ?match({atomic,ok},
804	   rpc:call(
805	     N1, mnesia,create_table, [test_table,
806				       [%%{disc_copies, [node()]},
807					{ram_copies, [N1, N2]},
808					{attributes,
809					 record_info(fields,test_table)}]])),
810    mnesia_test_lib:sync_tables([N1, N2], [test_table]),
811
812    ?match({atomic,ok},
813	   rpc:call(
814	     N2, mnesia,create_table, [test_table2,
815				       [%%{disc_copies, [node()]},
816					{ram_copies, [N1, N2]},
817					{attributes,
818					 record_info(fields,test_table2)}]])),
819
820    mnesia_test_lib:sync_tables([N1, N2], [test_table, test_table2]),
821
822    %% Assure tables loaded
823    ?match({[ok, ok], []},
824	   rpc:multicall([N1, N2], mnesia, wait_for_tables,
825			 [[schema, test_table, test_table2], 10000])),
826
827    %% Write something on one end ...
828    Rec = #test_table{i=55},
829    ?match({atomic, ok},
830	   rpc:call(N1, mnesia, transaction,
831		    [fun() -> mnesia:write(Rec) end])),
832
833    %% ... and read it in the other
834    ?match({atomic, [Rec]},
835	   rpc:call(N2, mnesia, transaction,
836		    [fun() -> mnesia:read({test_table, 55}) end])),
837
838    %% Then do the same but start at the other end
839    Rec2 = #test_table2{i=155},
840    ?match({atomic, ok},
841	   rpc:call(N2, mnesia, transaction,
842		    [fun() ->
843			     mnesia:write(Rec2) end
844		    ])),
845
846    ?match({atomic, [Rec2]},
847	   rpc:call(N1, mnesia, transaction,
848		    [fun() -> mnesia:read({test_table2, 155}) end])),
849
850    ?verify_mnesia(Nodes, []),
851    ?cleanup(1, Config),
852    ok.
853
854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
855start_first_one_disc_less_then_two_more_disc_less(doc)->
856    ["no doc"];
857start_first_one_disc_less_then_two_more_disc_less(suite) -> [];
858start_first_one_disc_less_then_two_more_disc_less(Config) when is_list(Config) ->
859    Nodes = [N1, N2, N3] = ?init(3, Config),
860
861    ?match(ok, rpc:call(N1, mnesia, start, [[{schema_location, ram}]])),
862
863    %% Really should use test_lib:mnesia_start for these ones but ...
864    ?match({atomic, ok},
865	   rpc:call(N1, mnesia,add_table_copy, [schema, N2, ram_copies])),
866    ?match({atomic, ok},
867	   rpc:call(N1, mnesia,add_table_copy, [schema, N3, ram_copies])),
868
869    ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
870					     {extra_db_nodes, [N1]}]])),
871    ?match(ok, rpc:call(N3, mnesia, start, [[{schema_location, ram},
872					     {extra_db_nodes, [N1, N2]}]])),
873
874    %% Now create some tables
875    ?match({atomic,ok},
876	   rpc:call(
877	     N1, mnesia,create_table, [test_table,
878				      [%%{disc_copies, [node()]},
879				       {ram_copies, [N1, N2, N3]},
880				       {attributes,
881					record_info(fields,test_table)}]])),
882
883    %% Assure tables loaded
884    ?match({[ok, ok, ok], []},
885	   rpc:multicall([N1, N2, N3], mnesia, wait_for_tables,
886			 [[test_table], 1000])),
887
888    %% Write something on one end ...
889    ?match({atomic, ok},
890	   rpc:call(N1, mnesia, transaction,
891		    [fun() -> mnesia:write(#test_table{i=44}) end])),
892
893    %% Force synchronicity
894    ?match({atomic, ok},
895	   rpc:call(N1, mnesia, transaction,
896		    [fun() -> mnesia:write_lock_table(test_table) end])),
897
898    %% ... and read it in the others
899    ?match({[{atomic, [{test_table, 44, _, _, _}]},
900	     {atomic, [{test_table, 44, _, _, _}]}], []},
901	   rpc:multicall([N2, N3], mnesia, transaction,
902			 [fun() -> mnesia:read({test_table, 44}) end])),
903
904    %% Then do the other way around
905    ?match({atomic, ok},
906	   rpc:call(N3, mnesia, transaction,
907		    [fun() -> mnesia:write(#test_table{i=33}) end])),
908    %% Force synchronicity
909    ?match({atomic, ok},
910	   rpc:call(N3, mnesia, transaction,
911		    [fun() -> mnesia:write_lock_table(test_table) end])),
912
913    ?match({[{atomic, [{test_table, 44, _, _, _}]},
914	     {atomic, [{test_table, 44, _, _, _}]}], []},
915	   rpc:multicall([N1, N2], mnesia, transaction,
916			 [fun() -> mnesia:read({test_table, 44}) end])),
917
918    mnesia_test_lib:reload_appls([mnesia], Nodes),
919    ok.
920
921
922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
923schema_location_and_extra_db_nodes_combinations(doc)->
924    ["Test schema loaction and extra_db_nodes combinations."];
925schema_location_and_extra_db_nodes_combinations(suite) -> [];
926schema_location_and_extra_db_nodes_combinations(Config) when is_list(Config) ->
927    [N1, N2] = Nodes = ?init(2, Config),
928    ?match(ok, mnesia:create_schema([N1])),
929    ?match([], mnesia_test_lib:start_mnesia([N1])),
930
931    %% Really should use test_lib:mnesia_start for these ones but ...
932    ?match({atomic, ok},
933	   rpc:call(N1, mnesia,add_table_copy, [schema, N2, ram_copies])),
934
935    ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
936					     {extra_db_nodes, [N1]}]])),
937
938    %% Assure tables loaded
939    ?match({[ok, ok], []},
940	   rpc:multicall([N1, N2], mnesia, wait_for_tables,
941			 [[schema], 10000])),
942
943    ?verify_mnesia(Nodes, []),
944    ?cleanup(2, Config),
945    ok.
946
947
948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
949table_load_to_disc_less_nodes(doc)->
950    ["Load tables to disc less nodes"];
951table_load_to_disc_less_nodes(suite) -> [];
952table_load_to_disc_less_nodes(Config) when is_list(Config) ->
953    [N1, N2] = ?init(2, Config),
954
955    ?match(ok, rpc:call(N1, mnesia, start, [[{schema_location, ram}]])),
956
957    %% Really should use test_lib:mnesia_start for these ones but ...
958    ?match({atomic, ok},
959	   rpc:call(N1, mnesia,add_table_copy, [schema, N2, ram_copies])),
960
961    ?match(ok, rpc:call(N2, mnesia, start, [[{schema_location, ram},
962					     {extra_db_nodes, [N1]}]])),
963
964    %% Now create some tables
965    ?match({atomic,ok},
966	   rpc:call(
967	     N1, mnesia,create_table, [test_table,
968				      [%%{disc_copies, [node()]},
969				       {ram_copies, [N1, N2]},
970				       {attributes,
971					record_info(fields,test_table)}]])),
972
973    %% Assure tables loaded
974    ?match({[ok, ok], []},
975	   rpc:multicall([N1, N2], mnesia, wait_for_tables,
976			 [[test_table], 1000])),
977
978    %% Write something on one end ...
979    ?match({atomic, ok},
980	   rpc:call(N1, mnesia, transaction,
981		    [fun() -> mnesia:write(#test_table{i=44}) end])),
982
983    %% Force synchronicity
984    ?match({atomic, ok},
985	   rpc:call(N1, mnesia, transaction,
986		    [fun() -> mnesia:write_lock_table(test_table) end])),
987
988    %% ... and read it in the others
989    ?match({atomic, [{test_table, 44, _, _, _}]},
990	   rpc:call(N2, mnesia, transaction,
991		    [fun() -> mnesia:read({test_table, 44}) end])),
992
993    ?cleanup(2, Config),
994    ok.
995
996%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
997schema_merge(doc) ->
998    ["Provoke various schema merge situations.",
999     "Perform various schema updates while some nodes are down,",
1000     "stop the started nodes, start the stopped nodes and perform",
1001     "schema updates. Now we have a situation were some of the table",
1002     "definitions have been changed on two or more nodes independently",
1003     "of each other and when Mnesia on the nodes tries to connect",
1004     "to each other at restart the schema will be merged.",
1005     "Do also try to provoke schema merge situations were the",
1006     "schema cannot be merged."];
1007
1008schema_merge(suite) -> [];
1009
1010schema_merge(Config) when is_list(Config) ->
1011    [N1, N2]=Nodes=?acquire(2,Config),
1012
1013    mnesia_test_lib:kill_mnesia([N2]),
1014    receive after 1000 -> ok end,
1015
1016    Storage = mnesia_test_lib:storage_type(disc_copies, Config),
1017    ?match({atomic,ok},
1018	   rpc:call(
1019	     N1, mnesia,create_table,
1020	     [test_table,
1021	      [{Storage, [N1]},
1022	       {attributes,
1023		record_info(fields,test_table)}]])),
1024
1025    ?match({atomic, ok},
1026	   rpc:call(N1, mnesia, transaction,
1027		    [fun() -> mnesia:write(#test_table{i=44}) end])),
1028
1029    mnesia_test_lib:kill_mnesia([N1]),
1030    receive after 2000 -> ok end,
1031    %% Can't use std start because it waits for schema
1032    ?match(ok, rpc:call(N2, mnesia, start, [])),
1033
1034    ?match({atomic,ok},
1035	   rpc:call(
1036	     N2, mnesia,create_table,
1037	     [test_table2,
1038	      [{Storage, [N2]},
1039	       {attributes,
1040		record_info(fields,test_table2)}]])),
1041
1042    receive after 5000 -> ok end,
1043
1044    ?match({atomic, ok},
1045	   rpc:call(N2, mnesia, transaction,
1046		    [fun() -> mnesia:write(#test_table2{i=33}) end])),
1047
1048    %% Can't use std start because it waits for schema
1049    ?match(ok, rpc:call(N1, mnesia, start, [])),
1050
1051    %% Assure tables loaded
1052    ?match({[ok, ok], []},
1053	   rpc:multicall([N1, N2], mnesia, wait_for_tables,
1054			 [[schema, test_table, test_table2], 10000])),
1055
1056    %% ... and read it in the others
1057    ?match({[{atomic, [{test_table, 44, _, _, _}]},
1058	     {atomic, [{test_table, 44, _, _, _}]}], []},
1059	   rpc:multicall([N1, N2], mnesia, transaction,
1060			 [fun() -> mnesia:read({test_table, 44}) end])),
1061
1062    ?match({[{atomic, [{test_table2, 33, _}]},
1063	     {atomic, [{test_table2, 33, _}]}], []},
1064	   rpc:multicall([N1, N2], mnesia, transaction,
1065			 [fun() -> mnesia:read({test_table2, 33}) end])),
1066
1067    ?verify_mnesia(Nodes, []),
1068    ?cleanup(2, Config),
1069    ok.
1070
1071
1072-define(connect(Nodes), mnesia:change_config(extra_db_nodes, Nodes)).
1073-define(rpc_connect(From, Nodes),
1074	rpc:call(From, mnesia, change_config, [extra_db_nodes, Nodes])).
1075
1076
1077sort({ok, NS}) ->
1078    {ok, lists:sort(NS)};
1079sort(Ns) when is_tuple(Ns) ->
1080    Ns;
1081sort(NS) when is_list(NS) ->
1082    lists:sort(NS).
1083
1084
1085
1086
1087dynamic_basic(suite) -> [];
1088dynamic_basic(Config) when is_list(Config) ->
1089    Nodes = [N1, N2, N3] = ?acquire_nodes(3, Config),
1090    SNs = lists:sort(Nodes),
1091
1092    ?match({atomic, ok}, mnesia:create_table(tab1, [{ram_copies, Nodes--[N1]}, {disc_copies, [N1]}])),
1093    ?match({atomic, ok}, mnesia:create_table(tab2, [{disc_copies, Nodes}])),
1094
1095    ?match({ok, SNs}, sort(?rpc_connect(N1, Nodes))),     %% What shall happen?
1096    ?match({ok, []}, sort(?rpc_connect(N1, [nonode@nothosted]))),  %% What shall happen?
1097
1098    ?match([], mnesia_test_lib:kill_mnesia([N2])),
1099    ?match(ok, mnesia:delete_schema([N2])),
1100
1101    ?match(ok, mnesia:dirty_write({tab1, 1, 1})),
1102    ?match(ok, mnesia:dirty_write({tab2, 1, 1})),
1103
1104    ?match(ok, rpc:call(N2, mnesia, start, [[{extra_db_nodes, [N1]}, {schema, ?BACKEND}]])),
1105    ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab1,tab2],5000])),
1106    io:format("Here ~p ~n",[?LINE]),
1107    check_storage(N2, N1, [N3]),
1108    ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
1109    ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
1110
1111    ?match([], mnesia_test_lib:kill_mnesia([N3])),
1112    ?match(ok, mnesia:delete_schema([N3])),
1113
1114    io:format("T1 ~p ~n",[rpc:call(N3,?MODULE,c_nodes,[])]),
1115    ?match(ok, rpc:call(N3, mnesia, start, [[{schema, ?BACKEND}]])),
1116    io:format("T2 ~p ~n",[rpc:call(N3,?MODULE,c_nodes,[])]),
1117    timer:sleep(2000),
1118    io:format("T3 ~p ~n",[rpc:call(N3,?MODULE,c_nodes,[])]),
1119    ?match({ok, [N1]}, sort(?rpc_connect(N3, [N1]))),
1120    io:format("T4 ~p ~n",[rpc:call(N3,?MODULE,c_nodes,[])]),
1121    ?match(ok, rpc:call(N3, mnesia, wait_for_tables, [[tab1,tab2],5000])),
1122    io:format("Here ~p ~n",[?LINE]),
1123    check_storage(N3, N1, [N2]),
1124    ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
1125    ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
1126
1127    ?match([], mnesia_test_lib:kill_mnesia([N3])),
1128    ?match(ok, mnesia:delete_schema([N3])),
1129
1130    ?match(ok, rpc:call(N3, mnesia, start, [[{schema, ?BACKEND}]])),
1131    ?match({ok, [N3]}, sort(?rpc_connect(N1, [N3]))),
1132    ?match(ok, rpc:call(N3, mnesia, wait_for_tables, [[tab1,tab2],5000])),
1133    io:format("Here ~p ~n",[?LINE]),
1134    check_storage(N3, N1, [N2]),
1135    ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
1136    ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
1137
1138    mnesia_test_lib:kill_mnesia([N2]),
1139    ?match(ok, mnesia:delete_schema([N2])),
1140    ?match({atomic, ok}, mnesia:del_table_copy(schema, N2)),
1141
1142    % Ok, we have now removed references to node N2 from the other nodes
1143    % mnesia should come up now.
1144    ?match({atomic, ok}, mnesia:add_table_copy(tab1, N2, ram_copies)),
1145
1146    ?match(ok, rpc:call(N2, mnesia, start, [[{schema, ?BACKEND}]])),
1147    ?match({ok, _}, sort(?rpc_connect(N2, [N3]))),
1148
1149    ?match(SNs, sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
1150    ?match(SNs, sort(rpc:call(N2, mnesia, system_info, [running_db_nodes]))),
1151    ?match(SNs, sort(rpc:call(N3, mnesia, system_info, [running_db_nodes]))),
1152
1153    ?match(ok, rpc:call(N2, mnesia, wait_for_tables, [[tab1], 1000])),
1154    ?match([{tab1, 1, 1}], rpc:call(N2, mnesia, dirty_read, [tab1, 1])),
1155
1156    mnesia_test_lib:kill_mnesia([N2]),
1157
1158    %%% SYNC!!!
1159    timer:sleep(1000),
1160    sys:get_status(mnesia_monitor),
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, [[{schema, ?BACKEND}]])),
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
1179c_nodes() ->
1180    {mnesia_lib:val({current, db_nodes}),mnesia_lib:val(recover_nodes)}.
1181
1182
1183dynamic_ext(suite) ->    [];
1184dynamic_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]}, {schema, ?BACKEND}]])),
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 = erlang:unique_integer(),
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, [[{schema, ?BACKEND}]])),
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]}, {schema, ?BACKEND}]])),
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]}, {schema, ?BACKEND}]])),
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
1253check_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 = erlang:unique_integer(),
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
1302dynamic_bad(suite) ->    [];
1303dynamic_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%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1340unknown_config(doc) ->
1341    ["Try some unknown configuration parameters and see that expected",
1342     "things happens."];
1343unknown_config(suite)-> [];
1344unknown_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%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360inconsistent_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."];
1364inconsistent_database(suite) -> [];
1365inconsistent_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
1381