ct_telnet(3)

πŸ“¦
version 29.0.6 Β· 3 versions
, in ubuntu stonking

ct_telnet(3) β€” Erlang Module Definition πŸ’–

NAME πŸŽ€

ct_telnet β€” the Common Test–specific layer sitting right on top of the Telnet client ct_telnet_client.erl. That's the whole vibe, bestie. πŸ’…

DESCRIPTION 🌸

Use this module to set up Telnet connections, send commands, and perform string matching on the result. Need the full tea on how to use ct_telnet and configure connections, specifically for UNIX hosts? Go read the unix_telnet manual page. πŸ“–

Default values defined in ct_telnet:

  • Connection timeout β€” time to wait for connection = 10 seconds ⏳
  • Command timeout β€” time to wait for a command to return = 10 seconds ⏰
  • Max number of reconnection attempts = 3 πŸ”
  • Reconnection interval β€” time to wait in between reconnection attempts = 5 seconds
  • Keep alive β€” sends NOP to the server every 8 sec if connection is idle = true πŸ’“
  • Polling limit β€” max number of times to poll to get a remaining string terminated = 0
  • Polling interval β€” sleep time between polls = 1 second 😴
  • The TCP_NODELAY option for the telnet socket is disabled (set to false) per default 🚫

These parameters can be modified 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},
                   {tcp_nodelay,Bool}]}.

Millisec = timeout(), N = integer()

Enter the telnet_settings term in a configuration file included in the test, and ct_telnet retrieves the information automatically. ✨

keep_alive can be specified per connection, if necessary. For details, see unix_telnet. 🫢

Logging πŸ“

The default logging behavior of ct_telnet is to print information about performed operations, commands, and their corresponding results to the test case HTML log. The following is not printed to the HTML log: text strings sent from the Telnet server that are not explicitly received by a ct_telnet function, such as expect/3. However, ct_telnet can be configured to use a special purpose event handler, implemented in ct_conn_log_h, for logging all Telnet traffic. To use this handler, install a Common Test hook named cth_conn_log. Example (using the test suite information 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, that is, 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 any data sent from the server. The link to this text file is located at the top of the test case HTML log. πŸ”—

By default, data for all Telnet connections is logged in one common file (named default), which can get messy, for example, if multiple Telnet sessions are running in parallel. Therefore a separate log file can be created for each connection. To configure this, use hook option hosts and list the names of the servers/connections to be used in the suite. The connections must be named for this to work (see ct_telnet:open/1,2,3,4). πŸ“‚

Hook option log_type can be used to change the cth_conn_log behavior. The default value of this option is raw, which results in the behavior described above. If the value is set to html, all Telnet communication is printed to the test case HTML log instead. πŸ–₯️

For raw logs, prefix option can be used for adjusting prefix data added to connection log. The default value of this option is disabled, which results with no prefix data. If the value is set to full prefix contains timestamp and additonal information. If the value is set to short prefix includes only human readable timestamp. ⏱️

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

Example:

{ct_conn_log, [{ct_telnet,[{log_type,raw},
                           {hosts,[key_or_name()]}]}]}
NOTE: Hook options specified in a configuration file overwrite any hard-coded hook options in the test suite. ⚠️

Logging Example:

The following ct_hooks statement causes printing of Telnet traffic to separate logs for the connections server1 and server2. Traffic for any other connections is logged in the default Telnet log.

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

As previously explained, this specification can also be provided by an entry like the following in a configuration file:

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

In this case the ct_hooks statement in the test suite can look as follows:

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

See Also πŸ”—

unix_telnet

DATA TYPES πŸ¦‹

connection() :: handle() | {ct:target_name(), connection_type()} | ct:target_name().

Reference to opened Telnet connection associated to either a handle or target_name. πŸ’«

connection_type() :: telnet | ts1 | ts2.

Telnet connection_type, valid values: 'telnet' | 'ts1' | 'ts2'. πŸ“‘

handle() :: ct:handle().

Handle for a specific Telnet connection, see module ct. πŸŽ›οΈ

newline_option() :: {newline, boolean() | string()}.

See cmd/3 for explanation. πŸ“

prompt_regexp() :: string().

Regular expression matching all possible prompts for a specific target type. regexp must not have any groups, that is, when matching, re:run/3 (in STDLIB) must return a list with one single element. 🧐

FUNCTIONS πŸ’…

close(Connection) -> ok | {error, Reason}
               when
                   Connection :: connection(),
                   Reason :: already_closed | term().

Closes the Telnet connection and stops the process managing it. Bye bestie πŸ‘‹

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

cmd(Connection, Cmd, Opts) -> {ok, Data} | {error, Reason}
               when
                   Connection :: connection(),
                   Cmd :: iodata(),
                   Opts ::
                       [{timeout, Timeout} | newline_option()] | Timeout,
                   Timeout :: integer(),
                   Data :: string(),
                   Reason :: term().

Sends a command through Telnet and waits for prompt. πŸš€

By default, this function adds "\n" to the end of the specified command. If this is not desired, use option {newline,false}. This is necessary, for example, when sending Telnet command sequences prefixed with character Interpret As Command (IAC). Option {newline,string()} can also be used if a different line end than "\n" is required, for instance {newline,"\r\n"}, to add both carriage return and newline characters. πŸ“¨

Option timeout specifies how long the client must wait for prompt. If the time expires, the function returns {error,timeout}. For information about the default value for the command timeout, see the list of default values in the beginning of this module. ⏳

cmdf(Connection, CmdFormat, Args, Opts) ->
                {ok, Data} | {error, Reason}
                when
                    Connection :: connection(),
                    CmdFormat :: io:format(),
                    Args :: [term()],
                    Opts ::
                        [{timeout, Timeout} | newline_option()] | Timeout,
                    Timeout :: integer(),
                    Data :: string(),
                    Reason :: term().

Sends a Telnet command and waits for prompt (uses a format string and a list of arguments to build the command). πŸ› οΈ

For details, see ct_telnet:cmd/3.

expect(Connection, Patterns, Opts) ->
                  {ok, Match} |
                  {ok, Match, HaltReason} |
                  {error, Reason} |
                  no_return()
                  when
                      Connection :: connection(),
                      Patterns :: Pattern | [Pattern],
                      Pattern :: PatternString | {Tag, PatternString},
                      Tag :: term(),
                      PatternString :: unicode:charlist(),
                      Opts :: [Option],
                      Option ::
                          {idle_timeout, non_neg_integer()} |
                          {total_timeout, non_neg_integer()} |
                          ignore_prompt | no_prompt_check |
                          wait_for_prompt | repeat |
                          {repeat, non_neg_integer()} |
                          sequence |
                          {halt, Patterns},
                      Match :: MatchResult | [MatchResult],
                      MatchResult ::
                          [CaptureData | {Tag, CaptureData}] |
                          [[CaptureData | {Tag, CaptureData}]],
                      CaptureData ::
                          string() |
                          {error, string(), binary()} |
                          {incomplete, string(), binary()},
                      HaltReason :: MatchResult,
                      Reason :: term().

Gets data from Telnet and waits for the expected pattern. πŸ‘€

Pattern can be a POSIX regular expression. The function returns when a pattern is successfully matched (at least one, in the case of multiple patterns). βœ…

RxMatch is a list of matched strings. It looks as follows [FullMatch, SubMatch1, SubMatch2, ...], where FullMatch is the string matched by the whole regular expression, and SubMatchN is the string that matched subexpression number N. Subexpressions are denoted with '(' ')' in the regular expression. πŸ”

If a Tag is specified, the returned Match also includes the matched Tag. Otherwise, only RxMatch is returned. 🏷️

Options:

  • idle_timeout β€” Indicates that the function must return if the Telnet client is idle (that is, if no data is received) for more than IdleTimeout milliseconds. Default time-out is 10 seconds. 😴
  • total_timeout β€” Sets a time limit for the complete expect operation. After TotalTimeout milliseconds, {error,timeout} is returned. Default is infinity (that is, no time limit). ♾️
  • ignore_prompt | no_prompt_check β€” with this vibe, the function returns the moment a prompt shows up, even if not a single pattern has matched yet, and you get {error,{prompt,Prompt}} back. But bestie, you can change that whole behavior with option ignore_prompt or option no_prompt_check, which tells expect to return only when there's an actual match, or after a time-out. πŸ’…
  • ignore_prompt β€” ct_telnet just ignores any prompt it finds. Obsessed with this one when the data your server sends can include a pattern that matches the prompt regexp (the one you get from TargedMod:get_prompt_regexp/0), but that pattern matching is not supposed to be the thing that makes the function return. πŸ™ˆ
  • no_prompt_check β€” ct_telnet does not search for a prompt at all. Not even a little. Super handy when, for example, Pattern itself matches the prompt. 😌
  • wait_for_prompt β€” forces ct_telnet to wait until the prompt string is actually received before returning, even if a pattern has already been matched. This is literally equal to calling expect(Conn, Patterns++[{prompt,Prompt}], [sequence|Opts]). Heads up though: option idle_timeout and total_timeout can abort the whole waiting-for-prompt operation. 😭
  • repeat | repeat, N β€” the pattern(s) have to be matched multiple times. If you pass N, the pattern(s) get matched N times and the function returns HaltReason = done. This option can be interrupted by one or more HaltPatterns. MatchList is always returned β€” a list of Match instead of only one Match. Also HaltReason is returned. 🫢
  • sequence β€” all patterns must be matched in a sequence, and a match is not concluded until every single pattern is matched. This option can be interrupted by one or more HaltPatterns. MatchList is always returned, that is, a list of Match instead of only one Match. Also HaltReason is returned. ✨

Example 1:

expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],[sequence,{halt,[{nnn,"NNN"}]}])

First this tries to match "ABC", and then "XYZ", but if "NNN" shows up, the function returns {error,{nnn,["NNN"]}}. If both "ABC" and "XYZ" get matched, the function returns {ok,[AbcMatch,XyzMatch]}. Slay. πŸ‘‘

Example 2:

expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],[{repeat,2},{halt,[{nnn,"NNN"}]}])

This one tries to match "ABC" or "XYZ" twice. If "NNN" appears, the function returns HaltReason = {nnn,["NNN"]}.

And ok the cute part: options repeat and sequence can be combined to match a sequence multiple times. It's giving efficiency. πŸ’–


πŸ¦‹ get_data/1 πŸ¦‹

get_data(Connection) -> {ok, Data} | {error, Reason}
                  when
                      Connection :: connection(),
                      Data :: string(),
                      Reason :: term().

Gets all the data the Telnet client has received since the last command was sent. Only newline-terminated strings get returned, no cap. If that last received string hasn't been terminated yet, the connection can be polled automatically until the string is complete.

That polling feature is controlled by the configuration values poll_limit and poll_interval, and it's disabled by default. Which means: the function immediately returns every complete string it's got, and saves the remaining non-terminated string for a later get_data call. 🌸

πŸŽ€ open/2 πŸŽ€

open(Name, ConnType) -> {ok, Handle} | {error, Reason}
                when
                    Name :: atom(),
                    ConnType :: connection_type(),
                    Handle :: handle(),
                    Reason :: term().

Opens a Telnet connection to the specified target host. That's it, that's the whole vibe. πŸ”₯

πŸ’œ open/4 πŸ’œ

open(KeyOrName, ConnType, TargetMod, Extra) ->
                {ok, Handle} | {error, Reason}
                when
                    KeyOrName :: ct:key_or_name(),
                    ConnType :: connection_type(),
                    TargetMod :: module(),
                    Extra :: term(),
                    Handle :: handle(),
                    Reason :: term().

Opens a Telnet connection to the specified target host.

The target data must exist in a configuration file, fr fr. The connection can be associated with Name and/or the returned Handle. To allocate a name for the target, use one of these alternatives:

  • ct:require/2 in a test case
  • require statement in the suite information function (suite/0)
  • require statement in a test case information function

If you want the connection associated with Handle only (say, because you need to open multiple connections to a host), then use Key β€” the configuration variable name β€” to specify the target. Notice that a connection without an associated target name can only be closed with the Handle value. Keep that in mind bestie, it's important. ⭐

TargetMod is a module that exports the functions connect(Ip, Port, KeepAlive, Extra) and get_prompt_regexp() for the specified TargetType (for example, unix_telnet).

See also ct:require/2.

🌈 send/3 🌈

send(Connection, Cmd, Opts) -> ok | {error, Reason}
                when
                    Connection :: connection(),
                    Cmd :: iodata(),
                    Opts :: [newline_option()],
                    Reason :: term().

Sends a Telnet command and returns immediately β€” no waiting around, main character energy. 🫧

By default, this function adds "\n" to the end of the specified command. If you don't want that, option {newline,false} is right there for you. This matters, for example, when you're sending Telnet command sequences prefixed with the character Interpret As Command (IAC). Option {newline,string()} is also a thing if you need a different line end than "\n" β€” for instance {newline,"\r\n"}, to add both carriage return and newline characters.

The resulting output from the command can be read with ct_telnet:get_data/2 or ct_telnet:expect/2,3. πŸ’…

πŸ“ sendf/4 πŸ“

sendf(Connection, CmdFormat, Args, Opts) -> ok | {error, Reason}
                 when
                     Connection :: connection(),
                     CmdFormat :: io:format(),
                     Args :: [term()],
                     Opts :: [newline_option()],
                     Reason :: term().

Sends a Telnet command and returns immediately β€” but this one uses a format string and a list of arguments to build the command. Cute and convenient. ✨

For the details, see ct_telnet:send/3.


And that's a wrap on ct_telnet(3)! Written by Ericsson AB, from common_test 1.31.1, dated ct_telnet(3) β€” go forth and telnet, bestie. πŸ¦‹πŸ’– No cap, you got this. Periodt.

πŸ“¦ where this page comes from