aboutsummaryrefslogblamecommitdiffstats
path: root/erts/emulator/test/nif_SUITE.erl
blob: e47161fcbc815e3613899a919cba9813326f580a (plain) (tree)

























                                                                              
                                       
 
                             


                                        
                                                               

























































































































































                                                                                                          




































                                                                         
 











                                                                                                                                                                                                                                                                                                                                  



                                                                   
                                                                       





                                                                        
                                                                          
































                                                                         



                                 
                                                                                                                                                                                                                                    


                                                    
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 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(nif_SUITE).

%%-define(line_trace,true).

-include("test_server.hrl").

-export([all/1, fin_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1,
	 types/1, many_args/1, neg/1]).

-export([many_args_100/100]).
-define(nif_stub,nif_stub_error(?LINE)).

all(suite) ->
    [basic, reload, upgrade, heap_frag, types, many_args, neg].

fin_per_testcase(_Func, _Config) ->
    P1 = code:purge(nif_mod),
    Del = code:delete(nif_mod),
    P2 = code:purge(nif_mod),
    io:format("fin purged=~p, deleted=~p and then purged=~p\n",[P1,Del,P2]).

basic(doc) -> ["Basic smoke test of load_nif and a simple NIF call"];
basic(suite) -> [];
basic(Config) when is_list(Config) ->
    ensure_lib_loaded(Config),
    ?line true = (lib_version() =/= undefined),
    ?line [{load,1,1,101},{lib_version,1,2,102}] = call_history(),
    ?line [] = call_history(),
    ?line [?MODULE] = erlang:system_info(taints),
    ok.

reload(doc) -> ["Test reload callback in nif lib"];
reload(suite) -> [];  
reload(Config) when is_list(Config) ->    
    ensure_lib_loaded(Config),

    ?line Data = ?config(data_dir, Config),
    ?line File = filename:join(Data, "nif_mod"),
    ?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]),
    ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin),

    ?line nif_mod:load_nif_lib(Config, 1),

    ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()),
    ?line [{load,1,1,101},{get_priv_data_ptr,1,2,102}] = nif_mod_call_history(),    
        
    ?line nif_mod:load_nif_lib(Config, 2),
    ?line 2 = nif_mod:lib_version(),
    ?line [{reload,2,1,201},{lib_version,2,2,202}] = nif_mod_call_history(),    

    ?line nif_mod:load_nif_lib(Config, 1),
    ?line 1 = nif_mod:lib_version(),
    ?line [{reload,1,1,101},{lib_version,1,2,102}] = nif_mod_call_history(),    

    ?line true = erlang:delete_module(nif_mod),
    ?line [] = nif_mod_call_history(),    

    %%?line false= check_process_code(Pid, nif_mod),
    ?line true = erlang:purge_module(nif_mod),
    ?line [{unload,1,3,103}] = nif_mod_call_history(),    

    ?line [?MODULE, nif_mod] = erlang:system_info(taints),
    ok.

upgrade(doc) -> ["Test upgrade callback in nif lib"];
upgrade(suite) -> [];  
upgrade(Config) when is_list(Config) ->    
    ensure_lib_loaded(Config),

    ?line Data = ?config(data_dir, Config),
    ?line File = filename:join(Data, "nif_mod"),
    ?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]),
    ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin),

    ?line nif_mod:load_nif_lib(Config, 1),
    ?line {Pid,MRef} = nif_mod:start(),
    ?line 1 = call(Pid,lib_version),

    ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()),
    ?line [{load,1,1,101},{lib_version,1,2,102},{get_priv_data_ptr,1,3,103}] = nif_mod_call_history(),    
        
    %% Module upgrade with same lib-version
    ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin),
    ?line undefined = nif_mod:lib_version(),
    ?line 1 = call(Pid,lib_version),
    ?line [{lib_version,1,4,104}] = nif_mod_call_history(),

    ?line nif_mod:load_nif_lib(Config, 1),
    ?line 1 = nif_mod:lib_version(),
    ?line [{upgrade,1,5,105},{lib_version,1,6,106}] = nif_mod_call_history(),

    ?line upgraded = call(Pid,upgrade),
    ?line false = check_process_code(Pid, nif_mod),
    ?line true = erlang:purge_module(nif_mod),
    ?line [{unload,1,7,107}] = nif_mod_call_history(),

    ?line 1 = nif_mod:lib_version(),
    ?line [{lib_version,1,8,108}] = nif_mod_call_history(),

    ?line true = erlang:delete_module(nif_mod),
    ?line [] = nif_mod_call_history(),    

    ?line Pid ! die,
    ?line {'DOWN', MRef, process, Pid, normal} = receive_any(),
    ?line false = check_process_code(Pid, nif_mod),
    ?line true = erlang:purge_module(nif_mod),
    ?line [{unload,1,9,109}] = nif_mod_call_history(),    

    %% Module upgrade with different lib version
    ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin),
    ?line undefined = nif_mod:lib_version(),
    ?line {Pid2,MRef2} = nif_mod:start(),
    ?line undefined = call(Pid2,lib_version),

    ?line nif_mod:load_nif_lib(Config, 1),
    ?line hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()),
    ?line 1 = call(Pid2,lib_version),
    ?line [{load,1,1,101},{get_priv_data_ptr,1,2,102},{lib_version,1,3,103}] = nif_mod_call_history(),

    ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin),
    ?line undefined = nif_mod:lib_version(),
    ?line [] = nif_mod_call_history(),
    ?line 1 = call(Pid2,lib_version),
    ?line [{lib_version,1,4,104}] = nif_mod_call_history(),

    ?line nif_mod:load_nif_lib(Config, 2),
    ?line 2 = nif_mod:lib_version(),
    ?line [{upgrade,2,1,201},{lib_version,2,2,202}] = nif_mod_call_history(),

    ?line 1 = call(Pid2,lib_version),
    ?line [{lib_version,1,5,105}] = nif_mod_call_history(),

    ?line upgraded = call(Pid2,upgrade),
    ?line false = check_process_code(Pid2, nif_mod),
    ?line true = erlang:purge_module(nif_mod),
    ?line [{unload,1,6,106}] = nif_mod_call_history(),

    ?line 2 = nif_mod:lib_version(),
    ?line [{lib_version,2,3,203}] = nif_mod_call_history(),

    ?line true = erlang:delete_module(nif_mod),
    ?line [] = nif_mod_call_history(),    

    ?line Pid2 ! die,
    ?line {'DOWN', MRef2, process, Pid2, normal} = receive_any(),
    ?line false= check_process_code(Pid2, nif_mod),
    ?line true = erlang:purge_module(nif_mod),
    ?line [{unload,2,4,204}] = nif_mod_call_history(),    

    ?line [?MODULE, nif_mod] = erlang:system_info(taints),    
    ok.

heap_frag(doc) -> ["Test NIF building heap fragments"];
heap_frag(suite) -> [];  
heap_frag(Config) when is_list(Config) ->    
    ensure_lib_loaded(Config),
    
    heap_frag_do(1,1000000),
    ok.

heap_frag_do(N, Max) when N > Max ->
    ok;
heap_frag_do(N, Max) ->
    io:format("Create list of length ~p\n",[N]),
    L = lists:seq(1,N),
    L = list_seq(N),
    heap_frag_do(((N*5) div 4) + 1, Max).

types(doc) -> ["Type tests"];
types(suite) -> [];
types(Config) when is_list(Config) ->
    ensure_lib_loaded(Config),
    ?line ok = type_test(),
    lists:foreach(fun(Tpl) ->
                    Lst = erlang:tuple_to_list(Tpl),                 
                    Lst = tuple_2_list(Tpl)
                  end,
                  [{},{ok},{{}},{[],{}},{1,2,3,4,5}]),
    Stuff = [[],{},0,0.0,(1 bsl 100),(fun()-> ok end),make_ref(),self()],
    [eq_cmp(A,clone(B)) || A<-Stuff, B<-Stuff],                   
    ok.

clone(X) ->
    binary_to_term(term_to_binary(X)).

eq_cmp(A,B) ->
    eq_cmp_do(A,B),
    eq_cmp_do([A,B],[A,B]),
    eq_cmp_do({A,B},{A,B}).

eq_cmp_do(A,B) ->
    %%?t:format("compare ~p and ~p\n",[A,B]),
    Eq = (A =:= B),
    ?line Eq = is_identical(A,B),
    ?line Cmp = if
            A < B -> -1;
            A == B -> 0;
            A > B -> 1
        end,
    ?line Cmp = case compare(A,B) of
                    C when is_integer(C), C < 0 -> -1;
                    0 -> 0;
                    C when is_integer(C) -> 1
                end,       
    ok. 


many_args(doc) -> ["Test NIF with many arguments"];
many_args(suite) -> [];
many_args(Config) when is_list(Config) ->
    ?line ensure_lib_loaded(Config ,1),
    ?line ok = apply(?MODULE,many_args_100,lists:seq(1,100)),
    ?line ok = many_args_100(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100),
    ok.

        
    

neg(doc) -> ["Negative testing of load_nif"];
neg(suite) -> [];
neg(Config) when is_list(Config) ->
    ?line {'EXIT',{badarg,_}} = (catch erlang:load_nif(badarg, 0)),
    ?line {error,{load_failed,_}} = erlang:load_nif("pink_unicorn", 0),
    
    ?line Data = ?config(data_dir, Config),
    ?line File = filename:join(Data, "nif_mod"),
    ?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]),
    ?line {module,nif_mod} = erlang:load_module(nif_mod,Bin),

    ?line {error,{bad_lib,_}} = nif_mod:load_nif_lib(Config, no_init),    
    ?line ok.



ensure_lib_loaded(Config) ->
    ensure_lib_loaded(Config, 1).

ensure_lib_loaded(Config, Ver) ->
    ?line case lib_version() of
	      undefined ->
		  ?line Path = ?config(data_dir, Config),    
		  ?line Lib = "nif_SUITE." ++ integer_to_list(Ver),
		  ?line ok = erlang:load_nif(filename:join(Path,Lib), 0);
	      Ver when is_integer(Ver) ->
		  ok
	  end.

call(Pid,Cmd) ->
    %%io:format("~p calling ~p with ~p\n",[self(), Pid, Cmd]),
    Pid ! {self(), Cmd},
    receive
	{Pid,Reply} -> Reply
    end.

receive_any() ->
    receive M -> M end.	     

%% The NIFs:
lib_version() -> undefined.
call_history() -> ?nif_stub.
hold_nif_mod_priv_data(_Ptr) -> ?nif_stub.
nif_mod_call_history() -> ?nif_stub.
list_seq(_To) -> ?nif_stub.
type_test() -> ?nif_stub.
tuple_2_list(_) -> ?nif_stub.    
is_identical(_,_) -> ?nif_stub.
compare(_,_) -> ?nif_stub.
many_args_100(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_) -> ?nif_stub.
    
nif_stub_error(Line) ->
    exit({nif_not_loaded,module,?MODULE,line,Line}).