%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%

%%
-module(mnesia_nice_coverage_test).
-author('hakan@erix.ericsson.se').

-export([init_per_testcase/2, end_per_testcase/2,
         init_per_group/2, end_per_group/2,
         all/0, groups/0]).

-export([nice/1]).

-include("mnesia_test_lib.hrl").

-record(nice_tab, {key, val}).

init_per_testcase(Func, Conf) ->
    mnesia_test_lib:init_per_testcase(Func, Conf).

end_per_testcase(Func, Conf) ->
    mnesia_test_lib:end_per_testcase(Func, Conf).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
all() -> 
    [nice].

groups() -> 
    [].

init_per_group(_GroupName, Config) ->
    Config.

end_per_group(_GroupName, Config) ->
    Config.


nice(doc) -> [""];
nice(suite) -> [];
nice(Config) when is_list(Config) ->
    %% The whole test suite is one huge test case for the time beeing
    
    [Node1, Node2] = Nodes = ?acquire_nodes(2, Config), 
    Attrs = record_info(fields, nice_tab), 
    
    initialize(Attrs, Node1), 
    dirty_access(Node1), 
    success_and_fail(), 
    index_mgt(), 
    
    adm(Attrs, Node1, Node2), 
    snmp(Node1, Node2), 
    backup(Node1), 
    ?verify_mnesia(Nodes, []).

initialize(Attrs, Node1) ->
    ?match(Version when is_list(Version), mnesia:system_info(version)), 

    Schema = [{name, nice_tab}, 
	      {attributes, Attrs}, {ram_copies, [Node1]}], 

    ?match({_, _}, mnesia:system_info(schema_version)), 
    ?match({atomic, ok}, mnesia:create_table(Schema)), 

    ?match(ok, mnesia:info()), 
    ?match(set, mnesia:table_info(nice_tab, type)), 
    ?match(ok, mnesia:schema()), 
    ?match(ok, mnesia:schema(nice_tab)),
    ok.

dirty_access(Node1) ->
    TwoThree = #nice_tab{key=23, val=23}, 
    TwoFive  = #nice_tab{key=25, val=25}, 
    ?match([], mnesia:dirty_slot(nice_tab, 0)), 
    ?match(ok, mnesia:dirty_write(TwoThree)), 
    ?match([TwoThree], mnesia:dirty_read({nice_tab, 23})), 
    ?match(ok, mnesia:dirty_write(TwoFive)), 
    ?match(ok, mnesia:dirty_delete_object(TwoFive)), 

    ?match(23, mnesia:dirty_first(nice_tab)), 
    ?match('$end_of_table', mnesia:dirty_next(nice_tab, 23)), 
    ?match([TwoThree], mnesia:dirty_match_object(TwoThree)), 
    ?match(ok, mnesia:dirty_delete({nice_tab, 23})), 

    CounterSchema = [{ram_copies, [Node1]}], 
    ?match({atomic, ok}, mnesia:create_table(nice_counter_tab, CounterSchema)), 
    TwoFour  = {nice_counter_tab, 24, 24}, 
    ?match(ok, mnesia:dirty_write(TwoFour)), 
    ?match(34, mnesia:dirty_update_counter({nice_counter_tab, 24}, 10)), 
    TF = {nice_counter_tab, 24, 34}, 
    ?match([TF], mnesia:dirty_read({nice_counter_tab, 24})), 
    ?match(ok, mnesia:dirty_delete({nice_counter_tab, 24})), 
    ?match(ok, mnesia:dirty_delete_object(TF)),
    ok.

success_and_fail() ->
    ?match({atomic, a_good_trans}, mnesia:transaction(fun() ->good_trans()end)), 

    BadFun =
	fun() ->
		Two = #nice_tab{key=2, val=12}, 
		?match([Two], mnesia:match_object(#nice_tab{key='$1', val=12})), 
		?match([#nice_tab{key=3, val=13}], mnesia:wread({nice_tab, 3})), 
		?match(ok, mnesia:delete({nice_tab, 1})), 
		?match(ok, mnesia:delete_object(Two)), 
		mnesia:abort(bad_trans), 
		?match(bad, trans)
	end, 
    ?match({aborted, bad_trans}, mnesia:transaction(BadFun)), 
    ?match(L when is_list(L), mnesia:error_description(no_exists)), 
    ?match({atomic, ok}, mnesia:transaction(fun(A) -> lock(), A end, [ok])), 
    ?match({atomic, ok}, mnesia:transaction(fun(A) -> lock(), A end, [ok], 3)),
    ok.

good_trans() ->
    ?match([], mnesia:read(nice_tab, 3)), 
    ?match([], mnesia:read({nice_tab, 3})), 
    ?match(ok, mnesia:write(#nice_tab{key=14, val=4})), 
    ?match([14], mnesia:all_keys(nice_tab)), 

    Records = [ #nice_tab{key=K, val=K+10} || K <- lists:seq(1, 10) ], 
    Ok = [ ok || _ <- Records], 
    ?match(Ok, lists:map(fun(R) -> mnesia:write(R) end, Records)), 
    a_good_trans.


lock() ->
    ?match(ok, mnesia:s_write(#nice_tab{key=22, val=22})), 
    ?match(ok, mnesia:read_lock_table(nice_tab)), 
    ?match(ok, mnesia:write_lock_table(nice_tab)),
    ok.

index_mgt() ->
    UniversalRec = #nice_tab{key=4711, val=4711}, 
    ?match(ok, mnesia:dirty_write(UniversalRec)), 
    ValPos = #nice_tab.val, 
    ?match({atomic, ok}, mnesia:add_table_index(nice_tab, ValPos)), 

    IndexFun =
	fun() ->
		?match([UniversalRec], 
		       mnesia:index_read(nice_tab, 4711, ValPos)), 
		Pat = #nice_tab{key='$1', val=4711}, 
		?match([UniversalRec], 
		       mnesia:index_match_object(Pat, ValPos)), 
		index_trans
	end, 
    ?match({atomic, index_trans}, mnesia:transaction(IndexFun, infinity)), 
    ?match([UniversalRec], 
	   mnesia:dirty_index_read(nice_tab, 4711, ValPos)), 
    ?match([UniversalRec], 
	   mnesia:dirty_index_match_object(#nice_tab{key='$1', val=4711}, ValPos)), 

    ?match({atomic, ok}, mnesia:del_table_index(nice_tab, ValPos)),
    ok.

adm(Attrs, Node1, Node2) ->
    This = node(), 
    ?match({ok, This}, mnesia:subscribe(system)), 
    ?match({atomic, ok}, 
	   mnesia:add_table_copy(nice_tab, Node2, disc_only_copies)), 
    ?match({atomic, ok}, 
	   mnesia:change_table_copy_type(nice_tab, Node2, ram_copies)), 
    ?match({atomic, ok}, mnesia:del_table_copy(nice_tab, Node1)), 
    ?match(stopped, rpc:call(Node1, mnesia, stop, [])), 
    ?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [nice_tab])), 
    ?match(ok, mnesia:wait_for_tables([schema], infinity)), 

    Transformer = fun(Rec) ->
			  list_to_tuple(tuple_to_list(Rec) ++ [initial_value])
		  end, 
    ?match({atomic, ok}, 
	   mnesia:transform_table(nice_tab, Transformer, Attrs ++ [extra])), 

    ?match({atomic, ok}, mnesia:delete_table(nice_tab)), 
    DumpSchema = [{name, nice_tab}, {attributes, Attrs}, {ram_copies, [Node2]}], 
    ?match({atomic, ok}, mnesia:create_table(DumpSchema)), 
    ?match({atomic, ok}, mnesia:dump_tables([nice_tab])), 
    ?match({atomic, ok}, mnesia:move_table_copy(nice_tab, Node2, Node1)), 

    ?match(yes, mnesia:force_load_table(nice_counter_tab)), 
    ?match(ok, mnesia:sync_log()),
    ?match(dumped, mnesia:dump_log()),
    ok.

backup(Node1) ->
    Tab = backup_nice,
    Def = [{disc_copies, [Node1]}], 
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),    
    ?match({ok,_,_}, mnesia:activate_checkpoint([{name, cp}, {max, [Tab]}])), 
    File = "nice_backup.BUP",
    File2 = "nice_backup2.BUP",
    File3 = "nice_backup3.BUP",
    ?match(ok, mnesia:backup_checkpoint(cp, File)), 
    ?match(ok, mnesia:backup_checkpoint(cp, File, mnesia_backup)), 
    ?match(ok, mnesia:deactivate_checkpoint(cp)), 
    ?match(ok, mnesia:backup(File)), 
    ?match(ok, mnesia:backup(File, mnesia_backup)), 

    Fun = fun(X, Acc) -> {[X], Acc} end,
    ?match({ok, 0}, mnesia:traverse_backup(File, File2, Fun, 0)), 
    ?match({ok, 0}, mnesia:traverse_backup(File, mnesia_backup, dummy, read_only, Fun, 0)), 
    ?match(ok, mnesia:install_fallback(File)), 
    ?match(ok, mnesia:uninstall_fallback()), 
    ?match(ok, mnesia:install_fallback(File, mnesia_backup)), 
    ?match(ok, mnesia:dump_to_textfile(File3)), 
    ?match({atomic, ok}, mnesia:load_textfile(File3)),
    ?match(ok, file:delete(File)),
    ?match(ok, file:delete(File2)),
    ?match(ok, file:delete(File3)),
    ok.

snmp(Node1, Node2) ->
    Tab = nice_snmp, 
    Def = [{disc_copies, [Node1]}, {ram_copies, [Node2]}], 
    ?match({atomic, ok}, mnesia:create_table(Tab, Def)),
    ?match({aborted, {badarg, Tab, _}}, mnesia:snmp_open_table(Tab, [])),
    ?match({atomic, ok}, mnesia:snmp_open_table(Tab, [{key, integer}])),
    ?match(endOfTable, mnesia:snmp_get_next_index(Tab, [0])), 
    ?match(undefined, mnesia:snmp_get_row(Tab, [0])), 
    ?match(undefined, mnesia:snmp_get_mnesia_key(Tab, [0])), 
    ?match({atomic, ok}, mnesia:snmp_close_table(Tab)),
    ok.

