aboutsummaryrefslogblamecommitdiffstats
path: root/lib/kernel/test/wrap_log_reader_SUITE.erl
blob: a7d4e578d5b0910316f2620076c2e7a3642acbfa (plain) (tree)

















































                                                                         
                                                                      








                                       
                                   





















                                                            
                                     
























                                                                  
                                      



































                                                                        
                                      








































                                                                              
                                       











































                                                                       
                                       









































                                                                        
                                    





















































                                                                             
                                    


















                                                                  
                                 





































































































































































































                                                                            
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
%% 
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%% 
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%% 
%% %CopyrightEnd%
%%

-module(wrap_log_reader_SUITE).

%-define(debug, true).

-ifdef(debug).
-define(format(S, A), io:format(S, A)).
-define(line, put(line, ?LINE), ).
-define(privdir(_), "./disk_log_SUITE_priv").
-define(config(X,Y), foo).
-define(t,test_server).
-else.
-include("test_server.hrl").
-define(format(S, A), ok).
-define(privdir(Conf), ?config(priv_dir, Conf)).
-endif.

-export([all/1,
	 no_file/1,
	 one/1, one_empty/1, one_filled/1,
	 two/1, two_filled/1,
	 four/1, four_filled/1,
	 wrap/1, wrap_filled/1,
	 wrapping/1,
	 external/1,
	 error/1]).

-export([init_per_testcase/2, fin_per_testcase/2]).

all(suite) ->
    [no_file, one, two, four, wrap, wrapping, external, error].

init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
    Dog=?t:timetrap(?t:seconds(60)),
    [{watchdog, Dog} | Config].

fin_per_testcase(_Func, _Config) ->
    Dog=?config(watchdog, _Config),
    ?t:timetrap_cancel(Dog).

no_file(suite) -> [];
no_file(doc) -> ["No log file exists"];
no_file(Conf) when is_list(Conf) ->
    ?line code:add_path(?config(data_dir,Conf)),
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

    wlt ! {open, self(), File},
    ?line rec({error, {index_file_not_found, File}}, ?LINE),
    wlt ! {open, self(), File, 1},
    ?line rec({error, {index_file_not_found, File}}, ?LINE),
    wlt ! {open, self(), File, 4},
    ?line rec({error, {index_file_not_found, File}}, ?LINE),

    stop(),
    delete_files(File),
    ok.

one(suite) -> [one_empty, one_filled];
one(doc) -> ["One index file"].

one_empty(suite) -> [];
one_empty(doc) -> ["One empty index file"];
one_empty(Conf) when is_list(Conf) ->
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

    ?line open(sune, File, ?LINE),
    %% open
    ?line do_chunk([{open,File}, eof], wlt, ?LINE),
    ?line do_chunk([{open,File,1}, eof], wlt, ?LINE),
    wlt ! {open, self(), File, 2},
    ?line rec({error, {file_not_found, add_ext(File, 2)}}, ?LINE),
    ?line close(sune),

    %% closed
    ?line do_chunk([{open,File}, eof], wlt, ?LINE),
    ?line do_chunk([{open,File,1}, eof], wlt, ?LINE),
    wlt ! {open, self(), File, 2},
    ?line rec({error, {file_not_found, add_ext(File, 2)}}, ?LINE),

    stop(),
    delete_files(File),
    ok.

one_filled(suite) -> [];
one_filled(doc) -> ["One filled index file"];
one_filled(Conf) when is_list(Conf) ->
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

    ?line open(sune, File, ?LINE),
    ?line log_terms(sune, ["first round, one", "first round, two"]),
    ?line sync(sune),
    %% open
    test_one(File),
    ?line close(sune),
    %% closed
    test_one(File),

    stop(),
    delete_files(File),
    ok.

test_one(File) ->
    ?line do_chunk([{open,File}, 
		    {chunk, ["first round, one", "first round, two"]}, 
		    eof], wlt, ?LINE),
    ?line do_chunk([{open,File,1}, 
		    {chunk, ["first round, one", "first round, two"]}, 
		    eof], wlt, ?LINE),
    wlt ! {open, self(), File, 2},
    ?line rec({error, {file_not_found, add_ext(File, 2)}}, ?LINE),
    ?line do_chunk([{open,File,1}, {chunk, 1, ["first round, one"]}, 
		    {chunk, 1, ["first round, two"]}, eof], wlt, ?LINE),
    ok.

two(suite) -> [two_filled];
two(doc) -> ["Two index files"].

two_filled(suite) -> [];
two_filled(doc) -> ["Two filled index files"];
two_filled(Conf) when is_list(Conf) ->
    Dir = ?privdir(Conf),
    File = list_to_atom(join(Dir, "sune.LOG")),
    delete_files(File),
    start(),

    ?line open(sune, File, ?LINE),
    ?line log_terms(sune, ["first round, 11", "first round, 12"]),
    ?line log_terms(sune, ["first round, 21", "first round, 22"]),
    ?line sync(sune),
    %% open
    test_two(File),
    ?line close(sune),
    %% closed
    test_two(File),

    stop(),
    delete_files(File),
    ok.

test_two(File) ->
    ?line do_chunk([{open,File}, 
		    {chunk, infinity, ["first round, 11", "first round, 12"]},
		    {chunk, ["first round, 21", "first round, 22"]},
		    eof], wlt, ?LINE),
    ?line do_chunk([{open,File,1}, 
		    {chunk, ["first round, 11", "first round, 12"]},
		    eof], wlt, ?LINE),
    ?line do_chunk([{open,File,2}, 
		    {chunk, ["first round, 21", "first round, 22"]},
		    eof], wlt, ?LINE),
    wlt ! {open, self(), File, 3},
    ?line rec({error, {file_not_found, add_ext(File, 3)}}, ?LINE),
    ?line do_chunk([{open,File,1}, {chunk, 1, ["first round, 11"]},
		    {chunk, 2, ["first round, 12"]}, eof], wlt, ?LINE),
    ok.

four(suite) -> [four_filled];
four(doc) -> ["Four index files"].

four_filled(suite) -> [];
four_filled(doc) -> ["Four filled index files"];
four_filled(Conf) when is_list(Conf) ->
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

    ?line open(sune, File, ?LINE),
    ?line init_files(0),
    ?line sync(sune),
    %% open
    test_four(File),
    ?line close(sune),
    %% closed
    test_four(File),

    stop(),
    delete_files(File),
    ok.

test_four(File) ->
    ?line do_chunk([{open,File}, 
		    {chunk, ["first round, 11", "first round, 12"]},
		    {chunk, ["first round, 21", "first round, 22"]},
		    {chunk, ["first round, 31", "first round, 32"]},
		    {chunk, ["first round, 41", "first round, 42"]},
		    eof], wlt, ?LINE),
    ?line do_chunk([{open,File,1}, 
		    {chunk, ["first round, 11", "first round, 12"]},
		    eof], wlt, ?LINE),
    ?line do_chunk([{open,File,4}, 
		    {chunk, ["first round, 41", "first round, 42"]},
		    eof], wlt, ?LINE),
    wlt ! {open, self(), File, 5},
    ?line rec({error, {file_not_found, add_ext(File, 5)}}, ?LINE),
    ?line do_chunk([{open,File,1}, {chunk, 1, ["first round, 11"]},
		    {chunk, 2, ["first round, 12"]}, eof], wlt, ?LINE),
    ?line do_chunk([{open,File,4}, {chunk, 1, ["first round, 41"]},
		    {chunk, 2, ["first round, 42"]}, eof], wlt, ?LINE),
    ok.

wrap(suite) -> [wrap_filled];
wrap(doc) -> ["Wrap index file, first wrapping"].

wrap_filled(suite) -> [];
wrap_filled(doc) -> ["First wrap, open, filled index file"];
wrap_filled(Conf) when is_list(Conf) ->
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

    ?line open(sune, File, ?LINE),
    ?line init_files(0),
    ?line log_terms(sune, ["second round, 11", "second round, 12"]),
    ?line sync(sune),
    %% open
    test_wrap(File),
    ?line close(sune),
    %% closed
    test_wrap(File),

    stop(),
    delete_files(File),
    ok.

test_wrap(File) ->
    ?line do_chunk([{open,File}, 
		    {chunk, ["first round, 21", "first round, 22"]},
		    {chunk, ["first round, 31", "first round, 32"]},
		    {chunk, ["first round, 41", "first round, 42"]},
		    {chunk, ["second round, 11", "second round, 12"]},
		    eof], wlt, ?LINE),
    ?line do_chunk([{open,File,1}, 
		    {chunk, ["second round, 11", "second round, 12"]},
		    eof], wlt, ?LINE),
    ?line do_chunk([{open,File,2}, 
		    {chunk, ["first round, 21", "first round, 22"]},
		    eof], wlt, ?LINE),
    wlt ! {open, self(), File, 5},
    ?line rec({error, {file_not_found, add_ext(File, 5)}}, ?LINE),
    ?line do_chunk([{open,File,1}, {chunk, 1, ["second round, 11"]},
		    {chunk, 2, ["second round, 12"]}, eof], wlt, ?LINE),
    ?line do_chunk([{open,File,4}, {chunk, 1, ["first round, 41"]},
		    {chunk, 2, ["first round, 42"]}, eof], wlt, ?LINE),
    ok.

wrapping(suite) -> [];
wrapping(doc) -> ["Wrapping at the same time as reading"];
wrapping(Conf) when is_list(Conf) ->
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

    ?line open(sune, File, ?LINE),
    ?line init_files(1100),
    ?line sync(sune),
    ?line C1 = 
	do_chunk([{open,File}, {chunk, 1, ["first round, 11"]}], wlt, ?LINE),
    ?line log_terms(sune, ["second round, 11", "second round, 12"]),
    ?line sync(sune),
    ?line do_chunk([{chunk, 1, ["first round, 12"]}, 
		    %% Here two bad bytes are found.
		    {chunk, ["first round, 21", "first round, 22"]},
		    {chunk, ["first round, 31", "first round, 32"]},
		    {chunk, ["first round, 41", "first round, 42"]}, eof],
		   wlt, ?LINE, C1),
    start(),
    delete_files(File),
    ?line open(sune, File, ?LINE),
    ?line init_files(1100),
    ?line sync(sune),
    ?line C2 = 
	do_chunk([{open,File}, {chunk, 1, ["first round, 11"]}], wlt, ?LINE),
    ?line log_terms(sune, ["second round, 11", "second round, 12"]),
    ?line close(sune),
    ?line do_chunk([{chunk, 1, ["first round, 12"]}, 
		    %% Here two bad bytes are found.
		    {chunk, ["first round, 21", "first round, 22"]},
		    {chunk, ["first round, 31", "first round, 32"]},
		    {chunk, ["first round, 41", "first round, 42"]}, eof],
		   wlt, ?LINE, C2),
    start(),
    delete_files(File),
    ?line open(sune, File, ?LINE),
    ?line init_files(1100),
    ?line sync(sune),
    ?line C3 = do_chunk([{open,File}], wlt, ?LINE),
    ?line log_terms(sune, ["second round, 11"]),
    ?line sync(sune),
    ?line do_chunk([{chunk, 1, ["second round, 11"]}, 
		    {chunk, 1, ["first round, 21"]},
		    {chunk, 1, ["first round, 22"]}, 
		    {chunk, ["first round, 31", "first round, 32"]},
		    {chunk, ["first round, 41", "first round, 42"]}, eof],
		   wlt, ?LINE, C3),

    stop(),
    delete_files(File),
    ok.

external(suite) -> [];
external(doc) -> ["External format"];
external(Conf) when is_list(Conf) ->
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

    ?line open_ext(sune, File, ?FILE),
    ?line init_files_ext(0),
    ?line close(sune),
    P0 = pps(),
    wlt ! {open, self(), File},
    ?line rec({error, {not_a_log_file, add_ext(File, 1)}}, ?LINE),
    ?line true = (P0 == pps()),    

    stop(),
    delete_files(File),
    ok.

error(suite) -> [];
error(doc) -> ["Error situations"];
error(Conf) when is_list(Conf) ->
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

    P0 = pps(),
    wlt ! {open, self(), File, 1},
    ?line rec({error, {index_file_not_found, File}}, ?LINE),
    wlt ! {open, self(), File},
    ?line rec({error, {index_file_not_found, File}}, ?LINE),
    ?line true = (P0 == pps()),

    ?line open(sune, File, ?LINE),
    ?line close(sune),
    P1 = pps(),
    ?line First = add_ext(File, 1),
    ?line ok = file:delete(First),
    wlt ! {open, self(), File},
    ?line rec({error, {not_a_log_file, First}}, ?LINE),
    ?line true = (P1 == pps()),

    delete_files(File),
    ?line open(sune, File, ?LINE),
    ?line init_files(0),
    ?line close(sune),
    P2 = pps(),
    ?line C = do_chunk([{open,File}, 
			{chunk, ["first round, 11", "first round, 12"]}],
		       wlt, ?LINE),
    ?line Second = add_ext(File, 2),
    ?line ok = file:delete(Second),
    wlt ! {chunk, self(), C},
    ?line rec({error, {file_error, Second, {error, enoent}}}, ?LINE),
    ?line ok = file:write_file(Second, <<17:(3*8)>>), % three bytes
    wlt ! {chunk, self(), C},
    ?line rec({error, {not_a_log_file, Second}}, ?LINE),
    ?line do_chunk([close], wlt, ?LINE, C),
    ?line true = (P2 == pps()),

    delete_files(File),
    ?line open(sune, File, ?LINE),
    ?line init_files(0),
    ?line close(sune),
    P3 = pps(),
    timer:sleep(1100),
    Now = calendar:local_time(),
    ?line ok = file:change_time(First, Now),
    ?line C2 = do_chunk([{open,File}, 
			 {chunk, ["first round, 11", "first round, 12"]}],
			wlt, ?LINE),
    wlt ! {chunk, self(), C2},
    ?line rec({error,{is_wrapped,First}}, ?LINE),
    ?line do_chunk([close], wlt, ?LINE, C2),
    IndexFile = add_ext(File, idx),
    ?line ok = file:write_file(IndexFile, <<17:(3*8)>>),
    wlt ! {open, self(), File, 1},
    ?line rec({error, {index_file_not_found, File}}, ?LINE),
    ?line true = (P3 == pps()),

    stop(),
    delete_files(File),
    ok.

start() ->
    ?line ok = wrap_log_test:stop(),
    dl_wait(),
    ?line ok = wrap_log_test:init().

stop() ->
    ?line ok = wrap_log_test:stop(),
    dl_wait().

%% Give disk logs opened by 'logger' and 'wlt' time to close after
%% receiving EXIT signals.
dl_wait() ->
    case disk_log:accessible_logs() of
        {[], []} ->
            ok;
        _ ->
            timer:sleep(100),
            dl_wait()
    end.

delete_files(File) ->
    file:delete(add_ext(File, idx)),
    file:delete(add_ext(File, siz)),
    file:delete(add_ext(File, 1)),
    file:delete(add_ext(File, 2)),
    file:delete(add_ext(File, 3)),
    file:delete(add_ext(File, 4)),
    ok.

init_files(Delay) ->
    ?line log_terms(sune, ["first round, 11", "first round, 12"]),
    timer:sleep(Delay),
    ?line log_terms(sune, ["first round, 21", "first round, 22"]),
    timer:sleep(Delay),
    ?line log_terms(sune, ["first round, 31", "first round, 32"]),
    timer:sleep(Delay),
    ?line log_terms(sune, ["first round, 41", "first round, 42"]),
    timer:sleep(Delay),
    ok.

init_files_ext(Delay) ->
    ?line blog_terms(sune, ["first round, 11", "first round, 12"]),
    timer:sleep(Delay),
    ?line blog_terms(sune, ["first round, 21", "first round, 22"]),
    timer:sleep(Delay),
    ?line blog_terms(sune, ["first round, 31", "first round, 32"]),
    timer:sleep(Delay),
    ?line blog_terms(sune, ["first round, 41", "first round, 42"]),
    timer:sleep(Delay),
    ok.

join(A, B) ->
    filename:nativename(filename:join(A, B)).

do_chunk(Commands, Server, Where) ->
    do_chunk(Commands, Server, Where, foo).

do_chunk([{open, File, One} | Cs], S, W, _C) ->
    S ! {open, self(), File, One},
    ?line NC = rec1(ok, {W,?LINE}),
    do_chunk(Cs, S, W, NC);
do_chunk([{open, File} | Cs], S, W, _C) ->
    S ! {open, self(), File},
    ?line NC = rec1(ok, {W,?LINE}),
    do_chunk(Cs, S, W, NC);
do_chunk([{chunk, Terms} | Cs], S, W, C) ->
    S ! {chunk, self(), C},
    ?line NC = rec2(Terms, {W,?LINE}),
    do_chunk(Cs, S, W, NC);
do_chunk([{chunk, N, Terms} | Cs], S, W, C) ->
    S ! {chunk, self(), C, N},
    ?line NC = rec2(Terms, {W,?LINE}),
    do_chunk(Cs, S, W, NC);
do_chunk([eof], S, W, C) ->
    S ! {chunk, self(), C},
    ?line C1 = rec2(eof, {W,?LINE}),
    do_chunk([close], S, W, C1);
do_chunk([close], S, W, C) ->
    S ! {close, self(), C},
    ?line rec(ok, {W,?LINE});
do_chunk([], _S, _W, C) ->
    C.

add_ext(Name, Ext) ->
    lists:concat([Name, ".", Ext]).

%% disk_log.
open(Log, File, Where) ->
    logger ! {open, self(), Log, File},
    rec1(ok, Where).

open_ext(Log, File, Where) ->
    logger ! {open_ext, self(), Log, File},
    rec1(ok, Where).

close(Log) ->
    logger ! {close, self(), Log},
    rec(ok, ?LINE).

sync(Log) ->
    logger ! {sync, self(), Log},
    rec(ok, ?LINE).

log_terms(File, Terms) ->
    logger ! {log_terms, self(), File, Terms},
    rec(ok, ?LINE).

blog_terms(File, Terms) ->
    logger ! {blog_terms, self(), File, Terms},
    rec(ok, ?LINE).

rec1(M, Where) ->
    receive 
        {M, C} -> C;
        Else -> test_server:fail({error, {Where, Else}})
    after 1000  -> test_server:fail({error, {Where, time_out}})
    end.

rec2(M, Where) ->
    receive 
        {C, M} -> C;
        Else -> test_server:fail({error, {Where, Else}})
    after 1000  -> test_server:fail({error, {Where, time_out}})
    end.

rec(M, Where) ->
    receive 
        M ->
            ok;
        Else -> ?t:fail({error, {Where, Else}})
    after 1000 -> ?t:fail({error, {Where, time_out}})
    end.
	    
pps() ->
    {erlang:ports(), lists:filter({erlang, is_process_alive}, processes())}.