Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
miltertest(8)		    System Manager's Manual		 miltertest(8)

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  par-
       ticular	transaction  must  follow  a  series of	steps to be completed,
       namely negotiate, connection information, envelope sender, envelope re-
       cipient(s), header field(s), end-of-header, body	chunk(s),  end-of-mes-
       sage.   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  automati-
       cally.	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	inter-
	      nally).	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  exe-
	      cuted.  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 re-
	      quest more and more information.

       -V     Print version number and exit.

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

FUNCTIONS
       The  following functions	are made available to Lua scripts for exercis-
       ing 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	print-
	      able 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  in-
	      cluded,  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 mul-
	      tiplied 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,	repre-
	      sented  by  connection  conn, from the host named	host at	IP ad-
	      dress 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 spe-
	      cial  string "unspec", which will	tell the filter	that a connec-
	      tion 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 in-
	      dicating 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 noth-
	      ing.

       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	deter-
	      mine 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 con-
	      nection.	 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 con-
	      nection, as an integer.  This can	be compared to any of the  SM-
	      FIR_* 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  pa-
	      rameter 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_CON-
	      NECT,  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, ad-
	      vertising	 that the specified protocol version, protocol actions
	      and protocol steps are offered by	the MTA.  Returns the Lua con-
	      stant "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  mil-
	      tertest  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 re-
	      quested 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 re-
	      quested 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 op-
       eration is of interest, and it also dictates what the possible  parame-
       ter  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 re-
	      turns true only if the named header field	was added  (regardless
	      of  its  value).	 If two	parameters are given, the function re-
	      turns 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  (re-
	      gardless	of  its	 new value).  If two parameters	are given, the
	      function returns true only if the	named header field  was	 modi-
	      fied 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 re-
	      turns 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 func-
	      tion returns true	only if	the named header field was added  (re-
	      gardless	of its value).	If two parameters are given, the func-
	      tion returns true	only if	the named header field was added  with
	      the  specified  value.  If three parameters are given, the func-
	      tion 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 con-
	      tent.  With no parameters, the function returns true only	if the
	      body was changed (regardless of the new content).	 With one  pa-
	      rameter,	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  mes-
	      sage.   With  no	parameters,  the function returns true only if
	      quarantine was requested.	 With one parameter, the function  re-
	      turns  true  only	if quarantine was requested with the specified
	      reason string.

       MT_SMTPREPLY
	      Checks to	see if the filter requested a specific SMTP reply mes-
	      sage.  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 re-
       turned.	 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  exe-
       cuted,  all  macros corresponding stages	after the current one are dis-
       carded.	 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  re-
       served.

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

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

			  The Trusted Domain Project		 miltertest(8)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=miltertest&sektion=8&manpath=FreeBSD+Ports+14.3.quarterly>

home | help