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-module(compiler_1).
21-compile([export_all]).
22
23compiler_1() -> ok.
24
25-define(log(Format,Args),mnesia_test_lib:log(Format,Args,?FILE,?LINE)).
26-define(warning(Format,Args),?log("<WARNING> " ++ Format,Args)).
27-define(error(Format,Args),
28	mnesia_test_lib:note_error(Format,Args,?FILE,?LINE),
29	?log("<ERROR> " ++ Format,Args)).
30
31-define(match(ExpectedRes,Expr),
32	fun() ->
33	       AcTuAlReS = (catch (Expr)),
34	       case AcTuAlReS of
35		   ExpectedRes ->
36		       ?log("ok, result as expected: ~p~n",[AcTuAlReS]),
37		       {success,AcTuAlReS};
38		   _ ->
39		       ?error("actual result was: ~p~n",[AcTuAlReS]),
40		       {fail,AcTuAlReS}
41	       end
42       end()).
43
44-define(match_inverse(NotExpectedRes,Expr),
45	fun() ->
46	       AcTuAlReS = (catch (Expr)),
47	       case AcTuAlReS of
48		   NotExpectedRes ->
49		       ?error("actual result was: ~p~n",[AcTuAlReS]),
50		       {fail,AcTuAlReS};
51		   _ ->
52		       ?log("ok, result as expected: ~p~n",[AcTuAlReS]),
53		       {success,AcTuAlReS}
54	       end
55       end()).
56
57-define(match_receive(ExpectedMsg),
58	?match(ExpectedMsg,mnesia_test_lib:pick_msg())).
59
60%% ExpectedMsgs must be completely bound
61-define(match_multi_receive(ExpectedMsgs),
62	fun() ->
63		TmPeXpCtEdMsGs = lists:sort(ExpectedMsgs),
64		?match(TmPeXpCtEdMsGs,
65		       lists:sort(lists:map(fun(_) ->
66						    mnesia_test_lib:pick_msg()
67					    end,
68					    TmPeXpCtEdMsGs)))
69	end()).
70
71-define(setup(), mnesia_test_lib:setup(?FILE,?LINE)).
72
73-define(start_activities(Nodes),
74	fun() ->
75		AcTiViTyPiDs =
76		    lists:map(fun(Node) ->
77				      spawn_link(Node,
78						 mnesia_test_lib,
79						 activity_evaluator,
80						 [self()])
81			      end,
82			      Nodes),
83		?match_multi_receive(AcTiViTyPiDs)
84	end()).
85
86-define(start_transactions(Pids),
87	?match_multi_receive(lists:map(fun(Pid) ->
88					       Pid ! begin_trans,
89					       {Pid,begin_trans}
90				       end,
91				       Pids))).
92
93-define(acquire_nodes(N,Nodes),
94	mnesia_test_lib:acquire_nodes(N,Nodes,?FILE,?LINE)).
95
96
97
98%%% Copyright (C) 1996, Ellemtel Telecommunications Systems Laboratories
99%%% Author: Hakan Mattsson  hakan@erix.ericsson.se
100%%% Purpose: Evil usage of the API
101%%%
102%%% Invoke all functions in the API and try to cover all legal uses
103%%% cases as well the illegal dito. This is a complement to the
104%%% other more explicit test cases.
105%%%
106%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107%%%
108%%% show/0
109%%%
110%%%    Prints out the complete test case structure
111%%%
112%%% show/1
113%%%
114%%%    Prints out parts of the test case structure
115%%%
116%%% test/0
117%%%
118%%%    Run the complete test suite.
119%%%    Reads Nodes from nodes.profile and starts them if neccessary.
120%%%    Kills Mnesia and wipes out the Mnesia directories as a starter.
121%%%
122%%% test/1
123%%%
124%%%    Run parts of the test suite.
125%%%    Reads Nodes from nodes.profile and starts them if neccessary.
126%%%    Kills Mnesia and wipes out the Mnesia directories as a starter.
127%%%
128%%% test/2
129%%%
130%%%    Run parts of the test suite on the given Nodes,
131%%%    assuming that the nodes are up and running.
132%%%    Kills Mnesia and wipes out the Mnesia directories as a starter.
133%%%
134%%% test/3
135%%%
136%%%    Run parts of the test suite on permutations of the given Nodes,
137%%%    assuming that the nodes are up and running. Uses test/2.
138%%%    Kills Mnesia and wipes out the Mnesia directories as a starter.
139%%%
140%%% See the module mnesia_test_lib for further information.
141%%%
142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143
144show() -> mnesia_test_lib:show([{?MODULE,all}]).
145show(TestCases) -> mnesia_test_lib:show([{?MODULE,TestCases}]).
146test() -> mnesia_test_lib:test([{?MODULE,all}]).
147test(TestCases) ->  mnesia_test_lib:test([{?MODULE,TestCases}]).
148test(TestCases,Nodes) -> mnesia_test_lib:test([{?MODULE,TestCases}],Nodes).
149test(TestCases,Nodes,Config) -> mnesia_test_lib:test([{?MODULE,TestCases}],Nodes,Config).
150
151%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152
153old_all(suite) ->
154    [
155     system_info, table_info, error_description,
156     db_node_lifecycle, start_and_stop, transaction, checkpoint, backup,
157     table_lifecycle, replica_management, replica_location, index_lifecycle,
158     trans_access, dirty_access, table_sync, snmp_access, debug_support
159    ].
160
161trans_access(suite) ->
162    [ {mnesia_dirty_access_test,all} ].
163
164dirty_access(suite) ->
165     [ {mnesia_trans_access_test,all} ].
166
167%% Get meta info about Mnesia
168system_info(suite) -> [];
169system_info(Nodes) ->
170    ?match(yes,mnesia:system_info(is_running)),
171    ?match(Nodes,mnesia:system_info(db_nodes)),
172    ?match(Nodes,mnesia:system_info(running_db_nodes)),
173    ?match(true,mnesia:system_info(have_disc)),
174    ?match(A when atom(A),mnesia:system_info(debug)),
175    ?match(L when list(L),mnesia:system_info(directory)),
176    ?match(L when list(L),mnesia:system_info(log_version)),
177    ?match({_,_},mnesia:system_info(schema_version)),
178    ?match(L when list(L),mnesia:system_info(tables)),
179    ?match(L when list(L),mnesia:system_info(local_tables)),
180    ?match(L when list(L),mnesia:system_info(held_locks)),
181    ?match(L when list(L),mnesia:system_info(lock_queue)),
182    ?match(L when list(L),mnesia:system_info(transactions)),
183    ?match(I when integer(I),mnesia:system_info(transaction_failures)),
184    ?match(I when integer(I),mnesia:system_info(transaction_commits)),
185    ?match(I when integer(I),mnesia:system_info(transaction_restarts)),
186    ?match(L when list(L),mnesia:system_info(checkpoints)),
187    ?match(A when atom(A),mnesia:system_info(backup_module)),
188    ?match(true,mnesia:system_info(auto_repair)),
189    ?match({_,_},mnesia:system_info(dump_log_interval)),
190    ?match(A when atom(A),mnesia:system_info(dump_log_update_in_place)),
191    ?match(I when integer(I),mnesia:system_info(transaction_log_writes)),
192    ?match({'EXIT',{aborted,badarg}},mnesia:system_info(ali_baba)),
193    done.
194
195%% Get meta info about table
196table_info(suite) -> [];
197table_info(Nodes) ->
198    [Node1,Node2,Node3] = ?acquire_nodes(3,Nodes),
199
200    Tab = table_info,
201    Type = bag,
202    ValPos = 3,
203    Attrs = [k,v],
204    Arity = length(Attrs) +1,
205    Schema = [{name,Tab},{type,Type},{attributes,Attrs},{index,[ValPos]},
206	      {disc_only_copies,[Node1]},{ram_copies,[Node2]},{disc_copies,[Node3]}],
207    ?match({atomic,ok}, mnesia:create_table(Schema)),
208
209    Size = 10,
210    Keys = lists:seq(1,Size),
211    Records = [{Tab,A,7} || A <- Keys],
212    lists:foreach(fun(Rec) -> ?match(ok,mnesia:dirty_write(Rec)) end,Records),
213    ?match(Mem when integer(Mem),mnesia:table_info(Tab,memory)),
214    ?match(Size,mnesia:table_info(Tab,size)),
215    ?match(Type,mnesia:table_info(Tab,type)),
216    ?match([Node3],mnesia:table_info(Tab,disc_copies)),
217    ?match([Node2],mnesia:table_info(Tab,ram_copies)),
218    ?match([Node1],mnesia:table_info(Tab,disc_only_copies)),
219    Read = [Node1,Node2,Node3],
220    ?match(true,lists:member(mnesia:table_info(Tab,where_to_read),Read)),
221    Write = lists:sort([Node1,Node2,Node3]),
222    ?match(Write,lists:sort(mnesia:table_info(Tab,where_to_write))),
223    WriteLock = lists:sort([Node2,Node3]),
224    ?match([ValPos],mnesia:table_info(Tab,index)),
225    ?match(Arity,mnesia:table_info(Tab,arity)),
226    ?match(Attrs,mnesia:table_info(Tab,attributes)),
227    ?match({Tab,'_','_'},mnesia:table_info(Tab,wild_pattern)),
228    ?match({atomic,Attrs}, mnesia:transaction(fun() ->
229	     mnesia:table_info(Tab,attributes) end)),
230
231    done.
232
233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234%% Add and drop db nodes
235
236db_node_lifecycle(suite) -> [];
237db_node_lifecycle(Nodes) ->
238    [Node1,Node2] = ?acquire_nodes(2,Nodes),
239    Tab = db_node_lifecycle,
240
241    Schema = [{name,Tab},{ram_copies,[Node1,Node2]}],
242    ?match({atomic,ok}, mnesia:create_table(Schema)),
243    ?match({aborted,active}, rpc:call(Node1,mnesia,del_db_node,[Node2])),
244
245    ?match([], mnesia_test_lib:stop_mnesia(Nodes)),
246    ?match(ok, mnesia:delete_schema(Nodes)),
247    ?match({error,_}, mnesia:create_schema(foo)),
248    ?match({error,_}, mnesia:create_schema([foo])),
249    ?match({error,_}, mnesia:create_schema([foo@bar])),
250    ?match({error,_}, mnesia:start()),
251
252    ?match(ok, mnesia:create_schema(Nodes)),
253    ?match([],mnesia_test_lib:start_mnesia(Nodes)),
254    ?match({atomic,ok}, rpc:call(Node1,mnesia,del_db_node,[Node2])),
255    ?match({aborted,no_exists}, rpc:call(Node1,mnesia,del_db_node,[Node2])),
256    ?match({aborted,no_exists}, rpc:call(Node1,mnesia,del_db_node,[foo])),
257    ?match({aborted,no_exists}, rpc:call(Node1,mnesia,del_db_node,[foo@bar])),
258
259    ?match([], mnesia_test_lib:stop_mnesia([Node2])),
260    ?match(ok,mnesia:delete_schema([Node2])),
261    AddFun = fun() -> ?match({aborted,nested_transaction},
262			     mnesia:add_db_node(Node2)), ok end,
263    ?match({atomic,ok},rpc:call(Node1,mnesia,transaction,[AddFun])),
264    DelFun = fun() -> ?match({aborted,nested_transaction},
265			     mnesia:del_db_node(Node2)), ok end,
266    ?match({atomic,ok},rpc:call(Node1,mnesia,transaction,[DelFun])),
267
268    ?match({atomic,ok}, rpc:call(Node1,mnesia,add_db_node,[Node2])),
269    ?match({aborted,already_exists}, rpc:call(Node1,mnesia,add_db_node,[Node2])),
270    ?match([],mnesia_test_lib:start_mnesia([Node2])),
271    ?match({atomic,ok}, mnesia:create_table(Schema)),
272    done.
273
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275%% Start and stop the system
276
277start_and_stop(suite) -> [];
278start_and_stop(Nodes) ->
279    [Node1] = ?acquire_nodes(1,Nodes),
280
281    ?match(stopped, rpc:call(Node1,mnesia,stop,[])),
282    ?match(stopped, rpc:call(Node1,mnesia,stop,[])),
283    ?match({started,_}, rpc:call(Node1,mnesia,start,[])),
284    ?match({started,_}, rpc:call(Node1,mnesia,start,[])),
285    ?match(stopped, rpc:call(Node1,mnesia,stop,[])),
286    ?match([],mnesia_test_lib:start_mnesia(Nodes)),
287    done.
288
289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290%% Checkpoints and backup management
291
292checkpoint(suite) -> [];
293checkpoint(Nodes) ->
294    OneNode = ?acquire_nodes(1,Nodes),
295    checkpoint(OneNode,Nodes),
296    TwoNodes = ?acquire_nodes(2,Nodes),
297    checkpoint(TwoNodes,Nodes).
298
299checkpoint(TabNodes,Nodes) ->
300    [Node1] = ?acquire_nodes(1,TabNodes),
301    CreateTab = fun(Type,N,Ns) ->
302			Tab0 = lists:concat(["local_checkpoint_",Type,N]),
303			Tab = list_to_atom(Tab0),
304			Schema = [{name,Tab},{Type,Ns}],
305			?match({atomic,ok},mnesia:delete_table(Tab)),
306			?match({atomic,ok},mnesia:create_table(Schema)),
307			Tab
308		end,
309    CreateTabs = fun(Type) ->
310			 CreateTab(Type,1,hd(TabNodes)),
311			 CreateTab(Type,2,TabNodes),
312			 CreateTab(Type,3,lists:last(TabNodes))
313		 end,
314    Types = [ram_copies,disc_copies,disc_only_copies],
315    Tabs = lists:append(lists:map(CreateTabs,Types)),
316    Recs = lists:sort([{T,N,N} || T <- Tabs,N <- lists:seq(1,10)]),
317    lists:foreach(fun(R) -> ?match(ok,mnesia:dirty_write(R)) end,Recs),
318
319    CpName = a_checkpoint_name,
320    MinArgs = [{name,CpName},{min,Tabs},{allow_remote,false}],
321    ?match({ok,CpName,[Node1]},
322	   rpc:call(Node1,mnesia,activate_checkpoint,[MinArgs])),
323    ?match(ok,rpc:call(Node1,mnesia,deactivate_checkpoint,[CpName])),
324
325    MaxArgs = [{name,CpName},{max,Tabs},{allow_remote,true}],
326    ?match({ok,CpName,[Node1]},
327	   rpc:call(Node1,mnesia,activate_checkpoint,[MaxArgs])),
328    ?match(ok,rpc:call(Node1,mnesia,deactivate_checkpoint,[CpName])),
329
330    Args = [{name,CpName},{min,Tabs},{allow_remote,false}],
331    ?match({ok,CpName,[Node1]},
332	   rpc:call(Node1,mnesia,activate_checkpoint,[Args])),
333    Recs2 = lists:sort([{T,K,0} || {T,K,_} <- Recs]),
334    lists:foreach(fun(R) -> ?match(ok,mnesia:dirty_write(R)) end,Recs2),
335    ?match({atomic,ok},rpc:call(Node1,mnesia,deactivate_checkpoint,[CpName])),
336
337    ?match({error,no_exists},mnesia:deactivate_checkpoint(CpName)),
338    ?match({error,badarg},mnesia:activate_checkpoint(foo)),
339    ?match({error,badarg},mnesia:activate_checkpoint([{foo,foo}])),
340    ?match({error,badarg},mnesia:activate_checkpoint([{max,foo}])),
341    ?match({error,badarg},mnesia:activate_checkpoint([{min,foo}])),
342    ?match({error,no_exists},mnesia:activate_checkpoint([{min,[foo@bar]}])),
343    ?match({error,badarg},mnesia:activate_checkpoint([{allow_remote,foo}])),
344
345    Fun = fun(Tab) -> ?match({atomic,ok},mnesia:delete_table(Tab)) end,
346    lists:foreach(Fun,Tabs),
347    done.
348
349backup(suite) ->
350    [
351     backup_schema, restore_schema, backup_checkpoint, restore_tables
352    ].
353
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%% Use and misuse transactions
356
357transaction(suite) -> [];
358transaction(Nodes) ->
359    [Node1] = ?acquire_nodes(1,Nodes),
360    ?match({atomic,ali_baba}, mnesia:transaction(fun() -> ali_baba end)),
361    ?match({aborted,_},  mnesia:transaction(no_fun)),
362    ?match({aborted,_},  mnesia:transaction(?MODULE,no_fun,[foo])),
363
364    {success,[A,B,C,D,E,F,G,H]} = ?start_activities(lists:duplicate(8,Node1)),
365    ?start_transactions([A,B,C,D,E,F,G,H]),
366
367    A ! fun() -> mnesia:abort(abort_bad_trans) end,
368    ?match_receive({A,{aborted,abort_bad_trans}}),
369
370    B ! fun() -> 1 = 2 end,
371    ?match_receive({B,{aborted,_}}),
372
373    C ! fun() -> throw(throw_bad_trans) end,
374    ?match_receive({C,{aborted,{throw,throw_bad_trans}}}),
375
376    D ! fun() -> exit(exit_bad_trans) end,
377    ?match_receive({D,{aborted,exit_bad_trans}}),
378
379    E ! fun() -> exit(normal) end,
380    ?match_receive({E,{aborted,normal}}),
381
382    F ! fun() -> exit(abnormal) end,
383    ?match_receive({F,{aborted,abnormal}}),
384
385    G ! fun() -> exit(G,abnormal) end,
386    ?match_receive({'EXIT',G,abnormal}),
387
388    H ! fun() -> exit(H,kill) end,
389    ?match_receive({'EXIT',H,killed}),
390
391    ?match({atomic,ali_baba},
392	   mnesia:transaction(fun() -> ali_baba end,infinity)),
393    ?match({atomic,ali_baba},mnesia:transaction(fun() -> ali_baba end,1)),
394    ?match({atomic,ali_baba},mnesia:transaction(fun() -> ali_baba end,0)),
395    ?match({atomic,ali_baba},mnesia:transaction(fun() -> ali_baba end,-1)),
396    ?match({atomic,ali_baba},mnesia:transaction(fun() -> ali_baba end,foo)),
397    Fun = fun() -> ?match({aborted,nested_transaction},
398			  mnesia:transaction(fun() -> ok end)), ok end,
399    ?match({atomic,ok},mnesia:transaction(Fun)),
400    done.
401
402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403%% Create and delete tables
404
405%% Get meta info about table
406
407replica_location(suite) -> [];
408replica_location(Nodes) ->
409    [Node1,Node2,Node3] = ?acquire_nodes(3,Nodes),
410    Tab = replica_location,
411
412    %% Create three replicas
413    Schema = [{name,Tab},{disc_only_copies,[Node1]},
414	      {ram_copies,[Node2]},{disc_copies,[Node3]}],
415    ?match({atomic,ok}, mnesia:create_table(Schema)),
416    mnesia_test_lib:verify_replica_location(Tab,[Node1],[Node2],[Node3],Nodes),
417
418    %% Delete one replica
419    ?match({atomic,ok}, mnesia:del_table_copy(Tab, Node2)),
420    mnesia_test_lib:verify_replica_location(Tab,[Node1],[],[Node3],Nodes),
421
422    %% Move one replica
423    ?match({atomic,ok}, mnesia:move_table_copy(Tab, Node1, Node2)),
424    mnesia_test_lib:verify_replica_location(Tab,[Node2],[],[Node3],Nodes),
425
426    %% Change replica type
427    ?match({atomic,ok}, mnesia:change_table_copy_type(Tab, Node2,ram_copies)),
428    mnesia_test_lib:verify_replica_location(Tab,[],[Node2],[Node3],Nodes),
429
430    done.
431
432table_lifecycle(suite) -> [];
433table_lifecycle(Nodes) ->
434    [Node1,Node2] = ?acquire_nodes(2,Nodes),
435
436    ?match({atomic,ok}, mnesia:create_table([{type,bag},
437					     {ram_copies,[Node1]},
438					     {attributes,[rajtan,tajtan]},
439					     {name,order_of_args}])),
440    ?match([],mnesia:dirty_read({order_of_args,4711})),
441    ?match({atomic,ok}, mnesia:create_table([{name,already_exists},
442					    {ram_copies,[Node1]}])),
443    ?match({aborted,already_exists},
444	   mnesia:create_table([{name,already_exists},{ram_copies,[Node1]}])),
445    ?match({aborted,not_a_db_node},
446	   mnesia:create_table([{name,no_node},{ram_copies,[foo]}])),
447    ?match({aborted,not_a_db_node},
448	   mnesia:create_table([{name,no_host},{ram_copies,[foo@bar]}])),
449    ?match({aborted,badarg},
450	   mnesia:create_table([{name,zero_arity},{attributes,[]}])),
451    ?match({aborted,badarg}, mnesia:create_table([])),
452    ?match({aborted,badarg}, mnesia:create_table(atom)),
453    ?match({aborted,badarg},
454	   mnesia:create_table({cstruct,table_name_as_atom})),
455    ?match({aborted,bad_type},
456	   mnesia:create_table([{name,no_host},{ram_copies,foo}])),
457    ?match({aborted,bad_type},
458	   mnesia:create_table([{name,no_host},{disc_only_copies,foo}])),
459    ?match({aborted,bad_type},
460	   mnesia:create_table([{name,no_host},{disc_copies,foo}])),
461
462    CreateFun =
463	fun() -> ?match({aborted,nested_transaction},
464			mnesia:create_table([{name,nested_trans}])), ok
465	end,
466    ?match({atomic,ok},mnesia:transaction(CreateFun)),
467    ?match({atomic,ok},mnesia:create_table([{name,remote_tab},
468					    {ram_copies,[Node2]}])),
469
470    ?match({atomic,ok}, mnesia:create_table([{name,a_brand_new_tab},
471					    {ram_copies,[Node1]}])),
472    ?match([],mnesia:dirty_read({a_brand_new_tab,4711})),
473    ?match({atomic,ok}, mnesia:delete_table(a_brand_new_tab)),
474    ?match({'EXIT',{aborted,no_exists}},
475	   mnesia:dirty_read({a_brand_new_tab,4711})),
476    ?match({aborted,no_exists}, mnesia:delete_table(a_brand_new_tab)),
477    ?match({aborted,badarg}, mnesia:create_table([])),
478
479    ?match({atomic,ok}, mnesia:create_table([{name,nested_del_trans},
480					     {ram_copies,[Node1]}])),
481    DeleteFun = fun() -> ?match({aborted,nested_transaction},
482				mnesia:delete_table(nested_del_trans)), ok end,
483    ?match({atomic,ok}, mnesia:transaction(DeleteFun)),
484
485    ?match({aborted,bad_type},
486	   mnesia:create_table([{name,create_with_index},{index,2}])),
487    ?match({aborted,bad_index},
488	   mnesia:create_table([{name,create_with_index},{index,[-1]}])),
489    ?match({aborted,bad_index},
490	   mnesia:create_table([{name,create_with_index},{index,[0]}])),
491    ?match({aborted,bad_index},
492	   mnesia:create_table([{name,create_with_index},{index,[1]}])),
493    ?match({aborted,bad_index},
494	   mnesia:create_table([{name,create_with_index},{index,[2]}])),
495    ?match({atomic,ok},
496	   mnesia:create_table([{name,create_with_index},{index,[3]},
497			       {ram_copies,[Node1]}])),
498    done.
499
500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
501%% Add, drop and move replicas, change storage types
502%% Change table layout (only arity change supported)
503
504replica_management(suite) -> [];
505replica_management(Nodes) ->
506    %% add_table_copy/3, del_table_copy/2, move_table_copy/3,
507    %% change_table_copy_type/3, transform_table/3
508
509    [Node1,Node2,Node3] = ?acquire_nodes(3,Nodes),
510
511    Tab = replica_management,
512    Attrs = [k,v],
513
514    %%
515    %% Add, delete and change replicas
516    %%
517    ?match({atomic,ok},
518	   mnesia:create_table([{name,Tab},{attributes,Attrs},
519				{ram_copies,[Node1]}])),
520    mnesia_test_lib:verify_replica_location(Tab,[],[Node1],[],Nodes),
521    %% R - -
522    ?match({aborted,combine_error},
523	   mnesia:add_table_copy(Tab, Node2, disc_copies)),
524    ?match({aborted,combine_error},
525	   mnesia:change_table_copy_type(Tab, Node1, disc_copies)),
526    ?match({atomic,ok}, mnesia:del_table_copy(Tab,Node1)),
527    mnesia_test_lib:verify_replica_location(Tab,[],[],[],Nodes),
528    %% - - -
529    ?match({aborted,no_exists},
530	   mnesia:add_table_copy(Tab, Node3, ram_copies)),
531
532    ?match({atomic,ok}, mnesia:create_table([{name,Tab},
533					     {attributes,Attrs},
534					     {disc_copies,[Node1]}])),
535    mnesia_test_lib:verify_replica_location(Tab,[],[],[Node1],Nodes),
536    %% D - -
537    ?match({aborted,badarg},
538	   mnesia:add_table_copy(Tab, Node2, bad_storage_type)),
539    ?match({atomic,ok}, mnesia:add_table_copy(Tab, Node2, disc_only_copies)),
540    mnesia_test_lib:verify_replica_location(Tab,[Node2],[],[Node1],Nodes),
541    %% D DO -
542    ?match({atomic,ok}, mnesia:add_table_copy(Tab, Node3, ram_copies)),
543    mnesia_test_lib:verify_replica_location(Tab,[Node2],[Node3],[Node1],Nodes),
544    %% D DO R
545    ?match({atomic,ok},
546	   mnesia:change_table_copy_type(Tab, Node1, disc_only_copies)),
547    mnesia_test_lib:verify_replica_location(Tab,[Node1,Node2],[Node3],[],Nodes),
548    %% DO DO R
549    ?match({aborted,already_exists},
550	   mnesia:add_table_copy(Tab, Node3, ram_copies)),
551    ?match({atomic,ok}, mnesia:del_table_copy(Tab, Node1)),
552    mnesia_test_lib:verify_replica_location(Tab,[Node2],[Node3],[],Nodes),
553    %% - DO R
554    ?match({aborted,_}, mnesia:del_table_copy(Tab, Node1)),
555    ?match({atomic,ok}, mnesia:add_table_copy(Tab, Node1, disc_copies)),
556    mnesia_test_lib:verify_replica_location(Tab,[Node2],[Node3],[Node1],Nodes),
557    %% D DO R
558    ?match({atomic,ok},
559	   mnesia:change_table_copy_type(Tab, Node3, disc_only_copies)),
560    mnesia_test_lib:verify_replica_location(Tab,[Node2,Node3],[],[Node1],Nodes),
561    %% D DO DO
562    ?match({atomic,ok}, mnesia:del_table_copy(Tab, Node2)),
563    mnesia_test_lib:verify_replica_location(Tab,[Node3],[],[Node1],Nodes),
564    %% D - DO
565    ?match({aborted,already_exists},
566	   mnesia:change_table_copy_type(Tab, Node1, disc_copies)),
567
568    %%
569    %% Move replica
570    %%
571    ?match({atomic,ok}, mnesia:move_table_copy(Tab,Node1,Node2)),
572    mnesia_test_lib:verify_replica_location(Tab,[Node3],[],[Node2],Nodes),
573    %% - D DO
574    ?match({aborted,_}, mnesia:move_table_copy(Tab,Node1,Node2)),
575    ?match([], mnesia_test_lib:stop_mnesia([Node3])),
576    mnesia_test_lib:verify_replica_location(Tab,[Node3],[],[Node2],
577					    Nodes -- [Node3]),
578    %% - D DO
579    ?match({atomic,ok}, mnesia:move_table_copy(Tab,Node3,Node1)),
580    mnesia_test_lib:verify_replica_location(Tab,[Node1],[],[Node2],
581					    Nodes -- [Node3]),
582    %% DO D -
583    ?match([],mnesia_test_lib:start_mnesia([Node3])),
584    mnesia_test_lib:verify_replica_location(Tab,[Node1],[],[Node2],Nodes),
585    %% DO D -
586
587    %%
588    %% Transformer
589    %%
590
591    NewAttrs = Attrs ++ [extra],
592    Transformer =
593	fun(Rec) -> list_to_tuple(tuple_to_list(Rec) ++ [initial_value]) end,
594    ?match({atomic,ok}, mnesia:transform_table(Tab, Transformer,NewAttrs)),
595    ?match({atomic,ok},  mnesia:transform_table(Tab, fun(R) -> R end, Attrs)),
596    ?match({aborted,bad_type}, mnesia:transform_table(Tab, Transformer, 0)),
597    ?match({aborted,bad_type}, mnesia:transform_table(Tab, Transformer, -1)),
598    ?match({aborted,badarg}, mnesia:transform_table(Tab, Transformer, [])),
599    ?match({aborted,bad_type}, mnesia:transform_table(Tab, no_fun, NewAttrs)),
600
601    NestedFun =
602	fun() ->
603		?match({aborted,_},
604		       mnesia:move_table_copy(Tab,Node1,Node2)),
605		?match({aborted,_},
606		       mnesia:add_table_copy(Tab,Node1,ram_copies)),
607		?match({aborted,_},
608		       mnesia:del_table_copy(Tab,Node1)),
609		T = fun(_) -> 4711 end,
610		?match({aborted,_},
611		       mnesia:transform_table(Tab,Transformer, T)),
612		ok
613	end,
614    ?match({atomic,ok},mnesia:transaction(NestedFun)),
615    done.
616
617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
618%% Add and drop indecies
619
620index_lifecycle(suite) ->
621    [ add_table_index, create_live_table_index, del_table_index ].
622
623%% Add table index
624
625add_table_index(suite) -> [];
626add_table_index(Nodes) ->
627    [Node1] = ?acquire_nodes(1,Nodes),
628    Tab = add_table_index,
629    Schema = [{name,Tab},{attributes,[k,v]},{ram_copies,[Node1]}],
630    ?match({atomic,ok}, mnesia:create_table(Schema)),
631    ValPos = 3,
632    BadValPos = ValPos + 1,
633    ?match({aborted,bad_index}, mnesia:add_table_index(Tab,BadValPos)),
634    ?match({aborted,bad_index}, mnesia:add_table_index(Tab,2)),
635    ?match({aborted,bad_index}, mnesia:add_table_index(Tab,1)),
636    ?match({aborted,bad_index}, mnesia:add_table_index(Tab,0)),
637    ?match({aborted,bad_index}, mnesia:add_table_index(Tab,-1)),
638    ?match({atomic,ok}, mnesia:add_table_index(Tab,ValPos)),
639    ?match({aborted,already_exists}, mnesia:add_table_index(Tab,ValPos)),
640
641    NestedFun = fun() ->
642			?match({aborted,nested_transaction},
643			       mnesia:add_table_index(Tab,ValPos)),
644
645			ok
646		end,
647    ?match({atomic,ok},mnesia:transaction(NestedFun)),
648    done.
649
650create_live_table_index(suite) -> [];
651create_live_table_index(Nodes) ->
652    [Node1] = ?acquire_nodes(1,Nodes),
653    Tab = create_live_table_index,
654    Schema = [{name,Tab},{attributes,[k,v]},{ram_copies,[Node1]}],
655    ?match({atomic,ok}, mnesia:create_table(Schema)),
656    ValPos = 3,
657    mnesia:dirty_write({Tab,1,2}),
658
659    Fun = fun() ->
660		  ?match(ok, mnesia:write({Tab,2,2})),
661		  ok
662	  end,
663    ?match({atomic,ok},mnesia:transaction(Fun)),
664    ?match({atomic,ok}, mnesia:add_table_index(Tab,ValPos)),
665    done.
666
667%% Drop table index
668
669del_table_index(suite) ->[];
670del_table_index(Nodes) ->
671    [Node1] = ?acquire_nodes(1,Nodes),
672    Tab = del_table_index,
673    Schema = [{name,Tab},{attributes,[k,v]},{ram_copies,[Node1]}],
674    ?match({atomic,ok}, mnesia:create_table(Schema)),
675    ValPos = 3,
676    BadValPos = ValPos + 1,
677    ?match({atomic,ok}, mnesia:add_table_index(Tab,ValPos)),
678    ?match({aborted,no_exists},
679	   mnesia:del_table_index(Tab,BadValPos)),
680    ?match({atomic,ok}, mnesia:del_table_index(Tab,ValPos)),
681
682    NestedFun =
683	fun() ->
684		?match({aborted,nested_transaction},
685		       mnesia:del_table_index(Tab,ValPos)),
686		ok
687	end,
688    ?match({atomic,ok},mnesia:transaction(NestedFun)),
689    done.
690
691%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692%% Syncronize table with log or disc
693%%
694table_sync(suite) ->
695    [ dump_tables, dump_log, change_dump_log_config, wait_for_tables, force_load_table ].
696
697%% Dump ram tables on disc
698dump_tables(suite) -> [];
699dump_tables(Nodes) ->
700    [Node1,Node2] = ?acquire_nodes(2,Nodes),
701    Tab = dump_tables,
702    Schema = [{name,Tab},{attributes,[k,v]},{ram_copies,[Node2]}],
703    ?match({atomic,ok}, mnesia:create_table(Schema)),
704
705    %% Dump 10 records
706    Size = 10,
707    Keys = lists:seq(1,Size),
708    Records = [{Tab,A,7} || A <- Keys],
709    lists:foreach(fun(Rec) -> ?match(ok,mnesia:dirty_write(Rec)) end,Records),
710    AllKeys = fun() -> lists:sort(mnesia:all_keys(Tab)) end,
711
712    ?match({atomic,Keys}, mnesia:transaction(AllKeys)),
713    ?match(ok, mnesia:dump_tables(Tab)),
714
715    %% Delete one record
716    ?match(ok,mnesia:dirty_delete({Tab,5})),
717    Keys2 = lists:delete(5,Keys),
718    ?match({atomic,Keys2}, mnesia:transaction(AllKeys)),
719
720    %% Check that all 10 is restored after a stop
721    ?match([], mnesia_test_lib:stop_mnesia([Node1,Node2])),
722    ?match([],mnesia_test_lib:start_mnesia([Node1,Node2])),
723    ?match(ok,mnesia:wait_for_tables([Tab],infinity)),
724    ?match({atomic,Keys}, mnesia:transaction(AllKeys)),
725
726    ?match(ok, mnesia:dump_tables([foo])),
727    done.
728
729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
730%% Make Mnesia table accessible via SNMP
731
732snmp_access(suite) ->
733    [
734     snmp_open_table, snmp_close_table,
735     snmp_get_row, snmp_get_next_index, snmp_get_mnesia_key
736    ].
737
738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
739%% Check that the debug support has not decayed
740
741debug_support(suite) ->
742    [  info, schema, schema, kill, lkill ].
743
744