diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/test_server/src/test_server.erl | 287 | ||||
-rw-r--r-- | lib/test_server/src/test_server_ctrl.erl | 538 | ||||
-rw-r--r-- | lib/test_server/src/test_server_internal.hrl | 4 | ||||
-rw-r--r-- | lib/test_server/src/test_server_node.erl | 256 |
4 files changed, 70 insertions, 1015 deletions
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 2955809b03..2a45ace8c0 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -20,9 +20,6 @@ -define(DEFAULT_TIMETRAP_SECS, 60). -%%% START %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export([start/1,start/2]). - %%% TEST_SERVER_CTRL INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -export([run_test_case_apply/1,init_target_info/0,init_purify/0]). -export([cover_compile/1,cover_analyse/3]). @@ -60,49 +57,11 @@ -export([]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --record(state,{controller,jobs=[]}). - -include("test_server_internal.hrl"). -include_lib("kernel/include/file.hrl"). -define(pl2a(M), test_server_sup:package_atom(M)). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% -%% **** START *** CODE FOR REMOTE TARGET ONLY *** -%% -%% test_server -%% This process is started only if the test is to be run on a remote target -%% The process is then started on target -%% A socket connection is established with the test_server_ctrl process -%% on host, and information about target is sent to host. -start([ControllerHost]) when is_atom(ControllerHost) -> - start(atom_to_list(ControllerHost)); -start(ControllerHost) when is_list(ControllerHost) -> - start(ControllerHost,?MAIN_PORT). -start(ControllerHost,ControllerPort) -> - S = self(), - Pid = spawn(fun() -> init(ControllerHost,ControllerPort,S) end), - receive {Pid,started} -> {ok,Pid}; - {Pid,Error} -> Error - end. - -init(Host,Port,Starter) -> - global:register_name(?MODULE,self()), - process_flag(trap_exit,true), - test_server_sup:cleanup_crash_dumps(), - case gen_tcp:connect(Host,Port, [binary, - {reuseaddr,true}, - {packet,2}]) of - {ok,MainSock} -> - Starter ! {self(),started}, - request(MainSock,{target_info,init_target_info()}), - loop(#state{controller={Host,MainSock}}); - Error -> - Starter ! {self(),{error, - {could_not_contact_controller,Error}}} - end. - init_target_info() -> [$.|Emu] = code:objfile_extension(), {_, OTPRel} = init:script_id(), @@ -118,171 +77,10 @@ init_target_info() -> username=test_server_sup:get_username(), cookie=atom_to_list(erlang:get_cookie())}. - -loop(#state{controller={_,MainSock}} = State) -> - receive - {tcp, MainSock, <<1,Request/binary>>} -> - State1 = decode_main(binary_to_term(Request),State), - loop(State1); - {tcp_closed, MainSock} -> - gen_tcp:close(MainSock), - halt(); - {'EXIT',Pid,Reason} -> - case lists:keysearch(Pid,1,State#state.jobs) of - {value,{Pid,Name}} -> - case Reason of - normal -> ignore; - _other -> request(MainSock,{job_proc_killed,Name,Reason}) - end, - NewJobs = lists:keydelete(Pid,1,State#state.jobs), - loop(State#state{jobs = NewJobs}); - false -> - loop(State) - end - end. - -%% Decode request on main socket -decode_main({job,Port,Name},#state{controller={Host,_},jobs=Jobs}=State) -> - S = self(), - NewJob = spawn_link(fun() -> job(Host,Port,S) end), - receive {NewJob,started} -> State#state{jobs=[{NewJob,Name}|Jobs]}; - {NewJob,_Error} -> State - end. - init_purify() -> purify_new_leaks(). -%% Temporary job process on target -%% This process will live while all test cases in the job are executed. -%% A socket connection is established with the job process on host. -job(Host,Port,Starter) -> - process_flag(trap_exit,true), - init_purify(), - case gen_tcp:connect(Host,Port, [binary, - {reuseaddr,true}, - {packet,4}, - {active,false}]) of - {ok,JobSock} -> - Starter ! {self(),started}, - job(JobSock); - Error -> - Starter ! {self(),{error, - {could_not_contact_controller,Error}}} - end. - -job(JobSock) -> - JobDir = get_jobdir(), - ok = file:make_dir(JobDir), - ok = file:make_dir(filename:join(JobDir,?priv_dir)), - put(test_server_job_sock,JobSock), - put(test_server_job_dir,JobDir), - {ok,Cwd} = file:get_cwd(), - job_loop(JobSock), - ok = file:set_cwd(Cwd), - send_privdir(JobDir,JobSock), % also recursively removes jobdir - ok. - - -get_jobdir() -> - Now = now(), - {{Y,M,D},{H,Mi,S}} = calendar:now_to_local_time(Now), - Basename = io_lib:format("~w-~2.2.0w-~2.2.0w_~2.2.0w.~2.2.0w.~2.2.0w_~w", - [Y,M,D,H,Mi,S,element(3,Now)]), - %% if target has a file master, don't use prim_file to look up cwd - case lists:keymember(master,1,init:get_arguments()) of - true -> - {ok,Cwd} = file:get_cwd(), - Cwd ++ "/" ++ Basename; - false -> - filename:absname(Basename) - end. - -send_privdir(JobDir,JobSock) -> - LocalPrivDir = filename:join(JobDir,?priv_dir), - case file:list_dir(LocalPrivDir) of - {ok,List} when List/=[] -> - Tarfile0 = ?priv_dir ++ ".tar.gz", - Tarfile = filename:join(JobDir,Tarfile0), - {ok,Tar} = erl_tar:open(Tarfile,[write,compressed,cooked]), - ok = erl_tar:add(Tar,LocalPrivDir,?priv_dir,[]), - ok = erl_tar:close(Tar), - {ok,TarBin} = file:read_file(Tarfile), - file:delete(Tarfile), - ok = del_dir(JobDir), - request(JobSock,{{privdir,Tarfile0},TarBin}); - _ -> - ok = del_dir(JobDir), - request(JobSock,{privdir,empty_priv_dir}) - end. - -del_dir(Dir) -> - case file:read_file_info(Dir) of - {ok,#file_info{type=directory}} -> - {ok,Cont} = file:list_dir(Dir), - lists:foreach(fun(F) -> del_dir(filename:join(Dir,F)) end, Cont), - ok = file:del_dir(Dir); - {ok,#file_info{}} -> - ok = file:delete(Dir); - _r -> - %% This might be a symlink - let's try to delete it! - catch file:delete(Dir), - ok - end. - -%% -%% Receive and decode request on job socket -%% -job_loop(JobSock) -> - Request = recv(JobSock), - case decode_job(Request) of - ok -> job_loop(JobSock); - {stop,R} -> R - end. - -decode_job({{beam,Mod,Which},Beam}) -> - % FIXME, shared directory structure on host and target required, - % "Library beams" are not loaded from HOST... /Patrik - code:add_patha(filename:dirname(Which)), - % End of Patriks uglyness... - {module,Mod} = code:load_binary(Mod,Which,Beam), - ok; -decode_job({{datadir,Tarfile0},Archive}) -> - JobDir = get(test_server_job_dir), - Tarfile = filename:join(JobDir,Tarfile0), - ok = file:write_file(Tarfile,Archive), - % Cooked is temporary removed/broken - % ok = erl_tar:extract(Tarfile,[compressed,{cwd,JobDir},cooked]), - ok = erl_tar:extract(Tarfile,[compressed,{cwd,JobDir}]), - ok = file:delete(Tarfile), - ok; -decode_job({test_case,Case}) -> - Result = run_test_case_apply(Case), - JobSock = get(test_server_job_sock), - request(JobSock,{test_case_result,Result}), - case test_server_sup:tar_crash_dumps() of - {error,no_crash_dumps} -> request(JobSock,{crash_dumps,no_crash_dumps}); - {ok,TarFile} -> - {ok,TarBin} = file:read_file(TarFile), - file:delete(TarFile), - request(JobSock,{{crash_dumps,filename:basename(TarFile)},TarBin}) - end, - ok; -decode_job({sync_apply,{M,F,A}}) -> - R = apply(M,F,A), - request(get(test_server_job_sock),{sync_result,R}), - ok; -decode_job(job_done) -> - {stop,stopped}. - -%% -%% **** STOP *** CODE FOR REMOTE TARGET ONLY *** -%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% cover_compile({App,Include,Exclude,Cross}) -> %% {ok,AnalyseModules} | {error,Reason} @@ -606,33 +404,6 @@ run_test_case_apply({CaseNum,Mod,Func,Args,Name, DetFail = get(test_server_detected_fail), {Result,DetFail,ProcBef,ProcAft}. -run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> - case get(test_server_job_dir) of - undefined -> - %% i'm a local target - do_run_test_case_apply(Mod, Func, Args, Name, RunInit, - TimetrapData); - JobDir -> - %% i'm a remote target - case Args of - [Config] when is_list(Config) -> - {value,{data_dir,HostDataDir}} = - lists:keysearch(data_dir, 1, Config), - DataBase = filename:basename(HostDataDir), - TargetDataDir = filename:join(JobDir, DataBase), - Config1 = lists:keyreplace(data_dir, 1, Config, - {data_dir,TargetDataDir}), - TargetPrivDir = filename:join(JobDir, ?priv_dir), - Config2 = lists:keyreplace(priv_dir, 1, Config1, - {priv_dir,TargetPrivDir}), - do_run_test_case_apply(Mod, Func, [Config2], Name, RunInit, - TimetrapData); - _other -> - do_run_test_case_apply(Mod, Func, Args, Name, RunInit, - TimetrapData) - end - end. - -type tc_status() :: 'starting' | 'running' | 'init_per_testcase' | 'end_per_testcase' | {'framework',atom(),atom()} | 'tc'. @@ -649,7 +420,7 @@ run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> end_conf_pid :: pid() | 'undefined' }). -do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> +run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) -> {ok,Cwd} = file:get_cwd(), Args2Print = case Args of [Args1] when is_list(Args1) -> @@ -1540,10 +1311,10 @@ fw_error_notify(Mod, Func, Args, Error, Loc) -> %% is directed to console, major and/or minor log files. print(Detail,Format,Args) -> - local_or_remote_apply({test_server_ctrl,print,[Detail,Format,Args]}). + test_server_ctrl:print(Detail, Format, Args). print(Detail,Format,Args,Printer) -> - local_or_remote_apply({test_server_ctrl,print,[Detail,Format,Args,Printer]}). + test_server_ctrl:print(Detail, Format, Args, Printer). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% print_timsteamp(Detail,Leader) -> ok @@ -1553,7 +1324,7 @@ print(Detail,Format,Args,Printer) -> %% log files. print_timestamp(Detail,Leader) -> - local_or_remote_apply({test_server_ctrl,print_timestamp,[Detail,Leader]}). + test_server_ctrl:print_timestamp(Detail, Leader). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2683,7 +2454,7 @@ make_priv_dir() -> %% Returns the OsType of the target node. OsType is %% the same as returned from os:type() os_type() -> - test_server_ctrl:get_target_os_type(). + os:type(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2802,47 +2573,9 @@ purify_format(Format, Args) -> %% %% Generic send functions for communication with host %% -sync_local_or_remote_apply(Proxy,From,{M,F,A} = MFA) -> - case get(test_server_job_sock) of - undefined -> - %% i'm a local target - Result = apply(M,F,A), - if is_pid(Proxy) -> Proxy ! {sync_result_proxy,From,Result}; - true -> From ! {sync_result,Result} - end; - JobSock -> - %% i'm a remote target - request(JobSock,{sync_apply,MFA}), - {sync_result,Result} = recv(JobSock), - if is_pid(Proxy) -> Proxy ! {sync_result_proxy,From,Result}; - true -> From ! {sync_result,Result} - end - end. -local_or_remote_apply({M,F,A} = MFA) -> - case get(test_server_job_sock) of - undefined -> - %% i'm a local target - apply(M,F,A), - ok; - JobSock -> - %% i'm a remote target - request(JobSock,{apply,MFA}), - ok - end. - -request(Sock,Request) -> - gen_tcp:send(Sock,<<1,(term_to_binary(Request))/binary>>). - -%% -%% Generic receive function for communication with host -%% -recv(Sock) -> - case gen_tcp:recv(Sock,0) of - {error,closed} -> - gen_tcp:close(Sock), - exit(connection_lost); - {ok,<<1,Request/binary>>} -> - binary_to_term(Request); - {ok,<<0,B/binary>>} -> - B +sync_local_or_remote_apply(Proxy, From, {M,F,A}) -> + %% i'm a local target + Result = apply(M, F, A), + if is_pid(Proxy) -> Proxy ! {sync_result_proxy,From,Result}; + true -> From ! {sync_result,Result} end. diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index 4e465c02d1..e90586b7d4 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -34,118 +34,6 @@ %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% ARCHITECTURE -%% -%% The Erlang Test Server can be run on the target machine (local target) -%% or towards a remote target. The execution flow is mainly the same in -%% both cases, but with a remote target the test cases are (obviously) -%% executed on the target machine. Host and target communicates over -%% socket connections because the host should not be introduced as an -%% additional node in the distributed erlang system in which the test -%% cases are run. -%% -%% -%% Local Target: -%% ============= -%% -%% ----- -%% | | test_server_ctrl ({global,test_server}) -%% ----- (test_server_ctrl.erl) -%% | -%% | -%% ----- -%% | | JobProc -%% ----- (test_server_ctrl.erl and test_server.erl) -%% | -%% | -%% ----- -%% | | CaseProc -%% ----- (test_server.erl) -%% -%% -%% -%% test_server_ctrl is the main process in the system. It is a registered -%% process, and it will always be alive when testing is ongoing. -%% test_server_ctrl initiates testing and monitors JobProc(s). -%% -%% When target is local, and Test Server is *not* being used by a framework -%% application (where it might cause duplicate name problems in a distributed -%% test environment), the process is globally registered as 'test_server' -%% to be able to simulate the {global,test_server} process on a remote target. -%% -%% JobProc is spawned for each 'job' added to the test_server_ctrl. -%% A job can mean one test case, one test suite or one spec. -%% JobProc creates and writes logs and presents results from testing. -%% JobProc is the group leader for CaseProc. -%% -%% CaseProc is spawned for each test case. It runs the test case and -%% sends results and any other information to its group leader - JobProc. -%% -%% -%% -%% Remote Target: -%% ============== -%% -%% HOST TARGET -%% -%% ----- MainSock ----- -%% test_server_ctrl | |- - - - - - -| | {global,test_server} -%% (test_server_ctrl.erl) ----- ----- (test_server.erl) -%% | | -%% | | -%% ----- JobSock ----- -%% JobProcH | |- - - - - - -| | JobProcT -%% (test_server_ctrl.erl) ----- ----- (test_server.erl) -%% | -%% | -%% ----- -%% | | CaseProc -%% ----- (test_server.erl) -%% -%% -%% -%% -%% A separate test_server process only exists when target is remote. It -%% is then the main process on target. It is started when test_server_ctrl -%% is started, and a socket connection is established between -%% test_server_ctrl and test_server. The following information can be sent -%% over MainSock: -%% -%% HOST TARGET -%% -> {target_info, TargetInfo} (during initiation) -%% <- {job_proc_killed,Name,Reason} (if a JobProcT dies unexpectedly) -%% -> {job,Port,Name} (to start a new JobProcT) -%% -%% -%% When target is remote, JobProc is split into to processes: JobProcH -%% executing on Host and JobProcT executing on Target. (The two processes -%% execute the same code as JobProc does when target is local.) JobProcH -%% and JobProcT communicates over a socket connection. The following -%% information can be sent over JobSock: -%% -%% HOST TARGET -%% -> {test_case, Case} To start a new test case -%% -> {beam,Mod} .beam file as binary to be loaded -%% on target, e.g. a test suite -%% -> {datadir,Tarfile} Content of the datadir for a test suite -%% <- {apply,MFA} MFA to be applied on host, ignore return; -%% (apply is used for printing information in -%% log or console) -%% <- {sync_apply,MFA} MFA to be applied on host, wait for return -%% (used for starting and stopping slave nodes) -%% -> {sync_apply,MFA} MFA to be applied on target, wait for return -%% (used for cover compiling and analysing) -%% <-> {sync_result,Result} Return value from sync_apply -%% <- {test_case_result,Result} When a test case is finished -%% <- {crash_dumps,Tarfile} When a test case is finished -%% -> job_done When a job is finished -%% <- {privdir,Privdir} When a job is finished -%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - %%% SUPERVISOR INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -export([start/0, start/1, start_link/1, stop/0]). @@ -177,7 +65,6 @@ -export([format/1, format/2, format/3, to_string/1]). -export([get_target_info/0]). -export([get_hosts/0]). --export([get_target_os_type/0]). -export([node_started/1]). %%% DEBUGGER INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -537,20 +424,6 @@ kill_slavenodes() -> get_hosts() -> get(test_server_hosts). -get_target_os_type() -> - case whereis(?MODULE) of - undefined -> - %% This is probably called on the target node - os:type(); - Pid when Pid =:= self() -> - os:type(); - _pid -> - %% This is called on the controller, e.g. from a - %% specification clause of a test case - #target_info{os_type=OsType} = controller_call(get_target_info), - OsType - end. - %%-------------------------------------------------------------------- add_job(Name, TopCase) -> @@ -606,7 +479,7 @@ controller_call(Arg, Timeout) -> %% Mode 'lazy' ignores (and resets to []) any jobs in the state file %% -init([Param]) -> +init([_]) -> case os:getenv("TEST_SERVER_CALL_TRACE") of false -> ok; @@ -632,104 +505,14 @@ init([Param]) -> test_server_sup:cleanup_crash_dumps(), State = #state{jobs=[],finish=false}, put(test_server_free_targets,[]), - case contact_main_target(Param) of - {ok,TI} -> - ets:new(slave_tab, [named_table,set,public,{keypos,2}]), - set_hosts([TI#target_info.host]), - {ok,State#state{target_info=TI}}; - {error,Reason} -> - {stop,Reason} - end. - - -%% If the test is to be run at a remote target, this function sets up -%% a socket communication with the target. -contact_main_target(local) -> - %% When used by a general framework, global registration of - %% test_server should not be required. - case get_fw_mod(undefined) of - undefined -> - %% Local target! The global test_server process implemented by - %% test_server.erl will not be started, so we simulate it by - %% globally registering this process instead. - global:sync(), - case global:whereis_name(test_server) of - undefined -> - global:register_name(test_server, self()); - Pid -> - case node() of - N when N == node(Pid) -> - io:format(user, "Warning: test_server already running!\n", []), - global:re_register_name(test_server,self()); - _ -> - ok - end - end; - _ -> - ok - end, - TI = test_server:init_target_info(), + TI0 = test_server:init_target_info(), TargetHost = test_server_sup:hoststr(), - {ok,TI#target_info{where=local, - host=TargetHost, - naming=naming(), - master=TargetHost}}; - -contact_main_target(ParameterFile) -> - case read_parameters(ParameterFile) of - {ok,Par} -> - case test_server_node:start_remote_main_target(Par) of - {ok,TI} -> - {ok,TI}; - {error,Error} -> - {error,{could_not_start_main_target,Error}} - end; - {error,Error} -> - {error,{could_not_read_parameterfile,Error}} - end. - -read_parameters(File) -> - case file:consult(File) of - {ok,Data} -> - read_parameters(lists:flatten(Data), #par{naming=naming()}); - Error -> - Error - end. -read_parameters([{type,Type}|Data], Par) -> % mandatory - read_parameters(Data, Par#par{type=Type}); -read_parameters([{target,Target}|Data], Par) -> % mandatory - read_parameters(Data, Par#par{target=cast_to_list(Target)}); -read_parameters([{slavetargets,SlaveTargets}|Data], Par) -> - read_parameters(Data, Par#par{slave_targets=SlaveTargets}); -read_parameters([{longnames,Bool}|Data], Par) -> - Naming = if Bool->"-name"; true->"-sname" end, - read_parameters(Data, Par#par{naming=Naming}); -read_parameters([{master,{Node,Cookie}}|Data], Par) -> - read_parameters(Data, Par#par{master=cast_to_list(Node), - cookie=cast_to_list(Cookie)}); -read_parameters([Other|_Data], _Par) -> - {error,{illegal_parameter,Other}}; -read_parameters([], Par) when Par#par.type==undefined -> - {error, {missing_mandatory_parameter,type}}; -read_parameters([], Par) when Par#par.target==undefined -> - {error, {missing_mandatory_parameter,target}}; -read_parameters([], Par0) -> - Par = - case {Par0#par.type, Par0#par.master} of - {ose, undefined} -> - %% Use this node as master and bootserver for target - %% and slave nodes - Par0#par{master = atom_to_list(node()), - cookie = atom_to_list(erlang:get_cookie())}; - {ose, _Master} -> - %% Master for target and slave nodes was defined in parameterfile - Par0; - _ -> - %% Use target as master for slave nodes, - %% (No master is used for target) - Par0#par{master="test_server@" ++ Par0#par.target} - end, - {ok,Par}. + TI = TI0#target_info{host=TargetHost, + naming=naming(), + master=TargetHost}, + ets:new(slave_tab, [named_table,set,public,{keypos,2}]), + set_hosts([TI#target_info.host]), + {ok,State#state{target_info=TI}}. naming() -> case lists:member($., test_server_sup:hoststr()) of @@ -1210,25 +993,17 @@ handle_cast({node_started,Node}, State) -> %% Pid = pid() %% Reason = term() %% -%% Handles exit messages from linked processes. Only test suites and -%% possibly a target client are expected to be linked. -%% When a test suite terminates, it is removed from the job queue. -%% If a target client terminates it means that we lost contact with -%% target. The test_server_ctrl process is terminated, and teminate/2 -%% will do the cleanup +%% Handles exit messages from linked processes. Only test suites are +%% expected to be linked. When a test suite terminates, it is removed +%% from the job queue. If a target client terminates it means that we +%% lost contact with target. The test_server_ctrl process is +%% terminated, and teminate/2 will do the cleanup handle_info({'EXIT',Pid,Reason}, State) -> case lists:keysearch(Pid,2,State#state.jobs) of false -> - TI = State#state.target_info, - case TI#target_info.target_client of - Pid -> - %% The target client died - lost contact with target - {stop,{lost_contact_with_target,Reason},State}; - _other -> - %% not our problem - {noreply,State} - end; + %% not our problem + {noreply,State}; {value,{Name,_}} -> NewJobs = lists:keydelete(Pid, 2, State#state.jobs), case Reason of @@ -1303,14 +1078,8 @@ handle_info({tcp_closed,Sock}, State=#state{trc=Sock}) -> %%! Maybe print something??? {noreply,State#state{trc=false}}; handle_info({tcp_closed,Sock}, State) -> - case test_server_node:nodedown(Sock,State#state.target_info) of - target_died -> - %% terminate/2 will do the cleanup - {stop,target_died,State}; - _ -> - {noreply,State} - end; - + test_server_node:nodedown(Sock, State#state.target_info), + {noreply,State}; handle_info(_, State) -> %% dummy; accept all, do nothing. {noreply, State}. @@ -2318,9 +2087,7 @@ do_add_end_per_suite_and_skip(LastMod, LastRef, Mod, FwMod) -> %% Runs the specified tests, then displays/logs the summary. run_test_cases(TestSpec, Config, TimetrapData) -> - - maybe_open_job_sock(), - + test_server:init_purify(), case lists:member(no_src, get(test_server_logopts)) of true -> ok; @@ -2330,8 +2097,6 @@ run_test_cases(TestSpec, Config, TimetrapData) -> run_test_cases_loop(TestSpec, [Config], TimetrapData, [], []), - maybe_get_privdir(), - {AllSkippedN,UserSkipN,AutoSkipN,SkipStr} = case get(test_server_skipped) of {0,0} -> {0,0,0,""}; @@ -2350,41 +2115,6 @@ run_test_cases(TestSpec, Config, TimetrapData) -> print(major, "=auto_skipped ~p", [AutoSkipN]), exit(test_suites_done). -%% If the test is run at a remote target, this function sets up a socket -%% communication with the target for handling this particular job. -maybe_open_job_sock() -> - TI = get_target_info(), - case TI#target_info.where of - local -> - %% local target - test_server:init_purify(); - MainSock -> - %% remote target - {ok,LSock} = gen_tcp:listen(0, [binary, - {reuseaddr,true}, - {packet,4}, - {active,false}]), - {ok,Port} = inet:port(LSock), - request(MainSock, {job,Port,get(test_server_name)}), - case gen_tcp:accept(LSock, ?ACCEPT_TIMEOUT) of - {ok,Sock} -> put(test_server_ctrl_job_sock, Sock); - {error,Reason} -> exit({no_contact,Reason}) - end - end. - -%% If the test is run at a remote target, this function waits for a -%% tar packet containing the privdir created by the test case. -maybe_get_privdir() -> - case get(test_server_ctrl_job_sock) of - undefined -> - %% local target - ok; - Sock -> - %% remote target - request(Sock, job_done), - gen_tcp:close(Sock) - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% run_test_cases_loop(TestCases, Config, TimetrapData, Mode, Status) -> ok @@ -2899,7 +2629,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0, end, CurrMode = curr_mode(Ref, Mode0, Mode), - ConfCaseResult = run_test_case(Ref, 0, Mod, Func, [ActualCfg], skip_init, target, + ConfCaseResult = run_test_case(Ref, 0, Mod, Func, [ActualCfg], skip_init, TimetrapData, CurrMode), case ConfCaseResult of @@ -3023,7 +2753,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0, end; run_test_cases_loop([{make,Ref,{Mod,Func,Args}}|Cases0], Config, TimetrapData, Mode, Status) -> - case run_test_case(Ref, 0, Mod, Func, Args, skip_init, host, TimetrapData) of + case run_test_case(Ref, 0, Mod, Func, Args, skip_init, TimetrapData) of {_,Why={'EXIT',_},_} -> print(minor, "~n*** ~p failed.~n" " Skipping all cases.", [Func]), @@ -3068,7 +2798,7 @@ run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status) end, case run_test_case(undefined, Num+1, Mod, Func, Args, - run_init, target, TimetrapData, Mode) of + run_init, TimetrapData, Mode) of %% callback to framework module failed, exit immediately {_,{framework_error,{FwMod,FwFunc},Reason},_} -> print(minor, "~n*** ~p failed in ~p. Reason: ~p~n", [FwMod,FwFunc,Reason]), @@ -3757,23 +3487,23 @@ handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases) -> %% RetVal is the result of executing the test case. It contains info %% about the execution time and the return value of the test case function. -run_test_case(Ref, Num, Mod, Func, Args, RunInit, Where, TimetrapData) -> +run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData) -> file:set_cwd(filename:dirname(get(test_server_dir))), - run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where, + run_test_case1(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, [], self()). -run_test_case(Ref, Num, Mod, Func, Args, skip_init, Where, TimetrapData, Mode) -> +run_test_case(Ref, Num, Mod, Func, Args, skip_init, TimetrapData, Mode) -> %% a conf case is always executed by the main process - run_test_case1(Ref, Num, Mod, Func, Args, skip_init, Where, + run_test_case1(Ref, Num, Mod, Func, Args, skip_init, TimetrapData, Mode, self()); -run_test_case(Ref, Num, Mod, Func, Args, RunInit, Where, TimetrapData, Mode) -> +run_test_case(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, Mode) -> file:set_cwd(filename:dirname(get(test_server_dir))), Main = self(), case check_prop(parallel, Mode) of false -> %% this is a sequential test case - run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where, + run_test_case1(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, Mode, Main); _Ref -> %% this a parallel test case, spawn the new process @@ -3785,11 +3515,11 @@ run_test_case(Ref, Num, Mod, Func, Args, RunInit, Where, TimetrapData, Mode) -> [put(Key, Val) || {Key,Val} <- Dictionary], set_io_buffering({tc,Main}), run_test_case1(Ref, Num, Mod, Func, Args, RunInit, - Where, TimetrapData, Mode, Main) + TimetrapData, Mode, Main) end) end. -run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where, +run_test_case1(Ref, Num, Mod, Func, Args, RunInit, TimetrapData, Mode, Main) -> group_leader(test_server_io:get_gl(Main == self()), self()), @@ -3802,12 +3532,6 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where, Main ! {started,Ref,self(),Num,Mod,Func} end, TSDir = get(test_server_dir), - case Where of - target -> - maybe_send_beam_and_datadir(Mod); - host -> - ok - end, print(major, "=case ~p:~p", [Mod, Func]), MinorName = start_minor_log_file(Mod, Func), @@ -3865,7 +3589,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where, %% run the test case {Result,DetectedFail,ProcsBefore,ProcsAfter} = run_test_case_apply(Num, Mod, Func, [UpdatedArgs], get_name(Mode), - RunInit, Where, TimetrapData), + RunInit, TimetrapData), {Time,RetVal,Loc,Opts,Comment} = case Result of Normal={_Time,_RetVal,_Loc,_Opts,_Comment} -> Normal; @@ -3982,7 +3706,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where, true -> ok end, - check_new_crash_dumps(Where), + test_server_sup:check_new_crash_dumps(), %% if io is being buffered, send finished message %% (no matter if case runs on parallel or main process) @@ -4010,109 +3734,6 @@ do_unless_parallel(Main, Action) when is_function(Action, 0) -> num2str(0) -> ""; num2str(N) -> integer_to_list(N). -%% If remote target, this function sends the test suite (if not already sent) -%% and the content of datadir til target. -maybe_send_beam_and_datadir(Mod) -> - case get(test_server_ctrl_job_sock) of - undefined -> - %% local target - ok; - JobSock -> - %% remote target - case get(test_server_downloaded_suites) of - undefined -> - send_beam_and_datadir(Mod, JobSock), - put(test_server_downloaded_suites, [Mod]); - Suites -> - case lists:member(Mod, Suites) of - false -> - send_beam_and_datadir(Mod, JobSock), - put(test_server_downloaded_suites, [Mod|Suites]); - true -> - ok - end - end - end. - -send_beam_and_datadir(Mod, JobSock) -> - case code:which(Mod) of - non_existing -> - io:format("** WARNING: Suite ~w could not be found on host\n", - [Mod]); - BeamFile -> - send_beam(JobSock, Mod, BeamFile) - end, - DataDir = get_data_dir(Mod), - case file:read_file_info(DataDir) of - {ok,_I} -> - {ok,All} = file:list_dir(DataDir), - AddTarFiles = - case controller_call(get_target_info) of - #target_info{os_family=ose} -> - ObjExt = code:objfile_extension(), - Wc = filename:join(DataDir, "*" ++ ObjExt), - ModsInDatadir = filelib:wildcard(Wc), - SendBeamFun = fun(X) -> send_beam(JobSock, X) end, - lists:foreach(SendBeamFun, ModsInDatadir), - %% No need to send C code or makefiles since - %% no compilation can be done on target anyway. - %% Compiled C code must exist on target. - %% Beam files are already sent as binaries. - %% Erlang source are sent in case the test case - %% is to compile it. - Filter = fun("Makefile") -> false; - ("Makefile.src") -> false; - (Y) -> - case filename:extension(Y) of - ".c" -> false; - ObjExt -> false; - _ -> true - end - end, - lists:filter(Filter, All); - _ -> - All - end, - Tarfile = "data_dir.tar.gz", - {ok,Tar} = erl_tar:open(Tarfile, [write,compressed]), - ShortDataDir = filename:basename(DataDir), - AddTarFun = - fun(File) -> - Long = filename:join(DataDir, File), - Short = filename:join(ShortDataDir, File), - ok = erl_tar:add(Tar, Long, Short, []) - end, - lists:foreach(AddTarFun, AddTarFiles), - ok = erl_tar:close(Tar), - {ok,TarBin} = file:read_file(Tarfile), - file:delete(Tarfile), - request(JobSock, {{datadir,Tarfile}, TarBin}); - {error,_R} -> - ok - end. - -send_beam(JobSock, BeamFile) -> - Mod=filename:rootname(filename:basename(BeamFile), code:objfile_extension()), - send_beam(JobSock, list_to_atom(Mod), BeamFile). -send_beam(JobSock, Mod, BeamFile) -> - {ok,BeamBin} = file:read_file(BeamFile), - request(JobSock, {{beam,Mod,BeamFile}, BeamBin}). - -check_new_crash_dumps(Where) -> - case Where of - target -> - case get(test_server_ctrl_job_sock) of - undefined -> - ok; - Socket -> - read_job_sock_loop(Socket) - end; - _ -> - ok - end, - test_server_sup:check_new_crash_dumps(). - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% progress(Result, CaseNum, Mod, Func, Location, Reason, Time, %% Comment, TimeFormat) -> Result @@ -4480,11 +4101,10 @@ do_format_exception(Reason={Error,Stack}) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, -%% Where, TimetrapData) -> +%% TimetrapData) -> %% {{Time,RetVal,Loc,Opts,Comment},DetectedFail,ProcessesBefore,ProcessesAfter} | %% {{died,Reason,unknown,Comment},DetectedFail,ProcessesBefore,ProcessesAfter} %% Name = atom() -%% Where = target | host %% Time = float() (seconds) %% RetVal = term() %% Loc = term() @@ -4499,23 +4119,10 @@ do_format_exception(Reason={Error,Stack}) -> %% sent over socket to target, and test_server runs the case and sends the %% result back over the socket. Else test_server runs the case directly on host. -run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, host, +run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, TimetrapData) -> test_server:run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit, - TimetrapData}); -run_test_case_apply(CaseNum, Mod, Func, Args, Name, RunInit, target, - TimetrapData) -> - case get(test_server_ctrl_job_sock) of - undefined -> - %% local target - test_server:run_test_case_apply({CaseNum,Mod,Func,Args,Name,RunInit, - TimetrapData}); - JobSock -> - %% remote target - request(JobSock, {test_case,{CaseNum,Mod,Func,Args,Name,RunInit, - TimetrapData}}), - read_job_sock_loop(JobSock) - end. + TimetrapData}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% print(Detail, Format, Args) -> ok @@ -5182,60 +4789,6 @@ stop_node(Slave) -> controller_call({stop_node,Slave}). -%%-------------------------------------------------------------------- -%% Functions handling target communication over socket - -%% Generic send function for communication with target -request(Sock,Request) -> - gen_tcp:send(Sock,<<1,(term_to_binary(Request))/binary>>). - -%% Receive and decode request on job specific socket -%% Used when test is running on a remote target -read_job_sock_loop(Sock) -> - case gen_tcp:recv(Sock,0) of - {error,Reason} -> - gen_tcp:close(Sock), - exit({controller,connection_lost,Reason}); - {ok,<<1,Request/binary>>} -> - case decode(binary_to_term(Request)) of - ok -> - read_job_sock_loop(Sock); - {stop,Result} -> - Result - end - end. - -decode({apply,{M,F,A}}) -> - apply(M,F,A), - ok; -decode({sync_apply,{M,F,A}}) -> - R = apply(M,F,A), - request(get(test_server_ctrl_job_sock),{sync_result,R}), - ok; -decode({sync_result,Result}) -> - {stop,Result}; -decode({test_case_result,Result}) -> - {stop,Result}; -decode({privdir,empty_priv_dir}) -> - {stop,ok}; -decode({{privdir,PrivDirTar},TarBin}) -> - Root = get(test_server_log_dir_base), - unpack_tar(Root,PrivDirTar,TarBin), - {stop,ok}; -decode({crash_dumps,no_crash_dumps}) -> - {stop,ok}; -decode({{crash_dumps,CrashDumpTar},TarBin}) -> - Dir = test_server_sup:crash_dump_dir(), - unpack_tar(Dir,CrashDumpTar,TarBin), - {stop,ok}. - -unpack_tar(Dir,TarFileName0,TarBin) -> - TarFileName = filename:join(Dir,TarFileName0), - ok = file:write_file(TarFileName,TarBin), - ok = erl_tar:extract(TarFileName,[compressed,{cwd,Dir}]), - ok = file:delete(TarFileName). - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% DEBUGGER INTERFACE %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -5380,16 +4933,7 @@ cover_compile({App,CoverFile}) -> cover_compile1({App,Exclude,Include,Cross}). cover_compile1(What) -> - case get(test_server_ctrl_job_sock) of - undefined -> - %% local target - test_server:cover_compile(What); - JobSock -> - %% remote target - request(JobSock, {sync_apply,{test_server,cover_compile,[What]}}), - read_job_sock_loop(JobSock) - end. - + test_server:cover_compile(What). %% Read the coverfile for an application and return a list of modules %% that are members of the application but shall not be compiled @@ -5491,17 +5035,7 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, Stop, TestDir) -> cover_analyse(Analyse, AnalyseMods, Stop) -> TestDir = get(test_server_log_dir_base), - case get(test_server_ctrl_job_sock) of - undefined -> - %% local target - test_server:cover_analyse({Analyse,TestDir}, AnalyseMods, Stop); - JobSock -> - %% remote target - request(JobSock, {sync_apply,{test_server, - cover_analyse, - [Analyse,AnalyseMods, Stop]}}), - read_job_sock_loop(JobSock) - end. + test_server:cover_analyse({Analyse,TestDir}, AnalyseMods, Stop). %% Cover analysis, cross application diff --git a/lib/test_server/src/test_server_internal.hrl b/lib/test_server/src/test_server_internal.hrl index b58b42805e..d204c35293 100644 --- a/lib/test_server/src/test_server_internal.hrl +++ b/lib/test_server/src/test_server_internal.hrl @@ -24,8 +24,7 @@ %% Target information generated by test_server:init_target_info/0 and %% test_server_ctrl:contact_main_target/2 %% Once initiated, this information will never change!! --record(target_info, {where, % local | Socket - os_family, % atom(); win32 | unix +-record(target_info, {os_family, % atom(); win32 | unix os_type, % result of os:type() host, % string(); the name of the target machine version, % string() @@ -43,7 +42,6 @@ % itself is master for slave nodes %% The following are only used for remote targets - target_client, % reference to a client talking to target slave_targets=[]}).% list() of atom(); all available % targets for starting slavenodes diff --git a/lib/test_server/src/test_server_node.erl b/lib/test_server/src/test_server_node.erl index 872f15f2be..b307d93c7d 100644 --- a/lib/test_server/src/test_server_node.erl +++ b/lib/test_server/src/test_server_node.erl @@ -26,7 +26,7 @@ %% Test Controller interface -export([is_release_available/1]). --export([start_remote_main_target/1,stop/1]). +-export([stop/1]). -export([start_tracer_node/2,trace_nodes/2,stop_tracer_node/1]). -export([start_node/5, stop_node/2]). -export([kill_nodes/1, nodedown/2]). @@ -57,79 +57,8 @@ is_release_available(Rel) -> false end. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%% Start main target node on remote host -%%% The target node must not know the controller node via erlang distribution. -start_remote_main_target(Parameters) -> - #par{type=TargetType, - target=TargetHost, - naming=Naming, - master=MasterNode, - cookie=MasterCookie, - slave_targets=SlaveTargets} = Parameters, - - lists:foreach(fun(T) -> maybe_reboot_target({TargetType,T}) end, - [list_to_atom(TargetHost)|SlaveTargets]), - - Cmd0 = get_main_target_start_command(TargetType,TargetHost,Naming, - MasterNode,MasterCookie), - Cmd = - case os:getenv("TEST_SERVER_FRAMEWORK") of - FW when FW =:= false; FW =:= "undefined" -> Cmd0; - FW -> Cmd0 ++ " -env TEST_SERVER_FRAMEWORK " ++ FW - end, - - {ok,LSock} = gen_tcp:listen(?MAIN_PORT,[binary,{reuseaddr,true},{packet,2}]), - case start_target(TargetType,TargetHost,Cmd) of - {ok,TargetClient,AcceptTimeout} -> - case gen_tcp:accept(LSock,AcceptTimeout) of - {ok,Sock} -> - gen_tcp:close(LSock), - receive - {tcp,Sock,Bin} when is_binary(Bin) -> - case unpack(Bin) of - error -> - gen_tcp:close(Sock), - close_target_client(TargetClient), - {error,bad_message}; - {ok,{target_info,TI}} -> - put(test_server_free_targets,SlaveTargets), - {ok, TI#target_info{where=Sock, - host=TargetHost, - naming=Naming, - master=MasterNode, - target_client=TargetClient, - slave_targets=SlaveTargets}} - end; - {tcp_closed,Sock} -> - gen_tcp:close(Sock), - close_target_client(TargetClient), - {error,could_not_contact_target} - after AcceptTimeout -> - gen_tcp:close(Sock), - close_target_client(TargetClient), - {error,timeout} - end; - Error -> - %%! maybe something like kill_target(...)??? - gen_tcp:close(LSock), - close_target_client(TargetClient), - {error,{could_not_contact_target,Error}} - end; - Error -> - gen_tcp:close(LSock), - {error,{could_not_start_target,Error}} - end. - stop(TI) -> - kill_nodes(TI), - case TI#target_info.where of - local -> % there is no remote target to stop - ok; - Sock -> % stop remote target - gen_tcp:close(Sock), - close_target_client(TI#target_info.target_client) - end. + kill_nodes(TI). nodedown(Sock, TI) -> Match = #slave_info{name='$1',socket=Sock,client='$2',_='_'}, @@ -146,14 +75,8 @@ nodedown(Sock, TI) -> false -> ok end, slave_died; - [] -> - case TI#target_info.where of - Sock -> - %% test_server_ctrl will do the cleanup - target_died; - _ -> - ignore - end + [] -> + ok end. @@ -167,10 +90,7 @@ start_tracer_node(TraceFile,TI) -> Match = #slave_info{name='$1',_='_'}, SlaveNodes = lists:map(fun([N]) -> [" ",N] end, ets:match(slave_tab,Match)), - TargetNode = case TI#target_info.where of - local -> node(); - _ -> "test_server@" ++ TI#target_info.host - end, + TargetNode = node(), Cookie = TI#target_info.cookie, {ok,LSock} = gen_tcp:listen(0,[binary,{reuseaddr,true},{packet,2}]), {ok,TracePort} = inet:port(LSock), @@ -471,129 +391,29 @@ start_node_slave(SlaveName, OptList, From, TI) -> Ret = case start_which_node(OptList) of {error,Reason} -> {{error,Reason},undefined,undefined}; - Host0 -> do_start_node_slave(Host0,SlaveName,Args,Prog,Cleanup,TI) + Host0 -> do_start_node_slave(Host0,SlaveName,Args,Prog,Cleanup) end, gen_server:reply(From,Ret). -do_start_node_slave(Host0, SlaveName, Args, Prog, Cleanup, TI) -> - case TI#target_info.where of - local -> - Host = - case Host0 of - local -> test_server_sup:hoststr(); - _ -> cast_to_list(Host0) - end, - Cmd = Prog ++ " " ++ Args, - %% Can use slave.erl here because I'm both controller and target - %% so I will ping the new node anyway - case slave:start(Host, SlaveName, Args, no_link, Prog) of - {ok,Nodename} -> - case Cleanup of - true -> ets:insert(slave_tab,#slave_info{name=Nodename}); - false -> ok - end, - {{ok,Nodename}, Host, Cmd, [], []}; - Ret -> - {Ret, Host, Cmd} - end; - - _Sock -> - %% Cannot use slave.erl here because I'm only controller, and will - %% not ping the new node. Only target shall contact the new node!! - no_contact_start_slave(Host0,SlaveName,Args,Prog,Cleanup,TI) - end. - - - -no_contact_start_slave(Host, Name, Args0, Prog, Cleanup,TI) -> - Args1 = case string:str(Args0,"-setcookie") of - 0 -> "-setcookie " ++ TI#target_info.cookie ++ " " ++ Args0; - _ -> Args0 +do_start_node_slave(Host0, SlaveName, Args, Prog, Cleanup) -> + Host = + case Host0 of + local -> test_server_sup:hoststr(); + _ -> cast_to_list(Host0) + end, + Cmd = Prog ++ " " ++ Args, + %% Can use slave.erl here because I'm both controller and target + %% so I will ping the new node anyway + case slave:start(Host, SlaveName, Args, no_link, Prog) of + {ok,Nodename} -> + case Cleanup of + true -> ets:insert(slave_tab,#slave_info{name=Nodename}); + false -> ok end, - Args = TI#target_info.naming ++ " " ++ cast_to_list(Name) ++ " " ++ Args1, - case Host of - local -> - case get(test_server_free_targets) of - [] -> - io:format("Starting slave ~p on HOST~n", [Name]), - TargetType = test_server_sup:get_os_family(), - Cmd0 = get_slave_node_start_command(TargetType, - Prog, - TI#target_info.master), - Cmd = Cmd0 ++ " " ++ Args, - do_no_contact_start_slave(TargetType, - test_server_sup:hoststr(), - Cmd, Cleanup,TI, false); - [H|T] -> - TargetType = TI#target_info.os_family, - Cmd0 = get_slave_node_start_command(TargetType, - Prog, - TI#target_info.master), - Cmd = Cmd0 ++ " " ++ Args, - case do_no_contact_start_slave(TargetType,H,Cmd,Cleanup, - TI,true) of - {error,remove} -> - io:format("Cannot start node on ~p, " - "removing from slave " - "target list.", [H]), - put(test_server_free_targets,T), - no_contact_start_slave(Host,Name,Args,Prog, - Cleanup,TI); - {error,keep} -> - %% H is added to the END OF THE LIST - %% in order to avoid the same target to - %% be selected each time - put(test_server_free_targets,T++[H]), - no_contact_start_slave(Host,Name,Args,Prog, - Cleanup,TI); - R -> - put(test_server_free_targets,T), - R - end - end; - _ -> - TargetType = TI#target_info.os_family, - Cmd0 = get_slave_node_start_command(TargetType, - Prog, - TI#target_info.master), - Cmd = Cmd0 ++ " " ++ Args, - do_no_contact_start_slave(TargetType, Host, Cmd, Cleanup, TI, false) - end. - -do_no_contact_start_slave(TargetType,Host0,Cmd0,Cleanup,TI,Retry) -> - %% Must use TargetType instead of TI#target_info.os_familiy here - %% because if there were no free_targets we will be starting the - %% slave node on host which might have a different os_familiy - Host = cast_to_list(Host0), - {ok,LSock} = gen_tcp:listen(0,[binary, - {reuseaddr,true}, - {packet,2}]), - {ok,WaitPort} = inet:port(LSock), - Cmd = lists:concat([Cmd0, " -s ", ?MODULE, " node_started ", - test_server_sup:hoststr(), " ", WaitPort]), - - case start_target(TargetType,Host,Cmd) of - {ok,Client,AcceptTimeout} -> - case wait_for_node_started(LSock,AcceptTimeout, - Client,Cleanup,TI,self()) of - {error,_}=WaitError -> - if Retry -> - case maybe_reboot_target(Client) of - {error,_} -> {error,remove}; - ok -> {error,keep} - end; - true -> - {WaitError,Host,Cmd} - end; - {Ok,Warning} -> - {Ok,Host,Cmd,[],Warning} - end; - StartError -> - gen_tcp:close(LSock), - if Retry -> {error,remove}; - true -> {{error,{could_not_start_target,StartError}},Host,Cmd} - end + {{ok,Nodename}, Host, Cmd, [], []}; + Ret -> + {Ret, Host, Cmd} end. @@ -777,40 +597,10 @@ kill_node(SI,TI) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Platform specific code -start_target(unix,TargetHost,Cmd0) -> - Cmd = - case test_server_sup:hoststr() of - TargetHost -> Cmd0; - _ -> lists:concat(["rsh ",TargetHost, " ", Cmd0]) - end, - open_port({spawn, Cmd}, [stream]), - {ok,undefined,?ACCEPT_TIMEOUT}. - -maybe_reboot_target(_) -> - {error, cannot_reboot_target}. - close_target_client(undefined) -> ok. - -%% -%% Command for starting main target -%% -get_main_target_start_command(unix,_TargetHost,Naming, - _MasterNode,_MasterCookie) -> - Prog = pick_erl_program(default), - Prog ++ " " ++ Naming ++ " test_server" ++ - " -boot start_sasl -sasl errlog_type error" - " -s test_server start " ++ test_server_sup:hoststr(). - -%% -%% Command for starting slave nodes -%% -get_slave_node_start_command(unix, Prog, MasterNode) -> - cast_to_list(Prog) ++ " -detached -master " ++ MasterNode. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% cast_to_list(X) -> string() %%% X = list() | atom() | void() |