Skip to content

Commit

Permalink
Merge branch 'siri/common_test/ct_netconfc/OTP-10025' into maint
Browse files Browse the repository at this point in the history
* siri/common_test/ct_netconfc/OTP-10025:
  [common_test] Move ct_netconfc_SUITE into datadir and run with ct_test_support
  [common_test] Don't abort test if opening of connection fails
  [common_test] Don't allow named (required) connection to be opened twice
  [common_test] Don't abort test run if connection process crashes
  [common_test] Add netconf client, ct_netconfc
  • Loading branch information
sirihansen committed Aug 17, 2012
2 parents 9125e91 + bc8f2b8 commit f11a10e
Show file tree
Hide file tree
Showing 18 changed files with 4,221 additions and 84 deletions.
1 change: 1 addition & 0 deletions lib/.gitignore
Expand Up @@ -7,6 +7,7 @@
/common_test/doc/src/ct_rpc.xml
/common_test/doc/src/ct_snmp.xml
/common_test/doc/src/ct_ssh.xml
/common_test/doc/src/ct_netconfc.xml
/common_test/doc/src/ct_telnet.xml
/common_test/doc/src/unix_telnet.xml

Expand Down
7 changes: 4 additions & 3 deletions lib/common_test/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
# Copyright Ericsson AB 2003-2011. All Rights Reserved.
# Copyright Ericsson AB 2003-2012. 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
Expand Down Expand Up @@ -46,7 +46,8 @@ CT_MODULES = \
ct_rpc \
ct_snmp \
unix_telnet \
ct_slave
ct_slave \
ct_netconfc

CT_XML_FILES = $(CT_MODULES:=.xml)

Expand Down Expand Up @@ -123,7 +124,7 @@ $(HTMLDIR)/%.gif: %.gif

docs: pdf html man

$(CT_XML_FILES):
$(CT_XML_FILES): %.xml: ../../src/%.erl
escript $(DOCGEN)/priv/bin/xml_from_edoc.escript -preprocess true -i $(XMERL_DIR)/include \
-i ../../../test_server/include -i ../../include \
-i ../../../../erts/lib/kernel/include -i ../../../../lib/kernel/include \
Expand Down
3 changes: 2 additions & 1 deletion lib/common_test/doc/src/ref_man.xml
Expand Up @@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
<year>2003</year><year>2011</year>
<year>2003</year><year>2012</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
Expand Down Expand Up @@ -71,6 +71,7 @@
<xi:include href="ct_cover.xml"/>
<xi:include href="ct_ftp.xml"/>
<xi:include href="ct_ssh.xml"/>
<xi:include href="ct_netconfc.xml"/>
<xi:include href="ct_rpc.xml"/>
<xi:include href="ct_snmp.xml"/>
<xi:include href="ct_telnet.xml"/>
Expand Down
8 changes: 6 additions & 2 deletions lib/common_test/src/Makefile
Expand Up @@ -70,14 +70,18 @@ MODULES= \
ct_hooks\
ct_hooks_lock\
cth_log_redirect\
cth_surefire
cth_surefire \
ct_netconfc \
ct_conn_log_h \
cth_conn_log

TARGET_MODULES= $(MODULES:%=$(EBIN)/%)
BEAM_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))

ERL_FILES= $(MODULES:=.erl)
HRL_FILES = \
ct_util.hrl
ct_util.hrl \
ct_netconfc.hrl
EXTERNAL_HRL_FILES = \
../include/ct.hrl \
../include/ct_event.hrl
Expand Down
3 changes: 3 additions & 0 deletions lib/common_test/src/common_test.app.src
Expand Up @@ -33,6 +33,8 @@
ct_master_event,
ct_master_logs,
ct_master_status,
ct_netconfc,
ct_conn_log_h,
ct_repeat,
ct_rpc,
ct_run,
Expand All @@ -49,6 +51,7 @@
ct_config_xml,
ct_slave,
cth_log_redirect,
cth_conn_log,
cth_surefire
]},
{registered, [ct_logs,
Expand Down
230 changes: 230 additions & 0 deletions lib/common_test/src/ct_conn_log_h.erl
@@ -0,0 +1,230 @@
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2012. 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(ct_conn_log_h).

%%%
%%% A handler that can be connected to the error_logger event
%%% handler. Writes all ct connection events. See comments in
%%% cth_conn_log for more information.
%%%

-include("ct_util.hrl").

-export([init/1,
handle_event/2, handle_call/2, handle_info/2,
terminate/2]).

-record(state, {group_leader,logs=[]}).

-define(WIDTH,80).

%%%-----------------------------------------------------------------
%%% Callbacks
init({GL,Logs}) ->
open_files(Logs,#state{group_leader=GL}).

open_files([{ConnMod,{LogType,Logs}}|T],State) ->
case do_open_files(Logs,[]) of
{ok,Fds} ->
open_files(T,State#state{logs=[{ConnMod,{LogType,Fds}} |
State#state.logs]});
Error ->
Error
end;
open_files([],State) ->
{ok,State}.


do_open_files([{Tag,File}|Logs],Acc) ->
case file:open(File, [write]) of
{ok,Fd} ->
do_open_files(Logs,[{Tag,Fd}|Acc]);
{error,Reason} ->
{error,{could_not_open_log,File,Reason}}
end;
do_open_files([],Acc) ->
{ok,lists:reverse(Acc)}.

handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() ->
{ok, State};
handle_event({_Type,_GL,{Pid,{ct_connection,Action,ConnName},Report}},State) ->
Info = conn_info(Pid,#conn_log{name=ConnName,action=Action}),
write_report(now(),Info,Report,State),
{ok, State};
handle_event({_Type,_GL,{Pid,Info=#conn_log{},Report}},State) ->
write_report(now(),conn_info(Pid,Info),Report,State),
{ok, State};
handle_event({error_report,_,{Pid,_,[{ct_connection,ConnName}|R]}},State) ->
%% Error reports from connection
write_error(now(),conn_info(Pid,#conn_log{name=ConnName}),R,State),
{ok, State};
handle_event(_, State) ->
{ok, State}.

handle_info(_, State) ->
{ok, State}.

handle_call(_Query, State) ->
{ok, {error, bad_query}, State}.

terminate(_,#state{logs=Logs}) ->
[file:close(Fd) || {_,_,Fds} <- Logs, Fd <- Fds],
ok.


%%%-----------------------------------------------------------------
%%% Writing reports
write_report(Time,#conn_log{module=ConnMod}=Info,Data,State) ->
{LogType,Fd} = get_log(Info,State),
io:format(Fd,"~n~s~s~s",[format_head(ConnMod,LogType,Time),
format_title(LogType,Info),
format_data(ConnMod,LogType,Data)]).

write_error(Time,#conn_log{module=ConnMod}=Info,Report,State) ->
case get_log(Info,State) of
{html,_} ->
%% The error will anyway be written in the html log by the
%% sasl error handler, so don't write it again.
ok;
{LogType,Fd} ->
io:format(Fd,"~n~s~s~s",[format_head(ConnMod,LogType,Time," ERROR"),
format_title(LogType,Info),
format_error(LogType,Report)])
end.

get_log(Info,State) ->
case proplists:get_value(Info#conn_log.module,State#state.logs) of
{html,_} ->
{html,State#state.group_leader};
{LogType,Fds} ->
{LogType,get_fd(Info,Fds)};
undefined ->
{html,State#state.group_leader}
end.

get_fd(#conn_log{name=undefined},Fds) ->
proplists:get_value(default,Fds);
get_fd(#conn_log{name=ConnName},Fds) ->
case proplists:get_value(ConnName,Fds) of
undefined ->
proplists:get_value(default,Fds);
Fd ->
Fd
end.

%%%-----------------------------------------------------------------
%%% Formatting
format_head(ConnMod,LogType,Time) ->
format_head(ConnMod,LogType,Time,"").

format_head(ConnMod,raw,Time,Text) ->
io_lib:format("~n~p, ~p~s, ",[now_to_time(Time),ConnMod,Text]);
format_head(ConnMod,_,Time,Text) ->
Head = pad_char_end(?WIDTH,pretty_head(now_to_time(Time),ConnMod,Text),$=),
io_lib:format("~n~s",[Head]).

format_title(raw,#conn_log{client=Client}=Info) ->
io_lib:format("Client ~p ~s ~s",[Client,actionstr(Info),serverstr(Info)]);
format_title(_,Info) ->
Title = pad_char_end(?WIDTH,pretty_title(Info),$=),
io_lib:format("~n~s", [Title]).

format_data(_,_,NoData) when NoData == ""; NoData == <<>> ->
"";
format_data(ConnMod,LogType,Data) ->
ConnMod:format_data(LogType,Data).

format_error(raw,Report) ->
io_lib:format("~n~p~n",[Report]);
format_error(pretty,Report) ->
[io_lib:format("~n ~p: ~p",[K,V]) || {K,V} <- Report].




%%%-----------------------------------------------------------------
%%% Helpers
conn_info(LoggingProc, #conn_log{client=undefined} = ConnInfo) ->
conn_info(ConnInfo#conn_log{client=LoggingProc});
conn_info(_, ConnInfo) ->
conn_info(ConnInfo).

conn_info(#conn_log{client=Client, module=undefined} = ConnInfo) ->
case ets:lookup(ct_connections,Client) of
[#conn{address=Address,callback=Callback}] ->
ConnInfo#conn_log{address=Address,module=Callback};
[] ->
ConnInfo
end;
conn_info(ConnInfo) ->
ConnInfo.


now_to_time({_,_,MicroS}=Now) ->
{calendar:now_to_local_time(Now),MicroS}.

pretty_head({{{Y,Mo,D},{H,Mi,S}},MicroS},ConnMod,Text0) ->
Text = string:to_upper(atom_to_list(ConnMod) ++ Text0),
io_lib:format("= ~s ==== ~s-~s-~p::~s:~s:~s,~s ",
[Text,t(D),month(Mo),Y,t(H),t(Mi),t(S),
micro2milli(MicroS)]).

pretty_title(#conn_log{client=Client}=Info) ->
io_lib:format("= Client ~p ~s Server ~s ",
[Client,actionstr(Info),serverstr(Info)]).

actionstr(#conn_log{action=send}) -> "----->";
actionstr(#conn_log{action=recv}) -> "<-----";
actionstr(#conn_log{action=open}) -> "opened session to";
actionstr(#conn_log{action=close}) -> "closed session to";
actionstr(_) -> "<---->".

serverstr(#conn_log{name=undefined,address=Address}) ->
io_lib:format("~p",[Address]);
serverstr(#conn_log{name=Alias,address=Address}) ->
io_lib:format("~p(~p)",[Alias,Address]).

month(1) -> "Jan";
month(2) -> "Feb";
month(3) -> "Mar";
month(4) -> "Apr";
month(5) -> "May";
month(6) -> "Jun";
month(7) -> "Jul";
month(8) -> "Aug";
month(9) -> "Sep";
month(10) -> "Oct";
month(11) -> "Nov";
month(12) -> "Dec".

micro2milli(X) ->
pad0(3,integer_to_list(X div 1000)).

t(X) ->
pad0(2,integer_to_list(X)).

pad0(N,Str) ->
M = length(Str),
lists:duplicate(N-M,$0) ++ Str.

pad_char_end(N,Str,Char) ->
case length(lists:flatten(Str)) of
M when M<N -> Str ++ lists:duplicate(N-M,Char);
_ -> Str
end.

0 comments on commit f11a10e

Please sign in to comment.