Provided by: opendkim-tools_2.10.3-3build1_i386 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

       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)