mnesia_rocksdb/test/mnesia_rocksdb_error_handling.erl
2019-11-18 16:43:08 +01:00

117 lines
3.6 KiB
Erlang

-module(mnesia_rocksdb_error_handling).
-export([run/0,
run/4]).
run() ->
setup(),
%% run only one test for 'fatal', to save time.
[run(Type, Op, L, MaintainSz) || MaintainSz <- [false, true],
Type <- [set, bag],
Op <- [insert, update, delete],
L <- levels()]
++ [run(set, insert, fatal, false)].
run(Type, Op, Level, MaintainSz) ->
setup(),
{ok, Tab} = create_tab(Type, Level, MaintainSz),
mnesia:dirty_write({Tab, a, 1}), % pre-existing data
with_mock(Level, Op, Tab, fun() ->
try_write(Op, Type, Tab),
expect_error(Level, Tab)
end).
levels() ->
[debug, verbose, warning, error].
setup() ->
mnesia:stop(),
start_mnesia().
create_tab(Type, Level, MaintainSz) ->
TabName = tab_name(Type, Level, MaintainSz),
%% create error store before the table
case ets:info(?MODULE) of
undefined ->
?MODULE = ets:new(?MODULE, [bag, public, named_table]),
ok;
_ ->
ok
end,
UserProps = user_props(Level, MaintainSz),
{atomic, ok} = mnesia:create_table(TabName, [{rdb, [node()]},
{user_properties, UserProps}]),
{ok, TabName}.
tab_name(Type, Level, MaintainSz) ->
binary_to_atom(iolist_to_binary(
["t" | [["_", atom_to_list(A)]
|| A <- [?MODULE, Type, Level, MaintainSz]]]), utf8).
user_props(Level, MaintainSz) ->
[{maintain_sz, MaintainSz},
{rocksdb_opts, [ {on_write_error, Level}
, {on_write_error_store, ?MODULE} ]}].
start_mnesia() ->
mnesia_rocksdb_tlib:start_mnesia(reset),
ok.
with_mock(Level, Op, Tab, F) ->
mnesia:subscribe(system),
mnesia:set_debug_level(debug),
meck:new(mnesia_rocksdb_lib, [passthrough]),
meck:expect(mnesia_rocksdb_lib, put, 4, {error, some_put_error}),
meck:expect(mnesia_rocksdb_lib, write, 3, {error, some_write_error}),
meck:expect(mnesia_rocksdb_lib, delete, 3, {error,some_delete_error}),
try {Level, Op, Tab, F()} of
{_, _, _, ok} ->
ok;
Other ->
io:fwrite("OTHER: ~p~n", [Other]),
ok
catch
exit:{{aborted,_},_} ->
Level = error,
ok
after
mnesia:set_debug_level(none),
mnesia:unsubscribe(system),
meck:unload(mnesia_rocksdb_lib)
end.
try_write(insert, set, Tab) ->
mnesia:dirty_write({Tab, b, 2});
try_write(insert, bag, Tab) ->
mnesia:dirty_write({Tab, a, 2});
try_write(update, _, Tab) ->
mnesia:dirty_write({Tab, a, 1});
try_write(delete, _, Tab) ->
mnesia:dirty_delete({Tab, a}).
expect_error(Level, Tab) ->
Tag = rpt_tag(Level),
receive
{mnesia_system_event, {mnesia_fatal, Fmt, Args, _Core}} ->
Tag = mnesia_fatal,
io:fwrite("EVENT(~p, ~p):~n ~s", [Tag, Tab, io_lib:fwrite(Fmt, Args)]),
ok;
{mnesia_system_event, {Tag, Fmt, Args}} ->
io:fwrite("EVENT(~p, ~p):~n ~s", [Tag, Tab, io_lib:fwrite(Fmt, Args)]),
ok
after 1000 ->
error({expected_error, [Level, Tab]})
end,
%% Also verify that an error entry has been written into the error store.
1 = ets:select_delete(?MODULE, [{{{Tab, '_'}, '_', '_'}, [], [true]}]),
ok.
rpt_tag(fatal ) -> mnesia_fatal;
rpt_tag(error ) -> mnesia_error;
rpt_tag(warning) -> mnesia_warning;
rpt_tag(verbose) -> mnesia_info;
rpt_tag(debug ) -> mnesia_info.