From 55d975b3a1266d50b5a55004a004d0f244d5a17b Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Wed, 15 May 2013 12:09:36 +0200 Subject: [common_test] Add new option 'no_prompt_check' to ct_telnet:expect/3. If this option is used, ct_telnet will not search for a prompt before attempting to match the given pattern. This is useful if, for instance, the Pattern itself matches the prompt or if the telnet session starts interactive programs which do not display the normal prompt. --- lib/common_test/src/ct_telnet.erl | 56 ++++++-- lib/common_test/test/ct_telnet_SUITE.erl | 7 +- .../ct_telnet_own_server_SUITE.erl | 146 ++++++++++++++++++++- lib/common_test/test/telnet_server.erl | 15 ++- 4 files changed, 205 insertions(+), 19 deletions(-) diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index b748c17f30..4755d939e0 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.erl @@ -309,7 +309,7 @@ expect(Connection,Patterns) -> %%% Tag = term() %%% Opts = [Opt] %%% Opt = {timeout,Timeout} | repeat | {repeat,N} | sequence | -%%% {halt,HaltPatterns} | ignore_prompt +%%% {halt,HaltPatterns} | ignore_prompt | no_prompt_check %%% Timeout = integer() %%% N = integer() %%% HaltPatterns = Patterns @@ -336,14 +336,28 @@ expect(Connection,Patterns) -> %%% will also include the matched Tag. Else, only %%% RxMatch is returned.

%%% -%%%

The function will always return when a prompt is found, unless -%%% the ignore_prompt options is used.

-%%% %%%

The timeout option indicates that the function %%% shall return if the telnet client is idle (i.e. if no data is %%% received) for more than Timeout milliseconds. Default %%% timeout is 10 seconds.

%%% +%%%

The function will always return when a prompt is found, unless +%%% any of the ignore_prompt or +%%% no_prompt_check options are used, in which case it +%%% will return when a match is found or after a timeout.

+%%% +%%%

If the ignore_prompt option is used, +%%% ct_telnet will ignore any prompt found. This option +%%% is useful if data sent by the server could include a pattern that +%%% would match the prompt regexp (as returned by +%%% TargedMod:get_prompt_regexp/0), but which should not +%%% cause the function to return.

+%%% +%%%

If the no_prompt_check option is used, +%%% ct_telnet will not search for a prompt at all. This +%%% is useful if, for instance, the Pattern itself +%%% matches the prompt.

+%%% %%%

The repeat option indicates that the pattern(s) %%% shall be matched multiple times. If N is given, the %%% pattern(s) will be matched N times, and the function @@ -728,7 +742,8 @@ teln_get_all_data(Pid,Prx,Data,Acc,LastLine) -> haltpatterns=[], seq=false, repeat=false, - found_prompt=false}). + found_prompt=false, + prompt_check=true}). %% @hidden %% @doc Externally the silent_teln_expect function shall only be used @@ -754,10 +769,16 @@ silent_teln_expect(Pid,Data,Pattern,Prx,Opts) -> %% condition is fullfilled. %% 3b) Repeat (sequence): 2) is repeated either N times or until a %% halt condition is fullfilled. -teln_expect(Pid,Data,Pattern0,Prx,Opts) -> HaltPatterns = case - get_ignore_prompt(Opts) of true -> get_haltpatterns(Opts); false - -> [prompt | get_haltpatterns(Opts)] end, +teln_expect(Pid,Data,Pattern0,Prx,Opts) -> + HaltPatterns = + case get_ignore_prompt(Opts) of + true -> + get_haltpatterns(Opts); + false -> + [prompt | get_haltpatterns(Opts)] + end, + PromptCheck = get_prompt_check(Opts), Seq = get_seq(Opts), Pattern = convert_pattern(Pattern0,Seq), @@ -767,7 +788,8 @@ teln_expect(Pid,Data,Pattern0,Prx,Opts) -> HaltPatterns = case prx=Prx, timeout=Timeout, seq=Seq, - haltpatterns=HaltPatterns}, + haltpatterns=HaltPatterns, + prompt_check=PromptCheck}, case get_repeat(Opts) of false -> @@ -831,7 +853,9 @@ get_haltpatterns(Opts) -> end. get_ignore_prompt(Opts) -> lists:member(ignore_prompt,Opts). - +get_prompt_check(Opts) -> + not lists:member(no_prompt_check,Opts). + %% Repeat either single or sequence. All match results are accumulated %% and returned when a halt condition is fulllfilled. repeat_expect(Rest,_Pattern,Acc,#eo{repeat=0}) -> @@ -892,6 +916,9 @@ get_data1(Pid) -> %% lines and each line is matched against each pattern. %% one_expect: split data chunk at prompts +one_expect(Data,Pattern,EO) when EO#eo.prompt_check==false -> +% io:format("Raw Data ~p Pattern ~p EO ~p ",[Data,Pattern,EO]), + one_expect1(Data,Pattern,[],EO#eo{found_prompt=false}); one_expect(Data,Pattern,EO) -> case match_prompt(Data,EO#eo.prx) of {prompt,UptoPrompt,PromptType,Rest} -> @@ -950,6 +977,8 @@ seq_expect(Data,[],Acc,_EO) -> {match,lists:reverse(Acc),Data}; seq_expect([],Patterns,Acc,_EO) -> {continue,Patterns,lists:reverse(Acc),[]}; +seq_expect(Data,Patterns,Acc,EO) when EO#eo.prompt_check==false -> + seq_expect1(Data,Patterns,Acc,[],EO#eo{found_prompt=false}); seq_expect(Data,Patterns,Acc,EO) -> case match_prompt(Data,EO#eo.prx) of {prompt,UptoPrompt,PromptType,Rest} -> @@ -1013,6 +1042,13 @@ match_lines(Data,Patterns,EO) -> {Tag,Match} -> {Tag,Match,[]} end; + {noline,Rest} when EO#eo.prompt_check==false -> + case match_line(Rest,Patterns,false,EO) of + nomatch -> + {nomatch,Rest}; + {Tag,Match} -> + {Tag,Match,[]} + end; {noline,Rest} -> {nomatch,Rest}; {Line,Rest} -> diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl index c75f0f5843..a378c531f0 100644 --- a/lib/common_test/test/ct_telnet_SUITE.erl +++ b/lib/common_test/test/ct_telnet_SUITE.erl @@ -53,8 +53,9 @@ end_per_suite(Config) -> ct_test_support:end_per_suite(Config). init_per_testcase(own_server=TestCase, Config) -> - TS = telnet_server:start([{port,1234},{users,[{?erl_telnet_server_user, - ?erl_telnet_server_pwd}]}]), + TS = telnet_server:start([{port,?erl_telnet_server_port}, + {users,[{?erl_telnet_server_user, + ?erl_telnet_server_pwd}]}]), ct_test_support:init_per_testcase(TestCase, [{telnet_server,TS}|Config]); init_per_testcase(TestCase, Config) -> ct_test_support:init_per_testcase(TestCase, Config). @@ -92,7 +93,7 @@ own_server(Config) -> DataDir = ?config(data_dir, Config), Suite = filename:join(DataDir, "ct_telnet_own_server_SUITE"), Cfg = {unix,[{telnet,"localhost"}, - {port, 1234}, + {port, ?erl_telnet_server_port}, {username,?erl_telnet_server_user}, {password,?erl_telnet_server_pwd}, {wait_for_linebreak, false}, diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl index 2173c68c11..3f7c0d68bf 100644 --- a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl +++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl @@ -19,7 +19,18 @@ suite() -> [{require,erl_telnet_server,{unix,[telnet]}}]. all() -> [expect, - expect_repeat]. + expect_repeat, + expect_sequence, + expect_error_prompt, + expect_error_timeout, + no_prompt_check, + no_prompt_check_repeat, + no_prompt_check_sequence, + no_prompt_check_timeout, + ignore_prompt, + ignore_prompt_repeat, + ignore_prompt_sequence, + ignore_prompt_timeout]. groups() -> []. @@ -30,6 +41,7 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +%% Simple expect expect(_) -> {ok, Handle} = ct_telnet:open(erl_telnet_server), ok = ct_telnet:send(Handle, "echo ayt"), @@ -37,10 +49,136 @@ expect(_) -> ok = ct_telnet:close(Handle), ok. +%% Expect with repeat option expect_repeat(_) -> {ok, Handle} = ct_telnet:open(erl_telnet_server), - ok = ct_telnet:send(Handle, "repeat xy"), - {ok,[["xy"],["xy"]],done} = ct_telnet:expect(Handle, ["xy"], - [{repeat,2}]), + ok = ct_telnet:send(Handle, "echo_ml xy xy"), + {ok,[["xy"],["xy"]],done} = ct_telnet:expect(Handle, ["xy"],[{repeat,2}]), + ok = ct_telnet:close(Handle), + ok. + +%% Expect with sequence option +expect_sequence(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo_ml ab cd ef"), + {ok,[["ab"],["cd"],["ef"]]} = ct_telnet:expect(Handle, + [["ab"],["cd"],["ef"]], + [sequence]), + ok = ct_telnet:close(Handle), + ok. + +%% Check that expect returns when a prompt is found, even if pattern +%% is not matched. +expect_error_prompt(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo xxx> yyy"), + {error,{prompt,"> "}} = ct_telnet:expect(Handle, ["yyy"]), + ok = ct_telnet:close(Handle), + ok. + +%% Check that expect returns after idle timeout, and even if the +%% expected pattern is received - as long as not newline or prompt is +%% received it will not match. +expect_error_timeout(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo_no_prompt xxx"), + {error,timeout} = ct_telnet:expect(Handle, ["xxx"], [{timeout,1000}]), + ok = ct_telnet:close(Handle), + ok. + +%% expect with ignore_prompt option should not return even if a prompt +%% is found. The pattern after the prompt (here "> ") can be matched. +ignore_prompt(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo xxx> yyy"), + {ok,["yyy"]} = ct_telnet:expect(Handle, ["yyy"], [ignore_prompt]), + ok = ct_telnet:close(Handle), + ok. + +%% expect with ignore_prompt and repeat options. +ignore_prompt_repeat(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo_ml yyy> yyy>"), + {ok,[["yyy"],["yyy"]],done} = ct_telnet:expect(Handle, ["yyy"], + [{repeat,2}, + ignore_prompt]), + ok = ct_telnet:close(Handle), + ok. + +%% expect with ignore_prompt and sequence options. +ignore_prompt_sequence(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo_ml xxx> yyy> zzz> "), + {ok,[["xxx"],["yyy"],["zzz"]]} = ct_telnet:expect(Handle, + [["xxx"],["yyy"],["zzz"]], + [sequence, + ignore_prompt]), + ok = ct_telnet:close(Handle), + ok. + +%% Check that expect returns after idle timeout when ignore_prompt +%% option is used. +%% As for expect without the ignore_prompt option, it a newline or a +%% prompt is required in order for the pattern to match. +ignore_prompt_timeout(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo xxx"), + {error,timeout} = ct_telnet:expect(Handle, ["yyy"], [ignore_prompt, + {timeout,1000}]), + ok = ct_telnet:send(Handle, "echo xxx"), % sends prompt and newline + {ok,["xxx"]} = ct_telnet:expect(Handle, ["xxx"], [ignore_prompt, + {timeout,1000}]), + ok = ct_telnet:send(Handle, "echo_no_prompt xxx\n"), % no prompt, but newline + {ok,["xxx"]} = ct_telnet:expect(Handle, ["xxx"], [ignore_prompt, + {timeout,1000}]), + ok = ct_telnet:send(Handle, "echo_no_prompt xxx"), % no prompt, no newline + {error,timeout} = ct_telnet:expect(Handle, ["xxx"], [ignore_prompt, + {timeout,1000}]), + ok = ct_telnet:close(Handle), + ok. + +%% no_prompt_check option shall match pattern both when prompt is sent +%% and when it is not. +no_prompt_check(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo xxx"), + {ok,["xxx"]} = ct_telnet:expect(Handle, ["xxx"], [no_prompt_check]), + ok = ct_telnet:send(Handle, "echo_no_prompt yyy"), + {ok,["yyy"]} = ct_telnet:expect(Handle, ["yyy"], [no_prompt_check]), + ok = ct_telnet:close(Handle), + ok. + +%% no_prompt_check and repeat options +no_prompt_check_repeat(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo_ml xxx xxx"), + {ok,[["xxx"],["xxx"]],done} = ct_telnet:expect(Handle,["xxx"], + [{repeat,2}, + no_prompt_check]), + ok = ct_telnet:send(Handle, "echo_ml_no_prompt yyy yyy"), + {ok,[["yyy"],["yyy"]],done} = ct_telnet:expect(Handle,["yyy"], + [{repeat,2}, + no_prompt_check]), + ok = ct_telnet:close(Handle), + ok. + +%% no_prompt_check and sequence options +no_prompt_check_sequence(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo_ml_no_prompt ab cd ef"), + {ok,[["ab"],["cd"],["ef"]]} = ct_telnet:expect(Handle, + [["ab"],["cd"],["ef"]], + [sequence, + no_prompt_check]), + ok = ct_telnet:close(Handle), + ok. + +%% Check that expect returns after idle timeout when no_prompt_check +%% option is used. +no_prompt_check_timeout(_) -> + {ok, Handle} = ct_telnet:open(erl_telnet_server), + ok = ct_telnet:send(Handle, "echo xxx"), + {error,timeout} = ct_telnet:expect(Handle, ["yyy"], [no_prompt_check, + {timeout,1000}]), ok = ct_telnet:close(Handle), ok. diff --git a/lib/common_test/test/telnet_server.erl b/lib/common_test/test/telnet_server.erl index 5843155eee..31884aa182 100644 --- a/lib/common_test/test/telnet_server.erl +++ b/lib/common_test/test/telnet_server.erl @@ -93,6 +93,7 @@ do_accept(LSock,Server) -> end. init_client(#state{client=Sock}=State) -> + dbg("Server sending: ~p~n",["login: "]), R = case gen_tcp:send(Sock,"login: ") of ok -> loop(State); @@ -164,8 +165,18 @@ do_handle_data(Data,#state{authorized={user,_}}=State) -> do_handle_data("echo "++ Data,State) -> send(Data++"\r\n> ",State), {ok,State}; -do_handle_data("repeat "++ Data,State) -> - send(Data++"\r\n"++Data++"\r\n> ",State), +do_handle_data("echo_no_prompt "++ Data,State) -> + send(Data,State), + {ok,State}; +do_handle_data("echo_ml "++ Data,State) -> + Lines = string:tokens(Data," "), + ReturnData = string:join(Lines,"\n"), + send(ReturnData++"\r\n> ",State), + {ok,State}; +do_handle_data("echo_ml_no_prompt "++ Data,State) -> + Lines = string:tokens(Data," "), + ReturnData = string:join(Lines,"\n"), + send(ReturnData,State), {ok,State}; do_handle_data([],State) -> send("> ",State), -- cgit v1.2.3