aboutsummaryrefslogblamecommitdiffstats
path: root/lib/kernel/test/wrap_log_reader_SUITE.erl
blob: 40a016aed0822688352d9ce971c04eb47ef04ee1 (plain) (tree)
1
2
3
4
5
6
7
8
9

                   
  
                                                        
  


                                                                   
  






                                                                           
  




                               
                       







                                             
                                           
                          
                                                            

       

                                                                    
                   



                                   



                    
                                                   
 


                                 
 
         

                                                        


                                        

                                                        
 





                         
                                     
           

                                    
           
 
 

                                  
 
                                   
       
 
                      
                                   
                                                      





                                 
                                                      
                                  
                                                      
                                  
                                                      




                       
 
                        
                                     




                                 
                            
           

                                               
                                  

                                                            

             

                                               
                                  
                                                            




                       
                         
                                      




                                 


                                                              

                   
                







                       





                                                                
                                  


                                                                  

       
 
                          
                                      




                                               



                                                            

                   
                







                       









                                                                        
                                  


                                                                 

       
 
                           
                                       




                                 


                            

                    
                







                       











                                                              
                                  




                                                                 

       
 
                                       
                                       




                                 



                                                              

                    
                







                       











                                                                
                                  




                                                                  

       
                                        
                                    




                                 



                            
                                                                             







                                                                    

                       



                            
                                                                             







                                                                    

                       











                                                                    




                       
                   
                                    




                                 


                                

                               

                                                            




                       
                    
                                 






                                  
                                                      
                               

                                                      
 

                            
               

                             
                               

                                                 

                       


                            
               




                                                                   
                             

                                                               
                             


                                                  

                       


                            


                                



                                                                    
                              

                                           
                                   
                                                  
                                  

                                                      





                       
                              
              
                              

         
                              






















                                                                  
                                                            
                       
                                                            
                       
                                                            
                       
                                                            



                        
                                                             
                       
                                                             
                       
                                                             
                       
                                                             










                                               
                             


                                          
                             


                                           
                                


                                              
                                


                           
                              


                                
                       

































                                               

                                                      




                    

                                                      





                

                                                     
        
 
        
                                                                               
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1998-2016. 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(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_lib("common_test/include/ct.hrl").
-define(format(S, A), ok).
-define(privdir(Conf), proplists:get_value(priv_dir, Conf)).
-endif.

-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
	 init_per_group/2,end_per_group/2,
	 no_file/1,
	 one_empty/1, one_filled/1,
	 two_filled/1,
	 four_filled/1,
	 wrap_filled/1,
	 wrapping/1,
	 external/1,
	 error/1]).

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

suite() ->
    [{ct_hooks,[ts_install_cth]},
     {timetrap,{minutes,1}}].

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

groups() -> 
    [{one, [], [one_empty, one_filled]},
     {two, [], [two_filled]}, {four, [], [four_filled]},
     {wrap, [], [wrap_filled]}].

init_per_suite(Config) ->
    Config.

end_per_suite(_Config) ->
    ok.

init_per_group(_GroupName, Config) ->
    Config.

end_per_group(_GroupName, Config) ->
    Config.


init_per_testcase(Func, Config) ->
    Config.

end_per_testcase(_Func, _Config) ->
    ok.

%% No log file exists.
no_file(Conf) when is_list(Conf) ->
    code:add_path(proplists:get_value(data_dir,Conf)),
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

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

    stop(),
    delete_files(File),
    ok.


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

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

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

    stop(),
    delete_files(File),
    ok.

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

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

    stop(),
    delete_files(File),
    ok.

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


%% 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(),

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

    stop(),
    delete_files(File),
    ok.

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


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

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

    stop(),
    delete_files(File),
    ok.

test_four(File) ->
    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),
    do_chunk([{open,File,1},
	      {chunk, ["first round, 11", "first round, 12"]},
	      eof], wlt, ?LINE),
    do_chunk([{open,File,4},
	      {chunk, ["first round, 41", "first round, 42"]},
	      eof], wlt, ?LINE),
    wlt ! {open, self(), File, 5},
    rec({error, {file_not_found, add_ext(File, 5)}}, ?LINE),
    do_chunk([{open,File,1}, {chunk, 1, ["first round, 11"]},
	      {chunk, 2, ["first round, 12"]}, eof], wlt, ?LINE),
    do_chunk([{open,File,4}, {chunk, 1, ["first round, 41"]},
	      {chunk, 2, ["first round, 42"]}, eof], wlt, ?LINE),
    ok.


%% 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(),

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

    stop(),
    delete_files(File),
    ok.

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

%% 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(),

    open(sune, File, ?LINE),
    init_files(1100),
    sync(sune),
    C1 =
	do_chunk([{open,File}, {chunk, 1, ["first round, 11"]}], wlt, ?LINE),
    log_terms(sune, ["second round, 11", "second round, 12"]),
    sync(sune),
    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),
    open(sune, File, ?LINE),
    init_files(1100),
    sync(sune),
    C2 =
	do_chunk([{open,File}, {chunk, 1, ["first round, 11"]}], wlt, ?LINE),
    log_terms(sune, ["second round, 11", "second round, 12"]),
    close(sune),
    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),
    open(sune, File, ?LINE),
    init_files(1100),
    sync(sune),
    C3 = do_chunk([{open,File}], wlt, ?LINE),
    log_terms(sune, ["second round, 11"]),
    sync(sune),
    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 format.
external(Conf) when is_list(Conf) ->
    Dir = ?privdir(Conf),
    File = join(Dir, "sune.LOG"),
    delete_files(File),
    start(),

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

    stop(),
    delete_files(File),
    ok.

%% 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},
    rec({error, {index_file_not_found, File}}, ?LINE),
    wlt ! {open, self(), File},
    rec({error, {index_file_not_found, File}}, ?LINE),
    true = (P0 == pps()),

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

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

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

    stop(),
    delete_files(File),
    ok.

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

stop() ->
    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) ->
    log_terms(sune, ["first round, 11", "first round, 12"]),
    timer:sleep(Delay),
    log_terms(sune, ["first round, 21", "first round, 22"]),
    timer:sleep(Delay),
    log_terms(sune, ["first round, 31", "first round, 32"]),
    timer:sleep(Delay),
    log_terms(sune, ["first round, 41", "first round, 42"]),
    timer:sleep(Delay),
    ok.

init_files_ext(Delay) ->
    blog_terms(sune, ["first round, 11", "first round, 12"]),
    timer:sleep(Delay),
    blog_terms(sune, ["first round, 21", "first round, 22"]),
    timer:sleep(Delay),
    blog_terms(sune, ["first round, 31", "first round, 32"]),
    timer:sleep(Delay),
    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},
    NC = rec1(ok, {W,?LINE}),
    do_chunk(Cs, S, W, NC);
do_chunk([{open, File} | Cs], S, W, _C) ->
    S ! {open, self(), File},
    NC = rec1(ok, {W,?LINE}),
    do_chunk(Cs, S, W, NC);
do_chunk([{chunk, Terms} | Cs], S, W, C) ->
    S ! {chunk, self(), C},
    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},
    NC = rec2(Terms, {W,?LINE}),
    do_chunk(Cs, S, W, NC);
do_chunk([eof], S, W, C) ->
    S ! {chunk, self(), C},
    C1 = rec2(eof, {W,?LINE}),
    do_chunk([close], S, W, C1);
do_chunk([close], S, W, C) ->
    S ! {close, self(), C},
    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 -> ct:fail({error, {Where, Else}})
    after 1000  -> ct:fail({error, {Where, time_out}})
    end.

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

rec(M, Where) ->
    receive 
        M ->
            ok;
        Else -> ct:fail({error, {Where, Else}})
    after 5000 -> ct:fail({error, {Where, time_out}})
    end.

pps() ->
    {erlang:ports(), lists:filter(fun erlang:is_process_alive/1, processes())}.