~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to lib/mnesia/test/mnesia_evil_backup.erl

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%%
 
2
%% %CopyrightBegin%
 
3
%%
 
4
%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
 
5
%%
 
6
%% The contents of this file are subject to the Erlang Public License,
 
7
%% Version 1.1, (the "License"); you may not use this file except in
 
8
%% compliance with the License. You should have received a copy of the
 
9
%% Erlang Public License along with this software. If not, it can be
 
10
%% retrieved online at http://www.erlang.org/.
 
11
%%
 
12
%% Software distributed under the License is distributed on an "AS IS"
 
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 
14
%% the License for the specific language governing rights and limitations
 
15
%% under the License.
 
16
%%
 
17
%% %CopyrightEnd%
 
18
%%
 
19
 
 
20
%%
 
21
%%%----------------------------------------------------------------------
 
22
%%% File    : mnesia_evil_backup.erl
 
23
%%% Author  : Dan Gudmundsson <dgud@legolas>
 
24
%%% Purpose : Evil backup tests
 
25
%%% Created : 3 Jun 1998 by Dan Gudmundsson <dgud@erix.ericsson.se>
 
26
%%%----------------------------------------------------------------------
 
27
 
 
28
-module(mnesia_evil_backup).
 
29
-author('dgud@erix.ericsson.se').
 
30
-compile(export_all).
 
31
-include("mnesia_test_lib.hrl").
 
32
 
 
33
%%-export([Function/Arity, ...]).
 
34
 
 
35
init_per_testcase(Func, Conf) ->
 
36
    mnesia_test_lib:init_per_testcase(Func, Conf).
 
37
 
 
38
end_per_testcase(Func, Conf) ->
 
39
    mnesia_test_lib:end_per_testcase(Func, Conf).
 
40
 
 
41
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
42
 
 
43
all() -> 
 
44
    [backup, bad_backup, global_backup_checkpoint,
 
45
     {group, restore_tables}, traverse_backup,
 
46
     selective_backup_checkpoint,
 
47
     incremental_backup_checkpoint, install_fallback,
 
48
     uninstall_fallback, local_fallback,
 
49
     sops_with_checkpoint].
 
50
 
 
51
groups() -> 
 
52
    [{restore_tables, [],
 
53
      [restore_errors, restore_clear, restore_keep,
 
54
       restore_recreate, restore_clear_ram]}].
 
55
 
 
56
init_per_group(_GroupName, Config) ->
 
57
    Config.
 
58
 
 
59
end_per_group(_GroupName, Config) ->
 
60
    Config.
 
61
 
 
62
 
 
63
backup(doc) -> ["Checking the interface to the function backup",
 
64
                "We don't check that the backups can be used here",
 
65
                "That is checked in install_fallback and in restore"];
 
66
backup(suite) -> [];
 
67
backup(Config) when is_list(Config) -> 
 
68
    [Node1, Node2] = _Nodes = ?acquire_nodes(2, Config),
 
69
    Tab = backup_tab,
 
70
    Def = [{disc_copies, [Node1]}, {ram_copies, [Node2]}],
 
71
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),  
 
72
    ?match(ok, mnesia:dirty_write({Tab, 1, test_ok})),
 
73
    File = "backup_test.BUP",
 
74
    ?match(ok, mnesia:backup(File)),
 
75
 
 
76
    File2 = "backup_test2.BUP",
 
77
    Tab2 = backup_tab2,
 
78
    Def2 = [{disc_only_copies, [Node2]}],
 
79
    ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),  
 
80
    ?match(ok, mnesia:backup(File2, mnesia_backup)),
 
81
 
 
82
    File3 = "backup_test3.BUP",
 
83
    mnesia_test_lib:kill_mnesia([Node2]),
 
84
    ?match({error, _}, mnesia:backup(File3, mnesia_backup)),
 
85
 
 
86
    ?match(ok, file:delete(File)),
 
87
    ?match(ok, file:delete(File2)),
 
88
    ?match({error, _}, file:delete(File3)),
 
89
    ?verify_mnesia([Node1], [Node2]).
 
90
 
 
91
 
 
92
bad_backup(suite) -> [];
 
93
bad_backup(Config) when is_list(Config) -> 
 
94
    [Node1] = ?acquire_nodes(1, Config),
 
95
    Tab = backup_tab,
 
96
    Def = [{disc_copies, [Node1]}],
 
97
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),
 
98
    ?match(ok, mnesia:dirty_write({Tab, 1, test_ok})),
 
99
    File = "backup_test.BUP",
 
100
    ?match(ok, mnesia:backup(File)),
 
101
    file:write_file(File, "trash", [append]),
 
102
    ?match(ok, mnesia:dirty_write({Tab, 1, test_bad})),
 
103
    ?match({atomic,[Tab]}, mnesia:restore(File, [{clear_tables, [Tab]}])),
 
104
    ?match([{Tab,1,test_ok}], mnesia:dirty_read(Tab, 1)),
 
105
    
 
106
    ?match(ok, file:delete(File)),
 
107
    ?verify_mnesia([Node1], []).
 
108
 
 
109
 
 
110
 
 
111
global_backup_checkpoint(doc) -> 
 
112
    ["Checking the interface to the function backup_checkpoint",
 
113
     "We don't check that the backups can be used here",
 
114
     "That is checked in install_fallback and in restore"];
 
115
global_backup_checkpoint(suite) -> [];
 
116
global_backup_checkpoint(Config) when is_list(Config) ->
 
117
    [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),    
 
118
    Tab = backup_cp,
 
119
    Def = [{disc_copies, [Node1]}, {ram_copies, [Node2]}],
 
120
    File = "backup_checkpoint.BUP",
 
121
    File2 = "backup_checkpoint2.BUP",
 
122
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),    
 
123
    ?match(ok, mnesia:dirty_write({Tab, 1, test_ok})),
 
124
    ?match({error, _}, mnesia:backup_checkpoint(cp_name, File)),
 
125
    Spec = [{name, cp_name}, {max,  mnesia:system_info(tables)}],
 
126
    ?match({ok, _Name, _Ns}, mnesia:activate_checkpoint(Spec)),
 
127
    ?match(ok, mnesia:backup_checkpoint(cp_name, File)),
 
128
    ?match({error, _}, mnesia:backup_checkpoint(cp_name_nonexist, File)),
 
129
    ?match(ok, mnesia:backup_checkpoint(cp_name, File2, mnesia_backup)),
 
130
    ?match({error, _}, file:delete(File)),
 
131
    ?match(ok, file:delete(File2)),
 
132
    ?verify_mnesia(Nodes, []).
 
133
 
 
134
 
 
135
restore_errors(suite) -> [];
 
136
restore_errors(Config) when is_list(Config) ->
 
137
    [_Node] = ?acquire_nodes(1, Config),
 
138
    ?match({aborted, enoent}, mnesia:restore(notAfile, [])),
 
139
    ?match({aborted, {badarg, _}}, mnesia:restore(notAfile, not_a_list)),
 
140
    ?match({aborted, {badarg, _}}, mnesia:restore(notAfile, [test_badarg])),
 
141
    ?match({aborted, {badarg, _}}, mnesia:restore(notAfile, [{test_badarg, xxx}])),
 
142
    ?match({aborted, {badarg, _}}, mnesia:restore(notAfile, [{skip_tables, xxx}])),
 
143
    ?match({aborted, {badarg, _}}, mnesia:restore(notAfile, [{recreate_tables, [schema]}])),
 
144
    ?match({aborted, {badarg, _}}, mnesia:restore(notAfile, [{default_op, asdklasd}])),
 
145
    ok.
 
146
 
 
147
restore_clear(suite) -> [];
 
148
restore_clear(Config) when is_list(Config) ->
 
149
    restore(Config, clear_tables).
 
150
 
 
151
restore_keep(suite) -> [];
 
152
restore_keep(Config) when is_list(Config) ->
 
153
    restore(Config, keep_tables).
 
154
 
 
155
restore_recreate(suite) -> [];
 
156
restore_recreate(Config) when is_list(Config) ->
 
157
    restore(Config, recreate_tables).
 
158
 
 
159
check_tab(Records, Line) ->
 
160
    Verify = fun({Table, Key, Val}) -> 
 
161
                     case catch mnesia:dirty_read({Table, Key}) of
 
162
                         [{Table, Key, Val}] -> ok;
 
163
                         Else ->
 
164
                             mnesia_test_lib:error("Not matching on Node ~p ~n"
 
165
                                                   " Expected ~p~n Actual  ~p~n", 
 
166
                                                   [node(), {Table, Key, Val}, Else],
 
167
                                                   ?MODULE, Line),
 
168
                             exit(error)     
 
169
                     end;
 
170
                (Recs) ->
 
171
                     [{Tab, Key, _}, _] = Recs,
 
172
                     SRecs = lists:sort(Recs),
 
173
                     R_Recs = lists:sort(catch mnesia:dirty_read({Tab, Key})),
 
174
                     case R_Recs of
 
175
                         SRecs -> ok;
 
176
                         Else ->
 
177
                             mnesia_test_lib:error("Not matching on Node ~p ~n"
 
178
                                                   " Expected ~p~n Actual  ~p~n", 
 
179
                                                   [node(), SRecs, Else],
 
180
                                                   ?MODULE, Line),
 
181
                             exit(error)
 
182
                     end
 
183
             end,
 
184
    lists:foreach(Verify, Records).
 
185
 
 
186
restore(Config, Op)  ->
 
187
    [Node1, Node2, _Node3] = Nodes = ?acquire_nodes(3, Config),
 
188
    
 
189
    Tab1 = ram_snmp,
 
190
    Def1 = [{snmp, [{key, integer}]}, {ram_copies, [Node1]}],
 
191
    Tab2 = disc_index,
 
192
    Def2 = [{index, [val]}, {disc_copies, [Node1, Node2]}],
 
193
    Tab3 = dionly_bag,
 
194
    Def3 = [{type, bag}, {disc_only_copies, Nodes}],
 
195
    ?match({atomic, ok}, mnesia:create_table(Tab1, Def1)),
 
196
    ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),
 
197
    ?match({atomic, ok}, mnesia:create_table(Tab3, Def3)),
 
198
 
 
199
    File1 = "restore1.BUP",
 
200
    File2 = "restore2.BUP",    
 
201
 
 
202
    Restore = fun(O, A) ->
 
203
                      case mnesia:restore(O, A) of
 
204
                          {atomic, Tabs} when is_list(Tabs) -> {atomic, lists:sort(Tabs)};
 
205
                          Other -> Other
 
206
                      end
 
207
              end,
 
208
    Tabs = lists:sort([Tab1, Tab2, Tab3]),
 
209
    
 
210
    [mnesia:dirty_write({Tab1, N, N+42}) || N <- lists:seq(1, 10)],
 
211
    [mnesia:dirty_write({Tab2, N, N+43}) || N <- lists:seq(1, 10)],
 
212
    [mnesia:dirty_write({Tab3, N, N+44}) || N <- lists:seq(1, 10)],
 
213
    
 
214
    Res1 = [{Tab1, N, N+42} || N <- lists:seq(1, 10)],
 
215
    Res2 = [{Tab2, N, N+43} || N <- lists:seq(1, 10)],
 
216
    Res3 = [{Tab3, N, N+44} || N <- lists:seq(1, 10)],
 
217
    
 
218
    {ok, Name, _} = mnesia:activate_checkpoint([{min, Tabs}, {ram_overrides_dump, true}]),
 
219
    file:delete(File1),
 
220
    
 
221
    %% Test standard Restore on one table on one node
 
222
    ?match(ok, mnesia:backup_checkpoint(Name, File1)),
 
223
    ?match(ok, mnesia:deactivate_checkpoint(Name)),
 
224
    ?match(ok, mnesia:backup(File2)),
 
225
    [mnesia:dirty_write({Tab1, N, N+1}) || N <- lists:seq(1, 11)],
 
226
    [mnesia:dirty_write({Tab2, N, N+1}) || N <- lists:seq(1, 11)],
 
227
    [mnesia:dirty_write({Tab3, N, N+1}) || N <- lists:seq(1, 11)],
 
228
    _Res11 = [{Tab1, N, N+1} || N <- lists:seq(1, 11)],
 
229
    Res21 = [{Tab2, N, N+1} || N <- lists:seq(1, 11)],
 
230
    Res31 = [[{Tab3, N, N+1}, {Tab3, N, N+44}] || N <- lists:seq(1, 10)],
 
231
    
 
232
    ?match({atomic, [Tab1]}, Restore(File1, [{Op, [Tab1]},
 
233
                                             {skip_tables, Tabs -- [Tab1]}])),    
 
234
    case Op of 
 
235
        keep_tables -> 
 
236
            ?match([{Tab1, 11, 12}], mnesia:dirty_read({Tab1, 11}));
 
237
        clear_tables ->
 
238
            ?match([], mnesia:dirty_read({Tab1, 11}));
 
239
        recreate_tables ->
 
240
            ?match([], mnesia:dirty_read({Tab1, 11}))
 
241
    end,
 
242
    [rpc:call(Node, ?MODULE, check_tab, [Res1, ?LINE]) || Node <- Nodes],
 
243
    [rpc:call(Node, ?MODULE, check_tab, [Res21, ?LINE]) || Node <- Nodes],
 
244
    [rpc:call(Node, ?MODULE, check_tab, [Res31, ?LINE]) || Node <- Nodes],
 
245
 
 
246
    %% Restore all tables on it's nodes
 
247
    mnesia_schema:clear_table(Tab1),
 
248
    mnesia_schema:clear_table(Tab2),
 
249
    mnesia_schema:clear_table(Tab3),
 
250
    [mnesia:dirty_write({Tab1, N, N+1}) || N <- lists:seq(1, 11)],
 
251
    [mnesia:dirty_write({Tab2, N, N+1}) || N <- lists:seq(1, 11)],
 
252
    [mnesia:dirty_write({Tab3, N, N+1}) || N <- lists:seq(1, 11)],
 
253
 
 
254
    ?match({atomic, ok}, mnesia:del_table_copy(Tab2, Node1)),
 
255
 
 
256
    ?match({ok, Node1}, mnesia:subscribe({table, Tab1})),
 
257
    
 
258
    ?match({atomic, Tabs}, Restore(File1, [{default_op, Op},
 
259
                                           {module, mnesia_backup}])),
 
260
    case Op of 
 
261
        clear_tables ->
 
262
            ?match_receive({mnesia_table_event, {delete, {schema, Tab1}, _}}),
 
263
            ?match_receive({mnesia_table_event, {write, {schema, Tab1, _}, _}}),
 
264
            check_subscr(Tab1),
 
265
            [rpc:call(Node, ?MODULE, check_tab, [Res1, ?LINE]) || Node <- Nodes],
 
266
            [rpc:call(Node, ?MODULE, check_tab, [Res2, ?LINE]) || Node <- Nodes],
 
267
            [rpc:call(Node, ?MODULE, check_tab, [Res3, ?LINE]) || Node <- Nodes],         
 
268
            ?match([], mnesia:dirty_read({Tab1, 11})),
 
269
            ?match([], mnesia:dirty_read({Tab2, 11})),
 
270
            ?match([], mnesia:dirty_read({Tab3, 11})),
 
271
            %% Check Index
 
272
            ?match([{Tab2, 10, 53}], mnesia:dirty_index_read(Tab2, 53, val)),
 
273
            ?match([], mnesia:dirty_index_read(Tab2, 11, val)),
 
274
            %% Check Snmp
 
275
            ?match({ok, [1]}, mnesia:snmp_get_next_index(Tab1,[])),
 
276
            ?match({ok, {Tab1, 1, 43}}, mnesia:snmp_get_row(Tab1, [1])),
 
277
            ?match(undefined, mnesia:snmp_get_row(Tab1, [11])),
 
278
            %% Check schema info
 
279
            ?match([Node2], mnesia:table_info(Tab2, where_to_write));
 
280
        keep_tables -> 
 
281
            check_subscr(Tab1),
 
282
            [rpc:call(Node, ?MODULE, check_tab, [Res1, ?LINE]) || Node <- Nodes],
 
283
            [rpc:call(Node, ?MODULE, check_tab, [Res2, ?LINE]) || Node <- Nodes],
 
284
            [rpc:call(Node, ?MODULE, check_tab, [Res31, ?LINE]) || Node <- Nodes],          
 
285
            ?match([{Tab1, 11, 12}], mnesia:dirty_read({Tab1, 11})),
 
286
            ?match([{Tab2, 11, 12}], mnesia:dirty_read({Tab2, 11})),
 
287
            ?match([{Tab3, 11, 12}], mnesia:dirty_read({Tab3, 11})),
 
288
            ?match([{Tab2, 10, 53}], mnesia:dirty_index_read(Tab2, 53, val)),
 
289
            %% Check Index
 
290
            ?match([], mnesia:dirty_index_read(Tab2, 11, val)),
 
291
            ?match({ok, [1]}, mnesia:snmp_get_next_index(Tab1,[])),
 
292
            %% Check Snmp
 
293
            ?match({ok, {Tab1, 1, 43}}, mnesia:snmp_get_row(Tab1, [1])),
 
294
            ?match({ok, {Tab1, 11, 12}}, mnesia:snmp_get_row(Tab1, [11])),
 
295
            %% Check schema info
 
296
            ?match([Node2], mnesia:table_info(Tab2, where_to_write));
 
297
        recreate_tables ->
 
298
            check_subscr(Tab1, 0),
 
299
            [rpc:call(Node, ?MODULE, check_tab, [Res1, ?LINE]) || Node <- Nodes],
 
300
            [rpc:call(Node, ?MODULE, check_tab, [Res2, ?LINE]) || Node <- Nodes],
 
301
            [rpc:call(Node, ?MODULE, check_tab, [Res3, ?LINE]) || Node <- Nodes],       
 
302
            ?match([], mnesia:dirty_read({Tab1, 11})),
 
303
            ?match([], mnesia:dirty_read({Tab2, 11})),
 
304
            ?match([], mnesia:dirty_read({Tab3, 11})),
 
305
            %% Check Index
 
306
            ?match([{Tab2, 10, 53}], mnesia:dirty_index_read(Tab2, 53, val)),               
 
307
            ?match([], mnesia:dirty_index_read(Tab2, 11, val)),
 
308
            %% Check Snmp
 
309
            ?match({ok, [1]}, mnesia:snmp_get_next_index(Tab1,[])),
 
310
            ?match({ok, {Tab1, 1, 43}}, mnesia:snmp_get_row(Tab1, [1])),
 
311
            ?match(undefined, mnesia:snmp_get_row(Tab1, [11])),
 
312
            %% Check schema info
 
313
            Ns = lists:sort([Node1, Node2]),
 
314
            ?match(Ns, lists:sort(mnesia:table_info(Tab2, where_to_write)))         
 
315
    end,
 
316
    ?match(ok, file:delete(File1)),
 
317
    ?match(ok, file:delete(File2)),
 
318
    ?verify_mnesia(Nodes, []).
 
319
 
 
320
 
 
321
check_subscr(Tab) ->    
 
322
    check_subscr(Tab, 10).
 
323
 
 
324
check_subscr(_Tab, 0) ->    
 
325
    receive 
 
326
        Msg ->
 
327
            ?error("Too many msgs ~p~n", [Msg])
 
328
    after 500 ->
 
329
            ok
 
330
    end;
 
331
check_subscr(Tab, N) ->
 
332
    V = N +42,
 
333
    receive
 
334
        {mnesia_table_event, {write, {Tab, N, V}, _}} ->
 
335
            check_subscr(Tab, N-1)
 
336
    after 500 ->
 
337
            ?error("Missing ~p~n", [{Tab, N, V}])
 
338
    end.
 
339
 
 
340
restore_clear_ram(suite) -> [];
 
341
restore_clear_ram(Config) when is_list(Config) ->
 
342
    Nodes = ?acquire_nodes(3, [{diskless, true}|Config]),
 
343
    
 
344
    ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, Nodes}])),
 
345
    
 
346
    Write = fun(What) ->
 
347
                    mnesia:write({a,1,What}),
 
348
                    mnesia:write({a,2,What}),
 
349
                    mnesia:write({a,3,What})
 
350
            end,
 
351
    Bup = "restore_clear_ram.BUP",
 
352
 
 
353
    ?match({atomic, ok}, mnesia:transaction(Write, [initial])),
 
354
    ?match({ok, _, _}, mnesia:activate_checkpoint([{name,test}, 
 
355
                                                   {min, [schema, a]},
 
356
                                                   {ram_overrides_dump, true}])),
 
357
    ?match(ok, mnesia:backup_checkpoint(test, Bup)),
 
358
    
 
359
    ?match({atomic, ok}, mnesia:transaction(Write, [data])),
 
360
    ?match({atomic, [a]}, mnesia:restore(Bup, [{clear_tables,[a]},{default_op,skip_tables}])),
 
361
 
 
362
    restore_clear_ram_loop(100, Nodes, Bup),
 
363
    
 
364
    ok.
 
365
    
 
366
restore_clear_ram_loop(N, Nodes = [N1,N2,N3], Bup) when N > 0 ->
 
367
    ?match([], mnesia_test_lib:stop_mnesia(Nodes)),
 
368
    ?match({_, []}, rpc:multicall([N1,N2], mnesia, start, [[{extra_db_nodes, Nodes}]])),
 
369
    Key = rpc:async_call(N3, mnesia, start, [[{extra_db_nodes, Nodes}]]),
 
370
    ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, Nodes}])),
 
371
    ?match({atomic, [a]}, mnesia:restore(Bup, [{clear_tables,[a]},{default_op,skip_tables}])),
 
372
    ?match(ok, rpc:yield(Key)),
 
373
    ?match(ok, rpc:call(N3, mnesia, wait_for_tables, [[a], 3000])),
 
374
    case rpc:multicall(Nodes, mnesia, table_info, [a,size]) of
 
375
        {[3,3,3], []} ->
 
376
            restore_clear_ram_loop(N-1, Nodes, Bup);
 
377
        Error ->
 
378
            ?match(3, Error)
 
379
    end;
 
380
restore_clear_ram_loop(_,_,_) ->
 
381
    ok.
 
382
 
 
383
traverse_backup(doc) -> 
 
384
    ["Testing the traverse_backup interface, the resulting file is not tested though",
 
385
     "See install_fallback for result using the output file from traverse_backup",
 
386
     "A side effect is that the backup file contents are tested"];
 
387
traverse_backup(suite) -> [];
 
388
traverse_backup(Config) when is_list(Config) -> 
 
389
    [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 
390
    Tab = backup_tab,
 
391
    Def = [{disc_copies, [Node1]}, {ram_copies, [Node2]}],
 
392
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),  
 
393
    ?match(ok, mnesia:dirty_write({Tab, 1, test_nok})),
 
394
    ?match(ok, mnesia:dirty_write({Tab, 2, test_nok})),
 
395
    ?match(ok, mnesia:dirty_write({Tab, 3, test_nok})),
 
396
    ?match(ok, mnesia:dirty_write({Tab, 4, test_nok})),
 
397
    ?match(ok, mnesia:dirty_write({Tab, 5, test_nok})),
 
398
    File = "_treverse_backup.BUP",
 
399
    File2 = "traverse_backup2.BUP",
 
400
    File3 = "traverse_backup3.BUP",
 
401
    ?match(ok, mnesia:backup(File)),
 
402
            
 
403
    Fun = fun({backup_tab, N, _}, Acc) -> {[{backup_tab, N, test_ok}], Acc+1};
 
404
             (Other, Acc) -> {[Other], Acc}
 
405
          end,
 
406
 
 
407
    ?match({ok, 5}, mnesia:traverse_backup(File, read_only, Fun, 0)),
 
408
    ?match(ok, file:delete(read_only)),
 
409
    
 
410
    ?match({ok, 5}, mnesia:traverse_backup(File, mnesia_backup, 
 
411
                                           dummy, read_only, Fun, 0)),
 
412
 
 
413
    ?match({ok, 5}, mnesia:traverse_backup(File, File2, Fun, 0)),    
 
414
    ?match({ok, 5}, mnesia:traverse_backup(File2, mnesia_backup, 
 
415
                                           File3, mnesia_backup, Fun, 0)),
 
416
    
 
417
    BadFun = fun({bad_tab, _N, asd}, Acc) -> {{error, error}, Acc} end,    
 
418
    ?match({error, _}, mnesia:traverse_backup(File, read_only, BadFun, 0)),    
 
419
    ?match({error, _}, file:delete(read_only)),
 
420
    ?match(ok, file:delete(File)),
 
421
    ?match(ok, file:delete(File2)),
 
422
    ?match(ok, file:delete(File3)),
 
423
    ?verify_mnesia(Nodes, []).
 
424
 
 
425
 
 
426
install_fallback(doc) -> 
 
427
    ["This tests the install_fallback intf.",
 
428
     "It also verifies that the output from backup_checkpoint and traverse_backup",
 
429
     "is valid"];
 
430
install_fallback(suite) -> [];
 
431
install_fallback(Config) when is_list(Config) ->
 
432
    [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 
433
    Tab = fallbacks_test,
 
434
    Def = [{disc_copies, [Node1]}, {ram_copies, [Node2]}],
 
435
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),  
 
436
    ?match(ok, mnesia:dirty_write({Tab, 1, test_nok})),
 
437
    ?match(ok, mnesia:dirty_write({Tab, 2, test_nok})),
 
438
    ?match(ok, mnesia:dirty_write({Tab, 3, test_nok})),
 
439
    ?match(ok, mnesia:dirty_write({Tab, 4, test_nok})),
 
440
    ?match(ok, mnesia:dirty_write({Tab, 5, test_nok})),
 
441
 
 
442
    Tab2 = fallbacks_test2,
 
443
    Def2 = [{disc_copies, [node()]}],
 
444
    ?match({atomic, ok}, mnesia:create_table(Tab2, Def2)),  
 
445
    Tab3 = fallbacks_test3,
 
446
    ?match({atomic, ok}, mnesia:create_table(Tab3, Def2)),  
 
447
    Fun2 = fun(Key) ->
 
448
                  Rec = {Tab2, Key, test_ok},
 
449
                  mnesia:dirty_write(Rec),
 
450
                  [Rec]
 
451
          end,
 
452
    TabSize3 = 1000,
 
453
    OldRecs2 = [Fun2(K) || K <- lists:seq(1, TabSize3)],
 
454
    
 
455
    Spec =[{name, cp_name}, {max,  mnesia:system_info(tables)}],
 
456
    ?match({ok, _Name, Nodes}, mnesia:activate_checkpoint(Spec)),
 
457
    ?match(ok, mnesia:dirty_write({Tab, 6, test_nok})),
 
458
    [mnesia:dirty_write({Tab2, K, test_nok}) || K <- lists:seq(1, TabSize3 + 10)],
 
459
    File = "install_fallback.BUP",
 
460
    File2 = "install_fallback2.BUP",
 
461
    File3 = "install_fallback3.BUP",
 
462
    ?match(ok, mnesia:backup_checkpoint(cp_name, File)),
 
463
        
 
464
    Fun = fun({T, N, _}, Acc) when T == Tab ->
 
465
                  case N rem 2 of 
 
466
                      0 -> 
 
467
                          io:format("write ~p -> ~p~n", [N, T]),
 
468
                          {[{T, N, test_ok}], Acc + 1};
 
469
                      1 ->
 
470
                          io:format("write ~p -> ~p~n", [N, Tab3]),
 
471
                          {[{Tab3, N, test_ok}], Acc + 1}
 
472
                  end;
 
473
             ({T, N}, Acc) when T == Tab ->
 
474
                  case N rem 2 of 
 
475
                      0 -> 
 
476
                          io:format("delete ~p -> ~p~n", [N, T]),
 
477
                          {[{T, N}], Acc + 1};
 
478
                      1 ->
 
479
                          io:format("delete ~p -> ~p~n", [N, Tab3]),
 
480
                          {[{Tab3, N}], Acc + 1}
 
481
                  end;
 
482
             (Other, Acc) ->
 
483
                  {[Other], Acc}
 
484
          end,
 
485
    ?match({ok, _}, mnesia:traverse_backup(File, File2, Fun, 0)),
 
486
    ?match(ok, mnesia:install_fallback(File2)),
 
487
    
 
488
    mnesia_test_lib:kill_mnesia([Node1, Node2]),
 
489
    timer:sleep(timer:seconds(1)), % Let it die!
 
490
 
 
491
    ?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab, Tab2, Tab3])),
 
492
 
 
493
    % Verify 
 
494
    ?match([], mnesia:dirty_read({Tab, 1})),
 
495
    ?match([{Tab3, 1, test_ok}], mnesia:dirty_read({Tab3, 1})),
 
496
    ?match([{Tab, 2, test_ok}], mnesia:dirty_read({Tab, 2})),
 
497
    ?match([], mnesia:dirty_read({Tab3, 2})),
 
498
    ?match([], mnesia:dirty_read({Tab, 3})),
 
499
    ?match([{Tab3, 3, test_ok}], mnesia:dirty_read({Tab3, 3})),
 
500
    ?match([{Tab, 4, test_ok}], mnesia:dirty_read({Tab, 4})),
 
501
    ?match([], mnesia:dirty_read({Tab3, 4})),
 
502
    ?match([], mnesia:dirty_read({Tab, 5})),   
 
503
    ?match([{Tab3, 5, test_ok}], mnesia:dirty_read({Tab3, 5})),   
 
504
    ?match([], mnesia:dirty_read({Tab, 6})),   
 
505
    ?match([], mnesia:dirty_read({Tab3, 6})),   
 
506
    ?match([], [mnesia:dirty_read({Tab2, K}) || K <- lists:seq(1, TabSize3)] -- OldRecs2),
 
507
    ?match(TabSize3, mnesia:table_info(Tab2, size)),
 
508
 
 
509
    % Check the interface
 
510
    file:delete(File3),
 
511
    ?match({error, _}, mnesia:install_fallback(File3)),
 
512
    ?match({error, _}, mnesia:install_fallback(File2, mnesia_badmod)),
 
513
    ?match(ok, mnesia:install_fallback(File2, mnesia_backup)),
 
514
    ?match(ok, file:delete(File)),
 
515
    ?match(ok, file:delete(File2)),
 
516
    ?match({error, _}, file:delete(File3)),
 
517
    ?verify_mnesia(Nodes, []).
 
518
 
 
519
uninstall_fallback(suite) -> [];
 
520
uninstall_fallback(Config) when is_list(Config) ->
 
521
    [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 
522
    Tab = uinst_fallbacks_test,
 
523
    File = "uinst_fallback.BUP",
 
524
    File2 = "uinst_fallback2.BUP",
 
525
    Def = [{disc_copies, [Node1]}, {ram_copies, [Node2]}],
 
526
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),  
 
527
    ?match(ok, mnesia:dirty_write({Tab, 1, test_ok})),
 
528
    ?match(ok, mnesia:backup(File)),
 
529
    Fun = fun({T, N, _}, Acc) when T == Tab -> 
 
530
                  {[{T, N, test_nok}], Acc+1};
 
531
             (Other, Acc) -> {[Other], Acc}
 
532
          end,
 
533
    ?match({ok, _}, mnesia:traverse_backup(File, File2, Fun, 0)),
 
534
    ?match({error, enoent}, mnesia:uninstall_fallback()),
 
535
    ?match(ok, mnesia:install_fallback(File2)),
 
536
    ?match(ok, file:delete(File)),
 
537
    ?match(ok, file:delete(File2)),
 
538
    ?match(ok, mnesia:uninstall_fallback()),
 
539
    
 
540
    mnesia_test_lib:kill_mnesia([Node1, Node2]),
 
541
    timer:sleep(timer:seconds(1)), % Let it die!
 
542
    ?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab])),
 
543
    ?match([{Tab, 1, test_ok}], mnesia:dirty_read({Tab, 1})),
 
544
    ?verify_mnesia(Nodes, []).
 
545
 
 
546
local_fallback(suite) -> [];
 
547
local_fallback(Config) when is_list(Config) ->
 
548
    [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),
 
549
    Tab = local_fallback,
 
550
    File = "local_fallback.BUP",
 
551
    Def = [{disc_copies, Nodes}],
 
552
    Key = foo,
 
553
    Pre =  {Tab, Key, pre},
 
554
    Post =  {Tab, Key, post},
 
555
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),  
 
556
    ?match(ok, mnesia:dirty_write(Pre)),
 
557
    ?match(ok, mnesia:backup(File)),
 
558
    ?match(ok, mnesia:dirty_write(Post)),
 
559
    Local = [{scope, local}],
 
560
    ?match({error, enoent}, mnesia:uninstall_fallback(Local)),
 
561
    ?match(ok, mnesia:install_fallback(File, Local)),
 
562
    ?match(true, mnesia:system_info(fallback_activated)),
 
563
    ?match(ok, mnesia:uninstall_fallback(Local)),
 
564
    ?match(false, mnesia:system_info(fallback_activated)),
 
565
    ?match(ok, mnesia:install_fallback(File, Local)),
 
566
    ?match(true, mnesia:system_info(fallback_activated)),
 
567
    
 
568
    ?match(false, rpc:call(Node2, mnesia, system_info , [fallback_activated])),
 
569
    ?match(ok, rpc:call(Node2, mnesia, install_fallback , [File, Local])),
 
570
    ?match([Post], mnesia:dirty_read({Tab, Key})),
 
571
    ?match([Post], rpc:call(Node2, mnesia, dirty_read, [{Tab, Key}])),
 
572
 
 
573
    ?match([], mnesia_test_lib:kill_mnesia(Nodes)),
 
574
    ?match([], mnesia_test_lib:start_mnesia(Nodes, [Tab])),
 
575
    ?match([Pre], mnesia:dirty_read({Tab, Key})),
 
576
    ?match([Pre], rpc:call(Node2, mnesia, dirty_read, [{Tab, Key}])),
 
577
    Dir = rpc:call(Node2, mnesia, system_info , [directory]),
 
578
 
 
579
    ?match(ok, mnesia:dirty_write(Post)),
 
580
    ?match([Post], mnesia:dirty_read({Tab, Key})),
 
581
    ?match([], mnesia_test_lib:kill_mnesia([Node2])),
 
582
    ?match(ok, mnesia:install_fallback(File, Local ++ [{mnesia_dir, Dir}])),
 
583
    ?match([], mnesia_test_lib:kill_mnesia([Node1])),
 
584
    
 
585
    ?match([], mnesia_test_lib:start_mnesia([Node2], [])),
 
586
    ?match(yes, rpc:call(Node2, mnesia, force_load_table, [Tab])),
 
587
    ?match([], mnesia_test_lib:start_mnesia(Nodes, [Tab])), 
 
588
    ?match([Pre], mnesia:dirty_read({Tab, Key})),
 
589
   
 
590
    ?match(ok, file:delete(File)),  
 
591
    ?verify_mnesia(Nodes, []).
 
592
    
 
593
selective_backup_checkpoint(doc) -> 
 
594
    ["Perform a selective backup of a checkpoint"];
 
595
selective_backup_checkpoint(suite) -> [];
 
596
selective_backup_checkpoint(Config) when is_list(Config) ->
 
597
    [Node1, Node2] = Nodes = ?acquire_nodes(2, Config),    
 
598
    Tab = sel_backup,
 
599
    OmitTab = sel_backup_omit,
 
600
    CpName = sel_cp,
 
601
    Def = [{disc_copies, [Node1, Node2]}],
 
602
    File = "selective_backup_checkpoint.BUP",
 
603
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),    
 
604
    ?match({atomic, ok}, mnesia:create_table(OmitTab, Def)),    
 
605
    ?match(ok, mnesia:dirty_write({Tab, 1, test_ok})),
 
606
    ?match(ok, mnesia:dirty_write({OmitTab, 1, test_ok})),
 
607
    CpSpec = [{name, CpName}, {max,  mnesia:system_info(tables)}],
 
608
    ?match({ok, CpName, _Ns}, mnesia:activate_checkpoint(CpSpec)),
 
609
 
 
610
    BupSpec = [{tables, [Tab]}],
 
611
    ?match(ok, mnesia:backup_checkpoint(CpName, File, BupSpec)),
 
612
 
 
613
    ?match([schema, sel_backup], bup_tables(File, mnesia_backup)),
 
614
    ?match(ok, file:delete(File)),
 
615
 
 
616
    BupSpec2 = [{tables, [Tab, OmitTab]}],
 
617
    ?match(ok, mnesia:backup_checkpoint(CpName, File, BupSpec2)),
 
618
 
 
619
    ?match([schema, sel_backup, sel_backup_omit],
 
620
           bup_tables(File, mnesia_backup)),
 
621
    ?match(ok, file:delete(File)),
 
622
    ?verify_mnesia(Nodes, []).
 
623
 
 
624
bup_tables(File, Mod) ->
 
625
    Fun = fun(Rec, Tabs) ->
 
626
                  Tab = element(1, Rec),
 
627
                  Tabs2 = [Tab | lists:delete(Tab, Tabs)],
 
628
                  {[Rec], Tabs2}
 
629
          end,
 
630
    case mnesia:traverse_backup(File, Mod, dummy, read_only, Fun, []) of
 
631
        {ok, Tabs} ->
 
632
            lists:sort(Tabs);
 
633
        {error, Reason} ->
 
634
            exit(Reason)
 
635
    end.
 
636
 
 
637
incremental_backup_checkpoint(doc) -> 
 
638
    ["Perform a incremental backup of a checkpoint"];
 
639
incremental_backup_checkpoint(suite) -> [];
 
640
incremental_backup_checkpoint(Config) when is_list(Config) ->
 
641
    [Node1] = Nodes = ?acquire_nodes(1, Config),    
 
642
    Tab = incr_backup,
 
643
    Def = [{disc_copies, [Node1]}],
 
644
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),
 
645
    OldRecs = [{Tab, K, -K} || K <- lists:seq(1, 5)],
 
646
    ?match([ok|_], [mnesia:dirty_write(R) || R <- OldRecs]),
 
647
    OldCpName = old_cp,
 
648
    OldCpSpec = [{name, OldCpName}, {min,  [Tab]}],
 
649
    ?match({ok, OldCpName, _Ns}, mnesia:activate_checkpoint(OldCpSpec)),
 
650
 
 
651
    BupSpec = [{tables, [Tab]}],
 
652
    OldFile = "old_full_backup.BUP",
 
653
    ?match(ok, mnesia:backup_checkpoint(OldCpName, OldFile, BupSpec)),
 
654
    ?match(OldRecs, bup_records(OldFile, mnesia_backup)),
 
655
    ?match(ok, mnesia:dirty_delete({Tab, 1})),
 
656
    ?match(ok, mnesia:dirty_write({Tab, 2, 2})),
 
657
    ?match(ok, mnesia:dirty_write({Tab, 3, -3})),
 
658
 
 
659
    NewCpName = new_cp,
 
660
    NewCpSpec = [{name, NewCpName}, {min,  [Tab]}],
 
661
    ?match({ok, NewCpName, _Ns}, mnesia:activate_checkpoint(NewCpSpec)),
 
662
    ?match(ok, mnesia:dirty_write({Tab, 4, 4})),
 
663
 
 
664
    NewFile = "new_full_backup.BUP",
 
665
    ?match(ok, mnesia:backup_checkpoint(NewCpName, NewFile, BupSpec)),
 
666
    NewRecs = [{Tab, 2, 2}, {Tab, 3, -3},
 
667
               {Tab, 4, 4}, {Tab, 4}, {Tab, 4, -4}, {Tab, 5, -5}],
 
668
    ?match(NewRecs, bup_records(NewFile, mnesia_backup)),
 
669
 
 
670
    DiffFile = "diff_backup.BUP",
 
671
    DiffBupSpec = [{tables, [Tab]}, {incremental, OldCpName}],
 
672
    ?match(ok, mnesia:backup_checkpoint(NewCpName, DiffFile, DiffBupSpec)),
 
673
    DiffRecs = [{Tab, 1}, {Tab, 2}, {Tab, 2, 2}, {Tab, 3}, {Tab, 3, -3},
 
674
                {Tab, 4}, {Tab, 4, 4}, {Tab, 4}, {Tab, 4, -4}],
 
675
    ?match(DiffRecs, bup_records(DiffFile, mnesia_backup)),
 
676
 
 
677
    ?match(ok, mnesia:deactivate_checkpoint(OldCpName)),
 
678
    ?match(ok, mnesia:deactivate_checkpoint(NewCpName)),
 
679
    ?match(ok, file:delete(OldFile)),
 
680
    ?match(ok, file:delete(NewFile)),
 
681
    ?match(ok, file:delete(DiffFile)),
 
682
 
 
683
    ?verify_mnesia(Nodes, []).
 
684
 
 
685
bup_records(File, Mod) ->
 
686
    Fun = fun(Rec, Recs) when element(1, Rec) == schema ->
 
687
                  {[Rec], Recs};
 
688
             (Rec, Recs) ->
 
689
                  {[Rec], [Rec | Recs]}
 
690
          end,
 
691
    case mnesia:traverse_backup(File, Mod, dummy, read_only, Fun, []) of
 
692
        {ok, Recs} ->
 
693
            lists:keysort(1, lists:keysort(2, lists:reverse(Recs)));
 
694
        {error, Reason} ->
 
695
            exit(Reason)
 
696
    end.
 
697
 
 
698
sops_with_checkpoint(doc) -> 
 
699
    ["Test schema operations during a checkpoint"];
 
700
sops_with_checkpoint(suite) -> [];
 
701
sops_with_checkpoint(Config) when is_list(Config) ->
 
702
    Ns = ?acquire_nodes(2, Config),
 
703
    
 
704
    ?match({ok, cp1, Ns}, mnesia:activate_checkpoint([{name, cp1},{max,mnesia:system_info(tables)}])),
 
705
    Tab = tab, 
 
706
    ?match({atomic, ok}, mnesia:create_table(Tab, [{disc_copies,Ns}])),
 
707
    OldRecs = [{Tab, K, -K} || K <- lists:seq(1, 5)],
 
708
    [mnesia:dirty_write(R) || R <- OldRecs],
 
709
    
 
710
    ?match({ok, cp2, Ns}, mnesia:activate_checkpoint([{name, cp2},{max,mnesia:system_info(tables)}])),
 
711
    File1 = "cp1_delete_me.BUP",
 
712
    ?match(ok, mnesia:dirty_write({Tab,6,-6})),
 
713
    ?match(ok, mnesia:backup_checkpoint(cp1, File1)),
 
714
    ?match(ok, mnesia:dirty_write({Tab,7,-7})),
 
715
    File2 = "cp2_delete_me.BUP",
 
716
    ?match(ok, mnesia:backup_checkpoint(cp2, File2)),
 
717
    
 
718
    ?match(ok, mnesia:deactivate_checkpoint(cp1)),
 
719
    ?match(ok, mnesia:backup_checkpoint(cp2, File1)),
 
720
    ?match(ok, mnesia:dirty_write({Tab,8,-8})),
 
721
    
 
722
    ?match({atomic,ok}, mnesia:delete_table(Tab)),
 
723
    ?match({error,_}, mnesia:backup_checkpoint(cp2, File2)),
 
724
    ?match({'EXIT',_}, mnesia:dirty_write({Tab,9,-9})),
 
725
 
 
726
    ?match({atomic,_}, mnesia:restore(File1, [{default_op, recreate_tables}])), 
 
727
    Test = fun(N) when N > 5 -> ?error("To many records in backup ~p ~n", [N]);
 
728
              (N) -> case mnesia:dirty_read(Tab,N) of
 
729
                         [{Tab,N,B}] when -B =:= N -> ok;
 
730
                         Other -> ?error("Not matching ~p ~p~n", [N,Other])
 
731
                     end
 
732
           end,
 
733
    [Test(N) || N <- mnesia:dirty_all_keys(Tab)],
 
734
    ?match({aborted,enoent}, mnesia:restore(File2, [{default_op, recreate_tables}])), 
 
735
    
 
736
    file:delete(File1), file:delete(File2),
 
737
 
 
738
    ?verify_mnesia(Ns, []).