ct_telnet

Common Test specific layer on top of telnet client ct_telnet_client.erl

Common Test specific layer on top of telnet client ct_telnet_client.erl

Use this module to set up telnet connections, send commands and perform string matching on the result. See the unix_telnet manual page for information about how to use ct_telnet, and configure connections, specifically for unix hosts.

The following default values are defined in ct_telnet:

  Connection timeout = 10 sec (time to wait for connection)
  Command timeout = 10 sec (time to wait for a command to return)
  Max no of reconnection attempts = 3
  Reconnection interval = 5 sek (time to wait in between reconnection attempts)
  Keep alive = true (will send NOP to the server every 8 sec if connection is idle)
  Polling limit = 0 (max number of times to poll to get a remaining string terminated)
  Polling interval = 1 sec (sleep time between polls)

These parameters can be altered by the user with the following configuration term:

  {telnet_settings, [{connect_timeout,Millisec},
                     {command_timeout,Millisec},
                     {reconnection_attempts,N},
                     {reconnection_interval,Millisec},
                     {keep_alive,Bool},
                     {poll_limit,N},
                     {poll_interval,Millisec}]}.

Millisec = integer(), N = integer()

Enter the telnet_settings term in a configuration file included in the test and ct_telnet will retrieve the information automatically. Note that keep_alive may be specified per connection if required. See unix_telnet for details.

Logging

The default logging behaviour of ct_telnet is to print information to the test case HTML log about performed operations and commands and their corresponding results. What won't be printed to the HTML log are text strings sent from the telnet server that are not explicitly received by means of a ct_telnet function such as expect/3. ct_telnet may however be configured to use a special purpose event handler, implemented in ct_conn_log_h, for logging all telnet traffic. To use this handler, you need to install a Common Test hook named cth_conn_log. Example (using the test suite info function):

  suite() ->
      [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].

conn_mod() is the name of the common_test module implementing the connection protocol, i.e. ct_telnet.

The cth_conn_log hook performs unformatted logging of telnet data to a separate text file. All telnet communication is captured and printed, including arbitrary data sent from the server. The link to this text file can be found on the top of the test case HTML log.

By default, data for all telnet connections is logged in one common file (named default), which might get messy e.g. if multiple telnet sessions are running in parallel. It is therefore possible to create a separate log file for each connection. To configure this, use the hook option hosts and list the names of the servers/connections that will be used in the suite. Note that the connections must be named for this to work (see the open function below).

The hook option named log_type may be used to change the cth_conn_log behaviour. The default value of this option is raw, which results in the behaviour described above. If the value is set to html, all telnet communication is printed to the test case HTML log instead.

All cth_conn_log hook options described above can also be specified in a configuration file with the configuration variable ct_conn_log. Example:

  {ct_conn_log, [{ct_telnet,[{log_type,raw},
                             {hosts,[key_or_name()]}]}]}

Note that hook options specified in a configuration file will overwrite any hardcoded hook options in the test suite!

Logging example

The following ct_hooks statement will cause printing of telnet traffic to separate logs for the connections named server1 and server2. Traffic for any other connections will be logged in the default telnet log.

  suite() ->
      [{ct_hooks,
        [{cth_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}]}].

As previously explained, the above specification could also be provided by means of an entry like this in a configuration file:

  {ct_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}.

in which case the ct_hooks statement in the test suite may simply look like this:

  suite() ->
      [{ct_hooks, [{cth_conn_log, []}]}].

Types


connection() = handle() | {target_name() (see module ct), connection_type()} | target_name() (see module ct)

connection_type() = telnet | ts1 | ts2

handle() = handle() (see module ct_gen_conn)

prompt_regexp() = string()

Functions


open(Name) -> {ok, Handle} | {error, Reason}

Equivalent to open(Name, telnet).

open(Name, ConnType) -> {ok, Handle} | {error, Reason}

  • Name = target_name()
  • ConnType = connection_type() (see module ct_telnet)
  • Handle = handle() (see module ct_telnet)
  • Reason = term()

Open a telnet connection to the specified target host.

open(KeyOrName, ConnType, TargetMod) -> {ok, Handle} | {error, Reason}

open(KeyOrName, ConnType, TargetMod, Extra) -> {ok, Handle} | {error, Reason}

  • KeyOrName = Key | Name
  • Key = atom()
  • Name = target_name() (see module ct)
  • ConnType = connection_type()
  • TargetMod = atom()
  • Extra = term()
  • Handle = handle()
  • Reason = term()

Open a telnet connection to the specified target host.

The target data must exist in a configuration file. The connection may be associated with either Name and/or the returned Handle. To allocate a name for the target, use ct:require/2 in a test case, or use a require statement in the suite info function (suite/0), or in a test case info function. If you want the connection to be associated with Handle only (in case you need to open multiple connections to a host for example), simply use Key, the configuration variable name, to specify the target. Note that a connection that has no associated target name can only be closed with the handle value.

TargetMod is a module which exports the functions connect(Ip,Port,KeepAlive,Extra) and get_prompt_regexp() for the given TargetType (e.g. unix_telnet).

See also: ct:require/2.

close(Connection) -> ok | {error, Reason}

  • Connection = connection() (see module ct_telnet)
  • Reason = term()

Close the telnet connection and stop the process managing it.

A connection may be associated with a target name and/or a handle. If Connection has no associated target name, it may only be closed with the handle value (see the open/4 function).

cmd(Connection, Cmd) -> {ok, Data} | {error, Reason}

Equivalent to cmd(Connection, Cmd, []).

cmd(Connection, Cmd, Opts) -> {ok, Data} | {error, Reason}

  • Connection = connection() (see module ct_telnet)
  • Cmd = string()
  • Opts = [Opt]
  • Opt = {timeout, timeout()} | {newline, boolean()}
  • Data = [string()]
  • Reason = term()

Send a command via telnet and wait for prompt.

This function will by default add a newline to the end of the given command. If this is not desired, the option {newline,false} can be used. This is necessary, for example, when sending telnet command sequences (prefixed with the Interprete As Command, IAC, character).

The option timeout specifies how long the client shall wait for prompt. If the time expires, the function returns {error,timeout}. See the module description for information about the default value for the command timeout.

cmdf(Connection, CmdFormat, Args) -> {ok, Data} | {error, Reason}

cmdf(Connection, CmdFormat, Args, Opts) -> {ok, Data} | {error, Reason}

  • Connection = connection() (see module ct_telnet)
  • CmdFormat = string()
  • Args = list()
  • Opts = [Opt]
  • Opt = {timeout, timeout()} | {newline, boolean()}
  • Data = [string()]
  • Reason = term()

Send a telnet command and wait for prompt (uses a format string and list of arguments to build the command).

See cmd/3 further description.

get_data(Connection) -> {ok, Data} | {error, Reason}

  • Connection = connection() (see module ct_telnet)
  • Data = [string()]
  • Reason = term()

Get all data that has been received by the telnet client since the last command was sent. Note that only newline terminated strings are returned. If the last string received has not yet been terminated, the connection may be polled automatically until the string is complete. The polling feature is controlled by the poll_limit and poll_interval config values and is by default disabled (meaning the function will immediately return all complete strings received and save a remaining non-terminated string for a later get_data call).

send(Connection, Cmd) -> ok | {error, Reason}

Equivalent to send(Connection, Cmd, []).

send(Connection, Cmd, Opts) -> ok | {error, Reason}

  • Connection = connection() (see module ct_telnet)
  • Cmd = string()
  • Opts = [Opt]
  • Opt = {newline, boolean()}
  • Reason = term()

Send a telnet command and return immediately.

This function will by default add a newline to the end of the given command. If this is not desired, the option {newline,false} can be used. This is necessary, for example, when sending telnet command sequences (prefixed with the Interprete As Command, IAC, character).

The resulting output from the command can be read with get_data/1 or expect/2/3.

sendf(Connection, CmdFormat, Args) -> ok | {error, Reason}

sendf(Connection, CmdFormat, Args, Opts) -> ok | {error, Reason}

  • Connection = connection() (see module ct_telnet)
  • CmdFormat = string()
  • Args = list()
  • Opts = [Opt]
  • Opt = {newline, boolean()}
  • Reason = term()

Send a telnet command and return immediately (uses a format string and a list of arguments to build the command).

expect(Connection, Patterns) -> term()

expect(Connection, Patterns, Opts) -> {ok, Match} | {ok, MatchList, HaltReason} | {error, Reason}

  • Connection = connection() (see module ct_telnet)
  • Patterns = Pattern | [Pattern]
  • Pattern = string() | {Tag, string()} | prompt | {prompt, Prompt}
  • Prompt = string()
  • Tag = term()
  • Opts = [Opt]
  • Opt = {idle_timeout, IdleTimeout} | {total_timeout, TotalTimeout} | repeat | {repeat, N} | sequence | {halt, HaltPatterns} | ignore_prompt | no_prompt_check | wait_for_prompt | {wait_for_prompt, Prompt}
  • IdleTimeout = infinity | integer()
  • TotalTimeout = infinity | integer()
  • N = integer()
  • HaltPatterns = Patterns
  • MatchList = [Match]
  • Match = RxMatch | {Tag, RxMatch} | {prompt, Prompt}
  • RxMatch = [string()]
  • HaltReason = done | Match
  • Reason = timeout | {prompt, Prompt}

Get data from telnet and wait for the expected pattern.

Pattern can be a POSIX regular expression. The function returns as soon as a pattern has been successfully matched (at least one, in the case of multiple patterns).

RxMatch is a list of matched strings. It looks like this: [FullMatch, SubMatch1, SubMatch2, ...] where FullMatch is the string matched by the whole regular expression and SubMatchN is the string that matched subexpression no N. Subexpressions are denoted with '(' ')' in the regular expression

If a Tag is given, the returned Match will also include the matched Tag. Else, only RxMatch is returned.

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

The total_timeout option sets a time limit for the complete expect operation. After TotalTimeout milliseconds, {error,timeout} is returned. The default value is infinity (i.e. no time limit).

The function will return when a prompt is received, even if no pattern has yet been matched. In this event, {error,{prompt,Prompt}} is returned. However, this behaviour may be modified with the ignore_prompt or no_prompt_check option, which tells expect to return only 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 wait_for_prompt option forces ct_telnet to wait until the prompt string has been received before returning (even if a pattern has already been matched). This is equal to calling: expect(Conn, Patterns++[{prompt,Prompt}], [sequence|Opts]). Note that idle_timeout and total_timeout may abort the operation of waiting for 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 will return with HaltReason = done.

The sequence option indicates that all patterns shall be matched in a sequence. A match will not be concluded untill all patterns are matched.

Both repeat and sequence can be interrupted by one or more HaltPatterns. When sequence or repeat is used, there will always be a MatchList returned, i.e. a list of Match instead of only one Match. There will also be a HaltReason returned.

Examples:
expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}], [sequence,{halt,[{nnn,"NNN"}]}]).
will try to match "ABC" first and then "XYZ", but if "NNN" appears the function will return {error,{nnn,["NNN"]}}. If both "ABC" and "XYZ" are matched, the function will return {ok,[AbcMatch,XyzMatch]}.

expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}], [{repeat,2},{halt,[{nnn,"NNN"}]}]).
will try to match "ABC" or "XYZ" twice. If "NNN" appears the function will return with HaltReason = {nnn,["NNN"]}.

The repeat and sequence options can be combined in order to match a sequence multiple times.

format_data(How, X2) -> term()

See also

unix_telnet