bionic (8) miltertest.8.gz

Provided by: opendkim-tools_2.11.0~alpha-11build1_amd64 bug

NAME

       miltertest - milter unit test utility

SYNOPSIS

       miltertest [-D name[=value]] [-s script] [-u] [-v] [-V] [-w]

DESCRIPTION

       miltertest  simulates  the  MTA  side  of  an  MTA-milter  interaction  for testing a milter-aware filter
       application.  It takes as input a script using the Lua language, and by exporting some utility functions,
       makes it possible for users to write scripts that exercise a filter.

       See  documentation  on  Lua  (e.g.  http://www.lua.org)  for  the syntax of the language in general.  The
       documentation below describes functions that are added  to  Lua  by  this  application  to  make  testing
       possible.

       Documentation  on  milter  can be found at http://www.milter.org.  A particular transaction must follow a
       series of steps to be completed, namely negotiate,  connection  information,  envelope  sender,  envelope
       recipient(s), header field(s), end-of-header, body chunk(s), end-of-message.  To make the work of writing
       tests with miltertest simpler, any of these steps prior to end-of-message that is skipped will be  filled
       in using arbitrary, but legal, data.

       Interspersed  with  these  protocol  phases  are  optional  macro  (key/value)  deliveries  from the MTA.
       miltertest will never send these automatically.  If they are needed for your tests, you must send them as
       part of your test script.

OPTIONS

       -D name[=value]
              Defines  a global variable called name to the Lua interpreter.  If a value is provided, the global
              variable is set to that  value  (as  a  string,  although  Lua  can  convert  strings  to  numbers
              internally).  If no value is provided, the global variable is set to 1.

       -s script
              Use  the  contents  of  file script as the Lua script to be executed.  The default is to read from
              standard input.

       -u     After the filter  being  tested  is  terminated,  report  user  and  system  time  consumed.   See
              getrusage(2).

       -v     Increase verbose output.  May be specified multiple times to request more and more information.

       -V     Print version number and exit.

       -w     Don't wait for child status to be returned when testing is complete.

FUNCTIONS

       The  following functions are made available to Lua scripts for exercising a filter.  All functions return
       Lua constant "nil" on success or an error string on failure, unless otherwise indicated.

       mt.abort(conn)
              Aborts the transaction in progress on the specified connection.

       mt.bodyfile(conn, file)
              Sends the contents of the named file to the connection as  body  data.   If  there  is  any  error
              opening file for reading, the test aborts.

       mt.bodyrandom(conn, n)
              Sends at least n bytes of random-length lines of random printable ASCII data as body chunks to the
              specified connection.

       mt.bodystring(conn, str)
              Sends str as a chunk of body text on the specified connection.

       mt.chdir(directory)
              Changes the current working directory to the named directory.

       mt.connect(sockinfo[, count, interval])
              Makes a connection to a filter listening at the socket described by sockinfo.   Returns  a  handle
              referring  to  that  connection,  or  the  Lua constant "nil" on error.  If count and interval are
              included, they specify the number of times to try to connect to the filter and the  delay  between
              each  connection  in  seconds (with floating point values permitted).  If the environment variable
              MILTERTEST_RETRY_SPEED_FACTOR is set and appears to contain an integer, the value of interval  (if
              set)  will  be  multiplied  by  the value found in that environment variable.  This is included to
              allow tests in a large test suite to be easily adjusted on slow systems without reconfiguring  the
              entire test suite.

       mt.conninfo(conn, host, ip)
              Sends information about a new SMTP connection to the MTA, represented by connection conn, from the
              host named host at IP address ip (both strings).  If host is the Lua constant  "nil",  the  string
              "localhost"  is  assumed.   If  ip  is the Lua constant "nil", a DNS query will be made for the IP
              address matching host; if none is found, the test will abort.  The ip  may  also  be  the  special
              string  "unspec",  which  will  tell the filter that a connection came in from an unknown protocol
              family.

       mt.data(conn)
              Announces the DATA command on the specified connection, which occurs  between  the  last  RCPT  TO
              command and the beginning of the header block.

       mt.disconnect(conn[, polite]))
              Sends a "quit" message to the specified connection and then closes that connection.  The specified
              conn handle should no longer be used.  If polite is defined,  it  must  be  a  Boolean  indicating
              whether  a normal disconnect should be done (true) or an abrupt disconnect should be done (false).
              An abrupt disconnect skips standard protocol shutdown steps.

       mt.echo(string)
              Prints the specified string on standard output.  Returns nothing.

       mt.eoh(conn)
              Announces end-of-header on the specified connection.

       mt.eom(conn)
              Announces end-of-message on the specified connection, and begins capturing  any  other  operations
              the filter might perform in that phase.

       mt.eom_check(conn, op, param[, ...])
              Checks  the captured set of EOM operations (see above) to determine whether or not specific milter
              actions were requested by the filter.  Returns a Boolean value  (true  or  false).   See  the  EOM
              CHECKS section for details.

       mt.getheader(conn, hdr, n)
              Retrieves  the  value  of  the  nth instance of header field named hdr added during end-of-message
              processing on the specified connection.  This can be used by the script to verify that the  header
              thus  added contains the right thing.  Returns the value as a string, or the Lua constant "nil" on
              error.

       mt.getcwd()
              Returns the current working directory as a string.

       mt.getreply(conn)
              Returns the last milter reply received from the specified connection, as an integer.  This can  be
              compared  to  any  of  the  SMFIR_*  constants defined by milter to see if the filter responded as
              expected.  This value is initially set to the NULL character.

       mt.header(conn, name, value)
              Sends the header with the given name and value to the specified connection.

       mt.helo(conn, name)
              Sends HELO/EHLO information using the specified name as the parameter given.

       mt.macro(conn, type, name, value[, name2, value2[, ...]])
              Declares a macro called name whose value is value and whose type (matching  protocol  element)  is
              type.  Valid types are SMFIC_CONNECT, SMFIC_HELO, SMFIC_MAIL and SMFIC_RCPT.  Multiple macro names
              and values can be provided, but they must appear in pairs.

       mt.mailfrom(conn, envfrom[, ...])
              Announces envfrom as the envelope sender  of  a  new  message.   ESMTP  parameters  as  additional
              arguments are permitted.

       mt.negotiate(conn, version, actions, steps)
              Performs  milter  option  negotiation  with  the  connection  conn, advertising that the specified
              protocol version, protocol actions and protocol steps are offered by the  MTA.   Returns  the  Lua
              constant  "nil"  on  success or an error string on failure.  If any of the protocol parameters are
              "nil", the current defaults (defined in libmilter/mfdef.h, provided with the milter  source  code)
              will be used.

       mt.rcptto(conn, envrcpt[, ...])
              Announces envrcpt as an envelope recipient of a message.  ESMTP parameters as additional arguments
              are permitted.

       mt.set_timeout(n)
              Sets the read timeout to n seconds.  The default is ten seconds.  Returns nothing.

       mt.sleep(n)
              Sleeps for n seconds.  The value may be an integer (for whole seconds) or a  floating-point  value
              (for partial seconds).

       mt.signal(n)
              Sends the specified signal number n to the running filter.

       mt.startfilter(path, arg1, arg2, ...)
              Starts  the filter whose binary is located at path with argument vector comprised of strings path,
              arg1, arg2, etc.  Basically this is almost the same syntax as execl(3) except that miltertest also
              does the fork for you, and will remember the process ID in order to request a clean shutdown using
              SIGTERM and wait(2) at the end of the test script.   If  the  filter  could  not  be  started,  an
              exception is generated with an error message returned.

       mt.test_action(conn, action)
              Tests  whether  or  not the connection represented by conn requested the specified milter protocol
              action, specified  by  an  SMFIF_*  constant,  during  option  negotiation.   (See  the  libmilter
              documentation and/or include files for details.)

       mt.test_option(conn, option)
              Tests  whether  or  not the connection represented by conn requested the specified milter protocol
              option, specified  by  an  SMFIP_*  constant,  during  option  negotiation.   (See  the  libmilter
              documentation and/or include files for details.)

       mt.unknown(conn, str)
              Announces that the unknown SMTP command str arrived over the connection represented by conn.

EOM CHECKS

       The  mt.eom_check() function is used to determine what changes to the message the filter requested during
       its EOM callback.  The changes can be requested in any order.  The first parameter,  op,  indicates  what
       operation  is  of  interest,  and it also dictates what the possible parameter list is.  Valid values and
       corresponding parameters for op are as follows:

       MT_HDRADD
              Checks to see if a header field was added to  the  message.   If  no  parameters  are  given,  the
              function  returns  true  if  any header field was added.  If one parameter was given, the function
              returns true only if the named  header  field  was  added  (regardless  of  its  value).   If  two
              parameters  are given, the function returns true only if the named header field was added with the
              specified value.

       MT_HDRCHANGE
              Checks to see if an existing header field was changed.  If no parameters are given,  the  function
              returns  true  if any header field was modified.  If one parameter was given, the function returns
              true only if the named header field was modified (regardless of its new value).  If two parameters
              are  given,  the  function  returns  true  only if the named header field was modified to have the
              specified new value.

       MT_HDRDELETE
              Checks to see if an existing header field was deleted.  If no parameters are given,  the  function
              returns  true  if  any header field was deleted.  If one parameter was given, the function returns
              true only if the named header field was deleted.

       MT_HDRINSERT
              Checks to see if a header field was inserted into the message.  If no parameters  are  given,  the
              function  returns  true  if  any header field was added.  If one parameter was given, the function
              returns true only if the named  header  field  was  added  (regardless  of  its  value).   If  two
              parameters  are given, the function returns true only if the named header field was added with the
              specified value.  If three parameters are given, the function  returns  true  only  if  the  named
              header field was added with the specified value at the specified index.

       MT_RCPTADD
              Checks to see if an envelope recipient was added.  Currently only one parameter may be provided.

       MT_RCPTDELETE
              Checks to see if an envelope recipient was deleted.  Currently only one parameter may be provided.

       MT_BODYCHANGE
              Checks  to  see  if  the  message's  body  was replaced by other content.  With no parameters, the
              function returns true only if the body was changed (regardless of  the  new  content).   With  one
              parameter, the function returns true only if the body was changed to the specified new content.

       MT_QUARANTINE
              Checks  to  see  if  the  filter  requested  quarantining of the message.  With no parameters, the
              function returns true only if quarantine was requested.  With one parameter, the function  returns
              true only if quarantine was requested with the specified reason string.

       MT_SMTPREPLY
              Checks  to  see  if  the  filter requested a specific SMTP reply message.  With no parameters, the
              function returns true only if a specific reply was requested.  With one  parameter,  the  function
              returns  true  only  if  a  specific  reply  was requested with the specified SMTP code.  With two
              parameters, the function returns true only if a specific reply was requested  with  the  specified
              SMTP  code  and  enhanced status code.  With three parameters, the function returns true only if a
              specific reply was requested with the specified SMTP code, enhanced status code, and text.

EXAMPLE

       -- Echo that the test is starting
       mt.echo("*** begin test")
       -- start the filter
       mt.startfilter("../myfilter", "-p", "inet:12345@localhost")
       mt.sleep(2)

       -- try to connect to it
       conn = mt.connect("inet:12345@localhost")
       if conn == nil then
            error "mt.connect() failed"
       end

       -- send connection information
       -- mt.negotiate() is called implicitly
       if mt.conninfo(conn, "localhost", "127.0.0.1") ~= nil then
            error "mt.conninfo() failed"
       end
       if mt.getreply(conn) ~= SMFIR_CONTINUE then
            error "mt.conninfo() unexpected reply"
       end

       -- send envelope macros and sender data
       -- mt.helo() is called implicitly
       mt.macro(conn, SMFIC_MAIL, "i", "test-id")
       if mt.mailfrom(conn, "user@example.com") ~= nil then
            error "mt.mailfrom() failed"
       end
       if mt.getreply(conn) ~= SMFIR_CONTINUE then
            error "mt.mailfrom() unexpected reply"
       end

       -- send headers
       -- mt.rcptto() is called implicitly
       if mt.header(conn, "From", "user@example.com") ~= nil then
            error "mt.header(From) failed"
       end
       if mt.getreply(conn) ~= SMFIR_CONTINUE then
            error "mt.header(From) unexpected reply"
       end
       if mt.header(conn, "Date", "Tue, 22 Dec 2009 13:04:12 -0800") ~= nil then
            error "mt.header(Date) failed"
       end
       if mt.getreply(conn) ~= SMFIR_CONTINUE then
            error "mt.header(Date) unexpected reply"
       end
       if mt.header(conn, "Subject", "Signing test") ~= nil then
            error "mt.header(Subject) failed"
       end
       if mt.getreply(conn) ~= SMFIR_CONTINUE then
            error "mt.header(Subject) unexpected reply"
       end
       -- send EOH
       if mt.eoh(conn) ~= nil then
            error "mt.eoh() failed"
       end
       if mt.getreply(conn) ~= SMFIR_CONTINUE then
            error "mt.eoh() unexpected reply"
       end

       -- send body
       if mt.bodystring(conn, "This is a test!\r\n") ~= nil then
            error "mt.bodystring() failed"
       end
       if mt.getreply(conn) ~= SMFIR_CONTINUE then
            error "mt.bodystring() unexpected reply"
       end
       -- end of message; let the filter react
       if mt.eom(conn) ~= nil then
            error "mt.eom() failed"
       end
       if mt.getreply(conn) ~= SMFIR_ACCEPT then
            error "mt.eom() unexpected reply"
       end

       -- verify that a test header field got added
       if not mt.eom_check(conn, MT_HDRINSERT, "Test-Header") then
            error "no header added"
       end

       -- wrap it up!
       mt.disconnect(conn)

NOTES

       If a filter negotiates one of the SMFIP_NO* protocol option bits and a script attempts to perform one  of
       those protocol steps, an error is returned.  It is up to the test author to use mt.test_option() function
       to see if performing a protocol step has been explicitly disabled by the filter.

MILTER NOTES

       When mt.macro() is called, it replaces all previous macros of the same type with the ones provided in the
       argument  list.  Thus, one call should be made that lists the complete set rather than one call per name-
       value pair.  Also, as each stage in the milter process is executed, all macros corresponding stages after
       the  current  one  are  discarded.  For example, calling mt.helo(), which corresponds to SMFIC_HELO, will
       cause all prior macros of type SMFIC_MAIL and SMFIC_RCPT to be discarded as they represent a milter stage
       that comes later than SMFIC_HELO.

       Since  the  milter  protocol and the internals of libmilter itself are not formally documented, there are
       myriad other subtleties of the milter protocol and implementation that are not documented  here  and  may
       not be documented elsewhere, and could change without notice.  Caveat emptor.

VERSION

       This man page covers version 1.5.0 of miltertest.

       Copyright (c) 2009-2014, The Trusted Domain Project.  All rights reserved.

SEE ALSO

       Milter -- http://www.milter.org

       Lua -- http://www.lua.org

                                           The Trusted Domain Project                              miltertest(8)