diff --git a/configure.ac b/configure.ac
index ed28c8b03..6c92dd026 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,663 +1,661 @@
 ## $Id$
 
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 ## This is CDS Invenio main configure.ac file.  If you change this
 ## file, then please run "autoreconf" to regenerate the "configure"
 ## script.
 
 ## Initialize autoconf and automake:
-AC_INIT(cds-invenio, 0.93.50.20080318, cds.support@cern.ch)
-AM_INIT_AUTOMAKE(cds-invenio, 0.93.50.20080318)
+AC_INIT(cds-invenio, 0.93.50.20080323, cds.support@cern.ch)
+AM_INIT_AUTOMAKE(cds-invenio, 0.93.50.20080323)
 
 ## By default we shall install into /opt/cds-invenio.  (Do not use
 ## AC_PREFIX_DEFAULT for this, because it would not work well with
 ## the localstatedir hack below.)
 test "${prefix}" = NONE && prefix=/opt/cds-invenio
 
 ## Check for install:
 AC_PROG_INSTALL
 
 ## Check for gettext support:
 AM_GNU_GETTEXT(external)
 AM_GNU_GETTEXT_VERSION(0.14.4)
 
 ## Check for MySQL client:
 AC_MSG_CHECKING(for mysql)
 AC_ARG_WITH(mysql, AC_HELP_STRING([--with-mysql], [path to a specific MySQL binary (optional)]), MYSQL=${withval})
 if test -n "$MYSQL"; then
    AC_MSG_RESULT($MYSQL)
 else
    AC_PATH_PROG(MYSQL, mysql)
    if test -z "$MYSQL"; then
       AC_MSG_ERROR([
       MySQL command-line client was not found in your PATH.  
       Please install it first.
       Available from <http://mysql.com/>.])
    fi
 fi
 
 ## Check for Python:
 AC_MSG_CHECKING(for python)
 AC_ARG_WITH(python, AC_HELP_STRING([--with-python], [path to a specific Python binary (optional)]), PYTHON=${withval})
 if test -n "$PYTHON"; then
    AC_MSG_RESULT($PYTHON)
 else
    AC_PATH_PROG(PYTHON, python)
    if test -z "$PYTHON"; then
       AC_MSG_ERROR([
       Python was not found in your PATH.  Please either install it
       in your PATH or specify --with-python configure option.
       Python is available from <http://python.org/>.])
    fi
 fi
 
 ## Check for Python version and modules:
 AC_MSG_CHECKING(for required Python modules)
 $PYTHON ${srcdir}/configure-tests.py
 if test $? -ne 0; then
    AC_MSG_ERROR([Please fix the above Python problem before continuing.])
 fi
 AC_MSG_RESULT(found)
 
 ## Check for PHP:
 AC_PATH_PROG(PHP, php)
 
 ## Check for Acrobat Reader:
 AC_PATH_PROG(ACROREAD, acroread)
 if test -z "$ACROREAD"; then
    AC_MSG_WARN([
    Acrobat Reader was not found in your PATH.  It is used in
    the WebSubmit module for automatic conversion of submitted documents.
    You can continue without it but you will miss some CDS Invenio
    functionality.  We recommend you to install it first and to rerun
    the configure script.  Acrobat Reader is available from
    <http://www.adobe.com/products/acrobat/readstep.html>.])
 fi
 
 ## Check for gzip:
 AC_PATH_PROG(GZIP, gzip)
 if test -z "$GZIP"; then
    AC_MSG_WARN([
    Gzip was not found in your PATH.  It is used in
    the WebSubmit module to compress the data submitted in an archive.
    You can continue without it but you will miss some CDS Invenio
    functionality.  We recommend you to install it first and to rerun
    the configure script.  Gzip is available from
    <http://www.gzip.org/>.])
 fi
 
 ## Check for gunzip:
 AC_PATH_PROG(GUNZIP, gunzip)
 if test -z "$GUNZIP"; then
    AC_MSG_WARN([
    Gunzip was not found in your PATH.  It is used in
    the WebSubmit module to correctly deal with submitted compressed
    files.
    You can continue without it but you will miss some CDS Invenio
    functionality.  We recommend you to install it first and to rerun
    the configure script.  Gunzip is available from
    <http://www.gzip.org/>.])
 fi
 
 ## Check for tar:
 AC_PATH_PROG(TAR, tar)
 if test -z "$TAR"; then
    AC_MSG_WARN([
    Tar was not found in your PATH.  It is used in
    the WebSubmit module to pack the submitted data into an archive.
    You can continue without it but you will miss some CDS Invenio
    functionality.  We recommend you to install it first and to rerun
    the configure script.  Tar is available from
    <ftp://prep.ai.mit.edu/pub/gnu/tar/>.])
 fi
 
 ## Check for ps2pdf:
 AC_PATH_PROG(PS2PDF, ps2pdf)
 if test -z "$PS2PDF"; then
    AC_MSG_WARN([
    ps2pdf was not found in your PATH.  It is used in
    the WebSubmit module to convert submitted PostScripts into PDF.
    You can continue without it but you will miss some CDS Invenio
    functionality.  We recommend you to install it first and to rerun
    the configure script.  ps2pdf is available from
    <http://www.cs.wisc.edu/~ghost/doc/AFPL/>.])
 fi
 
 ## Check for pdftotext:
 AC_PATH_PROG(PDFTOTEXT, pdftotext)
 if test -z "$PDFTOTEXT"; then
    AC_MSG_WARN([
    pdftotext was not found in your PATH.  It is used for the fulltext indexation
    of PDF files.
    You can continue without it but you may miss fulltext searching capability
    of CDS Invenio.  We recomend you to install it first and to rerun the configure
    script.  pdftotext is available from <http://www.foolabs.com/xpdf/home.html>.
    ])
 fi
 
 ## Check for pdftk:
 AC_PATH_PROG(PDFTK, pdftk)
 if test -z "$PDFTK"; then
    AC_MSG_WARN([
    pdftk was not found in your PATH.  It is used for the fulltext file stamping.
    You can continue without it but you may miss this feature of CDS Invenio.  
    We recomend you to install it first and to rerun the configure
    script.  pdftk is available from <http://www.accesspdf.com/pdftk/>.
    ])
 fi
 
 ## Check for pdf2ps:
 AC_PATH_PROG(PDF2PS, pdf2ps)
 if test -z "$PDF2PS"; then
    AC_MSG_WARN([
    pdf2ps was not found in your PATH.  It is used in
    the WebSubmit module to convert submitted PDFs into PostScript.
    You can continue without it but you will miss some CDS Invenio
    functionality.  We recommend you to install it first and to rerun
    the configure script.  pdf2ps is available from
    <http://www.cs.wisc.edu/~ghost/doc/AFPL/>.])
 fi
 
 ## Check for pstotext:
 AC_PATH_PROG(PSTOTEXT, pstotext)
 if test -z "$PSTOTEXT"; then
    AC_MSG_WARN([
    pstotext was not found in your PATH.  It is used for the fulltext indexation
    of PDF and PostScript files.
    You can continue without it but you may miss fulltext searching capability
    of CDS Invenio.  We recomend you to install it first and to rerun the configure
    script.  pstotext is available from <http://www.cs.wisc.edu/~ghost/doc/AFPL/>.
    ])
 fi
 
 ## Check for ps2ascii:
 AC_PATH_PROG(PSTOASCII, ps2ascii)
 if test -z "$PSTOASCII"; then
    AC_MSG_WARN([
    ps2ascii was not found in your PATH.  It is used for the fulltext indexation
    of PostScript files.
    You can continue without it but you may miss fulltext searching capability
    of CDS Invenio.  We recomend you to install it first and to rerun the configure
    script.  ps2ascii is available from <http://www.cs.wisc.edu/~ghost/doc/AFPL/>.
    ])
 fi
 
 ## Check for antiword:
 AC_PATH_PROG(ANTIWORD, antiword)
 if test -z "$ANTIWORD"; then
    AC_MSG_WARN([
    antiword was not found in your PATH.  It is used for the fulltext indexation
    of Microsoft Word files.
    You can continue without it but you may miss fulltext searching capability
    of CDS Invenio.  We recomend you to install it first and to rerun the configure
    script.  antiword is available from <http://www.winfield.demon.nl/index.html>.
    ])
 fi
 
 ## Check for catdoc:
 AC_PATH_PROG(CATDOC, catdoc)
 if test -z "$CATDOC"; then
    AC_MSG_WARN([
    catdoc was not found in your PATH.  It is used for the fulltext indexation
    of Microsoft Word files.
    You can continue without it but you may miss fulltext searching capability
    of CDS Invenio.  We recomend you to install it first and to rerun the configure
    script.  catdoc is available from <http://www.ice.ru/~vitus/catdoc/index.html>.
    ])
 fi
 
 ## Check for wvText:
 AC_PATH_PROG(WVTEXT, wvText)
 if test -z "$WVTEXT"; then
    AC_MSG_WARN([
    wvText was not found in your PATH.  It is used for the fulltext indexation
    of Microsoft Word files.
    You can continue without it but you may miss fulltext searching capability
    of CDS Invenio.  We recomend you to install it first and to rerun the configure
    script.  wvText is available from <http://sourceforge.net/projects/wvware>.
    ])
 fi
 
 ## Check for ppthtml:
 AC_PATH_PROG(PPTHTML, ppthtml)
 if test -z "$PPTHTML"; then
    AC_MSG_WARN([
    ppthtml was found in your PATH. It is used for the fulltext indexation
    of Microsoft PowerPoint files.
    You can continue without it but you may miss fulltext searching capability
    of CDS Invenio.  We recomend you to install it first and to rerun the configure
    script.  ppthtml is available from <http://www.xlhtml.org/>.
    ])
 fi
 
 ## Check for xlhtml:
 AC_PATH_PROG(XLHTML, xlhtml)
 if test -z "$XLHTML"; then
    AC_MSG_WARN([
    xlhtml was found in your PATH. It is used for the fulltext indexation
    of Microsoft Excel files.
    You can continue without it but you may miss fulltext searching capability
    of CDS Invenio.  We recomend you to install it first and to rerun the configure
    script.  xlhtml is available from <http://chicago.sourceforge.net/xlhtml/>.
    ])
 fi
 
 ## Check for html2text:
 AC_PATH_PROG(HTMLTOTEXT, html2text)
 if test -z "$HTMLTOTEXT"; then
    AC_MSG_WARN([
    html2text was found in your PATH. It is used for the fulltext indexation
    of Microsoft PowerPoint and Excel files.
    You can continue without it but you may miss fulltext searching capability
    of CDS Invenio.  We recomend you to install it first and to rerun the configure
    script.  html2text is available from <http://userpage.fu-berlin.de/~mbayer/tools/html2text.html>.
    ])
 fi
 
 ## Check for Giftext:
 AC_PATH_PROG(GIFTEXT, giftext)
 if test -z "$GIFTEXT"; then
    AC_MSG_WARN([
    Giftext was not found in your PATH.  It is used in
    the WebSubmit module to create an icon from a submitted picture.
    You can continue without it but you will miss some CDS Invenio
    functionality.  We recommend you to install it first and to rerun
    the configure script.  Giftext is available from
    <http://prtr-13.ucsc.edu/~badger/software/libungif/getting.shtml>.])
 fi
 
 ## Check for file:
 AC_PATH_PROG(FILE, file)
 if test -z "$FILE"; then
    AC_MSG_WARN([
    File was not found in your PATH.  It is used in
    the WebSubmit module to check the validity of the submitted files.
    You can continue without it but you will miss some CDS Invenio
    functionality.  We recommend you to install it first and to rerun
    the configure script.  File is available from
    <ftp://ftp.astron.com/pub/file/>.])
 fi
 
 ## Check for convert:
 AC_PATH_PROG(CONVERT, convert)
 if test -z "$CONVERT"; then
    AC_MSG_WARN([
    Convert was not found in your PATH.  It is used in
    the WebSubmit module to create an icon from a submitted picture.
    You can continue without it but you will miss some CDS Invenio
    functionality.  We recommend you to install it first and to rerun
    the configure script.  Convert is available from
    <http://www.imagemagick.org/>.])
 fi
 
 ## Check for CLISP:
 AC_MSG_CHECKING(for clisp)
 AC_ARG_WITH(clisp, AC_HELP_STRING([--with-clisp], [path to a specific CLISP binary (optional)]), CLISP=${withval})
 if test -n "$CLISP"; then
    AC_MSG_RESULT($CLISP)
 else
    AC_PATH_PROG(CLISP, clisp)
    if test -z "$CLISP"; then
       AC_MSG_WARN([
       GNU CLISP was not found in your PATH.  It is used by the WebStat
       module to produce statistics about CDS Invenio usage.  (Alternatively,
       SBCL or CMUCL can be used instead of CLISP.)
       You can continue without it but you will miss this feature.  We
       recommend you to install it first (if you don't have neither CMUCL
       nor SBCL) and to rerun the configure script.
       GNU CLISP is available from <http://clisp.cons.org/>.])
    fi
 fi
 
 ## Check for CMUCL:
 AC_MSG_CHECKING(for cmucl)
 AC_ARG_WITH(cmucl, AC_HELP_STRING([--with-cmucl], [path to a specific CMUCL binary (optional)]), CMUCL=${withval})
 if test -n "$CMUCL"; then
    AC_MSG_RESULT($CMUCL)
 else
    AC_PATH_PROG(CMUCL, cmucl)
    if test -z "$CMUCL"; then
       AC_MSG_CHECKING(for lisp) # CMUCL can also be installed under `lisp' exec name
       AC_PATH_PROG(CMUCL, lisp)
    fi
    if test -z "$CMUCL"; then
       AC_MSG_WARN([
       CMUCL was not found in your PATH.  It is used by the WebStat
       module to produce statistics about CDS Invenio usage.  (Alternatively,
       CLISP or SBCL can be used instead of CMUCL.)
       You can continue without it but you will miss this feature.  We
       recommend you to install it first (if you don't have neither CLISP
       nor SBCL) and to rerun the configure script.
       CMUCL is available from <http://www.cons.org/cmucl/>.])
    fi
 fi
 
 ## Check for SBCL:
 AC_MSG_CHECKING(for sbcl)
 AC_ARG_WITH(sbcl, AC_HELP_STRING([--with-sbcl], [path to a specific SBCL binary (optional)]), SBCL=${withval})
 if test -n "$SBCL"; then
    AC_MSG_RESULT($SBCL)
 else
    AC_PATH_PROG(SBCL, sbcl)
    if test -z "$SBCL"; then
       AC_MSG_WARN([
       SBCL was not found in your PATH.  It is used by the WebStat
       module to produce statistics about CDS Invenio usage.  (Alternatively,
       CLISP or CMUCL can be used instead of SBCL.)
       You can continue without it but you will miss this feature.  We
       recommend you to install it first (if you don't have neither CLISP
       nor CMUCL) and to rerun the configure script.
       SBCL is available from <http://sbcl.sourceforge.net/>.])
    fi
 fi
 
 ## Check for gnuplot:
 AC_PATH_PROG(GNUPLOT, gnuplot)
 if test -z "$GNUPLOT"; then
    AC_MSG_WARN([
    Gnuplot was not found in your PATH.  It is used by the BibRank
    module to produce graphs about download and citation history.
    You can continue without it but you will miss these graphs.  We
    recommend you to install it first and to rerun the configure script.
    Gnuplot is available from <http://www.gnuplot.info/>.])
 fi
 
 ## Substitute variables:
 AC_SUBST(VERSION)
 AC_SUBST(MYSQL)
 AC_SUBST(PHP)
 AC_SUBST(PYTHON)
 AC_SUBST(CLIDIR)
 AC_SUBST(PDFTOTEXT)
 AC_SUBST(PDFTK)
 AC_SUBST(PDF2PS)
 AC_SUBST(PSTOTEXT)
 AC_SUBST(PSTOASCII)
 AC_SUBST(ANTIWORD)
 AC_SUBST(CATDOC)
 AC_SUBST(WVTEXT)
 AC_SUBST(PPTHTML)
 AC_SUBST(XLHTML)
 AC_SUBST(HTMLTOTEXT)
 AC_SUBST(localstatedir, `eval echo "${localstatedir}"`)
 AC_SUBST(CACHEDIR)
 AC_SUBST(CLISP)
 AC_SUBST(CMUCL)
 AC_SUBST(SBCL)
 AC_SUBST(GNUPLOT)
 AC_SUBST(DJPEG)
 AC_SUBST(CONVERT)
 AC_SUBST(GIFTEXT)
 AC_SUBST(JPEGSIZE)
 AC_SUBST(PNMSCALE)
 AC_SUBST(PPMQUANT)
 AC_SUBST(PPMTOGIF)
 AC_SUBST(GIFINTER)
 AC_SUBST(GIFRSIZE)
 
 ## Define output files:
 AC_CONFIG_FILES([config.nice  \
 	  Makefile \
           po/Makefile.in \
 	  config/Makefile \
 	  config/invenio-autotools.conf \
 	  modules/Makefile \
 	  modules/bibconvert/Makefile \
 	  modules/bibconvert/bin/Makefile \
 	  modules/bibconvert/bin/bibconvert \
 	  modules/bibconvert/doc/Makefile \
 	  modules/bibconvert/doc/admin/Makefile \
 	  modules/bibconvert/doc/hacking/Makefile \
 	  modules/bibconvert/etc/Makefile \
 	  modules/bibconvert/lib/Makefile \
 	  modules/bibmatch/Makefile \
 	  modules/bibmatch/bin/Makefile \
 	  modules/bibmatch/bin/bibmatch \
 	  modules/bibmatch/doc/Makefile \
 	  modules/bibmatch/doc/admin/Makefile \
 	  modules/bibmatch/etc/Makefile \
 	  modules/bibmatch/lib/Makefile \
 	  modules/bibedit/Makefile \
 	  modules/bibedit/bin/Makefile \
 	  modules/bibedit/bin/refextract \
 	  modules/bibedit/bin/xmlmarclint \
 	  modules/bibedit/bin/xmlmarc2textmarc \
 	  modules/bibedit/bin/bibedit \
 	  modules/bibedit/doc/Makefile \
 	  modules/bibedit/doc/admin/Makefile \
 	  modules/bibedit/doc/hacking/Makefile \
 	  modules/bibedit/etc/Makefile \
 	  modules/bibedit/lib/Makefile \
 	  modules/bibedit/web/Makefile \
 	  modules/bibedit/web/admin/Makefile \
 	  modules/bibformat/Makefile \
 	  modules/bibformat/bin/Makefile \
 	  modules/bibformat/bin/bibreformat \
 	  modules/bibformat/doc/Makefile \
 	  modules/bibformat/doc/admin/Makefile \
 	  modules/bibformat/doc/hacking/Makefile \
 	  modules/bibformat/etc/Makefile \
 	  modules/bibformat/etc/output_formats/Makefile \
 	  modules/bibformat/etc/format_templates/Makefile \
 	  modules/bibformat/lib/Makefile \
 	  modules/bibformat/lib/elements/Makefile \
 	  modules/bibformat/web/Makefile \
 	  modules/bibformat/web/admin/Makefile \
 	  modules/bibharvest/Makefile \
 	  modules/bibharvest/bin/Makefile \
 	  modules/bibharvest/bin/bibharvest \
 	  modules/bibharvest/bin/oaiharvest \
 	  modules/bibharvest/bin/oaiarchive \
 	  modules/bibharvest/doc/Makefile \
 	  modules/bibharvest/doc/admin/Makefile \
 	  modules/bibharvest/doc/hacking/Makefile \
 	  modules/bibharvest/lib/Makefile \
 	  modules/bibharvest/web/Makefile \
 	  modules/bibharvest/web/admin/Makefile \
 	  modules/bibclassify/Makefile \
 	  modules/bibclassify/bin/Makefile \
 	  modules/bibclassify/bin/bibclassify \
 	  modules/bibclassify/bin/bibclassifyd \
 	  modules/bibclassify/doc/Makefile \
 	  modules/bibclassify/doc/admin/Makefile \
 	  modules/bibclassify/doc/hacking/Makefile \
 	  modules/bibclassify/etc/Makefile
 	  modules/bibclassify/lib/Makefile
 	  modules/bibindex/Makefile \
 	  modules/bibindex/bin/Makefile \
 	  modules/bibindex/bin/bibindex \
 	  modules/bibindex/bin/bibstat \
 	  modules/bibindex/doc/Makefile \
 	  modules/bibindex/doc/admin/Makefile \
 	  modules/bibindex/doc/hacking/Makefile \
 	  modules/bibindex/lib/Makefile \
 	  modules/bibindex/web/Makefile \
 	  modules/bibindex/web/admin/Makefile \
 	  modules/bibrank/Makefile \
 	  modules/bibrank/bin/Makefile \
 	  modules/bibrank/bin/bibrank \
 	  modules/bibrank/bin/bibrankgkb \
 	  modules/bibrank/doc/Makefile \
 	  modules/bibrank/doc/admin/Makefile \
 	  modules/bibrank/doc/hacking/Makefile \
 	  modules/bibrank/etc/Makefile \
 	  modules/bibrank/etc/bibrankgkb.cfg \
 	  modules/bibrank/etc/demo_jif.cfg \
 	  modules/bibrank/etc/template_single_tag_rank_method.cfg \
 	  modules/bibrank/lib/Makefile \
 	  modules/bibrank/web/Makefile \
 	  modules/bibrank/web/admin/Makefile \
 	  modules/bibsched/Makefile \
 	  modules/bibsched/bin/Makefile \
 	  modules/bibsched/bin/bibsched \
 	  modules/bibsched/bin/bibtaskex \
 	  modules/bibsched/doc/Makefile \
 	  modules/bibsched/doc/admin/Makefile \
 	  modules/bibsched/doc/hacking/Makefile \
 	  modules/bibsched/lib/Makefile \
 	  modules/bibupload/Makefile \
 	  modules/bibupload/bin/Makefile \
 	  modules/bibupload/bin/bibupload \
 	  modules/bibupload/doc/Makefile \
 	  modules/bibupload/doc/admin/Makefile \
 	  modules/bibupload/doc/hacking/Makefile \
 	  modules/bibupload/lib/Makefile \
 	  modules/elmsubmit/Makefile \
 	  modules/elmsubmit/bin/Makefile \
 	  modules/elmsubmit/bin/elmsubmit \
 	  modules/elmsubmit/doc/Makefile \
 	  modules/elmsubmit/doc/admin/Makefile \
 	  modules/elmsubmit/doc/hacking/Makefile \
 	  modules/elmsubmit/etc/Makefile \
 	  modules/elmsubmit/etc/elmsubmit.cfg \
 	  modules/elmsubmit/lib/Makefile \
 	  modules/miscutil/Makefile \
 	  modules/miscutil/bin/Makefile \
 	  modules/miscutil/bin/dbexec \
-	  modules/miscutil/bin/testsuite \
-	  modules/miscutil/bin/regressiontestsuite \
 	  modules/miscutil/bin/inveniocfg \
 	  modules/miscutil/lib/Makefile \
 	  modules/miscutil/demo/Makefile \
 	  modules/miscutil/sql/Makefile \
 	  modules/miscutil/web/Makefile \
 	  modules/miscutil/doc/Makefile \
 	  modules/miscutil/doc/hacking/Makefile \
 	  modules/webaccess/Makefile \
 	  modules/webaccess/bin/Makefile \
 	  modules/webaccess/bin/authaction \
 	  modules/webaccess/bin/webaccessadmin \
 	  modules/webaccess/doc/Makefile \
 	  modules/webaccess/doc/admin/Makefile \
 	  modules/webaccess/doc/hacking/Makefile \
 	  modules/webaccess/lib/Makefile \
 	  modules/webaccess/web/Makefile \
 	  modules/webaccess/web/admin/Makefile \
 	  modules/webalert/Makefile \
 	  modules/webalert/bin/Makefile \
 	  modules/webalert/bin/alertengine \
 	  modules/webalert/doc/Makefile \
 	  modules/webalert/doc/admin/Makefile \
 	  modules/webalert/doc/hacking/Makefile \
 	  modules/webalert/lib/Makefile \
 	  modules/webalert/web/Makefile \
 	  modules/webhelp/Makefile \
 	  modules/webhelp/web/Makefile \
 	  modules/webhelp/web/hacking/Makefile \
 	  modules/webhelp/web/admin/Makefile \
 	  modules/webhelp/web/admin/howto/Makefile \
 	  modules/websearch/Makefile \
 	  modules/websearch/bin/Makefile \
 	  modules/websearch/bin/webcoll \
 	  modules/websearch/doc/Makefile \
 	  modules/websearch/doc/admin/Makefile \
 	  modules/websearch/doc/hacking/Makefile \
 	  modules/websearch/lib/Makefile \
 	  modules/websearch/web/Makefile \
 	  modules/websearch/web/admin/Makefile \
 	  modules/websession/Makefile \
 	  modules/websession/bin/Makefile \
 	  modules/websession/bin/inveniogc \
 	  modules/websession/doc/Makefile \
 	  modules/websession/doc/admin/Makefile \
 	  modules/websession/doc/hacking/Makefile \
 	  modules/websession/lib/Makefile \
 	  modules/websession/web/Makefile \
 	  modules/webstat/Makefile \
 	  modules/webstat/bin/Makefile \
 	  modules/webstat/bin/webstat \
 	  modules/webstat/bin/webstatadmin \
 	  modules/webstat/doc/Makefile \
 	  modules/webstat/doc/admin/Makefile \
 	  modules/webstat/doc/hacking/Makefile \
 	  modules/webstat/etc/Makefile \
 	  modules/webstat/lib/Makefile \
 	  modules/webstyle/Makefile \
 	  modules/webstyle/bin/Makefile \
 	  modules/webstyle/bin/webdoc \
 	  modules/webstyle/css/Makefile \
 	  modules/webstyle/doc/Makefile \
 	  modules/webstyle/etc/Makefile \
 	  modules/webstyle/doc/admin/Makefile \
 	  modules/webstyle/doc/hacking/Makefile \
 	  modules/webstyle/img/Makefile \
 	  modules/webstyle/lib/Makefile \
 	  modules/webcomment/Makefile \
 	  modules/webcomment/doc/Makefile \
 	  modules/webcomment/doc/admin/Makefile \
 	  modules/webcomment/doc/hacking/Makefile \
 	  modules/webcomment/lib/Makefile \
 	  modules/webcomment/web/Makefile \
 	  modules/webcomment/web/admin/Makefile \
 	  modules/webbasket/Makefile \
 	  modules/webbasket/doc/Makefile \
 	  modules/webbasket/doc/admin/Makefile \
 	  modules/webbasket/doc/hacking/Makefile \
 	  modules/webbasket/lib/Makefile \
 	  modules/webbasket/web/Makefile \
 	  modules/webjournal/Makefile \
 	  modules/webjournal/doc/Makefile \
 	  modules/webjournal/doc/admin/Makefile \
 	  modules/webjournal/doc/hacking/Makefile \
 	  modules/webjournal/lib/Makefile \
 	  modules/webjournal/lib/widgets/Makefile \
 	  modules/webmessage/Makefile \
 	  modules/webmessage/bin/Makefile \
 	  modules/webmessage/bin/webmessageadmin \
 	  modules/webmessage/doc/Makefile \
 	  modules/webmessage/doc/admin/Makefile \
 	  modules/webmessage/doc/hacking/Makefile \
 	  modules/webmessage/lib/Makefile \
 	  modules/webmessage/web/Makefile \
 	  modules/websubmit/Makefile \
 	  modules/websubmit/bin/Makefile \
 	  modules/websubmit/bin/thumbmaker \
 	  modules/websubmit/etc/Makefile \
 	  modules/websubmit/doc/Makefile \
 	  modules/websubmit/doc/admin/Makefile \
 	  modules/websubmit/doc/hacking/Makefile \
 	  modules/websubmit/lib/Makefile \
 	  modules/websubmit/lib/functions/Makefile \
 	  modules/websubmit/web/Makefile \
 	  modules/websubmit/web/admin/Makefile \
 	  ])
 
 ## Finally, write output files:
 AC_OUTPUT
 
 ## Write help:
 AC_MSG_RESULT([****************************************************************************])
 AC_MSG_RESULT([** Your CDS Invenio installation is now ready for building.               **])
 AC_MSG_RESULT([** You have entered the following parameters:                             **])
 AC_MSG_RESULT([**   - CDS Invenio main install directory: ${prefix}])
 AC_MSG_RESULT([**   - Python executable: $PYTHON])
 AC_MSG_RESULT([**   - MySQL client executable: $MYSQL])
 AC_MSG_RESULT([**   - CLISP executable: $CLISP])
 AC_MSG_RESULT([**   - CMUCL executable: $CMUCL])
 AC_MSG_RESULT([**   - SBCL executable: $SBCL])
 AC_MSG_RESULT([** Here are the steps to continue the building process:                   **])
 AC_MSG_RESULT([**   1) Type 'make' to build your CDS Invenio system.                     **])
 AC_MSG_RESULT([**   2) Type 'make install' to install your CDS Invenio system.           **])
 AC_MSG_RESULT([** After that you can start customizing your installation as documented   **])
 AC_MSG_RESULT([** in the INSTALL file (i.e. edit invenio.conf, run inveniocfg, etc).     **])
 AC_MSG_RESULT([** Good luck, and thanks for choosing CDS Invenio.                        **])
 AC_MSG_RESULT([**              -- CDS Development Group <cds.support@cern.ch>            **])
 AC_MSG_RESULT([****************************************************************************])
 
 ## end of file
diff --git a/modules/bibclassify/lib/bibclassify_regression_tests.py b/modules/bibclassify/lib/bibclassify_regression_tests.py
index c8395082b..88833446e 100644
--- a/modules/bibclassify/lib/bibclassify_regression_tests.py
+++ b/modules/bibclassify/lib/bibclassify_regression_tests.py
@@ -1,63 +1,63 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """BibClassify Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages, \
                               test_web_page_existence
 
 class BibClassifyWebPagesAvailabilityTest(unittest.TestCase):
     """Check BibClassify web pages whether they are up or not."""
 
     def test_availability_bibclassify_admin_guide(self):
         """bibclassify - availability of BibClassify Admin Guide page"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/admin/bibclassify-admin-guide',
                                                expected_text="BibClassify Admin Guide"))
         return
 
     def test_availability_bibclassify_admin_guide_images(self):
         """bibclassify - availability of BibClassify Admin Guide images"""
         test_web_page_existence(CFG_SITE_URL + '/img/admin/bibclassify-admin-guide-cloud.jpeg')
 
     def test_availability_bibclassify_hacking_pages(self):
         """bibclassify - availability of BibClassify Hacking Guide pages"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/hacking/bibclassify-internals',
                                                expected_text="BibClassify Internals"))
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/hacking/bibclassify-hep-taxonomy',
                                                expected_text="The HEP taxonomy: rationale and extensions"))
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/hacking/bibclassify-extraction-algorithm',
                                                expected_text="The code behind BibClassify: the extraction algorithm"))
         return
 
-test_suite = make_test_suite(BibClassifyWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(BibClassifyWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibconvert/lib/bibconvert_regression_tests.py b/modules/bibconvert/lib/bibconvert_regression_tests.py
index 05a22a22e..727103c5e 100644
--- a/modules/bibconvert/lib/bibconvert_regression_tests.py
+++ b/modules/bibconvert/lib/bibconvert_regression_tests.py
@@ -1,68 +1,68 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """BibConvert Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages, \
                               test_web_page_existence
 
 class BibConvertWebPagesAvailabilityTest(unittest.TestCase):
     """Check BibConvert web pages whether they are up or not."""
 
     def test_availability_bibconvert_admin_guide(self):
         """bibconvert - availability of BibConvert Admin Guide page"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/admin/bibconvert-admin-guide',
                                                expected_text="BibConvert Admin Guide"))
         return
 
     def test_availability_bibconvert_admin_guide_parts(self):
         """bibconvert - availability of BibConvert Admin Guide parts"""
         test_web_page_existence(CFG_SITE_URL + '/admin/bibconvert/bibtex.cfg')
         test_web_page_existence(CFG_SITE_URL + '/admin/bibconvert/dcq.cfg')
         test_web_page_existence(CFG_SITE_URL + '/admin/bibconvert/dcq.dat')
         test_web_page_existence(CFG_SITE_URL + '/admin/bibconvert/dcxml-to-marcxml.cfg')
         test_web_page_existence(CFG_SITE_URL + '/admin/bibconvert/example_oaimarc2xm.xsl')
         test_web_page_existence(CFG_SITE_URL + '/admin/bibconvert/example_oaimarc2xm_collID.kb')
         test_web_page_existence(CFG_SITE_URL + '/admin/bibconvert/sample.cfg')
         test_web_page_existence(CFG_SITE_URL + '/admin/bibconvert/sample.dat')
         test_web_page_existence(CFG_SITE_URL + '/admin/bibconvert/sample.kb')
 
     def test_availability_bibconvert_hacking_pages(self):
         """bibconvert - availability of BibConvert Hacking Guide pages"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/hacking/bibconvert-internals',
                                                expected_text="BibConvert Internals"))
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/hacking/bibconvert-api',
                                                expected_text="BibConvert API"))
         return
 
-test_suite = make_test_suite(BibConvertWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(BibConvertWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibconvert/lib/bibconvert_tests.py b/modules/bibconvert/lib/bibconvert_tests.py
index 149a801f1..5b907810b 100644
--- a/modules/bibconvert/lib/bibconvert_tests.py
+++ b/modules/bibconvert/lib/bibconvert_tests.py
@@ -1,139 +1,136 @@
 # -*- coding: utf-8 -*-
 
 ## $Id$
 ## CDS Invenio bibconvert unit tests.
 
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.  
+## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the bibconvert."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import bibconvert
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TestFormattingFunctions(unittest.TestCase):
     """Test bibconvert formatting functions."""
 
     def test_ff(self):
         """bibconvert - formatting functions"""
-        
+
         self.assertEqual("Hello world!", bibconvert.FormatField("ello world", "ADD(H,!)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world", "ABR(11,!)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("xHello world!x", "CUT(x,x)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("He11o wor1d!", "REP(1,l)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world!", "SUP(NUM)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world!", "LIM(12,R)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world!", "WORDS(2)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world!", "MINL(5)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world!", "MAXL(12)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world! @", "EXP(@,1)"))
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world!", "IF(Hello world!,ORIG,)"))
         self.assertEqual("", bibconvert.FormatField("Hello world!", "NUM()"))
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world!   ", "SHAPE()"))
         self.assertEqual("HELLO WORLD!", bibconvert.FormatField("Hello world!", "UP()"))
         self.assertEqual("hello world!", bibconvert.FormatField("Hello world!", "DOWN()"))
         self.assertEqual("Hello World!", bibconvert.FormatField("Hello world!", "CAP()"))
 
 
 class TestGlobalFormattingFunctions(unittest.TestCase):
     """Test bibconvert global formatting functions."""
 
     def test_gff(self):
         """bibconvert - global formatting functions"""
-    
+
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world!","DEFP()"))
 
 class TestGenerateValues(unittest.TestCase):
     """Test bibconvert value generation."""
 
     def test_gv(self):
         """bibconvert - value generation"""
-        
+
         self.assertEqual("Hello world!", bibconvert.generate("VALUE(Hello world!)"))
 
 class TestParseData(unittest.TestCase):
     """Test bibconvert input data parsing."""
 
     def test_idp(self):
         """bibconvert - input data parsing"""
-        
+
         self.assertEqual(['A','B','C','D'], bibconvert.parse_field_definition("A---B---C---D"))
 
 class TestRegExp(unittest.TestCase):
     """Test bibconvert regular expressions"""
 
     def test_regexp(self):
         """bibconvert - regular expressions"""
-        
+
         self.assertEqual("Hello world!", bibconvert.FormatField("Hello world!", "RE([A-Z][a-z].*!)"))
 
 class TestBCCL(unittest.TestCase):
     """Test bibconvert BCCL complinacy"""
 
     def xtest_bccl_09(self):
         """bibconvert - BCCL v.0.9 compliancy"""
 
         # FIXME: put proper tests here
         self.assertEqual(1, 1)
 
 class TestKnowledgeBase(unittest.TestCase):
     """Test bibconvert knowledge base"""
 
     def xtest_enc(self):
         """bibconvert - knowledge base"""
-        
+
         # FIXME: put proper tests here
         self.assertEqual(1, 1)
 
 class TestErrorCodes(unittest.TestCase):
     """Test bibconvert error codes"""
 
     def xtest_enc(self):
         """bibconvert - error codes"""
-        
+
         # FIXME: put proper tests here
         self.assertEqual(1, 1)
 
 class TestEncodings(unittest.TestCase):
     """Test bibconvert encodings"""
 
     def xtest_enc(self):
         """bibconvert - encodings"""
-        
+
         # FIXME: put proper tests here
         self.assertEqual(1, 1)
 
 
-def create_test_suite():
-    """Return test suite for the bibconvert module."""
-
-    return unittest.TestSuite((unittest.makeSuite(TestFormattingFunctions, 'test'),
-                               unittest.makeSuite(TestGlobalFormattingFunctions, 'test'),
-                               unittest.makeSuite(TestGenerateValues, 'test'),
-                               unittest.makeSuite(TestParseData, 'test'),
-                               unittest.makeSuite(TestRegExp, 'test'),
-                               unittest.makeSuite(TestBCCL, 'test'),
-                               unittest.makeSuite(TestKnowledgeBase, 'test'),
-                               unittest.makeSuite(TestErrorCodes, 'test'),
-                               unittest.makeSuite(TestEncodings, 'test'),
-                               ))
+TEST_SUITE = make_test_suite(TestFormattingFunctions,
+                             TestGlobalFormattingFunctions,
+                             TestGenerateValues,
+                             TestParseData,
+                             TestRegExp,
+                             TestBCCL,
+                             TestKnowledgeBase,
+                             TestErrorCodes,
+                             TestEncodings,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/bibedit/lib/bibedit_regression_tests.py b/modules/bibedit/lib/bibedit_regression_tests.py
index 1ea128bb5..426442fc7 100644
--- a/modules/bibedit/lib/bibedit_regression_tests.py
+++ b/modules/bibedit/lib/bibedit_regression_tests.py
@@ -1,69 +1,69 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """BibEdit Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class BibEditWebPagesAvailabilityTest(unittest.TestCase):
     """Check BibEdit web pages whether they are up or not."""
 
     def test_bibedit_admin_interface_availability(self):
         """bibedit - availability of BibEdit Admin interface pages"""
 
         baseurl = CFG_SITE_URL + '/admin/bibedit/bibeditadmin.py/'
 
         _exports = ['', 'index', 'edit', 'submit']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'Authorization failure'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_bibedit_admin_guide_availability(self):
         """bibedit - availability of BibEdit Admin guide pages"""
 
         url = CFG_SITE_URL + '/help/admin/bibedit-admin-guide'
         error_messages = test_web_page_content(url,
                                                expected_text="BibEdit Admin Guide")
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(BibEditWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(BibEditWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibedit/lib/bibrecord_tests.py b/modules/bibedit/lib/bibrecord_tests.py
index 0219114d6..82da34930 100644
--- a/modules/bibedit/lib/bibrecord_tests.py
+++ b/modules/bibedit/lib/bibrecord_tests.py
@@ -1,822 +1,821 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 __revision__ = "$Id$"
 
 import unittest
 from string import expandtabs, replace
 
 from invenio.config import CFG_TMPDIR, CFG_ETCDIR
 from invenio import bibrecord
+from invenio.testutils import make_test_suite, run_test_suite
 
 # pylint: disable-msg=C0301
 
 class BibRecordSanityTest(unittest.TestCase):
     """ bibrecord - sanity test (xml -> create records -> xml)"""
     def test_for_sanity(self):
         """ bibrecord - demo file sanity test (xml -> create records -> xml)"""
         f = open(CFG_TMPDIR + '/demobibdata.xml', 'r')
         xmltext = f.read()
         f.close()
         # let's try to reproduce the demo XML MARC file by parsing it and printing it back:
         recs = map((lambda x:x[0]), bibrecord.create_records(xmltext))
         xmltext_reproduced = bibrecord.records_xml_output(recs)
         x = xmltext_reproduced
         y = xmltext
         # 'normalize' the two XML MARC files for the purpose of comparing
         x = expandtabs(x)
         y = expandtabs(y)
         x = x.replace(' ', '')
         y = y.replace(' ', '')
         x = x.replace('<!DOCTYPEcollectionSYSTEM"file://%s/bibedit/MARC21slim.dtd">\n<collection>' % CFG_ETCDIR,
                       '<collectionxmlns="http://www.loc.gov/MARC21/slim">')
         x = x.replace('</record><record>', "</record>\n<record>")
         x = x.replace('</record></collection>', "</record>\n</collection>\n")
         x = x[1:100]
         y = y[1:100]
         self.assertEqual(x, y)
 
 class BibRecordSuccessTest(unittest.TestCase):
     """ bibrecord - demo file parsing test """
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize stuff"""
         f = open(CFG_TMPDIR + '/demobibdata.xml', 'r')
         xmltext = f.read()
         f.close()
         self.recs = map((lambda x: x[0]), bibrecord.create_records(xmltext))
 
     def test_records_created(self):
         """ bibrecord - demo file how many records are created """
         self.assertEqual(95, len(self.recs))
 
     def test_tags_created(self):
         """ bibrecord - demo file which tags are created """
         ## check if the tags are correct
         # tags = ['020', '037', '041', '080', '088', '100', '245', '246', '250', '260', '270', '300', '340', '490', '500', '502', '520', '590', '595', '650', '653', '690', '700', '710', '856', '909', '980', '999']
 
         tags = [u'003', u'005', '020', '035', '037', '041', '080', '088', '100', '245', '246', '250', '260', '269', '270', '300', '340', '490', '500', '502', '520', '590', '595', '650', '653', '690', '695', '700', '710', '720', '856', '859', '901', '909', '916', '960', '961', '962', '963', '970', '980', '999', 'FFT']
 
         t = []
         for rec in self.recs:
             t.extend(rec.keys())
         t.sort()
         #eliminate the elements repeated
         tt = []
         for x in t:
             if not x in tt:
                 tt.append(x)
 
         self.assertEqual(tags, tt)
 
     def test_fields_created(self):
         """bibrecord - demo file how many fields are created"""
         ## check if the number of fields for each record is correct
 
         fields = [14, 14, 8, 11, 11, 12, 11, 15, 10, 18, 14, 16, 10, 9, 15, 10, 11, 11, 11, 9, 11, 11, 10, 9, 9, 9, 10, 9, 10, 10, 8, 9, 8, 9, 14, 13, 14, 14, 15, 12, 12, 12, 15, 14, 12, 16, 16, 15, 15, 14, 16, 15, 15, 15, 16, 15, 16, 15, 15, 16, 15, 14, 14, 15, 12, 13, 11, 15, 8, 11, 14, 13, 12, 13, 6, 6, 25, 24, 27, 26, 26, 24, 26, 27, 25, 28, 24, 23, 27, 25, 25, 26, 26, 24, 19]
 
         cr = []
         ret = []
         for rec in self.recs:
             cr.append(len(rec.values()))
             ret.append(rec)
         self.assertEqual(fields, cr)
 
 class BibRecordBadInputTreatmentTest(unittest.TestCase):
     """ bibrecord - testing for bad input treatment """
     def test_wrong_attribute(self):
         """bibrecord - bad input subfield \'cde\' instead of \'code\'"""
         ws = bibrecord.CFG_BIBRECORD_WARNING_MSGS
         xml_error1 = """
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield tag="041" ind1=" " ind2=" ">
         <subfield code="a">eng</subfield>
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe, John</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2=" ">
         <subfield cde="a">On the foo and bar</subfield>
         </datafield>
         </record>
         """
         (rec, st, e) = bibrecord.create_record(xml_error1, 1, 1)
         ee =''
         for i in e:
             if type(i).__name__ == 'str':
                 if i.count(ws[3])>0:
                     ee = i
         self.assertEqual(bibrecord.warning((3, '(field number: 4)')), ee)
 
     def test_missing_attribute(self):
         """ bibrecord - bad input missing \"tag\" """
         ws = bibrecord.CFG_BIBRECORD_WARNING_MSGS
         xml_error2 = """
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield ind1=" " ind2=" ">
         <subfield code="a">eng</subfield>
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe, John</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2=" ">
         <subfield code="a">On the foo and bar</subfield>
         </datafield>
         </record>
         """
         (rec, st, e) = bibrecord.create_record(xml_error2, 1, 1)
         ee = ''
         for i in e:
             if type(i).__name__ == 'str':
                 if i.count(ws[1])>0:
                     ee = i
         self.assertEqual(bibrecord.warning((1, '(field number(s): [2])')), ee)
 
     def test_empty_datafield(self):
         """ bibrecord - bad input no subfield """
         ws = bibrecord.CFG_BIBRECORD_WARNING_MSGS
         xml_error3 = """
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield tag="041" ind1=" " ind2=" ">
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe, John</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2=" ">
         <subfield code="a">On the foo and bar</subfield>
         </datafield>
         </record>
         """
         (rec, st, e) = bibrecord.create_record(xml_error3, 1, 1)
         ee = ''
         for i in e:
             if type(i).__name__ == 'str':
                 if i.count(ws[8])>0:
                     ee = i
         self.assertEqual(bibrecord.warning((8, '(field number: 2)')), ee)
 
     def test_missing_tag(self):
         """bibrecord - bad input missing end \"tag\" """
         ws = bibrecord.CFG_BIBRECORD_WARNING_MSGS
         xml_error4 = """
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield tag="041" ind1=" " ind2=" ">
         <subfield code="a">eng</subfield>
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe, John</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2=" ">
         <subfield code="a">On the foo and bar</subfield>
         </record>
         """
         (rec, st, e) = bibrecord.create_record(xml_error4, 1, 1)
         ee = ''
         for i in e:
             if type(i).__name__ == 'str':
                 if i.count(ws[99])>0:
                     ee = i
         self.assertEqual(bibrecord.warning((99, '(Tagname : datafield)')), ee)
 
 class BibRecordAccentedUnicodeLettersTest(unittest.TestCase):
     """ bibrecord - testing accented UTF-8 letters """
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize stuff"""
         self.xml_example_record = """<record>
   <controlfield tag="001">33</controlfield>
   <datafield tag="041" ind1=" " ind2=" ">
     <subfield code="a">eng</subfield>
   </datafield>
   <datafield tag="100" ind1=" " ind2=" ">
     <subfield code="a">Döè1, John</subfield>
   </datafield>
   <datafield tag="100" ind1=" " ind2=" ">
     <subfield code="a">Doe2, J>ohn</subfield>
     <subfield code="b">editor</subfield>
   </datafield>
   <datafield tag="245" ind1=" " ind2="1">
     <subfield code="a">Пушкин</subfield>
   </datafield>
   <datafield tag="245" ind1=" " ind2="2">
     <subfield code="a">On the foo and bar2</subfield>
   </datafield>
 </record>"""
         (self.rec, st, e) = bibrecord.create_record(self.xml_example_record, 1, 1)
 
     def test_accented_unicode_characters(self):
         """bibrecord - accented Unicode letters"""
         self.assertEqual(self.xml_example_record,
                          bibrecord.record_xml_output(self.rec))
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "100", " ", " "),
                          [([('a', 'Döè1, John')], " ", " ", "", 3), ([('a', 'Doe2, J>ohn'), ('b', 'editor')], " ", " ", "", 4)])
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "245", " ", "1"),
                          [([('a', 'Пушкин')], " ", '1', "", 5)])
 
 class BibRecordGettingFieldValuesTest(unittest.TestCase):
     """ bibrecord - testing for getting field/subfield values """
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize stuff"""
         xml_example_record = """
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield tag="041" ind1=" " ind2=" ">
         <subfield code="a">eng</subfield>
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe1, John</subfield>
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe2, John</subfield>
         <subfield code="b">editor</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2="1">
         <subfield code="a">On the foo and bar1</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2="2">
         <subfield code="a">On the foo and bar2</subfield>
         </datafield>
         </record>
         """
         (self.rec, st, e) = bibrecord.create_record(xml_example_record, 1, 1)
 
     def test_get_field_instances(self):
         """bibrecord - getting field instances"""
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "100", " ", " "),
                          [([('a', 'Doe1, John')], " ", " ", "", 3), ([('a', 'Doe2, John'), ('b', 'editor')], " ", " ", "", 4)])
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "", " ", " "),
                         [('245', [([('a', 'On the foo and bar1')], " ", '1', "", 5), ([('a', 'On the foo and bar2')], " ", '2', "", 6)]), ('001', [([], " ", " ", '33', 1)]), ('100', [([('a', 'Doe1, John')], " ", " ", "", 3), ([('a', 'Doe2, John'), ('b', 'editor')], " ", " ", "", 4)]), ('041', [([('a', 'eng')], " ", " ", "", 2)])])
 
     def test_get_field_values(self):
         """bibrecord - getting field values"""
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", " ", "a"),
                          ['Doe1, John', 'Doe2, John'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", " ", "b"),
                          ['editor'])
 
     def test_get_field_value(self):
         """bibrecord - getting first field value"""
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", " ", " ", "a"),
                          'Doe1, John')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", " ", " ", "b"),
                          'editor')
 
     def test_get_subfield_values(self):
         """bibrecord - getting subfield values"""
         fi1, fi2 = bibrecord.record_get_field_instances(self.rec, "100", " ", " ")
         self.assertEqual(bibrecord.field_get_subfield_values(fi1, "b"), [])
         self.assertEqual(bibrecord.field_get_subfield_values(fi2, "b"), ["editor"])
 
 class BibRecordGettingFieldValuesViaWildcardsTest(unittest.TestCase):
     """ bibrecord - testing for getting field/subfield values via wildcards """
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize stuff"""
         xml_example_record = """
         <record>
         <controlfield tag="001">1</controlfield>
         <datafield tag="100" ind1="C" ind2="5">
         <subfield code="a">val1</subfield>
         </datafield>
         <datafield tag="555" ind1="A" ind2="B">
         <subfield code="a">val2</subfield>
         </datafield>
         <datafield tag="555" ind1="A" ind2=" ">
         <subfield code="a">val3</subfield>
         </datafield>
         <datafield tag="555" ind1=" " ind2=" ">
         <subfield code="a">val4a</subfield>
         <subfield code="b">val4b</subfield>
         </datafield>
         <datafield tag="555" ind1=" " ind2="B">
         <subfield code="a">val5</subfield>
         </datafield>
         <datafield tag="556" ind1="A" ind2="C">
         <subfield code="a">val6</subfield>
         </datafield>
         <datafield tag="556" ind1="A" ind2=" ">
         <subfield code="a">val7a</subfield>
         <subfield code="b">val7b</subfield>
         </datafield>
         </record>
         """
         (self.rec, st, e) = bibrecord.create_record(xml_example_record, 1, 1)
 
     def test_get_field_instances_via_wildcard(self):
         """bibrecord - getting field instances via wildcards"""
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "100", " ", " "),
                          [])
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "100", "%", " "),
                          [])
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "100", "%", "%"),
                          [([('a', 'val1')], 'C', '5', "", 2)])
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "55%", "A", "%"),
                          [([('a', 'val2')], 'A', 'B', "", 3),
                           ([('a', 'val3')], 'A', " ", "", 4),
                           ([('a', 'val6')], 'A', 'C', "", 7),
                           ([('a', 'val7a'), ('b', 'val7b')], 'A', " ", "", 8)])
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "55%", "A", " "),
                          [([('a', 'val3')], 'A', " ", "", 4),
                           ([('a', 'val7a'), ('b', 'val7b')], 'A', " ", "", 8)])
         self.assertEqual(bibrecord.record_get_field_instances(self.rec, "556", "A", " "),
                          [([('a', 'val7a'), ('b', 'val7b')], 'A', " ", "", 8)])
 
     def test_get_field_values_via_wildcard(self):
         """bibrecord - getting field values via wildcards"""
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", " ", " "),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", "%", " ", " "),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", "%", " "),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", "%", "%", " "),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", "%", "%", "z"),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", " ", "%"),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", " ", "a"),
                         [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", "%", " ", "a"),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", "%", "%", "a"),
                          ['val1'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", "%", "%", "%"),
                          ['val1'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", "A", "%", "a"),
                          ['val2', 'val3', 'val6', 'val7a'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", "A", " ", "a"),
                          ['val3', 'val7a'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "556", "A", " ", "a"),
                          ['val7a'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "555", " ", " ", " "),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "555", " ", " ", "z"),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "555", " ", " ", "%"),
                          ['val4a', 'val4b'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", " ", " ", "b"),
                          ['val4b'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", "%", "%", "b"),
                          ['val4b', 'val7b'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", "A", " ", "b"),
                          ['val7b'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", "A", "%", "b"),
                          ['val7b'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", "A", " ", "a"),
                          ['val3', 'val7a'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", "A", "%", "a"),
                          ['val2', 'val3', 'val6', 'val7a'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", "%", "%", "a"),
                          ['val2', 'val3', 'val4a', 'val5', 'val6', 'val7a'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "55%", " ", " ", "a"),
                          ['val4a'])
 
     def test_get_field_value_via_wildcard(self):
         """bibrecord - getting first field value via wildcards"""
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", " ", " ", " "),
                          '')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", "%", " ", " "),
                          '')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", " ", "%", " "),
                          '')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", "%", "%", " "),
                          '')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", " ", " ", "%"),
                          '')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", " ", " ", "a"),
                          '')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", "%", " ", "a"),
                          '')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", "%", "%", "a"),
                          'val1')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "100", "%", "%", "%"),
                          'val1')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", "A", "%", "a"),
                          'val2')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", "A", " ", "a"),
                          'val3')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "556", "A", " ", "a"),
                          'val7a')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "555", " ", " ", " "),
                          '')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "555", " ", " ", "%"),
                          'val4a')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", " ", " ", "b"),
                          'val4b')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", "%", "%", "b"),
                          'val4b')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", "A", " ", "b"),
                          'val7b')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", "A", "%", "b"),
                          'val7b')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", "A", " ", "a"),
                          'val3')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", "A", "%", "a"),
                          'val2')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", "%", "%", "a"),
                          'val2')
         self.assertEqual(bibrecord.record_get_field_value(self.rec, "55%", " ", " ", "a"),
                          'val4a')
 
 class BibRecordAddFieldTest(unittest.TestCase):
     """ bibrecord - testing adding field """
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize stuff"""
         xml_example_record = """
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield tag="041" ind1=" " ind2=" ">
         <subfield code="a">eng</subfield>
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe1, John</subfield>
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe2, John</subfield>
         <subfield code="b">editor</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2="1">
         <subfield code="a">On the foo and bar1</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2="2">
         <subfield code="a">On the foo and bar2</subfield>
         </datafield>
         </record>
         """
         (self.rec, st, e) = bibrecord.create_record(xml_example_record, 1, 1)
 
     def test_add_controlfield(self):
         """bibrecord - adding controlfield"""
         field_number_1 = bibrecord.record_add_field(self.rec, "003", " ", " ", "SzGeCERN")
         field_number_2 = bibrecord.record_add_field(self.rec, "004", " ", " ", "Test")
         self.assertEqual(field_number_1, 7)
         self.assertEqual(field_number_2, 8)
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "003", " ", " ", ""),
                          ['SzGeCERN'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "004", " ", " ", ""),
                          ['Test'])
 
     def test_add_datafield(self):
         """bibrecord - adding datafield"""
         field_number_1 = bibrecord.record_add_field(self.rec, "100", " ", " ", "",
                                                     [('a', 'Doe3, John')])
         field_number_2 = bibrecord.record_add_field(self.rec, "100", " ", " ", "",
                                                     [('a', 'Doe4, John'), ('b', 'editor')])
         self.assertEqual(field_number_1, 7)
         self.assertEqual(field_number_2, 8)
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", " ", "a"),
                          ['Doe1, John', 'Doe2, John', 'Doe3, John', 'Doe4, John'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", " ", "b"),
                          ['editor', 'editor'])
 
     def test_add_controlfield_on_desired_position(self):
         """bibrecord - adding controlfield on desired position"""
         field_number_1 = bibrecord.record_add_field(self.rec, "005", " ", " ", "Foo", [], 0)
         field_number_2 = bibrecord.record_add_field(self.rec, "006", " ", " ", "Bar", [], 0)
         self.assertEqual(field_number_1, 0)
         self.assertEqual(field_number_2, 7)
 
     def test_add_datafield_on_desired_position(self):
         """bibrecord - adding datafield on desired position"""
         field_number_1 = bibrecord.record_add_field(self.rec, "100", " ", " ", " ",
                                                     [('a', 'Doe3, John')], 0)
         field_number_2 = bibrecord.record_add_field(self.rec, "100", " ", " ", " ",
                                                     [('a', 'Doe4, John'), ('b', 'editor')], 0)
         self.assertEqual(field_number_1, 0)
         self.assertEqual(field_number_2, 7)
 
 class BibRecordDeleteFieldTest(unittest.TestCase):
     """ bibrecord - testing field deletion """
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize stuff"""
         xml_example_record = """
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield tag="041" ind1=" " ind2=" ">
         <subfield code="a">eng</subfield>
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe1, John</subfield>
         </datafield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Doe2, John</subfield>
         <subfield code="b">editor</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2="1">
         <subfield code="a">On the foo and bar1</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2="2">
         <subfield code="a">On the foo and bar2</subfield>
         </datafield>
         </record>
         """
         (self.rec, st, e) = bibrecord.create_record(xml_example_record, 1, 1)
 
         xml_example_record_empty = """
         <record>
         </record>
         """
         (self.rec_empty, st, e) = bibrecord.create_record(xml_example_record_empty, 1, 1)
 
     def test_delete_controlfield(self):
         """bibrecord - deleting controlfield"""
         bibrecord.record_delete_field(self.rec, "001", " ", " ")
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "001", " ", " ", " "),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", " ", "b"),
                          ['editor'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "245", " ", "2", "a"),
                          ['On the foo and bar2'])
 
     def test_delete_datafield(self):
         """bibrecord - deleting datafield"""
         bibrecord.record_delete_field(self.rec, "100", " ", " ")
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "001", " ", " ", ""),
                          ['33'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "100", " ", " ", "b"),
                          [])
         bibrecord.record_delete_field(self.rec, "245", " ", " ")
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "245", " ", "1", "a"),
                          ['On the foo and bar1'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "245", " ", "2", "a"),
                          ['On the foo and bar2'])
         bibrecord.record_delete_field(self.rec, "245", " ", "2")
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "245", " ", "1", "a"),
                          ['On the foo and bar1'])
         self.assertEqual(bibrecord.record_get_field_values(self.rec, "245", " ", "2", "a"),
                          [])
 
     def test_add_delete_add_field_to_empty_record(self):
         """bibrecord - adding, deleting, and adding back a field to an empty record"""
         field_number_1 = bibrecord.record_add_field(self.rec_empty, "003", " ", " ", "SzGeCERN")
         self.assertEqual(field_number_1, 1)
         self.assertEqual(bibrecord.record_get_field_values(self.rec_empty, "003", " ", " ", ""),
                          ['SzGeCERN'])
         bibrecord.record_delete_field(self.rec_empty, "003", " ", " ")
         self.assertEqual(bibrecord.record_get_field_values(self.rec_empty, "003", " ", " ", ""),
                          [])
         field_number_1 = bibrecord.record_add_field(self.rec_empty, "003", " ", " ", "SzGeCERN2")
         self.assertEqual(field_number_1, 1)
         self.assertEqual(bibrecord.record_get_field_values(self.rec_empty, "003", " ", " ", ""),
                          ['SzGeCERN2'])
 
 class BibRecordSpecialTagParsingTest(unittest.TestCase):
     """ bibrecord - parsing special tags (FMT, FFT)"""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """setting up example records"""
         self.xml_example_record_with_fmt = """
         <record>
          <controlfield tag="001">33</controlfield>
          <datafield tag="041" ind1=" " ind2=" ">
           <subfield code="a">eng</subfield>
          </datafield>
          <datafield tag="FMT" ind1=" " ind2=" ">
           <subfield code="f">HB</subfield>
           <subfield code="g">Let us see if this gets inserted well.</subfield>
          </datafield>
         </record>
         """
         self.xml_example_record_with_fft = """
         <record>
          <controlfield tag="001">33</controlfield>
          <datafield tag="041" ind1=" " ind2=" ">
           <subfield code="a">eng</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">file:///foo.pdf</subfield>
           <subfield code="a">http://bar.com/baz.ps.gz</subfield>
          </datafield>
         </record>
         """
         self.xml_example_record_with_xyz = """
         <record>
          <controlfield tag="001">33</controlfield>
          <datafield tag="041" ind1=" " ind2=" ">
           <subfield code="a">eng</subfield>
          </datafield>
          <datafield tag="XYZ" ind1=" " ind2=" ">
           <subfield code="f">HB</subfield>
           <subfield code="g">Let us see if this gets inserted well.</subfield>
          </datafield>
         </record>
         """
 
     def test_parsing_file_containing_fmt_special_tag_with_correcting(self):
         """bibrecord - parsing special FMT tag, correcting on"""
         rec, st, e = bibrecord.create_record(self.xml_example_record_with_fmt, 1, 1)
         self.assertEqual(rec,
                          {u'001': [([], " ", " ", '33', 1)],
                           'FMT': [([('f', 'HB'), ('g', 'Let us see if this gets inserted well.')], " ", " ", "", 3)],
                           '041': [([('a', 'eng')], " ", " ", "", 2)]})
         self.assertEqual(bibrecord.record_get_field_values(rec, "041", " ", " ", "a"),
                          ['eng'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "FMT", " ", " ", "f"),
                          ['HB'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "FMT", " ", " ", "g"),
                          ['Let us see if this gets inserted well.'])
 
     def test_parsing_file_containing_fmt_special_tag_without_correcting(self):
         """bibrecord - parsing special FMT tag, correcting off"""
         rec, st, e = bibrecord.create_record(self.xml_example_record_with_fmt, 1, 0)
         self.assertEqual(rec,
                          {u'001': [([], " ", " ", '33', 1)],
                           'FMT': [([('f', 'HB'), ('g', 'Let us see if this gets inserted well.')], " ", " ", "", 3)],
                           '041': [([('a', 'eng')], " ", " ", "", 2)]})
         self.assertEqual(bibrecord.record_get_field_values(rec, "041", " ", " ", "a"),
                          ['eng'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "FMT", " ", " ", "f"),
                          ['HB'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "FMT", " ", " ", "g"),
                          ['Let us see if this gets inserted well.'])
 
     def test_parsing_file_containing_fft_special_tag_with_correcting(self):
         """bibrecord - parsing special FFT tag, correcting on"""
         rec, st, e = bibrecord.create_record(self.xml_example_record_with_fft, 1, 1)
         self.assertEqual(rec,
                          {u'001': [([], " ", " ", '33', 1)],
                           'FFT': [([('a', 'file:///foo.pdf'), ('a', 'http://bar.com/baz.ps.gz')], " ", " ", "", 3)],
                           '041': [([('a', 'eng')], " ", " ", "", 2)]})
         self.assertEqual(bibrecord.record_get_field_values(rec, "041", " ", " ", "a"),
                          ['eng'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "FFT", " ", " ", "a"),
                          ['file:///foo.pdf', 'http://bar.com/baz.ps.gz'])
 
     def test_parsing_file_containing_fft_special_tag_without_correcting(self):
         """bibrecord - parsing special FFT tag, correcting off"""
         rec, st, e = bibrecord.create_record(self.xml_example_record_with_fft, 1, 0)
         self.assertEqual(rec,
                          {u'001': [([], " ", " ", '33', 1)],
                           'FFT': [([('a', 'file:///foo.pdf'), ('a', 'http://bar.com/baz.ps.gz')], " ", " ", "", 3)],
                           '041': [([('a', 'eng')], " ", " ", "", 2)]})
         self.assertEqual(bibrecord.record_get_field_values(rec, "041", " ", " ", "a"),
                          ['eng'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "FFT", " ", " ", "a"),
                          ['file:///foo.pdf', 'http://bar.com/baz.ps.gz'])
 
     def test_parsing_file_containing_xyz_special_tag_with_correcting(self):
         """bibrecord - parsing unrecognized special XYZ tag, correcting on"""
         # XYZ should not get accepted when correcting is on; should get changed to 000
         rec, st, e = bibrecord.create_record(self.xml_example_record_with_xyz, 1, 1)
         self.assertEqual(rec,
                          {u'001': [([], " ", " ", '33', 1)],
                           '000': [([('f', 'HB'), ('g', 'Let us see if this gets inserted well.')], " ", " ", "", 3)],
                           '041': [([('a', 'eng')], " ", " ", "", 2)]})
         self.assertEqual(bibrecord.record_get_field_values(rec, "041", " ", " ", "a"),
                          ['eng'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "XYZ", " ", " ", "f"),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(rec, "XYZ", " ", " ", "g"),
                          [])
         self.assertEqual(bibrecord.record_get_field_values(rec, "000", " ", " ", "f"),
                          ['HB'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "000", " ", " ", "g"),
                          ['Let us see if this gets inserted well.'])
 
     def test_parsing_file_containing_xyz_special_tag_without_correcting(self):
         """bibrecord - parsing unrecognized special XYZ tag, correcting off"""
         # XYZ should get accepted without correcting
         rec, st, e = bibrecord.create_record(self.xml_example_record_with_xyz, 1, 0)
         self.assertEqual(rec,
                          {u'001': [([], " ", " ", '33', 1)],
                           'XYZ': [([('f', 'HB'), ('g', 'Let us see if this gets inserted well.')], " ", " ", "", 3)],
                           '041': [([('a', 'eng')], " ", " ", "", 2)]})
         self.assertEqual(bibrecord.record_get_field_values(rec, "041", " ", " ", "a"),
                          ['eng'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "XYZ", " ", " ", "f"),
                          ['HB'])
         self.assertEqual(bibrecord.record_get_field_values(rec, "XYZ", " ", " ", "g"),
                          ['Let us see if this gets inserted well.'])
 
 
 class BibRecordPrintingTest(unittest.TestCase):
     """ bibrecord - testing for printing record """
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize stuff"""
         self.xml_example_record = """
         <record>
         <controlfield tag="001">81</controlfield>
         <datafield tag="037" ind1=" " ind2=" ">
         <subfield code="a">TEST-ARTICLE-2006-001</subfield>
         </datafield>
         <datafield tag="037" ind1=" " ind2=" ">
         <subfield code="a">ARTICLE-2006-001</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2=" ">
         <subfield code="a">Test ti</subfield>
         </datafield>
         </record>"""
 
         self.xml_example_record_short = """
         <record>
         <controlfield tag="001">81</controlfield>
         <datafield tag="037" ind1=" " ind2=" ">
         <subfield code="a">TEST-ARTICLE-2006-001</subfield>
         </datafield>
         <datafield tag="037" ind1=" " ind2=" ">
         <subfield code="a">ARTICLE-2006-001</subfield>
         </datafield>
         </record>"""
 
         self.xml_example_multi_records = """
         <record>
         <controlfield tag="001">81</controlfield>
         <datafield tag="037" ind1=" " ind2=" ">
         <subfield code="a">TEST-ARTICLE-2006-001</subfield>
         </datafield>
         <datafield tag="037" ind1=" " ind2=" ">
         <subfield code="a">ARTICLE-2006-001</subfield>
         </datafield>
         <datafield tag="245" ind1=" " ind2=" ">
         <subfield code="a">Test ti</subfield>
         </datafield>
         </record>
         <record>
         <controlfield tag="001">82</controlfield>
         <datafield tag="100" ind1=" " ind2=" ">
         <subfield code="a">Author, t</subfield>
         </datafield>
         </record>"""
 
         self.xml_example_multi_records_short = """
         <record>
         <controlfield tag="001">81</controlfield>
         <datafield tag="037" ind1=" " ind2=" ">
         <subfield code="a">TEST-ARTICLE-2006-001</subfield>
         </datafield>
         <datafield tag="037" ind1=" " ind2=" ">
         <subfield code="a">ARTICLE-2006-001</subfield>
         </datafield>
         </record>
         <record>
         <controlfield tag="001">82</controlfield>
         </record>"""
 
     def test_print_rec(self):
         """bibrecord - print rec"""
         rec, st, e = bibrecord.create_record(self.xml_example_record, 1, 1)
         rec_short, st_short, e_short = bibrecord.create_record(self.xml_example_record_short, 1, 1)
         self.assertEqual(bibrecord.create_record(bibrecord.print_rec(rec, tags=[]), 1, 1)[0], rec)
         self.assertEqual(bibrecord.create_record(bibrecord.print_rec(rec, tags=["001", "037"]), 1, 1)[0], rec_short)
         self.assertEqual(bibrecord.create_record(bibrecord.print_rec(rec, tags=["037"]), 1, 1)[0], rec_short)
 
     def test_print_recs(self):
         """bibrecord - print multiple recs"""
         list_of_recs = bibrecord.create_records(self.xml_example_multi_records, 1, 1)
         list_of_recs_elems = [elem[0] for elem in list_of_recs]
         list_of_recs_short = bibrecord.create_records(self.xml_example_multi_records_short, 1, 1)
         list_of_recs_short_elems = [elem[0] for elem in list_of_recs_short]
         self.assertEqual(bibrecord.create_records(bibrecord.print_recs(list_of_recs_elems, tags=[]), 1, 1), list_of_recs)
         self.assertEqual(bibrecord.create_records(bibrecord.print_recs(list_of_recs_elems, tags=["001", "037"]), 1, 1), list_of_recs_short)
         self.assertEqual(bibrecord.create_records(bibrecord.print_recs(list_of_recs_elems, tags=["037"]), 1, 1), list_of_recs_short)
 
-def create_test_suite():
-    """Return test suite for the bibrecord module"""
-    return unittest.TestSuite((unittest.makeSuite(BibRecordSanityTest, 'test'),
-                               unittest.makeSuite(BibRecordSuccessTest, 'test'),
-                               unittest.makeSuite(BibRecordBadInputTreatmentTest, 'test'),
-                               unittest.makeSuite(BibRecordGettingFieldValuesTest, 'test'),
-                               unittest.makeSuite(BibRecordGettingFieldValuesViaWildcardsTest, 'test'),
-                               unittest.makeSuite(BibRecordAddFieldTest, 'test'),
-                               unittest.makeSuite(BibRecordDeleteFieldTest, 'test'),
-                               unittest.makeSuite(BibRecordAccentedUnicodeLettersTest, 'test'),
-                               unittest.makeSuite(BibRecordSpecialTagParsingTest, 'test'),
-                               unittest.makeSuite(BibRecordPrintingTest, 'test'),
-                               ))
+TEST_SUITE = make_test_suite(BibRecordSanityTest,
+                             BibRecordSuccessTest,
+                             BibRecordBadInputTreatmentTest,
+                             BibRecordGettingFieldValuesTest,
+                             BibRecordGettingFieldValuesViaWildcardsTest,
+                             BibRecordAddFieldTest,
+                             BibRecordDeleteFieldTest,
+                             BibRecordAccentedUnicodeLettersTest,
+                             BibRecordSpecialTagParsingTest,
+                             BibRecordPrintingTest,)
+
 if __name__ == '__main__':
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/bibformat/lib/bibformat_engine_tests.py b/modules/bibformat/lib/bibformat_engine_tests.py
index b5eafc153..36b22fa69 100644
--- a/modules/bibformat/lib/bibformat_engine_tests.py
+++ b/modules/bibformat/lib/bibformat_engine_tests.py
@@ -1,717 +1,716 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Test cases for the BibFormat engine. Also test
 some utilities function in bibformat_utils module"""
 
 __revision__ = "$Id$"
 
 # pylint: disable-msg=C0301
 
 import unittest
 import os
 import sys
 
 from invenio import bibformat_engine
 from invenio import bibformat_utils
 from invenio import bibformat_config
 from invenio import bibformatadminlib
 from invenio import bibrecord
 from invenio.config import CFG_TMPDIR
+from invenio.testutils import make_test_suite, run_test_suite
 
 #CFG_BIBFORMAT_OUTPUTS_PATH = "..%setc%soutput_formats" % (os.sep, os.sep)
 #CFG_BIBFORMAT_TEMPLATES_PATH = "..%setc%sformat_templates" % (os.sep, os.sep)
 #CFG_BIBFORMAT_ELEMENTS_PATH = "elements"
 CFG_BIBFORMAT_OUTPUTS_PATH = "%s" % (CFG_TMPDIR)
 CFG_BIBFORMAT_TEMPLATES_PATH = "%s" % (CFG_TMPDIR)
 CFG_BIBFORMAT_ELEMENTS_PATH = "%s%stests_bibformat_elements" % (CFG_TMPDIR, os.sep)
 CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH = "tests_bibformat_elements"
 
 class FormatTemplateTest(unittest.TestCase):
     """ bibformat - tests on format templates"""
 
     def test_get_format_template(self):
         """bibformat - format template parsing and returned structure"""
 
         bibformat_engine.CFG_BIBFORMAT_TEMPLATES_PATH = CFG_BIBFORMAT_TEMPLATES_PATH
 
         #Test correct parsing and structure
         template_1 = bibformat_engine.get_format_template("Test1.bft", with_attributes=True)
         self.assert_(template_1 is not None)
         self.assertEqual(template_1['code'],  "test")
         self.assertEqual(template_1['attrs']['name'], "name_test")
         self.assertEqual(template_1['attrs']['description'], "desc_test")
 
         #Test correct parsing and structure of file without description or name
         template_2 = bibformat_engine.get_format_template("Test_2.bft", with_attributes=True)
         self.assert_(template_2 is not None)
         self.assertEqual(template_2['code'],  "test")
         self.assertEqual(template_2['attrs']['name'], "Test_2.bft")
         self.assertEqual(template_2['attrs']['description'], "")
 
         #Test correct parsing and structure of file without description or name
         unknown_template = bibformat_engine.get_format_template("test_no_template.test", with_attributes=True)
         self.assertEqual(unknown_template,  None)
 
 
     def test_get_format_templates(self):
         """ bibformat - loading multiple format templates"""
         bibformat_engine.CFG_BIBFORMAT_TEMPLATES_PATH = CFG_BIBFORMAT_TEMPLATES_PATH
 
         templates = bibformat_engine.get_format_templates(with_attributes=True)
         #test correct loading
         self.assert_("Test1.bft" in templates.keys())
         self.assert_("Test_2.bft" in templates.keys())
         self.assert_("Test3.bft" in templates.keys())
         self.assert_("Test_no_template.test" not in templates.keys())
 
         #Test correct pasrsing and structure
         self.assertEqual(templates['Test1.bft']['code'],  "test")
         self.assertEqual(templates['Test1.bft']['attrs']['name'], "name_test")
         self.assertEqual(templates['Test1.bft']['attrs']['description'], "desc_test")
 
     def test_get_format_template_attrs(self):
         """ bibformat - correct parsing of attributes in format template"""
         bibformat_engine.CFG_BIBFORMAT_TEMPLATES_PATH = CFG_BIBFORMAT_TEMPLATES_PATH
         attrs = bibformat_engine.get_format_template_attrs("Test1.bft")
         self.assertEqual(attrs['name'], "name_test")
         self.assertEqual(attrs['description'], "desc_test")
 
 
     def test_get_fresh_format_template_filename(self):
         """ bibformat - getting fresh filename for format template"""
         bibformat_engine.CFG_BIBFORMAT_TEMPLATES_PATH = CFG_BIBFORMAT_TEMPLATES_PATH
         filename_and_name_1 = bibformat_engine.get_fresh_format_template_filename("Test")
         self.assert_(len(filename_and_name_1) >= 2)
         self.assertEqual(filename_and_name_1[0], "Test.bft")
         filename_and_name_2 = bibformat_engine.get_fresh_format_template_filename("Test1")
         self.assert_(len(filename_and_name_2) >= 2)
         self.assert_(filename_and_name_2[0] != "Test1.bft")
         path = bibformat_engine.CFG_BIBFORMAT_TEMPLATES_PATH + os.sep + filename_and_name_2[0]
         self.assert_(not os.path.exists(path))
 
 class FormatElementTest(unittest.TestCase):
     """ bibformat - tests on format templates"""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """bibformat - setting python path to test elements"""
         sys.path.append('%s' % CFG_TMPDIR)
 
     def test_resolve_format_element_filename(self):
         """bibformat - resolving format elements filename """
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_PATH = CFG_BIBFORMAT_ELEMENTS_PATH
 
         #Test elements filename starting without bfe_, with underscore instead of space
         filenames = ["test 1", "test 1.py", "bfe_test 1", "bfe_test 1.py", "BFE_test 1",
                      "BFE_TEST 1", "BFE_TEST 1.py", "BFE_TeST 1.py", "BFE_TeST 1",
                      "BfE_TeST 1.py", "BfE_TeST 1","test_1", "test_1.py", "bfe_test_1",
                      "bfe_test_1.py", "BFE_test_1",
                      "BFE_TEST_1", "BFE_TEST_1.py", "BFE_Test_1.py", "BFE_TeST_1",
                      "BfE_TeST_1.py", "BfE_TeST_1"]
 
         for i in range(len(filenames)-2):
             filename_1 = bibformat_engine.resolve_format_element_filename(filenames[i])
             self.assert_(filename_1 is not None)
 
             filename_2 = bibformat_engine.resolve_format_element_filename(filenames[i+1])
             self.assertEqual(filename_1, filename_2)
 
 
         #Test elements filename starting with bfe_, and with underscores instead of spaces
         filenames = ["test 2", "test 2.py", "bfe_test 2", "bfe_test 2.py", "BFE_test 2",
                      "BFE_TEST 2", "BFE_TEST 2.py", "BFE_TeST 2.py", "BFE_TeST 2",
                      "BfE_TeST 2.py", "BfE_TeST 2","test_2", "test_2.py", "bfe_test_2",
                      "bfe_test_2.py", "BFE_test_2",
                      "BFE_TEST_2", "BFE_TEST_2.py", "BFE_TeST_2.py", "BFE_TeST_2",
                      "BfE_TeST_2.py", "BfE_TeST_2"]
 
         for i in range(len(filenames)-2):
             filename_1 = bibformat_engine.resolve_format_element_filename(filenames[i])
             self.assert_(filename_1 is not None)
 
             filename_2 = bibformat_engine.resolve_format_element_filename(filenames[i+1])
             self.assertEqual(filename_1, filename_2)
 
         #Test non existing element
         non_existing_element = bibformat_engine.resolve_format_element_filename("BFE_NON_EXISTING_ELEMENT")
         self.assertEqual(non_existing_element, None)
 
     def test_get_format_element(self):
         """bibformat - format elements parsing and returned structure"""
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_PATH = CFG_BIBFORMAT_ELEMENTS_PATH
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH = CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH
 
 
         #Test loading with different kind of names, for element with spaces in name, without bfe_
         element_1 = bibformat_engine.get_format_element("test 1", with_built_in_params=True)
         self.assert_(element_1 is not None)
         element_1_bis = bibformat_engine.get_format_element("bfe_tEst_1.py", with_built_in_params=True)
         self.assertEqual(element_1, element_1_bis)
 
         #Test loading with different kind of names, for element without spaces in name, wit bfe_
         element_2 = bibformat_engine.get_format_element("test 2", with_built_in_params=True)
         self.assert_(element_2 is not None)
         element_2_bis = bibformat_engine.get_format_element("bfe_tEst_2.py", with_built_in_params=True)
         self.assertEqual(element_2, element_2_bis)
 
         #Test loading incorrect elements
         element_3 = bibformat_engine.get_format_element("test 3", with_built_in_params=True)
         self.assertEqual(element_3, None)
         element_4 = bibformat_engine.get_format_element("test 4", with_built_in_params=True)
         self.assertEqual(element_4, None)
         unknown_element = bibformat_engine.get_format_element("TEST_NO_ELEMENT", with_built_in_params=True)
         self.assertEqual(unknown_element, None)
 
         #Test element without docstring
         element_5 = bibformat_engine.get_format_element("test_5", with_built_in_params=True)
         self.assert_(element_5 is not None)
         self.assertEqual(element_5['attrs']['description'], '')
         self.assert_({'name':"param1",
                      'description':"(no description provided)",
                      'default':""} in element_5['attrs']['params'] )
         self.assertEqual(element_5['attrs']['seealso'], [])
 
         #Test correct parsing:
 
         #Test type of element
         self.assertEqual(element_1['type'], "python")
         #Test name = element filename, with underscore instead of spaces,
         #without BFE_ and uppercase
         self.assertEqual(element_1['attrs']['name'], "TEST_1")
         #Test description parsing
         self.assertEqual(element_1['attrs']['description'], "Prints test")
         #Test @see parsing
         self.assertEqual(element_1['attrs']['seealso'], ["element2.py", "unknown_element.py"])
         #Test @param parsing
         self.assert_({'name':"param1",
                       'description':"desc 1",
                       'default':""} in element_1['attrs']['params'] )
 
         self.assert_({'name':"param2",
                       'description':"desc 2",
                       'default':"default value"} in element_1['attrs']['params'] )
 
 
 
         #Test non existing element
         non_existing_element = bibformat_engine.get_format_element("BFE_NON_EXISTING_ELEMENT")
         self.assertEqual(non_existing_element, None)
 
     def test_get_format_element_attrs_from_function(self):
         """ bibformat - correct parsing of attributes in 'format' docstring"""
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_PATH = CFG_BIBFORMAT_ELEMENTS_PATH
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH = CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH
         element_1 = bibformat_engine.get_format_element("test 1", with_built_in_params=True)
         function = element_1['code']
         attrs = bibformat_engine.get_format_element_attrs_from_function(function,
                                                                         element_1['attrs']['name'],
                                                                         with_built_in_params=True)
 
         self.assertEqual(attrs['name'], "TEST_1")
         #Test description parsing
         self.assertEqual(attrs['description'], "Prints test")
         #Test @see parsing
         self.assertEqual(attrs['seealso'], ["element2.py", "unknown_element.py"])
 
     def test_get_format_elements(self):
         """bibformat - multiple format elements parsing and returned structure"""
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_PATH = CFG_BIBFORMAT_ELEMENTS_PATH
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH = CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH
 
         elements = bibformat_engine.get_format_elements()
         self.assert_(isinstance(elements, dict))
         self.assertEqual(elements['TEST_1']['attrs']['name'], "TEST_1")
         self.assertEqual(elements['TEST_2']['attrs']['name'], "TEST_2")
         self.assert_("TEST_3" not in elements.keys())
         self.assert_("TEST_4" not in elements.keys())
 
     def test_get_tags_used_by_element(self):
         """bibformat - identification of tag usage inside element"""
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_PATH = bibformat_config.CFG_BIBFORMAT_ELEMENTS_PATH
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH = bibformat_config.CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH
         tags = bibformatadminlib.get_tags_used_by_element('bfe_abstract.py')
         self.failUnless(len(tags) == 4,
                         'Could not correctly identify tags used in bfe_abstract.py')
 
 class OutputFormatTest(unittest.TestCase):
     """ bibformat - tests on output formats"""
 
     def test_get_output_format(self):
         """ bibformat - output format parsing and returned structure """
         bibformat_engine.CFG_BIBFORMAT_OUTPUTS_PATH = CFG_BIBFORMAT_OUTPUTS_PATH
 
         filename_1 = bibformat_engine.resolve_output_format_filename("test1")
         output_1 = bibformat_engine.get_output_format(filename_1, with_attributes=True)
 
         self.assertEqual(output_1['attrs']['names']['generic'], "")
         self.assert_(isinstance(output_1['attrs']['names']['ln'], dict))
         self.assert_(isinstance(output_1['attrs']['names']['sn'], dict))
         self.assertEqual(output_1['attrs']['code'], "TEST1")
         self.assert_(len(output_1['attrs']['code']) <= 6)
         self.assertEqual(len(output_1['rules']), 4)
         self.assertEqual(output_1['rules'][0]['field'], '980.a')
         self.assertEqual(output_1['rules'][0]['template'], 'Picture_HTML_detailed.bft')
         self.assertEqual(output_1['rules'][0]['value'], 'PICTURE ')
         self.assertEqual(output_1['rules'][1]['field'], '980.a')
         self.assertEqual(output_1['rules'][1]['template'], 'Article.bft')
         self.assertEqual(output_1['rules'][1]['value'], 'ARTICLE')
         self.assertEqual(output_1['rules'][2]['field'], '980__a')
         self.assertEqual(output_1['rules'][2]['template'], 'Thesis_detailed.bft')
         self.assertEqual(output_1['rules'][2]['value'], 'THESIS ')
         self.assertEqual(output_1['rules'][3]['field'], '980__a')
         self.assertEqual(output_1['rules'][3]['template'], 'Pub.bft')
         self.assertEqual(output_1['rules'][3]['value'], 'PUBLICATION ')
         filename_2 = bibformat_engine.resolve_output_format_filename("TEST2")
         output_2 = bibformat_engine.get_output_format(filename_2, with_attributes=True)
 
         self.assertEqual(output_2['attrs']['names']['generic'], "")
         self.assert_(isinstance(output_2['attrs']['names']['ln'], dict))
         self.assert_(isinstance(output_2['attrs']['names']['sn'], dict))
         self.assertEqual(output_2['attrs']['code'], "TEST2")
         self.assert_(len(output_2['attrs']['code']) <= 6)
         self.assertEqual(output_2['rules'], [])
         unknown_output = bibformat_engine.get_output_format("unknow", with_attributes=True)
         self.assertEqual(unknown_output, {'rules':[],
                                           'default':"",
                                           'attrs':{'names':{'generic':"", 'ln':{}, 'sn':{}},
                                                    'description':'',
                                                    'code':"UNKNOW",
                                                    'visibility': 1,
                                                    'content_type':""}})
 
     def test_get_output_formats(self):
         """ bibformat - loading multiple output formats """
         bibformat_engine.CFG_BIBFORMAT_OUTPUTS_PATH = CFG_BIBFORMAT_OUTPUTS_PATH
         outputs = bibformat_engine.get_output_formats(with_attributes=True)
         self.assert_(isinstance(outputs, dict))
         self.assert_("TEST1.bfo" in outputs.keys())
         self.assert_("TEST2.bfo" in outputs.keys())
         self.assert_("unknow.bfo" not in outputs.keys())
 
         #Test correct parsing
         output_1 = outputs["TEST1.bfo"]
         self.assertEqual(output_1['attrs']['names']['generic'], "")
         self.assert_(isinstance(output_1['attrs']['names']['ln'], dict))
         self.assert_(isinstance(output_1['attrs']['names']['sn'], dict))
         self.assertEqual(output_1['attrs']['code'], "TEST1")
         self.assert_(len(output_1['attrs']['code']) <= 6)
 
     def test_get_output_format_attrs(self):
         """ bibformat - correct parsing of attributes in output format"""
         bibformat_engine.CFG_BIBFORMAT_OUTPUTS_PATH = CFG_BIBFORMAT_OUTPUTS_PATH
 
         attrs= bibformat_engine.get_output_format_attrs("TEST1")
 
         self.assertEqual(attrs['names']['generic'], "")
         self.assert_(isinstance(attrs['names']['ln'], dict))
         self.assert_(isinstance(attrs['names']['sn'], dict))
         self.assertEqual(attrs['code'], "TEST1")
         self.assert_(len(attrs['code']) <= 6)
 
     def test_resolve_output_format(self):
         """ bibformat - resolving output format filename"""
         bibformat_engine.CFG_BIBFORMAT_OUTPUTS_PATH = CFG_BIBFORMAT_OUTPUTS_PATH
 
         filenames = ["test1", "test1.bfo", "TEST1", "TeST1", "TEST1.bfo", "<b>test1"]
         for i in range(len(filenames)-2):
             filename_1 = bibformat_engine.resolve_output_format_filename(filenames[i])
             self.assert_(filename_1 is not None)
 
             filename_2 = bibformat_engine.resolve_output_format_filename(filenames[i+1])
             self.assertEqual(filename_1, filename_2)
 
     def test_get_fresh_output_format_filename(self):
         """ bibformat - getting fresh filename for output format"""
         bibformat_engine.CFG_BIBFORMAT_OUTPUTS_PATH = CFG_BIBFORMAT_OUTPUTS_PATH
 
         filename_and_name_1 = bibformat_engine.get_fresh_output_format_filename("test")
         self.assert_(len(filename_and_name_1) >= 2)
         self.assertEqual(filename_and_name_1[0], "TEST.bfo")
 
         filename_and_name_1_bis = bibformat_engine.get_fresh_output_format_filename("<test>")
         self.assert_(len(filename_and_name_1_bis) >= 2)
         self.assertEqual(filename_and_name_1_bis[0], "TEST.bfo")
 
         filename_and_name_2 = bibformat_engine.get_fresh_output_format_filename("test1")
         self.assert_(len(filename_and_name_2) >= 2)
         self.assert_(filename_and_name_2[0] != "TEST1.bfo")
         path = bibformat_engine.CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + filename_and_name_2[0]
         self.assert_(not os.path.exists(path))
 
         filename_and_name_3 = bibformat_engine.get_fresh_output_format_filename("test1testlong")
         self.assert_(len(filename_and_name_3) >= 2)
         self.assert_(filename_and_name_3[0] != "TEST1TESTLONG.bft")
         self.assert_(len(filename_and_name_3[0]) <= 6 + 1 + len(bibformat_config.CFG_BIBFORMAT_FORMAT_OUTPUT_EXTENSION))
         path = bibformat_engine.CFG_BIBFORMAT_OUTPUTS_PATH + os.sep + filename_and_name_3[0]
         self.assert_(not os.path.exists(path))
 
 class PatternTest(unittest.TestCase):
     """ bibformat - tests on re patterns"""
 
     def test_pattern_lang(self):
         """ bibformat - correctness of pattern 'pattern_lang'"""
         text = ''' <h1>Here is my test text</h1>
         <p align="center">
         <lang><en><b>Some words</b></en><fr>Quelques mots</fr><de>Einige Wörter</de> garbage </lang>
         Here ends the middle of my test text
         <lang><en><b>English</b></en><fr><b>Français</b></fr><de><b>Deutsch</b></de></lang>
         <b>Here ends my test text</b></p>'''
 
         result = bibformat_engine.pattern_lang.search(text)
         self.assertEqual(result.group("langs"), "<en><b>Some words</b></en><fr>Quelques mots</fr><de>Einige Wörter</de> garbage ")
 
         text = ''' <h1>Here is my test text</h1>
         <BFE_test param="
         <lang><en><b>Some words</b></en><fr>Quelques mots</fr><de>Einige Wörter</de> garbage </lang>" />
 
         '''
 
         result = bibformat_engine.pattern_lang.search(text)
         self.assertEqual(result.group("langs"), "<en><b>Some words</b></en><fr>Quelques mots</fr><de>Einige Wörter</de> garbage ")
 
     def test_ln_pattern(self):
         """ bibformat - correctness of pattern 'ln_pattern'"""
 
         text = "<en><b>Some words</b></en><fr>Quelques mots</fr><de>Einige Wörter</de> garbage "
         result = bibformat_engine.ln_pattern.search(text)
         self.assertEqual(result.group(1), "en")
         self.assertEqual(result.group(2), "<b>Some words</b>")
 
 
     def test_pattern_format_template_name(self):
         """ bibformat - correctness of pattern 'pattern_format_template_name'"""
         text = '''
         garbage
         <name><b>a name</b></name>
         <description>a <b>description</b> on
         2 lines </description>
         <h1>the content of the template</h1>
         content
         '''
         result = bibformat_engine.pattern_format_template_name.search(text)
         self.assertEqual(result.group('name'), "<b>a name</b>")
 
     def test_pattern_format_template_desc(self):
         """ bibformat - correctness of pattern 'pattern_format_template_desc'"""
         text = '''
         garbage
         <name><b>a name</b></name>
         <description>a <b>description</b> on
         2 lines </description>
         <h1>the content of the template</h1>
         content
         '''
         result = bibformat_engine.pattern_format_template_desc.search(text)
         self.assertEqual(result.group('desc'), '''a <b>description</b> on
         2 lines ''')
 
     def test_pattern_tag(self):
         """ bibformat - correctness of pattern 'pattern_tag'"""
         text = '''
         garbage but part of content
         <name><b>a name</b></name>
         <description>a <b>description</b> on
         2 lines </description>
         <h1>the content of the template</h1>
         <BFE_tiTLE param1="<b>value1</b>"
         param2=""/>
         my content is so nice!
         <BFE_title param1="value1"/>
         <BFE_title param1="value1"/>
         '''
         result = bibformat_engine.pattern_tag.search(text)
         self.assertEqual(result.group('function_name'), "tiTLE")
         self.assertEqual(result.group('params').strip(), '''param1="<b>value1</b>"
         param2=""''')
 
     def test_pattern_function_params(self):
         """ bibformat - correctness of pattern 'test_pattern_function_params'"""
         text = '''
         param1=""  param2="value2"
         param3="<b>value3</b>" garbage
 
         '''
         names = ["param1", "param2", "param3"]
         values = ["", "value2", "<b>value3</b>"]
         results = bibformat_engine.pattern_format_element_params.finditer(text) #TODO
         param_i = 0
         for match in results:
             self.assertEqual(match.group('param'), names[param_i])
             self.assertEqual(match.group('value'), values [param_i])
             param_i += 1
 
     def test_pattern_format_element_params(self):
         """ bibformat - correctness of pattern 'pattern_format_element_params'"""
         text = '''
         a description for my element
         some text
         @param param1 desc1
         @param param2 desc2
         @see seethis, seethat
         '''
         names = ["param1", "param2"]
         descriptions = ["desc1", "desc2"]
         results = bibformat_engine.pattern_format_element_params.finditer(text) #TODO
         param_i = 0
         for match in results:
             self.assertEqual(match.group('name'), names[param_i])
             self.assertEqual(match.group('desc'), descriptions[param_i])
             param_i += 1
 
     def test_pattern_format_element_seealso(self):
         """ bibformat - correctness of pattern 'pattern_format_element_seealso' """
         text = '''
         a description for my element
         some text
         @param param1 desc1
         @param param2 desc2
         @see seethis, seethat
         '''
         result = bibformat_engine.pattern_format_element_seealso.search(text)
         self.assertEqual(result.group('see').strip(), 'seethis, seethat')
 
 class MiscTest(unittest.TestCase):
     """ bibformat - tests on various functions"""
 
     def test_parse_tag(self):
         """ bibformat - result of parsing tags"""
         tags_and_parsed_tags = ['245COc',   ['245', 'C', 'O', 'c'],
                                 '245C_c',   ['245', 'C', '' , 'c'],
                                 '245__c',   ['245', '' , '' , 'c'],
                                 '245__$$c', ['245', '' , '' , 'c'],
                                 '245__$c',  ['245', '' , '' , 'c'],
                                 '245  $c',  ['245', '' , '' , 'c'],
                                 '245  $$c', ['245', '' , '' , 'c'],
                                 '245__.c',  ['245', '' , '' , 'c'],
                                 '245  .c',  ['245', '' , '' , 'c'],
                                 '245C_$c',  ['245', 'C', '' , 'c'],
                                 '245CO$$c', ['245', 'C', 'O', 'c'],
                                 '245CO.c',  ['245', 'C', 'O', 'c'],
                                 '245$c',    ['245', '' , '' , 'c'],
                                 '245.c',    ['245', '' , '' , 'c'],
                                 '245$$c',   ['245', '' , '' , 'c'],
                                 '245__%',   ['245', '' , '' , '%'],
                                 '245__$$%', ['245', '' , '' , '%'],
                                 '245__$%',  ['245', '' , '' , '%'],
                                 '245  $%',  ['245', '' , '' , '%'],
                                 '245  $$%', ['245', '' , '' , '%'],
                                 '245$%',    ['245', '' , '' , '%'],
                                 '245.%',    ['245', '' , '' , '%'],
                                 '245_O.%',  ['245', '' , 'O', '%'],
                                 '245.%',    ['245', '' , '' , '%'],
                                 '245$$%',   ['245', '' , '' , '%'],
                                 '2%5$$a',   ['2%5', '' , '' , 'a'],
                                 '2%%%%a',   ['2%%', '%', '%', 'a'],
                                 '2%%__a',   ['2%%', '' , '' , 'a'],
                                 '2%%a',     ['2%%', '' , '' , 'a']]
 
         for i in range(0, len(tags_and_parsed_tags), 2):
             parsed_tag = bibformat_utils.parse_tag(tags_and_parsed_tags[i])
             self.assertEqual(parsed_tag, tags_and_parsed_tags[i+1])
 
 class FormatTest(unittest.TestCase):
     """ bibformat - generic tests on function that do the formatting. Main functions"""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """ bibformat - prepare BibRecord objects"""
 
         self.xml_text_1 = '''
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield tag="980" ind1="" ind2="">
         <subfield code="a">thesis</subfield>
         </datafield>
         <datafield tag="950" ind1="" ind2="">
         <subfield code="b">Doe1, John</subfield>
         </datafield>
         <datafield tag="100" ind1="" ind2="">
         <subfield code="a">Doe2, John</subfield>
         <subfield code="b">editor</subfield>
         </datafield>
         <datafield tag="245" ind1="" ind2="1">
         <subfield code="a">On the foo and bar1</subfield>
         </datafield>
         <datafield tag="245" ind1="" ind2="2">
         <subfield code="a">On the foo and bar2</subfield>
         </datafield>
         <datafield tag="088" ind1="" ind2="">
         <subfield code="a">99999</subfield>
         </datafield>
         </record>
         '''
 
         #rec_1 = bibrecord.create_record(self.xml_text_1)
         self.bfo_1 = bibformat_engine.BibFormatObject(recID=None,
                                                       ln='fr',
                                                       xml_record=self.xml_text_1)
 
         self.xml_text_2 = '''
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield tag="980" ind1="" ind2="">
         <subfield code="b">thesis </subfield>
         </datafield>
         <datafield tag="950" ind1="" ind2="">
         <subfield code="b">Doe1, John</subfield>
         </datafield>
         <datafield tag="100" ind1="" ind2="">
         <subfield code="a">Doe2, John</subfield>
         <subfield code="b">editor</subfield>
         </datafield>
         <datafield tag="245" ind1="" ind2="1">
         <subfield code="b">On the foo and bar1</subfield>
         </datafield>
         <datafield tag="245" ind1="" ind2="2">
         <subfield code="b">On the foo and bar2</subfield>
         </datafield>
         </record>
         '''
         #self.rec_2 = bibrecord.create_record(xml_text_2)
         self.bfo_2 = bibformat_engine.BibFormatObject(recID=None,
                                                       ln='fr',
                                                       xml_record=self.xml_text_2)
 
 
         self.xml_text_3 = '''
         <record>
         <controlfield tag="001">33</controlfield>
         <datafield tag="041" ind1="" ind2="">
         <subfield code="a">eng</subfield>
         </datafield>
         <datafield tag="100" ind1="" ind2="">
         <subfield code="a">Doe1, John</subfield>
         </datafield>
         <datafield tag="100" ind1="" ind2="">
         <subfield code="a">Doe2, John</subfield>
         <subfield code="b">editor</subfield>
         </datafield>
         <datafield tag="245" ind1="" ind2="1">
         <subfield code="a">On the foo and bar1</subfield>
         </datafield>
         <datafield tag="245" ind1="" ind2="2">
         <subfield code="a">On the foo and bar2</subfield>
         </datafield>
         <datafield tag="980" ind1="" ind2="">
         <subfield code="a">article</subfield>
         </datafield>
         </record>
         '''
         #self.rec_3 = bibrecord.create_record(xml_text_3)
         self.bfo_3 = bibformat_engine.BibFormatObject(recID=None,
                                                       ln='fr',
                                                       xml_record=self.xml_text_3)
 
         self.empty_record_xml = '''
         <record>
         <controlfield tag="001">555</controlfield>
         </record>'''
 
     def test_decide_format_template(self):
         """ bibformat - choice made by function decide_format_template"""
         bibformat_engine.CFG_BIBFORMAT_OUTPUTS_PATH = CFG_BIBFORMAT_OUTPUTS_PATH
 
         result = bibformat_engine.decide_format_template(self.bfo_1, "test1")
         self.assertEqual(result, "Thesis_detailed.bft")
 
         result = bibformat_engine.decide_format_template(self.bfo_3, "test3")
         self.assertEqual(result, "Test3.bft")
 
         #Only default matches
         result = bibformat_engine.decide_format_template(self.bfo_2, "test1")
         self.assertEqual(result, "Default_HTML_detailed.bft")
 
         #No match at all for record
         result = bibformat_engine.decide_format_template(self.bfo_2, "test2")
         self.assertEqual(result, None)
 
         #Non existing output format
         result = bibformat_engine.decide_format_template(self.bfo_2, "UNKNOW")
         self.assertEqual(result, None)
 
     def test_format_record(self):
         """ bibformat - correct formatting"""
         bibformat_engine.CFG_BIBFORMAT_OUTPUTS_PATH = CFG_BIBFORMAT_OUTPUTS_PATH
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_PATH = CFG_BIBFORMAT_ELEMENTS_PATH
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH = CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH
         bibformat_engine.CFG_BIBFORMAT_TEMPLATES_PATH = CFG_BIBFORMAT_TEMPLATES_PATH
 
         #use output format that has no match TEST DISABLED DURING MIGRATION
         #result = bibformat_engine.format_record(recID=None, of="test2", xml_record=self.xml_text_2)
         #self.assertEqual(result.replace("\n", ""),"")
 
         #use output format that link to unknown template
         result = bibformat_engine.format_record(recID=None, of="test3", xml_record=self.xml_text_2)
         self.assertEqual(result.replace("\n", ""),"")
 
         #Unknown output format TEST DISABLED DURING MIGRATION
         #result = bibformat_engine.format_record(recID=None, of="unkno", xml_record=self.xml_text_3)
         #self.assertEqual(result.replace("\n", ""),"")
 
         #Default formatting
         result = bibformat_engine.format_record(recID=None, ln='fr', of="test3", xml_record=self.xml_text_3)
         self.assertEqual(result,'''<h1>hi</h1> this is my template\ntest<bfe_non_existing_element must disappear/><test_1  non prefixed element must stay as any normal tag/>tfrgarbage\n<br/>test me!&lt;b&gt;ok&lt;/b&gt;a default valueeditor\n<br/>test me!<b>ok</b>a default valueeditor\n<br/>test me!&lt;b&gt;ok&lt;/b&gt;a default valueeditor\n''')
 
     def test_empty_formatting(self):
         """bibformat - formatting empty record"""
         result = bibformat_engine.format_record(recID=0,
                                                 of='hb',
                                                 verbose=9,
                                                 xml_record=self.empty_record_xml)
         self.assertEqual(result, '')
 
         # FIXME: The commented test below currently fails, since xm
         # format is generated from the database
 
 ##         result = bibformat_engine.format_record(recID=0,
 ##                                                 of='xm',
 ##                                                 verbose=9,
 ##                                                 xml_record=self.empty_record_xml)
 ##         self.assertEqual(result, self.empty_record_xml)
 
     def test_format_with_format_template(self):
         """ bibformat - correct formatting with given template"""
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_PATH = CFG_BIBFORMAT_ELEMENTS_PATH
         bibformat_engine.CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH = CFG_BIBFORMAT_ELEMENTS_IMPORT_PATH
         bibformat_engine.CFG_BIBFORMAT_TEMPLATES_PATH = CFG_BIBFORMAT_TEMPLATES_PATH
 
         template = bibformat_engine.get_format_template("Test3.bft")
         result = bibformat_engine.format_with_format_template(format_template_filename = None,
                                                               bfo=self.bfo_1,
                                                               verbose=0,
                                                               format_template_code=template['code'])
 
         self.assert_(isinstance(result, tuple))
         self.assertEqual(result[0],'''<h1>hi</h1> this is my template\ntest<bfe_non_existing_element must disappear/><test_1  non prefixed element must stay as any normal tag/>tfrgarbage\n<br/>test me!&lt;b&gt;ok&lt;/b&gt;a default valueeditor\n<br/>test me!<b>ok</b>a default valueeditor\n<br/>test me!&lt;b&gt;ok&lt;/b&gt;a default valueeditor\n99999''')
 
-def create_test_suite():
-    """Return test suite for the bibformat module"""
-    return unittest.TestSuite((unittest.makeSuite(FormatTemplateTest,'test'),
-                               unittest.makeSuite(OutputFormatTest,'test'),
-                               unittest.makeSuite(FormatElementTest,'test'),
-                               unittest.makeSuite(PatternTest,'test'),
-                               unittest.makeSuite(MiscTest,'test'),
-                               unittest.makeSuite(FormatTest,'test')))
+TEST_SUITE = make_test_suite(FormatTemplateTest,
+                             OutputFormatTest,
+                             FormatElementTest,
+                             PatternTest,
+                             MiscTest,
+                             FormatTest,)
 
 if __name__ == '__main__':
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
diff --git a/modules/bibformat/lib/bibformat_regression_tests.py b/modules/bibformat/lib/bibformat_regression_tests.py
index b88715566..748a5d939 100644
--- a/modules/bibformat/lib/bibformat_regression_tests.py
+++ b/modules/bibformat/lib/bibformat_regression_tests.py
@@ -1,416 +1,416 @@
 # -*- coding: utf-8 -*-
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebSearch module regression tests."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL, CFG_SITE_LANG
 from invenio.testutils import make_test_suite, \
-                              warn_user_about_tests_and_run, \
+                              run_test_suite, \
                               test_web_page_content
 from invenio.bibformat import format_record
 
 class BibFormatAPITest(unittest.TestCase):
     """Check BibFormat API"""
 
     def test_basic_formatting(self):
         """bibformat - Checking BibFormat API"""
         result = format_record(recID=73,
                                of='hx',
                                ln=CFG_SITE_LANG,
                                verbose=0,
                                search_pattern=[],
                                xml_record=None,
                                user_info=None,
                                on_the_fly=True)
 
         pageurl = CFG_SITE_URL + '/record/73?of=hx'
         result = test_web_page_content(pageurl,
                                        expected_text=result)
 
 class BibFormatBibTeXTest(unittest.TestCase):
     """Check output produced by BibFormat for BibTeX output for
     various records"""
 
     def setUp(self):
         """Prepare some ideal outputs"""
         self.record_74_hx = '''<pre>
 @article{Wang:74,
       author       = "Wang, B and Lin, C Y and Abdalla, E",
       title        = "Quasinormal modes of Reissner-Nordstrom Anti-de Sitter
                       Black Holes",
       journal      = "Phys. Lett., B",
       number       = "hep-th/0003295",
       volume       = "481",
       pages        = "79-88",
       year         = "2000",
 }
 </pre>'''
 
     def test_bibtex_output(self):
         """bibformat - BibTeX output"""
 
         pageurl = CFG_SITE_URL + '/record/74?of=hx'
         result = test_web_page_content(pageurl,
                                        expected_text=self.record_74_hx)
         self.assertEqual([], result)
 
 class BibFormatDetailedHTMLTest(unittest.TestCase):
     """Check output produced by BibFormat for detailed HTML ouput for
     various records"""
 
     def setUp(self):
         """Prepare some ideal outputs"""
 
         # Record 7 (Article)
         self.record_74_hd_header = '''<table border="0" width="100%">
       <tr>
         <td>Published Article<small> / Particle Physics - Theory</small></td>
         <td><small><strong></strong></small></td>
         <td align="right"><strong>hep-th/0003295</strong></td>
       </tr>
     </table>'''
 
         self.record_74_hd_title = '''<center><big><big><strong>Quasinormal modes of Reissner-Nordstrom Anti-de Sitter Black Holes</strong></big></big></center>'''
 
         self.record_74_hd_authors = '''<a href="%(siteurl)s/search?f=author&amp;p=Wang%%2C%%20B&amp;ln=%(lang)s">Wang, B</a><small> (Fudan University)</small> ; <a href="%(siteurl)s/search?f=author&amp;p=Lin%%2C%%20C%%20Y&amp;ln=%(lang)s">Lin, C Y</a> ; <a href="%(siteurl)s/search?f=author&amp;p=Abdalla%%2C%%20E&amp;ln=%(lang)s">Abdalla, E</a><br />'''% \
                                      {'siteurl' : CFG_SITE_URL,
                                       'lang': CFG_SITE_LANG}
 
         self.record_74_hd_abstract = '''<small><strong>Abstract: </strong>Complex frequencies associated with quasinormal modes for large Reissner-Nordstr$\ddot{o}$m Anti-de Sitter black holes have been computed. These frequencies have close relation to the black hole charge and do not linearly scale withthe black hole temperature as in Schwarzschild Anti-de Sitter case. In terms of AdS/CFT correspondence, we found that the bigger the black hole charge is, the quicker for the approach to thermal equilibrium in the CFT. The propertiesof quasinormal modes for $l&gt;0$ have also been studied.</small><br />'''
 
         self.record_74_hd_pubinfo = '''<strong>Published in: </strong><a href="http://weblib.cern.ch/cgi-bin/ejournals?publication=Phys.%20Lett.%2C%20B&amp;volume=481&amp;year=2000&amp;page=79">Phys. Lett., B :481 2000 79-88</a>'''
 
         self.record_74_hd_fulltext = '''0003295.pdf"><img style="border:none"'''
 
         self.record_74_hd_citations = '''<strong>Cited by:</strong> try citation search for <a href="%(siteurl)s/search?f=reference&amp;p=hep-th/0003295&amp;ln=%(lang)s">hep-th/0003295</a>'''% \
                                       {'siteurl' : CFG_SITE_URL,
                                        'lang': CFG_SITE_LANG}
         self.record_74_hd_references = '''<li><small>[17]</small> <small>A. Chamblin, R. Emparan, C. V. Johnson and R. C. Myers, Phys. Rev., D60: 104026 (1999) 5070 90 110 130 150 r+ 130 230 330 50 70 90 110 130 150 r+</small> </li>'''
 
         # Record 7 (Picture)
         self.record_7_hd_header = '''<table border="0" width="100%">
       <tr>
         <td>Pictures<small> / Life at CERN</small></td>
         <td><small><strong></strong></small></td>
         <td align="right"><strong>CERN-GE-9806033</strong></td>
       </tr>
     </table>'''
 
         self.record_7_hd_title = '''<center><big><big><strong>Tim Berners-Lee</strong></big></big></center>'''
 
         self.record_7_hd_date = '''<center>28 Jun 1998</center>'''
 
         self.record_7_hd_abstract = '''<p><span class="blocknote">
  Caption</span><br /> <small>Conference "Internet, Web, What's next?" on 26 June 1998 at CERN : Tim Berners-Lee, inventor of the World-Wide Web and Director of the W3C, explains how the Web came to be and give his views on the future.</small></p><p><span class="blocknote">
  Légende</span><br /><small>Conference "Internet, Web, What's next?" le 26 juin 1998 au CERN: Tim Berners-Lee, inventeur du World-Wide Web et directeur du W3C, explique comment le Web est ne, et donne ses opinions sur l'avenir.</small></p>'''
         self.record_7_hd_resource = '''<img src="%s/record/7/files/icon-9806033.gif" alt="" /><br /><font size="-2"><b>© CERN Geneva</b></font>''' % CFG_SITE_URL
         self.record_7_hd_resource_link = '%s/record/7/files/9806033.jpeg' %  CFG_SITE_URL
 
     def test_detailed_html_output(self):
         """bibformat - Detailed HTML output"""
 
         # Test record 74 (Article)
         pageurl = CFG_SITE_URL + '/record/74?of=hd'
         result = test_web_page_content(pageurl,
                                        expected_text=[self.record_74_hd_header,
                                                       self.record_74_hd_title,
                                                       self.record_74_hd_authors,
                                                       self.record_74_hd_abstract,
                                                       self.record_74_hd_pubinfo,
                                                       self.record_74_hd_fulltext,
                                                       #self.record_74_hd_citations,
                                                       #self.record_74_hd_references
                                                       ])
         self.assertEqual([], result)
 
         # Test record 7 (Picture)
         pageurl = CFG_SITE_URL + '/record/7?of=hd'
         result = test_web_page_content(pageurl,
                                        expected_text=[self.record_7_hd_header,
                                                       self.record_7_hd_title,
                                                       self.record_7_hd_date,
                                                       self.record_7_hd_abstract,
                                                       self.record_7_hd_resource,
                                                       self.record_7_hd_resource_link])
         self.assertEqual([], result)
 
     def test_detailed_html_edit_record(self):
         """bibformat - Detailed HTML output edit record link presence"""
         pageurl = CFG_SITE_URL + '/record/74?of=hd'
         result = test_web_page_content(pageurl, username='admin',
                                        expected_text="Edit This Record")
         self.assertEqual([], result)
 
     def test_detailed_html_no_error_message(self):
         """bibformat - Detailed HTML output without error message"""
         # No error message should be displayed in the web interface, whatever happens
         pageurl = CFG_SITE_URL + '/record/74?of=hd'
         result = test_web_page_content(pageurl, username='admin',
                                        expected_text=["Exception",
                                                       "Could not"])
         self.assertNotEqual([], result)
 
         pageurl = CFG_SITE_URL + '/record/7?of=hd'
         result = test_web_page_content(pageurl, username='admin',
                                        expected_text=["Exception",
                                                       "Could not"])
         self.assertNotEqual([], result)
 
 class BibFormatNLMTest(unittest.TestCase):
     """Check output produced by BibFormat for NLM output for various
     records"""
 
     def setUp(self):
         """Prepare some ideal outputs"""
         self.record_70_xn = '''<?xml version="1.0" encoding="UTF-8"?>
 <articles>
 <article xmlns:xlink="http://www.w3.org/1999/xlink/">
   <front>
     <journal-meta>
       <journal-title>J. High Energy Phys.</journal-title>
       <abbrev-journal-title>J. High Energy Phys.</abbrev-journal-title>
       <issn>1126-6708</issn>
     </journal-meta>
     <article-meta>
       <title-group>
         <article-title>AdS/CFT For Non-Boundary Manifolds</article-title>
       </title-group>
       <contrib-group>
         <contrib contrib-type="author">
           <name>
             <surname>McInnes</surname>
             <given-names>B</given-names>
           </name>
           <aff>
             <institution>National University of Singapore</institution>
           </aff>
         </contrib>
       </contrib-group>
       <pub-date pub-type="pub">
         <year>2000</year>
       </pub-date>
       <volume>05</volume>
       <fpage/>
       <lpage/>
       <self-uri xlink:href="%(siteurl)s/record/70"/>
       <self-uri xlink:href="%(siteurl)s/record/70/files/0003291.pdf"/>
       <self-uri xlink:href="%(siteurl)s/record/70/files/0003291.ps.gz"/>
     </article-meta>
     <abstract>In its Euclidean formulation, the AdS/CFT correspondence begins as a study of Yang-Mills conformal field theories on the sphere, S^4. It has been successfully extended, however, to S^1 X S^3 and to the torus T^4. It is natural tohope that it can be made to work for any manifold on which it is possible to define a stable Yang-Mills conformal field theory. We consider a possible classification of such manifolds, and show how to deal with the most obviousobjection : the existence of manifolds which cannot be represented as boundaries. We confirm Witten's suggestion that this can be done with the help of a brane in the bulk.</abstract>
   </front>
   <article-type>research-article</article-type>
   <ref/>
 </article>
 
 </articles>''' % {'siteurl': CFG_SITE_URL}
 
     def test_nlm_output(self):
         """bibformat - NLM output"""
 
         pageurl = CFG_SITE_URL + '/record/70?of=xn'
         result = test_web_page_content(pageurl,
                                        expected_text=self.record_70_xn)
         try:
             self.assertEqual([], result)
         except AssertionError:
             result = test_web_page_content(pageurl,
                                            expected_text=self.record_70_xn.replace('<fpage/>', '<fpage></fpage>').replace('<lpage/>', '<lpage></lpage>'))
             self.assertEqual([], result)
 
 class BibFormatBriefHTMLTest(unittest.TestCase):
     """Check output produced by BibFormat for brief HTML ouput for
     various records"""
 
     def setUp(self):
         """Prepare some ideal outputs"""
 
         self.record_76_hb = '''<strong>Ιθάκη</strong>
  / <a href="%s/search?f=author&amp;p=%%CE%%9A%%CE%%B1%%CE%%B2%%CE%%AC%%CF%%86%%CE%%B7%%CF%%82%%2C%%20%%CE%%9A%%20%%CE%%A0&amp;ln=%s">Καβάφης, Κ Π</a>
 
 
 
 
 
 <br /><small>
 Σα βγεις στον πηγαιμό για την Ιθάκη,<br />
 να εύχεσαι νάναι μακρύς ο δρόμος,<br />
 γεμάτος περιπέτειες, γεμάτος γνώσεις [...] </small>''' % (CFG_SITE_URL, CFG_SITE_LANG)
 
 
     def test_brief_html_output(self):
         """bibformat - Brief HTML output"""
         pageurl = CFG_SITE_URL + '/record/76?of=HB'
         result = test_web_page_content(pageurl,
                                        expected_text=self.record_76_hb)
         self.assertEqual([], result)
 
 class BibFormatMARCXMLTest(unittest.TestCase):
     """Check output produced by BibFormat for MARCXML ouput for various records"""
 
     def setUp(self):
         """Prepare some ideal outputs"""
 
         self.record_9_xm = '''<?xml version="1.0" encoding="UTF-8"?>
 <collection xmlns="http://www.loc.gov/MARC21/slim">
 <record>
   <controlfield tag="001">9</controlfield>
   <datafield tag="041" ind1=" " ind2=" ">
     <subfield code="a">eng</subfield>
   </datafield>
   <datafield tag="088" ind1=" " ind2=" ">
     <subfield code="a">PRE-25553</subfield>
   </datafield>
   <datafield tag="088" ind1=" " ind2=" ">
     <subfield code="a">RL-82-024</subfield>
   </datafield>
   <datafield tag="100" ind1=" " ind2=" ">
     <subfield code="a">Ellis, J</subfield>
     <subfield code="u">University of Oxford</subfield>
   </datafield>
   <datafield tag="245" ind1=" " ind2=" ">
     <subfield code="a">Grand unification with large supersymmetry breaking</subfield>
   </datafield>
   <datafield tag="260" ind1=" " ind2=" ">
     <subfield code="c">Mar 1982</subfield>
   </datafield>
   <datafield tag="300" ind1=" " ind2=" ">
     <subfield code="a">18 p</subfield>
   </datafield>
   <datafield tag="650" ind1="1" ind2="7">
     <subfield code="2">SzGeCERN</subfield>
     <subfield code="a">General Theoretical Physics</subfield>
   </datafield>
   <datafield tag="700" ind1=" " ind2=" ">
     <subfield code="a">Ibanez, L E</subfield>
   </datafield>
   <datafield tag="700" ind1=" " ind2=" ">
     <subfield code="a">Ross, G G</subfield>
   </datafield>
   <datafield tag="909" ind1="C" ind2="0">
     <subfield code="y">1982</subfield>
   </datafield>
   <datafield tag="909" ind1="C" ind2="0">
     <subfield code="b">11</subfield>
   </datafield>
   <datafield tag="909" ind1="C" ind2="1">
     <subfield code="u">Oxford Univ.</subfield>
   </datafield>
   <datafield tag="909" ind1="C" ind2="1">
     <subfield code="u">Univ. Auton. Madrid</subfield>
   </datafield>
   <datafield tag="909" ind1="C" ind2="1">
     <subfield code="u">Rutherford Lab.</subfield>
   </datafield>
   <datafield tag="909" ind1="C" ind2="1">
     <subfield code="c">1990-01-28</subfield>
     <subfield code="l">50</subfield>
     <subfield code="m">2002-01-04</subfield>
     <subfield code="o">BATCH</subfield>
   </datafield>
   <datafield tag="909" ind1="C" ind2="S">
     <subfield code="s">h</subfield>
     <subfield code="w">1982n</subfield>
   </datafield>
   <datafield tag="980" ind1=" " ind2=" ">
     <subfield code="a">PREPRINT</subfield>
   </datafield>
 </record>
 </collection>'''
 
     def test_marcxml_output(self):
         """bibformat - MARCXML output"""
         pageurl = CFG_SITE_URL + '/record/9?of=xm'
         result = test_web_page_content(pageurl,
                                        expected_text=self.record_9_xm)
         self.assertEqual([], result)
 
 class BibFormatMARCTest(unittest.TestCase):
     """Check output produced by BibFormat for MARC ouput for various
     records"""
 
     def setUp(self):
         """Prepare some ideal outputs"""
 
         self.record_29_hm = '''000000029 001__ 29
 000000029 020__ $$a0720421039
 000000029 041__ $$aeng
 000000029 080__ $$a517.11
 000000029 100__ $$aKleene, Stephen Cole$$uUniversity of Wisconsin
 000000029 245__ $$aIntroduction to metamathematics
 000000029 260__ $$aAmsterdam$$bNorth-Holland$$c1952 (repr.1964.)
 000000029 300__ $$a560 p
 000000029 490__ $$aBibl. Matematica$$v1
 000000029 909C0 $$y1952
 000000029 909C0 $$b21
 000000029 909C1 $$c1990-01-27$$l00$$m2002-04-12$$oBATCH
 000000029 909CS $$sm$$w198606
 000000029 980__ $$aBOOK'''
 
     def test_marc_output(self):
         """bibformat - MARC output"""
 
         pageurl = CFG_SITE_URL + '/record/29?of=hm'
         result = test_web_page_content(pageurl,
                                        expected_text=self.record_29_hm)
         self.assertEqual([], result)
 
 class BibFormatTitleFormattingTest(unittest.TestCase):
     """Check title formatting produced by BibFormat."""
 
     def test_subtitle_in_html_brief(self):
         """bibformat - title subtitle in HTML brief formats"""
 	self.assertEqual([],
           test_web_page_content(CFG_SITE_URL + '/search?p=statistics+computer',
             expected_text="Statistics: a computer approach"))
 
     def test_subtitle_in_html_detailed(self):
         """bibformat - title subtitle in HTML detailed formats"""
 	self.assertEqual([],
           test_web_page_content(CFG_SITE_URL + '/search?p=statistics+computer&of=HD',
             expected_text="Statistics: a computer approach"))
 
     def test_title_edition_in_html_brief(self):
         """bibformat - title edition in HTML brief formats"""
 	self.assertEqual([],
           test_web_page_content(CFG_SITE_URL + '/search?p=2nd',
             expected_text="Introductory statistics: a decision map; 2nd ed"))
 
     def test_title_edition_in_html_detailed(self):
         """bibformat - title edition in HTML detailed formats"""
 	self.assertEqual([],
           test_web_page_content(CFG_SITE_URL + '/search?p=2nd&of=HD',
             expected_text="Introductory statistics: a decision map; 2nd ed"))
 
-test_suite = make_test_suite(BibFormatBibTeXTest,
+TEST_SUITE = make_test_suite(BibFormatBibTeXTest,
                              BibFormatDetailedHTMLTest,
                              BibFormatBriefHTMLTest,
                              BibFormatNLMTest,
                              BibFormatMARCTest,
                              BibFormatMARCXMLTest,
                              BibFormatAPITest,
                              BibFormatTitleFormattingTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
 
diff --git a/modules/bibformat/lib/bibformatadmin_regression_tests.py b/modules/bibformat/lib/bibformatadmin_regression_tests.py
index 8ab2b8961..727a13c1a 100644
--- a/modules/bibformat/lib/bibformatadmin_regression_tests.py
+++ b/modules/bibformat/lib/bibformatadmin_regression_tests.py
@@ -1,72 +1,72 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """BibFormat Admin Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class BibFormatAdminWebPagesAvailabilityTest(unittest.TestCase):
     """Check BibFormat Admin web pages whether they are up or not."""
 
     def test_bibformat_admin_interface_availability(self):
         """bibformatadmin - availability of BibFormat Admin interface pages"""
 
         baseurl = CFG_SITE_URL + '/admin/bibformat/'
 
         _exports = ['bibformatadmin.py/format_templates_manage',
                     'bibformatadmin.py/output_formats_manage',
                     'bibformatadmin.py/format_elements_doc',
                     'bibformatadmin.py/kb_manage']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'not authorized to perform'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_bibformat_admin_guide_availability(self):
         """bibformatadmin - availability of BibFormat Admin guide pages"""
 
         url = CFG_SITE_URL + '/help/admin/bibformat-admin-guide'
         error_messages = test_web_page_content(url,
                                                expected_text="BibFormat Admin Guide")
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(BibFormatAdminWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(BibFormatAdminWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibharvest/lib/bibharvestadmin_regression_tests.py b/modules/bibharvest/lib/bibharvestadmin_regression_tests.py
index e120b12cc..12296e440 100644
--- a/modules/bibharvest/lib/bibharvestadmin_regression_tests.py
+++ b/modules/bibharvest/lib/bibharvestadmin_regression_tests.py
@@ -1,69 +1,69 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """BibHarvest Admin Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class BibHarvestAdminWebPagesAvailabilityTest(unittest.TestCase):
     """Check BibHarvest Admin web pages whether they are up or not."""
 
     def test_bibharvest_admin_interface_pages_availability(self):
         """bibharvestadmin - availability of BibHarvest Admin interface pages"""
 
         baseurl = CFG_SITE_URL + '/admin/bibharvest/bibharvestadmin.py/'
 
         _exports = ['', 'editsource', 'addsource', 'delsource']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'Authorization failure'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_bibharvest_admin_guide_availability(self):
         """bibharvestadmin - availability of BibHarvest Admin guide pages"""
 
         url = CFG_SITE_URL + '/help/admin/bibharvest-admin-guide'
         error_messages = test_web_page_content(url,
                                                expected_text="BibHarvest Admin Guide")
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(BibHarvestAdminWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(BibHarvestAdminWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibharvest/lib/oai_repository_regression_tests.py b/modules/bibharvest/lib/oai_repository_regression_tests.py
index 57ec510c3..527f0339b 100644
--- a/modules/bibharvest/lib/oai_repository_regression_tests.py
+++ b/modules/bibharvest/lib/oai_repository_regression_tests.py
@@ -1,69 +1,69 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.  
+## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """OAIRepository Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 import time
 
 from invenio.config import CFG_SITE_URL, CFG_OAI_SLEEP
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class OAIRepositoryWebPagesAvailabilityTest(unittest.TestCase):
     """Check OAIRepository web pages whether they are up or not."""
 
     def test_your_baskets_pages_availability(self):
-        """oairepository - availability of OAI server pages""" 
+        """oairepository - availability of OAI server pages"""
 
         baseurl = CFG_SITE_URL + '/oai2d'
 
         _exports = [#fast commands first:
                     '?verb=Identify',
                     '?verb=ListMetadataFormats',
                     # sleepy commands now:
                     '?verb=ListSets',
                     '?verb=ListRecords',
                     '?verb=GetRecord']
-        
+
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             if url.endswith('Identify') or \
                url.endswith('ListMetadataFormats'):
                 pass
             else:
                 # some sleep required for verbs other than Identify
                 # and ListMetadataFormats, since oai2d refuses too
                 # frequent access:
-                time.sleep(CFG_OAI_SLEEP) 
+                time.sleep(CFG_OAI_SLEEP)
             error_messages.extend(test_web_page_content(url,
                                                         expected_text=
                                                         '</OAI-PMH>'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(OAIRepositoryWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(OAIRepositoryWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibharvest/lib/oai_repository_tests.py b/modules/bibharvest/lib/oai_repository_tests.py
index 348de3fd6..dedafd7fe 100644
--- a/modules/bibharvest/lib/oai_repository_tests.py
+++ b/modules/bibharvest/lib/oai_repository_tests.py
@@ -1,200 +1,197 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ## CDS Invenio OAI repository unit tests.
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the oai repository."""
 
 __revision__ = "$Id$"
 
 import unittest
 import re
 import time
 
 from invenio import oai_repository, search_engine
+from invenio.testutils import make_test_suite, run_test_suite
 
 from invenio.config import \
      CFG_OAI_LOAD, \
      CFG_OAI_ID_FIELD
 
 class TestVerbs(unittest.TestCase):
     """Test for OAI verb functionality."""
 
     def test_verbs(self):
         """bibharvest oai repository - testing verbs"""
         self.assertNotEqual(None, re.search("Identify", oai_repository.oaiidentify("")))
         self.assertNotEqual(None, re.search("ListIdentifiers", oai_repository.oailistidentifiers("")))
         self.assertNotEqual(None, re.search("ListRecords", oai_repository.oailistrecords("")))
         self.assertNotEqual(None, re.search("ListMetadataFormats", oai_repository.oailistmetadataformats("")))
         self.assertNotEqual(None, re.search("ListSets", oai_repository.oailistsets("")))
         self.assertNotEqual(None, re.search("GetRecord", oai_repository.oaigetrecord("")))
 
 class TestSelectiveHarvesting(unittest.TestCase):
     """Test set, from and until parameters used to do selective harvesting."""
 
     def test_set(self):
         """bibharvest oai repository - testing selective harvesting with 'set' parameter"""
         self.assertNotEqual([], oai_repository.oaigetsysnolist(set="cern:experiment"))
         self.assert_("Multifractal analysis of minimum bias events" in \
                      ''.join([oai_repository.print_record(recID) for recID in \
                               oai_repository.oaigetsysnolist(set="cern:experiment")]))
         self.assert_("Multifractal analysis of minimum bias events" not in \
                      ''.join([oai_repository.print_record(recID) for recID in \
                               oai_repository.oaigetsysnolist(set="cern:theory")]))
         self.assertEqual([], oai_repository.oaigetsysnolist(set="nonExistingSet"))
 
     def test_from_and_until(self):
         """bibharvest oai repository - testing selective harvesting with 'from' and 'until' parameters"""
 
         # List available records, get datestamps and play with them
         identifiers = oai_repository.oailistidentifiers("")
         datestamps = re.findall('<identifier>(?P<id>.*)</identifier>\s*<datestamp>(?P<date>.*)</datestamp>', identifiers)
 
         sample_datestamp = datestamps[0][1] # Take one datestamp
         sample_oai_id = datestamps[0][0] # Take corresponding oai id
         sample_id = search_engine.perform_request_search(p=sample_oai_id,
                                                          f=CFG_OAI_ID_FIELD)[0] # Find corresponding system number id
 
         # There must be some datestamps
         self.assertNotEqual([], datestamps)
 
         # We must be able to retrieve an id with the date we have just found
         self.assert_(sample_id in oai_repository.oaigetsysnolist(fromdate=sample_datestamp))
         self.assert_(sample_id in oai_repository.oaigetsysnolist(untildate=sample_datestamp))
         self.assert_(sample_id in oai_repository.oaigetsysnolist(untildate=sample_datestamp, \
                                                                  fromdate=sample_datestamp))
 
         # Same, with short format date. Eg 2007-12-13
         self.assert_(sample_id in oai_repository.oaigetsysnolist(fromdate=sample_datestamp.split('T')[0]))
         self.assert_(sample_id in oai_repository.oaigetsysnolist(untildate=sample_datestamp.split('T')[0]))
         self.assert_(sample_id in oai_repository.oaigetsysnolist(fromdate=sample_datestamp.split('T')[0], \
                                                                  untildate=sample_datestamp.split('T')[0]))
 
         # At later date (year after) we should not find our id again
         later_datestamp = sample_datestamp
         later_datestamp = sample_datestamp[0:3] + str(int(sample_datestamp[3]) + 1) + sample_datestamp[4:]
         self.assert_(sample_id not in oai_repository.oaigetsysnolist(fromdate=later_datestamp))
 
         # At earlier date (year before) we should not find our id again
         earlier_datestamp = sample_datestamp
         earlier_datestamp = sample_datestamp[0:3] + str(int(sample_datestamp[3]) - 1) + sample_datestamp[4:]
         self.assert_(sample_id not in oai_repository.oaigetsysnolist(untildate=earlier_datestamp))
 
         # From earliest date to latest date must include all oai records
         dates = [(time.mktime(time.strptime(date[1], "%Y-%m-%dT%H:%M:%SZ")), date[1]) for date in datestamps]
         dates = dict(dates)
         sorted_times = dates.keys()
         sorted_times.sort()
         earliest_datestamp = dates[sorted_times[0]]
         latest_datestamp = dates[sorted_times[-1]]
         self.assertEqual(len(oai_repository.oaigetsysnolist()), \
                          len(oai_repository.oaigetsysnolist(fromdate=earliest_datestamp, \
                                                             untildate=latest_datestamp)))
 
 class TestErrorCodes(unittest.TestCase):
     """Test for handling OAI error codes."""
 
     def test_issue_error_identify(self):
         """bibharvest oai repository - testing error codes"""
 
         self.assertNotEqual(None, re.search("badVerb", oai_repository.check_args({'verb':"IllegalVerb"})))
         self.assertNotEqual(None, re.search("badArgument", oai_repository.check_args({'verb':"Identify",
                                                                                       'test':"test"})))
         self.assertNotEqual(None, re.search("badArgument", oai_repository.check_args({'verb':"ListIdentifiers",
                                                                                       'metadataPrefix':"oai_dc",
                                                                                       'from':"some_random_date",
                                                                                       'until':"some_random_date"})))
         self.assertNotEqual(None, re.search("badArgument", oai_repository.check_args({'verb':"ListIdentifiers",
                                                                                       'metadataPrefix':"oai_dc",
                                                                                       'from':"2001-01-01",
                                                                                       'until':"2002-01-01T00:00:00Z"})))
         self.assertNotEqual(None, re.search("badArgument", oai_repository.check_args({'verb':"ListIdentifiers"})))
         self.assertNotEqual(None, re.search("cannotDisseminateFormat", oai_repository.check_args({'verb':"ListIdentifiers",
                                                                                                   'metadataPrefix':"illegal_mdp"})))
         # FIXME: Next test is disabled as long as oai_repository.py is
         # not able to catch it
 ##         self.assertNotEqual(None, re.search("badArgument", oai_repository.check_args({'verb':"ListIdentifiers",
 ##                                                                                       'metadataPrefix':"oai_dc",
 ##                                                                                       'metadataPrefix':"oai_dc"})))
         self.assertNotEqual(None, re.search("badArgument", oai_repository.check_args({'verb':"ListRecords",
                                                                                       'metadataPrefix':"oai_dc",
                                                                                       'set':"really_wrong_set",
                                                                                       'from':"some_random_date",
                                                                                       'until':"some_random_date"})))
         self.assertNotEqual(None, re.search("badArgument", oai_repository.check_args({'verb':"ListRecords"})))
 
 class TestEncodings(unittest.TestCase):
     """Test for OAI response encodings."""
 
     def test_encoding(self):
         """bibharvest oai repository - testing encodings"""
 
         self.assertEqual("&lt;&amp;>", oai_repository.encode_for_xml("<&>"))
         self.assertEqual("%20", oai_repository.escape_space(" "))
         self.assertEqual("%25%20%3F%23%3D%26%2F%3A%3B%2B", oai_repository.encode_for_url("% ?#=&/:;+"))
 
 class TestPerformance(unittest.TestCase):
     """Test performance of the repository """
 
     def setUp(self):
         """Setting up some variables"""
         # Determine how many records are served
         self.number_of_records = oai_repository.oaigetsysnolist("", "", "")
         if CFG_OAI_LOAD < self.number_of_records:
             self.number_of_records = CFG_OAI_LOAD
 
     def test_response_speed_oai(self):
         """bibharvest oai repository - speed of response for oai_dc output"""
         allowed_seconds_per_record_oai = 0.02
 
         # Test oai ListRecords performance
         t0 = time.time()
         oai_repository.oailistrecords('metadataPrefix=oai_dc&verb=ListRecords')
         t = time.time() - t0
         if t > self.number_of_records * allowed_seconds_per_record_oai:
             self.fail("""Response for ListRecords with metadataPrefix=oai_dc took too much time:
 %s seconds.
 Limit: %s seconds""" % (t, self.number_of_records * allowed_seconds_per_record_oai))
 
     def test_response_speed_marcxml(self):
         """bibharvest oai repository - speed of response for marcxml output"""
         allowed_seconds_per_record_marcxml = 0.05
 
         # Test marcxml ListRecords performance
         t0 = time.time()
         oai_repository.oailistrecords('metadataPrefix=marcxml&verb=ListRecords')
         t = time.time() - t0
         if t > self.number_of_records * allowed_seconds_per_record_marcxml:
             self.fail("""Response for ListRecords with metadataPrefix=marcxml took too much time:\n
 %s seconds.
 Limit: %s seconds""" % (t, self.number_of_records * allowed_seconds_per_record_marcxml))
 
-def create_test_suite():
-    """Return test suite for the oai repository."""
-
-
-    return unittest.TestSuite((unittest.makeSuite(TestVerbs, 'test'),
-                               unittest.makeSuite(TestErrorCodes, 'test'),
-                               unittest.makeSuite(TestEncodings, 'test'),
-                               unittest.makeSuite(TestSelectiveHarvesting, 'test'),
-                               unittest.makeSuite(TestPerformance, 'test')))
+TEST_SUITE = make_test_suite(TestVerbs,
+                             TestErrorCodes,
+                             TestEncodings,
+                             TestSelectiveHarvesting,
+                             TestPerformance,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/bibharvest/lib/oaiarchiveadmin_regression_tests.py b/modules/bibharvest/lib/oaiarchiveadmin_regression_tests.py
index 8b8c69531..0f80555ee 100644
--- a/modules/bibharvest/lib/oaiarchiveadmin_regression_tests.py
+++ b/modules/bibharvest/lib/oaiarchiveadmin_regression_tests.py
@@ -1,79 +1,79 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.  
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """OAIArchive Admin Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class OAIArchiveAdminWebPagesAvailabilityTest(unittest.TestCase):
     """Check OAIArchive Admin web pages whether they are up or not."""
 
     def test_oaiarchiveadmin_interface_pages_availability(self):
         """oaiarchiveadmin - availability of OAIArchive Admin interface pages""" 
 
         baseurl = CFG_SITE_URL + '/admin/bibharvest/oaiarchiveadmin.py/'
 
         _exports = ['', 'delset', 'editset', 'addset']
         
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'Authorization failure'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_oaiarchiveadmin_edit_set(self):
         """oaiarchiveadmin - edit set page"""
         test_edit_url = CFG_SITE_URL + \
                "/admin/bibharvest/oaiarchiveadmin.py/editset?oai_set_id=1"
         error_messages = test_web_page_content(test_edit_url,
                                                username='admin')
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_oaiarchiveadmin_delete_set(self):
         """oaiarchiveadmin - delete set page"""
         test_edit_url = CFG_SITE_URL + \
                "/admin/bibharvest/oaiarchiveadmin.py/delset?oai_set_id=1"
         error_messages = test_web_page_content(test_edit_url,
                                                username='admin')
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(OAIArchiveAdminWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(OAIArchiveAdminWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibindex/lib/bibindex_engine_stemmer_tests.py b/modules/bibindex/lib/bibindex_engine_stemmer_tests.py
index f54b11a9a..089d91686 100644
--- a/modules/bibindex/lib/bibindex_engine_stemmer_tests.py
+++ b/modules/bibindex/lib/bibindex_engine_stemmer_tests.py
@@ -1,65 +1,64 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the indexing engine."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import bibindex_engine_stemmer
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TestStemmer(unittest.TestCase):
     """Test stemmer."""
 
     def test_stemmer_none(self):
         """bibindex engine - no stemmer"""
         self.assertEqual("information",
                          bibindex_engine_stemmer.stem("information", None))
 
     def test_stemmer_english(self):
         """bibindex engine - English stemmer"""
         english_test_cases = [['information', 'inform'],
                               ['experiment', 'experi'],
                               ['experiments', 'experi'],
                               ['experimented', 'experi'],
                               ['experimenting', 'experi'],
                               ['experimental', 'experiment'],
                               ['experimentally', 'experiment'],
                               ['experimentation', 'experiment'],
                               ['experimentalism', 'experiment'],
                               ['experimenter', 'experiment'],
                               ['experimentalise', 'experimentalis'],
                               ['experimentalist', 'experimentalist'],
                               ['experimentalists', 'experimentalist'],
                               ['GeV', 'GeV'],
                               ['$\Omega$', '$\Omega$'],
                               ['e^-', 'e^-']]
         for test_word, expected_result in english_test_cases:
             self.assertEqual(expected_result,
                              bibindex_engine_stemmer.stem(test_word, "en"))
 
-def create_test_suite():
-    """Return test suite for the indexing engine."""
-    return unittest.TestSuite((unittest.makeSuite(TestStemmer,'test'),))
+TEST_SUITE = make_test_suite(TestStemmer,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/bibindex/lib/bibindex_engine_tests.py b/modules/bibindex/lib/bibindex_engine_tests.py
index 810eec253..430d71342 100644
--- a/modules/bibindex/lib/bibindex_engine_tests.py
+++ b/modules/bibindex/lib/bibindex_engine_tests.py
@@ -1,69 +1,68 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the indexing engine."""
 
 __revision__ = \
     "$Id$"
 
 import unittest
 
 from invenio import bibindex_engine
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TestListSetOperations(unittest.TestCase):
     """Test list set operations."""
 
     def test_list_union(self):
         """bibindex engine - list union"""
         self.assertEqual([1, 2, 3, 4],
                          bibindex_engine.list_union([1, 2, 3],
                                                     [1, 3, 4]))
 
 class TestWashIndexTerm(unittest.TestCase):
     """Test for washing index terms, useful for both searching and indexing."""
 
     def test_wash_index_term_short(self):
         """bibindex engine - wash index term, short word"""
         self.assertEqual("ellis",
                          bibindex_engine.wash_index_term("ellis"))
 
     def test_wash_index_term_long(self):
         """bibindex engine - wash index term, long word"""
         self.assertEqual(50*"e",
                          bibindex_engine.wash_index_term(1234*"e"))
 
     def test_wash_index_term_case(self):
         """bibindex engine - wash index term, lower the case"""
         self.assertEqual("ellis",
                          bibindex_engine.wash_index_term("Ellis"))
 
     def test_wash_index_term_unicode(self):
         """bibindex engine - wash index term, unicode"""
         self.assertEqual("ελληνικό αλφάβητο",
                          bibindex_engine.wash_index_term("Ελληνικό αλφάβητο"))
 
-def create_test_suite():
-    """Return test suite for the indexing engine."""
-    return unittest.TestSuite((unittest.makeSuite(TestListSetOperations,'test'),
-                               unittest.makeSuite(TestWashIndexTerm, 'test'),))
+TEST_SUITE = make_test_suite(TestListSetOperations,
+                             TestWashIndexTerm,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/bibindex/lib/bibindexadmin_regression_tests.py b/modules/bibindex/lib/bibindexadmin_regression_tests.py
index b19cb6ac9..ae0b3b2f4 100644
--- a/modules/bibindex/lib/bibindexadmin_regression_tests.py
+++ b/modules/bibindex/lib/bibindexadmin_regression_tests.py
@@ -1,78 +1,78 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """BibIndex Admin Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class BibIndexAdminWebPagesAvailabilityTest(unittest.TestCase):
     """Check BibIndex Admin web pages whether they are up or not."""
 
     def test_bibindex_admin_interface_pages_availability(self):
         """bibindexadmin - availability of BibIndex Admin interface pages"""
 
         baseurl = CFG_SITE_URL + '/admin/bibindex/bibindexadmin.py/'
 
         _exports = ['',
                     'index',
                     'index?mtype=perform_showindexoverview',
                     'index?mtype=perform_editindexes',
                     'index?mtype=perform_addindex',
                     'field',
                     'field?mtype=perform_showfieldoverview',
                     'field?mtype=perform_editfields',
                     'field?mtype=perform_addfield',
                     ]
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'Authorization failure'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_bibindex_admin_guide_availability(self):
         """bibindexadmin - availability of BibIndex Admin guide pages"""
 
         url = CFG_SITE_URL + '/help/admin/bibindex-admin-guide'
         error_messages = test_web_page_content(url,
                                                expected_text="BibIndex Admin Guide")
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(BibIndexAdminWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(BibIndexAdminWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibrank/lib/bibrank_citation_indexer_tests.py b/modules/bibrank/lib/bibrank_citation_indexer_tests.py
index f6206dd01..422aae85a 100644
--- a/modules/bibrank/lib/bibrank_citation_indexer_tests.py
+++ b/modules/bibrank/lib/bibrank_citation_indexer_tests.py
@@ -1,55 +1,52 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.  
+## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the citation indexer."""
 
 # pylint: disable-msg=C0301
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.bibrank_citation_indexer import last_updated_result
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TestCitationIndexer(unittest.TestCase):
     """Testing citation indexer."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize stuff"""
         self.rank_method_code = 'cit'
         self.updated_recid_list = [339705, 339704, 339708]
 
     def test_last_updated_result(self):
         """bibrank citation indexer - last updated result"""
         self.assert_(last_updated_result(self.rank_method_code,
                                          self.updated_recid_list))
 
-def create_test_suite():
-    """Return test suite for the bibrank citation indexer."""
-    return unittest.TestSuite((
-        unittest.makeSuite(TestCitationIndexer, 'test'),
-        ))
+TEST_SUITE = make_test_suite(TestCitationIndexer,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
 
diff --git a/modules/bibrank/lib/bibrank_citation_searcher_tests.py b/modules/bibrank/lib/bibrank_citation_searcher_tests.py
index 1849e2823..6c58de083 100644
--- a/modules/bibrank/lib/bibrank_citation_searcher_tests.py
+++ b/modules/bibrank/lib/bibrank_citation_searcher_tests.py
@@ -1,63 +1,62 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.  
+## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the citation searcher."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import bibrank_citation_searcher
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TestCitationSearcher(unittest.TestCase):
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize stuff"""
         self.recid = 339705
         self.recids = [339705, 339706]
         self.rank_method_code = 'citation'
-       
+
     def xtest_init_cited_by_dictionary(self):
         """bibrank citation searcher - init cited-by data"""
         # FIXME: test postponed
-        #self.assert_(bibrank_citation_searcher.init_cited_by_dictionary()) 
+        #self.assert_(bibrank_citation_searcher.init_cited_by_dictionary())
 
     def xtest_init_reference_list_dictionary(self):
         """bibrank citation searcher - init reference data"""
         # FIXME: test postponed
         #self.assert_(bibrank_citation_searcher.init_reference_list_dictionary())
 
     def xtest_calculate_cited_by_list(self):
         """bibrank citation searcher - get citing relevance"""
         # FIXME: test postponed
 
     def xtest_calculate_co_cited_with_list(self):
         """bibrank citation searcher - get co-cited-with data"""
         # FIXME: test postponed
-            
-def create_test_suite():
-    """Return test suite for the citation searcher.""" 
-    return unittest.TestSuite((unittest.makeSuite(TestCitationSearcher,'test'),))
+
+TEST_SUITE = make_test_suite(TestCitationSearcher,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
diff --git a/modules/bibrank/lib/bibrank_downloads_indexer_tests.py b/modules/bibrank/lib/bibrank_downloads_indexer_tests.py
index 08f0a69d3..ea2007817 100644
--- a/modules/bibrank/lib/bibrank_downloads_indexer_tests.py
+++ b/modules/bibrank/lib/bibrank_downloads_indexer_tests.py
@@ -1,55 +1,54 @@
 ## $Id$
 
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.  
+## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import bibrank_downloads_indexer
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TestListSetOperations(unittest.TestCase):
     """Test list set operations."""
 
     def test_uniq(self):
         """bibrank downloads indexer - uniq function"""
         self.assertEqual([1, 2, 3], bibrank_downloads_indexer.uniq([1, 2, 3, 3, 3, 2]))
-        
+
     def test_database_tuples_to_single_list(self):
         """bibrank downloads indexer - database tuples to list"""
         self.assertEqual([1, 2, 3], bibrank_downloads_indexer.database_tuples_to_single_list(((1,), (2,), (3,))))
-        
+
 class TestMergeDictionnaries(unittest.TestCase):
     """Test bibrank_downloads_indexer merge 2 dictionnaries"""
 
     def test_merge_with_old_dictionnary(self):
         """bibrank downloads indexer - merging with old dictionary"""
         self.assertEqual({1:[(2, 3)], 2:[(3, 4)], 3:[(4, 5)]}, bibrank_downloads_indexer.merge_with_old_dictionnary(\
             {3:[(4, 5)]}, {1:[(2, 3)], 2:[(3, 4)]}))
         self.assertEqual({1:[(2, 4)], 2:[(3, 4)]}, bibrank_downloads_indexer.merge_with_old_dictionnary(\
             {1:[(2, 1)]}, {1:[(2, 3)], 2:[(3, 4)]}))
         self.assertEqual({1:[(3, 3), (2, 3)], 2:[(3, 4)]}, bibrank_downloads_indexer.merge_with_old_dictionnary(\
             {1:[(2, 3)]}, {1:[(3, 3)], 2:[(3, 4)]}))
         self.assertEqual({}, bibrank_downloads_indexer.merge_with_old_dictionnary({}, {}))
-    
-def create_test_suite():
-    """Return test suite for the downlaods engine."""
-    return unittest.TestSuite((unittest.makeSuite(TestListSetOperations, 'test'),
-                               unittest.makeSuite(TestMergeDictionnaries, 'test')))
+
+TEST_SUITE = make_test_suite(TestListSetOperations,
+                             TestMergeDictionnaries,)
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/bibrank/lib/bibrank_record_sorter_tests.py b/modules/bibrank/lib/bibrank_record_sorter_tests.py
index e1c6e9919..7019d18a2 100644
--- a/modules/bibrank/lib/bibrank_record_sorter_tests.py
+++ b/modules/bibrank/lib/bibrank_record_sorter_tests.py
@@ -1,56 +1,55 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the ranking engine."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import bibrank_record_sorter
 from invenio.search_engine import HitSet
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TestListSetOperations(unittest.TestCase):
     """Test list set operations."""
 
     def test_record_sorter(self):
         """bibrank record sorter - sorting records"""
         hitset = HitSet()
         hitset += (1,2,5)
         hitset2 = HitSet()
         hitset2.add(5)
         rec_termcount = {1: 1, 2: 1, 5: 1}
         (res1, res2) = bibrank_record_sorter.sort_record_relevance({1: 50, 2:30, 3:70,4:10},rec_termcount,hitset, 50,0)
         self.assertEqual(([(1, 71), (3, 100)], list(hitset2)), (res1, list(res2)))
 
     def test_calculate_record_relevance(self):
         """bibrank record sorter - calculating relevances"""
         hitset = HitSet()
         hitset += (1,2,5)
         self.assertEqual(({1: 7, 2: 7, 5: 5}, {1: 1, 2: 1, 5: 1}),  bibrank_record_sorter.calculate_record_relevance(("testterm", 2.0),
 {"Gi":(0, 50.0), 1: (3, 4.0), 2: (4, 5.0), 5: (1, 3.5)}, hitset, {}, {}, 0, None))
 
-def create_test_suite():
-    """Return test suite for the indexing engine."""
-    return unittest.TestSuite((unittest.makeSuite(TestListSetOperations,'test'),))
+TEST_SUITE = make_test_suite(TestListSetOperations,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/bibrank/lib/bibrank_regression_tests.py b/modules/bibrank/lib/bibrank_regression_tests.py
index 0db90556f..93a9ef3a1 100644
--- a/modules/bibrank/lib/bibrank_regression_tests.py
+++ b/modules/bibrank/lib/bibrank_regression_tests.py
@@ -1,98 +1,98 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """BibRank Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class BibRankWebPagesAvailabilityTest(unittest.TestCase):
     """Check BibRank web pages whether they are up or not."""
 
     def test_rank_by_word_similarity_pages_availability(self):
         """bibrank - availability of ranking search results pages"""
 
         baseurl = CFG_SITE_URL + '/search'
 
         _exports = ['?p=ellis&r=wrd']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_similar_records_pages_availability(self):
         """bibrank - availability of similar records results pages"""
 
         baseurl = CFG_SITE_URL + '/search'
 
         _exports = ['?p=recid%3A18&rm=wrd']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
 class BibRankWordSimilarityRankingTest(unittest.TestCase):
     """Check BibRank word similarity ranking tools."""
 
     def test_search_results_ranked_by_similarity(self):
         """bibrank - search results ranked by word similarity"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=ellis&rm=wrd&of=id',
                                                expected_text="[8, 10, 11, 12, 47, 17, 13, 16, 18, 9, 14, 15]"))
 
     def test_similar_records_link(self):
         """bibrank - 'Similar records' link"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=recid%3A77&rm=wrd&of=id',
                                                expected_text="[84, 95, 85, 77]"))
 
 class BibRankCitationRankingTest(unittest.TestCase):
     """Check BibRank citation ranking tools."""
 
     def test_search_results_ranked_by_citations(self):
         """bibrank - search results ranked by number of citations"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?cc=Articles+%26+Preprints&p=Klebanov&rm=citation&of=id',
                                                expected_text="[85, 77, 84]"))
 
     def test_search_results_ranked_by_citations_verbose(self):
         """bibrank - search results ranked by number of citations, verbose output"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?cc=Articles+%26+Preprints&p=Klebanov&rm=citation&verbose=2',
                                                expected_text="find_citations retlist [[85, 0], [77, 2], [84, 3]]"))
 
-test_suite = make_test_suite(BibRankWebPagesAvailabilityTest,
+TEST_SUITE = make_test_suite(BibRankWebPagesAvailabilityTest,
                              BibRankWordSimilarityRankingTest,
                              BibRankCitationRankingTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibrank/lib/bibrank_tag_based_indexer_tests.py b/modules/bibrank/lib/bibrank_tag_based_indexer_tests.py
index 471c35635..6ba83a41e 100644
--- a/modules/bibrank/lib/bibrank_tag_based_indexer_tests.py
+++ b/modules/bibrank/lib/bibrank_tag_based_indexer_tests.py
@@ -1,47 +1,46 @@
 # -*- coding: utf-8 -*-
 
 ## $Id$
 
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the ranking engine."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import bibrank_tag_based_indexer
 from invenio.bibrank import split_ranges
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TestListSetOperations(unittest.TestCase):
     """Test list set operations."""
 
     def test_union_dicts(self):
         """bibrank tag based indexer - union dicts"""
         self.assertEqual({1: 5, 2: 6, 3: 9, 4: 10, 10: 1}, bibrank_tag_based_indexer.union_dicts({1: 5, 2: 6, 3: 9}, {3:9, 4:10, 10: 1}))
 
     def test_split_ranges(self):
         """bibrank tag based indexer - split ranges"""
         self.assertEqual([[0, 500], [600, 1000]], split_ranges("0-500,600-1000"))
 
-def create_test_suite():
-    """Return test suite for the indexing engine."""
-    return unittest.TestSuite((unittest.makeSuite(TestListSetOperations,'test'),))
+TEST_SUITE = make_test_suite(TestListSetOperations,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/bibrank/lib/bibrankadmin_regression_tests.py b/modules/bibrank/lib/bibrankadmin_regression_tests.py
index cde5ceef9..7ec9b7d9a 100644
--- a/modules/bibrank/lib/bibrankadmin_regression_tests.py
+++ b/modules/bibrank/lib/bibrankadmin_regression_tests.py
@@ -1,71 +1,71 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """BibRank Admin Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class BibRankAdminWebPagesAvailabilityTest(unittest.TestCase):
     """Check BibRank Admin web pages whether they are up or not."""
 
     def test_bibrank_admin_interface_pages_availability(self):
         """bibrankadmin - availability of BibRank Admin interface pages"""
 
         baseurl = CFG_SITE_URL + '/admin/bibrank/bibrankadmin.py/'
 
         _exports = ['', 'addrankarea', 'modifytranslations',
                     'modifycollection', 'showrankdetails', 'modifyrank',
                     'deleterank']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'Authorization failure'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_bibrank_admin_guide_availability(self):
         """bibrankadmin - availability of BibRank Admin guide pages"""
 
         url = CFG_SITE_URL + '/help/admin/bibrank-admin-guide'
         error_messages = test_web_page_content(url,
                                                expected_text="BibRank Admin Guide")
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(BibRankAdminWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(BibRankAdminWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/bibupload/lib/bibupload_regression_tests.py b/modules/bibupload/lib/bibupload_regression_tests.py
index dcbd3054b..fb3c15d4b 100644
--- a/modules/bibupload/lib/bibupload_regression_tests.py
+++ b/modules/bibupload/lib/bibupload_regression_tests.py
@@ -1,3096 +1,3096 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 # pylint: disable-msg=C0301
 
 """Regression tests for the BibUpload."""
 
 __revision__ = "$Id$"
 
 import re
 import unittest
 import datetime
 import os
 import time
 from urllib2 import urlopen
 from md5 import md5
 
 from invenio.config import CFG_OAI_ID_FIELD, CFG_PREFIX, CFG_SITE_URL, CFG_TMPDIR, \
     CFG_WEBSUBMIT_FILEDIR
 from invenio import bibupload
 from invenio.bibupload_config import CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG, \
                              CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG, \
                              CFG_BIBUPLOAD_STRONG_TAGS
 from invenio.search_engine import print_record
 from invenio.dbquery import run_sql
 from invenio.dateutils import convert_datestruct_to_datetext
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run
+from invenio.testutils import make_test_suite, run_test_suite
 from invenio.bibtask import task_set_option
 from invenio.bibdocfile import BibRecDocs
 
 # helper functions:
 
 def remove_tag_001_from_xmbuffer(xmbuffer):
     """Remove tag 001 from MARCXML buffer.  Useful for testing two
        MARCXML buffers without paying attention to recIDs attributed
        during the bibupload.
     """
     return re.sub(r'<controlfield tag="001">.*</controlfield>', '', xmbuffer)
 
 def compare_xmbuffers(xmbuffer1, xmbuffer2):
     """Compare two XM (XML MARC) buffers by removing whitespaces
        before testing.
     """
 
     def remove_blanks_from_xmbuffer(xmbuffer):
         """Remove \n and blanks from XMBUFFER."""
         out = xmbuffer.replace("\n", "")
         out = out.replace(" ", "")
         return out
 
     # remove whitespace:
     xmbuffer1 = remove_blanks_from_xmbuffer(xmbuffer1)
     xmbuffer2 = remove_blanks_from_xmbuffer(xmbuffer2)
 
     if xmbuffer1 != xmbuffer2:
         return "\n=" + xmbuffer1 + "=\n" + '!=' + "\n=" + xmbuffer2 + "=\n"
 
     return ''
 
 def remove_tag_001_from_hmbuffer(hmbuffer):
     """Remove tag 001 from HTML MARC buffer.  Useful for testing two
        HTML MARC buffers without paying attention to recIDs attributed
        during the bibupload.
     """
     return re.sub(r'(^|\n)(<pre>)?[0-9]{9}\s001__\s\d+($|\n)', '', hmbuffer)
 
 def compare_hmbuffers(hmbuffer1, hmbuffer2):
     """Compare two HM (HTML MARC) buffers by removing whitespaces
        before testing.
     """
 
     # remove eventual <pre>...</pre> formatting:
     hmbuffer1 = re.sub(r'^<pre>', '', hmbuffer1)
     hmbuffer2 = re.sub(r'^<pre>', '', hmbuffer2)
     hmbuffer1 = re.sub(r'</pre>$', '', hmbuffer1)
     hmbuffer2 = re.sub(r'</pre>$', '', hmbuffer2)
 
     # remove leading recid, leaving only field values:
     hmbuffer1 = re.sub(r'(^|\n)[0-9]{9}\s', '', hmbuffer1)
     hmbuffer2 = re.sub(r'(^|\n)[0-9]{9}\s', '', hmbuffer2)
 
     # remove leading whitespace:
     hmbuffer1 = re.sub(r'(^|\n)\s+', '', hmbuffer1)
     hmbuffer2 = re.sub(r'(^|\n)\s+', '', hmbuffer2)
 
     compare_hmbuffers = hmbuffer1 == hmbuffer2
 
     if not compare_hmbuffers:
         return "\n=" + hmbuffer1 + "=\n" + '!=' + "\n=" + hmbuffer2 + "=\n"
 
     return ''
 
 def try_url_download(url):
     """Try to download a given URL"""
     try:
         open_url = urlopen(url)
         open_url.read()
     except Exception, e:
         raise StandardError, "Downloading %s is impossible because of %s" \
             % (url, str(e))
     return True
 
 class BibUploadInsertModeTest(unittest.TestCase):
     """Testing insert mode."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialise the MARCXML variable"""
         self.test = """<record>
         <datafield tag ="245" ind1=" " ind2=" ">
         <subfield code="a">something</subfield>
         </datafield>
         <datafield tag ="700" ind1=" " ind2=" ">
         <subfield code="a">Tester, J Y</subfield>
         <subfield code="u">MIT</subfield>
         </datafield>
         <datafield tag ="700" ind1=" " ind2=" ">
         <subfield code="a">Tester, K J</subfield>
         <subfield code="u">CERN2</subfield>
         </datafield>
         <datafield tag ="700" ind1=" " ind2=" ">
         <subfield code="a">Tester, G</subfield>
         <subfield code="u">CERN3</subfield>
         </datafield>
         <datafield tag ="111" ind1=" " ind2=" ">
         <subfield code="a">test11</subfield>
         <subfield code="c">test31</subfield>
         </datafield>
         <datafield tag ="111" ind1=" " ind2=" ">
         <subfield code="a">test12</subfield>
         <subfield code="c">test32</subfield>
         </datafield>
         <datafield tag ="111" ind1=" " ind2=" ">
         <subfield code="a">test13</subfield>
         <subfield code="c">test33</subfield>
         </datafield>
         <datafield tag ="111" ind1=" " ind2=" ">
         <subfield code="b">test21</subfield>
         <subfield code="d">test41</subfield>
         </datafield>
         <datafield tag ="111" ind1=" " ind2=" ">
         <subfield code="b">test22</subfield>
         <subfield code="d">test42</subfield>
         </datafield>
         <datafield tag ="111" ind1=" " ind2=" ">
         <subfield code="a">test14</subfield>
         </datafield>
         <datafield tag ="111" ind1=" " ind2=" ">
         <subfield code="e">test51</subfield>
         </datafield>
         <datafield tag ="111" ind1=" " ind2=" ">
         <subfield code="e">test52</subfield>
         </datafield>
         <datafield tag ="100" ind1=" " ind2=" ">
         <subfield code="a">Tester, T</subfield>
         <subfield code="u">CERN</subfield>
         </datafield>
         </record>"""
         self.test_hm = """
         100__ $$aTester, T$$uCERN
         111__ $$atest11$$ctest31
         111__ $$atest12$$ctest32
         111__ $$atest13$$ctest33
         111__ $$btest21$$dtest41
         111__ $$btest22$$dtest42
         111__ $$atest14
         111__ $$etest51
         111__ $$etest52
         245__ $$asomething
         700__ $$aTester, J Y$$uMIT
         700__ $$aTester, K J$$uCERN2
         700__ $$aTester, G$$uCERN3
         """
 
     def test_create_record_id(self):
         """bibupload - insert mode, trying to create a new record ID in the database"""
         rec_id = bibupload.create_new_record()
         self.assertNotEqual(-1, rec_id)
 
     def test_no_retrieve_record_id(self):
         """bibupload - insert mode, detection of record ID in the input file"""
         # We create create the record out of the xml marc
         recs = bibupload.xml_marc_to_records(self.test)
         # We call the function which should retrieve the record id
         rec_id = bibupload.retrieve_rec_id(recs[0], 'insert')
         # We compare the value found with None
         self.assertEqual(None, rec_id)
 
     def test_insert_complete_xmlmarc(self):
         """bibupload - insert mode, trying to insert complete MARCXML file"""
         # Initialize the global variable
         task_set_option('verbose', 0)
         # We create create the record out of the xml marc
         recs = bibupload.xml_marc_to_records(self.test)
         # We call the main function with the record as a parameter
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # We retrieve the inserted xml
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         # Compare if the two MARCXML are the same
         self.assertEqual(compare_xmbuffers(remove_tag_001_from_xmbuffer(inserted_xm),
                                           self.test), '')
         self.assertEqual(compare_hmbuffers(remove_tag_001_from_hmbuffer(inserted_hm),
                                           self.test_hm), '')
 
 class BibUploadAppendModeTest(unittest.TestCase):
     """Testing append mode."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize the MARCXML variable"""
         self.test_existing = """<record>
         <controlfield tag="001">123456789</controlfield>
         <datafield tag ="100" ind1=" " ind2=" ">
         <subfield code="a">Tester, T</subfield>
         <subfield code="u">DESY</subfield>
         </datafield>
         </record>"""
         self.test_to_append = """<record>
         <controlfield tag="001">123456789</controlfield>
         <datafield tag ="100" ind1=" " ind2=" ">
         <subfield code="a">Tester, U</subfield>
         <subfield code="u">CERN</subfield>
         </datafield>
         </record>"""
         self.test_expected_xm = """<record>
         <controlfield tag="001">123456789</controlfield>
         <datafield tag ="100" ind1=" " ind2=" ">
         <subfield code="a">Tester, T</subfield>
         <subfield code="u">DESY</subfield>
         </datafield>
         <datafield tag ="100" ind1=" " ind2=" ">
         <subfield code="a">Tester, U</subfield>
         <subfield code="u">CERN</subfield>
         </datafield>
         </record>"""
         self.test_expected_hm = """
         001__ 123456789
         100__ $$aTester, T$$uDESY
         100__ $$aTester, U$$uCERN
         """
         # insert test record:
 
         test_to_upload =  self.test_existing.replace('<controlfield tag="001">123456789</controlfield>',
                                                      '')
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         self.test_recid = recid
         # replace test buffers with real recid of inserted test record:
         self.test_existing = self.test_existing.replace('123456789',
                                                         str(self.test_recid))
         self.test_to_append = self.test_to_append.replace('123456789',
                                                           str(self.test_recid))
         self.test_expected_xm = self.test_expected_xm.replace('123456789',
                                                               str(self.test_recid))
         self.test_expected_hm = self.test_expected_hm.replace('123456789',
                                                               str(self.test_recid))
 
     def test_retrieve_record_id(self):
         """bibupload - append mode, the input file should contain a record ID"""
         task_set_option('verbose', 0)
         # We create create the record out of the xml marc
         recs = bibupload.xml_marc_to_records(self.test_to_append)
         # We call the function which should retrieve the record id
         rec_id = bibupload.retrieve_rec_id(recs[0], 'append')
         # We compare the value found with None
         self.assertEqual(str(self.test_recid), rec_id)
         # clean up after ourselves:
         bibupload.wipe_out_record_from_all_tables(self.test_recid)
         return
 
     def test_update_modification_record_date(self):
         """bibupload - append mode, checking the update of the modification date"""
         # Initialize the global variable
         task_set_option('verbose', 0)
         # We create create the record out of the xml marc
         recs = bibupload.xml_marc_to_records(self.test_existing)
         # We call the function which should retrieve the record id
         rec_id = bibupload.retrieve_rec_id(recs[0], opt_mode='append')
         # Retrieve current localtime
         now = time.localtime()
         # We update the modification date
         bibupload.update_bibrec_modif_date(convert_datestruct_to_datetext(now), rec_id)
         # We retrieve the modification date from the database
         query = """SELECT DATE_FORMAT(modification_date,'%%Y-%%m-%%d %%H:%%i:%%s') FROM bibrec where id = %s"""
         res = run_sql(query % rec_id)
         # We compare the two results
         self.assertEqual(res[0][0], convert_datestruct_to_datetext(now))
         # clean up after ourselves:
         bibupload.wipe_out_record_from_all_tables(self.test_recid)
         return
 
     def test_append_complete_xml_marc(self):
         """bibupload - append mode, appending complete MARCXML file"""
         # Now we append a datafield
         # We create create the record out of the xml marc
         recs = bibupload.xml_marc_to_records(self.test_to_append)
         # We call the main function with the record as a parameter
         err, recid = bibupload.bibupload(recs[0], opt_mode='append')
         # We retrieve the inserted xm
         after_append_xm = print_record(recid, 'xm')
         after_append_hm = print_record(recid, 'hm')
         # Compare if the two MARCXML are the same
         self.assertEqual(compare_xmbuffers(after_append_xm, self.test_expected_xm), '')
         self.assertEqual(compare_hmbuffers(after_append_hm, self.test_expected_hm), '')
         # clean up after ourselves:
         bibupload.wipe_out_record_from_all_tables(self.test_recid)
         return
 
 class BibUploadCorrectModeTest(unittest.TestCase):
     """
     Testing correcting a record containing similar tags (identical
     tag, different indicators).  Currently CDS Invenio replaces only
     those tags that have matching indicators too, unlike ALEPH500 that
     does not pay attention to indicators, it corrects all fields with
     the same tag, regardless of the indicator values.
     """
 
     def setUp(self):
         """Initialize the MARCXML test record."""
         self.testrec1_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, Jane</subfield>
           <subfield code="u">Test Institute</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="8">
           <subfield code="a">Cool</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test, Jim</subfield>
           <subfield code="u">Test Laboratory</subfield>
          </datafield>
         </record>
         """
         self.testrec1_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, Jane$$uTest Institute
         10047 $$aTest, John$$uTest University
         10048 $$aCool
         10047 $$aTest, Jim$$uTest Laboratory
         """
         self.testrec1_xm_to_correct = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test, Joseph</subfield>
           <subfield code="u">Test Academy</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test2, Joseph</subfield>
           <subfield code="u">Test2 Academy</subfield>
          </datafield>
         </record>
         """
         self.testrec1_corrected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, Jane</subfield>
           <subfield code="u">Test Institute</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="8">
           <subfield code="a">Cool</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test, Joseph</subfield>
           <subfield code="u">Test Academy</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test2, Joseph</subfield>
           <subfield code="u">Test2 Academy</subfield>
          </datafield>
         </record>
         """
         self.testrec1_corrected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, Jane$$uTest Institute
         10048 $$aCool
         10047 $$aTest, Joseph$$uTest Academy
         10047 $$aTest2, Joseph$$uTest2 Academy
         """
         # insert test record:
         task_set_option('verbose', 0)
         test_record_xm = self.testrec1_xm.replace('<controlfield tag="001">123456789</controlfield>',
                                                   '')
         recs = bibupload.xml_marc_to_records(test_record_xm)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recID:
         self.testrec1_xm = self.testrec1_xm.replace('123456789', str(recid))
         self.testrec1_hm = self.testrec1_hm.replace('123456789', str(recid))
         self.testrec1_xm_to_correct = self.testrec1_xm_to_correct.replace('123456789', str(recid))
         self.testrec1_corrected_xm = self.testrec1_corrected_xm.replace('123456789', str(recid))
         self.testrec1_corrected_hm = self.testrec1_corrected_hm.replace('123456789', str(recid))
         # test of the inserted record:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm, self.testrec1_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm, self.testrec1_hm), '')
 
     def test_record_correction(self):
         """bibupload - correct mode, similar MARCXML tags/indicators"""
         # correct some tags:
         recs = bibupload.xml_marc_to_records(self.testrec1_xm_to_correct)
         err, recid = bibupload.bibupload(recs[0], opt_mode='correct')
         corrected_xm = print_record(recid, 'xm')
         corrected_hm = print_record(recid, 'hm')
         # did it work?
         self.assertEqual(compare_xmbuffers(corrected_xm, self.testrec1_corrected_xm), '')
         self.assertEqual(compare_hmbuffers(corrected_hm, self.testrec1_corrected_hm), '')
         # clean up after ourselves:
         bibupload.wipe_out_record_from_all_tables(recid)
         return
 
 class BibUploadReplaceModeTest(unittest.TestCase):
     """Testing replace mode."""
 
     def setUp(self):
         """Initialize the MARCXML test record."""
         self.testrec1_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, Jane</subfield>
           <subfield code="u">Test Institute</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="8">
           <subfield code="a">Cool</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test, Jim</subfield>
           <subfield code="u">Test Laboratory</subfield>
          </datafield>
         </record>
         """
         self.testrec1_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, Jane$$uTest Institute
         10047 $$aTest, John$$uTest University
         10048 $$aCool
         10047 $$aTest, Jim$$uTest Laboratory
         """
         self.testrec1_xm_to_replace = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test, Joseph</subfield>
           <subfield code="u">Test Academy</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test2, Joseph</subfield>
           <subfield code="u">Test2 Academy</subfield>
          </datafield>
         </record>
         """
         self.testrec1_replaced_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test, Joseph</subfield>
           <subfield code="u">Test Academy</subfield>
          </datafield>
          <datafield tag="100" ind1="4" ind2="7">
           <subfield code="a">Test2, Joseph</subfield>
           <subfield code="u">Test2 Academy</subfield>
          </datafield>
         </record>
         """
         self.testrec1_replaced_hm = """
         001__ 123456789
         10047 $$aTest, Joseph$$uTest Academy
         10047 $$aTest2, Joseph$$uTest2 Academy
         """
         # insert test record:
         task_set_option('verbose', 0)
         test_record_xm = self.testrec1_xm.replace('<controlfield tag="001">123456789</controlfield>',
                                                   '')
         recs = bibupload.xml_marc_to_records(test_record_xm)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recID:
         self.testrec1_xm = self.testrec1_xm.replace('123456789', str(recid))
         self.testrec1_hm = self.testrec1_hm.replace('123456789', str(recid))
         self.testrec1_xm_to_replace = self.testrec1_xm_to_replace.replace('123456789', str(recid))
         self.testrec1_replaced_xm = self.testrec1_replaced_xm.replace('123456789', str(recid))
         self.testrec1_replaced_hm = self.testrec1_replaced_hm.replace('123456789', str(recid))
         # test of the inserted record:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm, self.testrec1_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm, self.testrec1_hm), '')
 
     def test_record_replace(self):
         """bibupload - replace mode, similar MARCXML tags/indicators"""
         # replace some tags:
         recs = bibupload.xml_marc_to_records(self.testrec1_xm_to_replace)
         err, recid = bibupload.bibupload(recs[0], opt_mode='replace')
         replaced_xm = print_record(recid, 'xm')
         replaced_hm = print_record(recid, 'hm')
         # did it work?
         self.assertEqual(compare_xmbuffers(replaced_xm, self.testrec1_replaced_xm), '')
         self.assertEqual(compare_hmbuffers(replaced_hm, self.testrec1_replaced_hm), '')
         # clean up after ourselves:
         bibupload.wipe_out_record_from_all_tables(recid)
         return
 
 class BibUploadReferencesModeTest(unittest.TestCase):
     """Testing references mode."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize the MARCXML variable"""
         self.test_insert = """<record>
         <controlfield tag="001">123456789</controlfield>
         <datafield tag ="100" ind1=" " ind2=" ">
         <subfield code="a">Tester, T</subfield>
         <subfield code="u">CERN</subfield>
         </datafield>
         </record>"""
         self.test_reference = """<record>
         <controlfield tag="001">123456789</controlfield>
         <datafield tag =\"""" + bibupload.CFG_BIBUPLOAD_REFERENCE_TAG + """\" ind1="C" ind2="5">
         <subfield code="m">M. Lüscher and P. Weisz, String excitation energies in SU(N) gauge theories beyond the free-string approximation,</subfield>
         <subfield code="s">J. High Energy Phys. 07 (2004) 014</subfield>
         </datafield>
         </record>"""
         self.test_reference_expected_xm = """<record>
         <controlfield tag="001">123456789</controlfield>
         <datafield tag ="100" ind1=" " ind2=" ">
         <subfield code="a">Tester, T</subfield>
         <subfield code="u">CERN</subfield>
         </datafield>
         <datafield tag =\"""" + bibupload.CFG_BIBUPLOAD_REFERENCE_TAG + """\" ind1="C" ind2="5">
         <subfield code="m">M. Lüscher and P. Weisz, String excitation energies in SU(N) gauge theories beyond the free-string approximation,</subfield>
         <subfield code="s">J. High Energy Phys. 07 (2004) 014</subfield>
         </datafield>
         </record>"""
         self.test_insert_hm = """
         001__ 123456789
         100__ $$aTester, T$$uCERN
         """
         self.test_reference_expected_hm = """
         001__ 123456789
         100__ $$aTester, T$$uCERN
         %(reference_tag)sC5 $$mM. Lüscher and P. Weisz, String excitation energies in SU(N) gauge theories beyond the free-string approximation,$$sJ. High Energy Phys. 07 (2004) 014
         """ % {'reference_tag': bibupload.CFG_BIBUPLOAD_REFERENCE_TAG}
         # insert test record:
         task_set_option('verbose', 0)
         test_insert = self.test_insert.replace('<controlfield tag="001">123456789</controlfield>',
                                                '')
         recs = bibupload.xml_marc_to_records(test_insert)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recID:
         self.test_insert = self.test_insert.replace('123456789', str(recid))
         self.test_insert_hm = self.test_insert_hm.replace('123456789', str(recid))
         self.test_reference = self.test_reference.replace('123456789', str(recid))
         self.test_reference_expected_xm = self.test_reference_expected_xm.replace('123456789', str(recid))
         self.test_reference_expected_hm = self.test_reference_expected_hm.replace('123456789', str(recid))
         # test of the inserted record:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm, self.test_insert), '')
         self.assertEqual(compare_hmbuffers(inserted_hm, self.test_insert_hm), '')
         self.test_recid = recid
 
     def test_reference_complete_xml_marc(self):
         """bibupload - reference mode, inserting references MARCXML file"""
         # We create create the record out of the xml marc
         recs = bibupload.xml_marc_to_records(self.test_reference)
         # We call the main function with the record as a parameter
         err, recid = bibupload.bibupload(recs[0], opt_mode='reference')
         # We retrieve the inserted xml
         reference_xm = print_record(recid, 'xm')
         reference_hm = print_record(recid, 'hm')
         # Compare if the two MARCXML are the same
         self.assertEqual(compare_xmbuffers(reference_xm, self.test_reference_expected_xm), '')
         self.assertEqual(compare_hmbuffers(reference_hm, self.test_reference_expected_hm), '')
         # clean up after ourselves:
         bibupload.wipe_out_record_from_all_tables(self.test_recid)
         return
 
 class BibUploadFMTModeTest(unittest.TestCase):
     """Testing FMT mode."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize the MARCXML variable"""
         self.new_xm_with_fmt = """
         <record>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="FMT" ind1=" " ind2=" ">
           <subfield code="f">HB</subfield>
           <subfield code="g">Test. Okay.</subfield>
           <subfield code="d">2008-03-14 15:14:00</subfield>
          </datafield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux</subfield>
          </datafield>
         </record>
         """
         self.expected_xm_after_inserting_new_xm_with_fmt = """
         <record>
          <controlfield tag="001">123456789</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux</subfield>
          </datafield>
         </record>
         """
         self.expected_hm_after_inserting_new_xm_with_fmt = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux
         """
         self.recid3_xm_before_all_the_tests = print_record(3, 'xm')
         self.recid3_hm_before_all_the_tests = print_record(3, 'hm')
         self.recid3_xm_with_fmt = """
         <record>
          <controlfield tag="001">3</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="FMT" ind1=" " ind2=" ">
           <subfield code="f">HB</subfield>
           <subfield code="g">Test. Here is some format value.</subfield>
          </datafield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Doe, John</subfield>
           <subfield code="u">CERN</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the foos and bars</subfield>
          </datafield>
         </record>
         """
         self.recid3_xm_with_fmt_only_first = """
         <record>
          <controlfield tag="001">3</controlfield>
          <datafield tag="FMT" ind1=" " ind2=" ">
           <subfield code="f">HB</subfield>
           <subfield code="g">Test. Let us see if this gets inserted well.</subfield>
          </datafield>
         </record>
         """
         self.recid3_xm_with_fmt_only_second = """
         <record>
          <controlfield tag="001">3</controlfield>
          <datafield tag="FMT" ind1=" " ind2=" ">
           <subfield code="f">HB</subfield>
           <subfield code="g">Test. Yet another test, to be run after the first one.</subfield>
          </datafield>
          <datafield tag="FMT" ind1=" " ind2=" ">
           <subfield code="f">HD</subfield>
           <subfield code="g">Test. Let's see what will be stored in the detailed format field.</subfield>
          </datafield>
         </record>
         """
 
     def restore_recid3(self):
         """Helper function that restores recID 3 MARCXML, using the
            value saved before all the tests started to execute.
            (see self.recid3_xm_before_all_the_tests).
            Does not restore HB and HD formats.
         """
         recs = bibupload.xml_marc_to_records(self.recid3_xm_before_all_the_tests)
         err, recid = bibupload.bibupload(recs[0], opt_mode='replace')
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm, self.recid3_xm_before_all_the_tests), '')
         self.assertEqual(compare_hmbuffers(inserted_hm, self.recid3_hm_before_all_the_tests), '')
 
     def test_inserting_new_record_containing_fmt_tag(self):
         """bibupload - FMT tag, inserting new record containing FMT tag"""
         recs = bibupload.xml_marc_to_records(self.new_xm_with_fmt)
         (dummy, new_recid) = bibupload.bibupload(recs[0], opt_mode='insert')
         xm_after = print_record(new_recid, 'xm')
         hm_after = print_record(new_recid, 'hm')
         hb_after = print_record(new_recid, 'hb')
         self.assertEqual(compare_xmbuffers(xm_after,
                                           self.expected_xm_after_inserting_new_xm_with_fmt.replace('123456789', str(new_recid))), '')
         self.assertEqual(compare_hmbuffers(hm_after,
                                           self.expected_hm_after_inserting_new_xm_with_fmt.replace('123456789', str(new_recid))), '')
         self.assertEqual(run_sql('SELECT last_updated from bibfmt WHERE id_bibrec=%s', (new_recid, ))[0][0], datetime.datetime(2008, 3, 14, 15, 14))
         self.failUnless(hb_after.startswith("Test. Okay."))
 
     def test_updating_existing_record_formats_in_format_mode(self):
         """bibupload - FMT tag, updating existing record via format mode"""
         xm_before = print_record(3, 'xm')
         hm_before = print_record(3, 'hm')
         # insert first format value:
         recs = bibupload.xml_marc_to_records(self.recid3_xm_with_fmt_only_first)
         bibupload.bibupload(recs[0], opt_mode='format')
         xm_after = print_record(3, 'xm')
         hm_after = print_record(3, 'hm')
         hb_after = print_record(3, 'hb')
         self.assertEqual(xm_after, xm_before)
         self.assertEqual(hm_after, hm_before)
         self.failUnless(hb_after.startswith("Test. Let us see if this gets inserted well."))
         # now insert another format value and recheck:
         recs = bibupload.xml_marc_to_records(self.recid3_xm_with_fmt_only_second)
         bibupload.bibupload(recs[0], opt_mode='format')
         xm_after = print_record(3, 'xm')
         hm_after = print_record(3, 'hm')
         hb_after = print_record(3, 'hb')
         hd_after = print_record(3, 'hd')
         self.assertEqual(xm_after, xm_before)
         self.assertEqual(hm_after, hm_before)
         self.failUnless(hb_after.startswith("Test. Yet another test, to be run after the first one."))
         self.failUnless(hd_after.startswith("Test. Let's see what will be stored in the detailed format field."))
         # restore original record 3:
         self.restore_recid3()
 
     def test_updating_existing_record_formats_in_correct_mode(self):
         """bibupload - FMT tag, updating existing record via correct mode"""
         xm_before = print_record(3, 'xm')
         hm_before = print_record(3, 'hm')
         # insert first format value:
         recs = bibupload.xml_marc_to_records(self.recid3_xm_with_fmt_only_first)
         bibupload.bibupload(recs[0], opt_mode='correct')
         xm_after = print_record(3, 'xm')
         hm_after = print_record(3, 'hm')
         hb_after = print_record(3, 'hb')
         self.assertEqual(xm_after, xm_before)
         self.assertEqual(hm_after, hm_before)
         self.failUnless(hb_after.startswith("Test. Let us see if this gets inserted well."))
         # now insert another format value and recheck:
         recs = bibupload.xml_marc_to_records(self.recid3_xm_with_fmt_only_second)
         bibupload.bibupload(recs[0], opt_mode='correct')
         xm_after = print_record(3, 'xm')
         hm_after = print_record(3, 'hm')
         hb_after = print_record(3, 'hb')
         hd_after = print_record(3, 'hd')
         self.assertEqual(xm_after, xm_before)
         self.assertEqual(hm_after, hm_before)
         self.failUnless(hb_after.startswith("Test. Yet another test, to be run after the first one."))
         self.failUnless(hd_after.startswith("Test. Let's see what will be stored in the detailed format field."))
         # restore original record 3:
         self.restore_recid3()
 
     def test_updating_existing_record_formats_in_replace_mode(self):
         """bibupload - FMT tag, updating existing record via replace mode"""
         # insert first format value:
         recs = bibupload.xml_marc_to_records(self.recid3_xm_with_fmt_only_first)
         bibupload.bibupload(recs[0], opt_mode='replace')
         xm_after = print_record(3, 'xm')
         hm_after = print_record(3, 'hm')
         hb_after = print_record(3, 'hb')
         self.assertEqual(compare_xmbuffers(xm_after,
                                           '<record><controlfield tag="001">3</controlfield></record>'), '')
         self.assertEqual(compare_hmbuffers(hm_after,
                                           '000000003 001__ 3'), '')
         self.failUnless(hb_after.startswith("Test. Let us see if this gets inserted well."))
         # now insert another format value and recheck:
         recs = bibupload.xml_marc_to_records(self.recid3_xm_with_fmt_only_second)
         bibupload.bibupload(recs[0], opt_mode='replace')
         xm_after = print_record(3, 'xm')
         hm_after = print_record(3, 'hm')
         hb_after = print_record(3, 'hb')
         hd_after = print_record(3, 'hd')
         self.assertEqual(compare_xmbuffers(xm_after, """
                                            <record>
                                            <controlfield tag="001">3</controlfield>
                                            </record>"""), '')
         self.assertEqual(compare_hmbuffers(hm_after, '000000003 001__ 3'), '')
         self.failUnless(hb_after.startswith("Test. Yet another test, to be run after the first one."))
         self.failUnless(hd_after.startswith("Test. Let's see what will be stored in the detailed format field."))
         # final insertion and recheck:
         recs = bibupload.xml_marc_to_records(self.recid3_xm_with_fmt)
         bibupload.bibupload(recs[0], opt_mode='replace')
         xm_after = print_record(3, 'xm')
         hm_after = print_record(3, 'hm')
         hb_after = print_record(3, 'hb')
         hd_after = print_record(3, 'hd')
         self.assertEqual(compare_xmbuffers(xm_after, """
                                            <record>
                                            <controlfield tag="001">3</controlfield>
                                            <controlfield tag="003">SzGeCERN</controlfield>
                                            <datafield tag="100" ind1=" " ind2=" ">
                                            <subfield code="a">Doe, John</subfield>
                                            <subfield code="u">CERN</subfield>
                                            </datafield>
                                            <datafield tag="245" ind1=" " ind2=" ">
                                            <subfield code="a">On the foos and bars</subfield>
                                            </datafield>
                                            </record>
                                            """), '')
         self.assertEqual(compare_hmbuffers(hm_after, """
                                            001__ 3
                                            003__ SzGeCERN
                                            100__ $$aDoe, John$$uCERN
                                            245__ $$aOn the foos and bars
                                            """), '')
         self.failUnless(hb_after.startswith("Test. Here is some format value."))
         self.failUnless(hd_after.startswith("Test. Let's see what will be stored in the detailed format field."))
         # restore original record 3:
         self.restore_recid3()
 
 class BibUploadRecordsWithSYSNOTest(unittest.TestCase):
     """Testing uploading of records that have external SYSNO present."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize the MARCXML test records."""
         self.verbose = 0
         # Note that SYSNO fields are repeated but with different
         # subfields, this is to test whether bibupload would not
         # mistakenly pick up wrong values.
         self.xm_testrec1 = """
         <record>
          <controlfield tag="001">123456789</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 1</subfield>
          </datafield>
          <datafield tag="%(sysnotag)s" ind1="%(sysnoind1)s" ind2="%(sysnoind2)s">
           <subfield code="%(sysnosubfieldcode)s">sysno1</subfield>
          </datafield>
          <datafield tag="%(sysnotag)s" ind1="%(sysnoind1)s" ind2="%(sysnoind2)s">
           <subfield code="0">sysno2</subfield>
          </datafield>
         </record>
         """ % {'sysnotag': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[0:3],
                'sysnoind1': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] or " ",
                'sysnoind2': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] or " ",
                'sysnosubfieldcode': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[5:6],
                }
         self.hm_testrec1 = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux 1
         %(sysnotag)s%(sysnoind1)s%(sysnoind2)s $$%(sysnosubfieldcode)ssysno1
         %(sysnotag)s%(sysnoind1)s%(sysnoind2)s $$0sysno2
         """ % {'sysnotag': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[0:3],
                'sysnoind1': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4],
                'sysnoind2': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5],
                'sysnosubfieldcode': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[5:6],
                }
         self.xm_testrec1_to_update = """
         <record>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 1 Updated</subfield>
          </datafield>
          <datafield tag="%(sysnotag)s" ind1="%(sysnoind1)s" ind2="%(sysnoind2)s">
           <subfield code="%(sysnosubfieldcode)s">sysno1</subfield>
          </datafield>
          <datafield tag="%(sysnotag)s" ind1="%(sysnoind1)s" ind2="%(sysnoind2)s">
           <subfield code="0">sysno2</subfield>
          </datafield>
         </record>
         """ % {'sysnotag': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[0:3],
                'sysnoind1': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] or " ",
                'sysnoind2': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] or " ",
                'sysnosubfieldcode': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[5:6],
                }
         self.xm_testrec1_updated = """
         <record>
          <controlfield tag="001">123456789</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 1 Updated</subfield>
          </datafield>
          <datafield tag="%(sysnotag)s" ind1="%(sysnoind1)s" ind2="%(sysnoind2)s">
           <subfield code="%(sysnosubfieldcode)s">sysno1</subfield>
          </datafield>
          <datafield tag="%(sysnotag)s" ind1="%(sysnoind1)s" ind2="%(sysnoind2)s">
           <subfield code="0">sysno2</subfield>
          </datafield>
         </record>
         """ % {'sysnotag': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[0:3],
                'sysnoind1': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] or " ",
                'sysnoind2': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] or " ",
                'sysnosubfieldcode': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[5:6],
                }
         self.hm_testrec1_updated = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux 1 Updated
         %(sysnotag)s%(sysnoind1)s%(sysnoind2)s $$%(sysnosubfieldcode)ssysno1
         %(sysnotag)s%(sysnoind1)s%(sysnoind2)s $$0sysno2
         """ % {'sysnotag': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[0:3],
                'sysnoind1': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4],
                'sysnoind2': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5],
                'sysnosubfieldcode': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[5:6],
                }
         self.xm_testrec2 = """
         <record>
          <controlfield tag="001">987654321</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 2</subfield>
          </datafield>
          <datafield tag="%(sysnotag)s" ind1="%(sysnoind1)s" ind2="%(sysnoind2)s">
           <subfield code="%(sysnosubfieldcode)s">sysno2</subfield>
          </datafield>
          <datafield tag="%(sysnotag)s" ind1="%(sysnoind1)s" ind2="%(sysnoind2)s">
           <subfield code="0">sysno1</subfield>
          </datafield>
         </record>
         """ % {'sysnotag': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[0:3],
                'sysnoind1': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4] or " ",
                'sysnoind2': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5] or " ",
                'sysnosubfieldcode': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[5:6],
                }
         self.hm_testrec2 = """
         001__ 987654321
         003__ SzGeCERN
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux 2
         %(sysnotag)s%(sysnoind1)s%(sysnoind2)s $$%(sysnosubfieldcode)ssysno2
         %(sysnotag)s%(sysnoind1)s%(sysnoind2)s $$0sysno1
         """ % {'sysnotag': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[0:3],
                'sysnoind1': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[3:4],
                'sysnoind2': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[4:5],
                'sysnosubfieldcode': CFG_BIBUPLOAD_EXTERNAL_SYSNO_TAG[5:6],
                }
 
     def test_insert_the_same_sysno_record(self):
         """bibupload - SYSNO tag, refuse to insert the same SYSNO record"""
         # initialize bibupload mode:
         if self.verbose:
             print "test_insert_the_same_sysno_record() started"
         # insert record 1 first time:
         testrec_to_insert_first = self.xm_testrec1.replace('<controlfield tag="001">123456789</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         task_set_option('verbose', 0)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='insert')
         inserted_xm = print_record(recid1, 'xm')
         inserted_hm = print_record(recid1, 'hm')
         # use real recID when comparing whether it worked:
         self.xm_testrec1 =  self.xm_testrec1.replace('123456789', str(recid1))
         self.hm_testrec1 =  self.hm_testrec1.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec1), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec1), '')
         # insert record 2 first time:
         testrec_to_insert_first = self.xm_testrec2.replace('<controlfield tag="001">987654321</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         task_set_option('verbose', 0)
         err2, recid2 = bibupload.bibupload(recs[0], opt_mode='insert')
         inserted_xm = print_record(recid2, 'xm')
         inserted_hm = print_record(recid2, 'hm')
         # use real recID when comparing whether it worked:
         self.xm_testrec2 =  self.xm_testrec2.replace('987654321', str(recid2))
         self.hm_testrec2 =  self.hm_testrec2.replace('987654321', str(recid2))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec2), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec2), '')
         # try to insert updated record 1, it should fail:
         recs = bibupload.xml_marc_to_records(self.xm_testrec1_to_update)
         task_set_option('verbose', 0)
         err1_updated, recid1_updated = bibupload.bibupload(recs[0], opt_mode='insert')
         self.assertEqual(-1, recid1_updated)
         # delete test records
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid2)
         bibupload.wipe_out_record_from_all_tables(recid1_updated)
         if self.verbose:
             print "test_insert_the_same_sysno_record() finished"
 
     def test_insert_or_replace_the_same_sysno_record(self):
         """bibupload - SYSNO tag, allow to insert or replace the same SYSNO record"""
         # initialize bibupload mode:
         task_set_option('verbose', self.verbose)
         if self.verbose:
             print "test_insert_or_replace_the_same_sysno_record() started"
         # insert/replace record 1 first time:
         testrec_to_insert_first = self.xm_testrec1.replace('<controlfield tag="001">123456789</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='replace_or_insert')
         inserted_xm = print_record(recid1, 'xm')
         inserted_hm = print_record(recid1, 'hm')
         # use real recID in test buffers when comparing whether it worked:
         self.xm_testrec1 =  self.xm_testrec1.replace('123456789', str(recid1))
         self.hm_testrec1 =  self.hm_testrec1.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec1), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           self.hm_testrec1), '')
         # try to insert/replace updated record 1, it should be okay:
         task_set_option('verbose', self.verbose)
         recs = bibupload.xml_marc_to_records(self.xm_testrec1_to_update)
         err1_updated, recid1_updated = bibupload.bibupload(recs[0],
             opt_mode='replace_or_insert')
         inserted_xm = print_record(recid1_updated, 'xm')
         inserted_hm = print_record(recid1_updated, 'hm')
         self.assertEqual(recid1, recid1_updated)
         # use real recID in test buffers when comparing whether it worked:
         self.xm_testrec1_updated =  self.xm_testrec1_updated.replace('123456789', str(recid1))
         self.hm_testrec1_updated =  self.hm_testrec1_updated.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           self.xm_testrec1_updated), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           self.hm_testrec1_updated), '')
         # delete test records
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid1_updated)
         if self.verbose:
             print "test_insert_or_replace_the_same_sysno_record() finished"
 
     def test_replace_nonexisting_sysno_record(self):
         """bibupload - SYSNO tag, refuse to replace non-existing SYSNO record"""
         # initialize bibupload mode:
         task_set_option('verbose', self.verbose)
         if self.verbose:
             print "test_replace_nonexisting_sysno_record() started"
         # insert record 1 first time:
         testrec_to_insert_first = self.xm_testrec1.replace('<controlfield tag="001">123456789</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='replace_or_insert')
         inserted_xm = print_record(recid1, 'xm')
         inserted_hm = print_record(recid1, 'hm')
         # use real recID in test buffers when comparing whether it worked:
         self.xm_testrec1 =  self.xm_testrec1.replace('123456789', str(recid1))
         self.hm_testrec1 =  self.hm_testrec1.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec1), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec1), '')
         # try to replace record 2 it should fail:
         testrec_to_insert_first = self.xm_testrec2.replace('<controlfield tag="001">987654321</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err2, recid2 = bibupload.bibupload(recs[0], opt_mode='replace')
         self.assertEqual(-1, recid2)
         # delete test records
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid2)
         if self.verbose:
             print "test_replace_nonexisting_sysno_record() finished"
 
 class BibUploadRecordsWithEXTOAIIDTest(unittest.TestCase):
     """Testing uploading of records that have external EXTOAIID present."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize the MARCXML test records."""
         self.verbose = 0
         # Note that EXTOAIID fields are repeated but with different
         # subfields, this is to test whether bibupload would not
         # mistakenly pick up wrong values.
         self.xm_testrec1 = """
         <record>
          <controlfield tag="001">123456789</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="%(extoaiidtag)s" ind1="%(extoaiidind1)s" ind2="%(extoaiidind2)s">
           <subfield code="%(extoaiidsubfieldcode)s">extoaiid1</subfield>
          </datafield>
          <datafield tag="%(extoaiidtag)s" ind1="%(extoaiidind1)s" ind2="%(extoaiidind2)s">
           <subfield code="0">extoaiid2</subfield>
          </datafield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 1</subfield>
          </datafield>
         </record>
         """ % {'extoaiidtag': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[0:3],
                'extoaiidind1': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] or " ",
                'extoaiidind2': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] or " ",
                'extoaiidsubfieldcode': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[5:6],
                }
         self.hm_testrec1 = """
         001__ 123456789
         003__ SzGeCERN
         %(extoaiidtag)s%(extoaiidind1)s%(extoaiidind2)s $$%(extoaiidsubfieldcode)sextoaiid1
         %(extoaiidtag)s%(extoaiidind1)s%(extoaiidind2)s $$0extoaiid2
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux 1
         """ % {'extoaiidtag': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[0:3],
                'extoaiidind1': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4],
                'extoaiidind2': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5],
                'extoaiidsubfieldcode': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[5:6],
                }
         self.xm_testrec1_to_update = """
         <record>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="%(extoaiidtag)s" ind1="%(extoaiidind1)s" ind2="%(extoaiidind2)s">
           <subfield code="%(extoaiidsubfieldcode)s">extoaiid1</subfield>
          </datafield>
          <datafield tag="%(extoaiidtag)s" ind1="%(extoaiidind1)s" ind2="%(extoaiidind2)s">
           <subfield code="0">extoaiid2</subfield>
          </datafield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 1 Updated</subfield>
          </datafield>
         </record>
         """ % {'extoaiidtag': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[0:3],
                'extoaiidind1': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] or " ",
                'extoaiidind2': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] or " ",
                'extoaiidsubfieldcode': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[5:6],
                }
         self.xm_testrec1_updated = """
         <record>
          <controlfield tag="001">123456789</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="%(extoaiidtag)s" ind1="%(extoaiidind1)s" ind2="%(extoaiidind2)s">
           <subfield code="%(extoaiidsubfieldcode)s">extoaiid1</subfield>
          </datafield>
          <datafield tag="%(extoaiidtag)s" ind1="%(extoaiidind1)s" ind2="%(extoaiidind2)s">
           <subfield code="0">extoaiid2</subfield>
          </datafield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 1 Updated</subfield>
          </datafield>
         </record>
         """ % {'extoaiidtag': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[0:3],
                'extoaiidind1': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] or " ",
                'extoaiidind2': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] or " ",
                'extoaiidsubfieldcode': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[5:6],
                }
         self.hm_testrec1_updated = """
         001__ 123456789
         003__ SzGeCERN
         %(extoaiidtag)s%(extoaiidind1)s%(extoaiidind2)s $$%(extoaiidsubfieldcode)sextoaiid1
         %(extoaiidtag)s%(extoaiidind1)s%(extoaiidind2)s $$0extoaiid2
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux 1 Updated
         """ % {'extoaiidtag': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[0:3],
                'extoaiidind1': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4],
                'extoaiidind2': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5],
                'extoaiidsubfieldcode': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[5:6],
                }
         self.xm_testrec2 = """
         <record>
          <controlfield tag="001">987654321</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="%(extoaiidtag)s" ind1="%(extoaiidind1)s" ind2="%(extoaiidind2)s">
           <subfield code="%(extoaiidsubfieldcode)s">extoaiid2</subfield>
          </datafield>
          <datafield tag="%(extoaiidtag)s" ind1="%(extoaiidind1)s" ind2="%(extoaiidind2)s">
           <subfield code="0">extoaiid1</subfield>
          </datafield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 2</subfield>
          </datafield>
         </record>
         """ % {'extoaiidtag': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[0:3],
                'extoaiidind1': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4] or " ",
                'extoaiidind2': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] != "_" and \
                             CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5] or " ",
                'extoaiidsubfieldcode': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[5:6],
                }
         self.hm_testrec2 = """
         001__ 987654321
         003__ SzGeCERN
         %(extoaiidtag)s%(extoaiidind1)s%(extoaiidind2)s $$%(extoaiidsubfieldcode)sextoaiid2
         %(extoaiidtag)s%(extoaiidind1)s%(extoaiidind2)s $$0extoaiid1
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux 2
         """ % {'extoaiidtag': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[0:3],
                'extoaiidind1': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[3:4],
                'extoaiidind2': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[4:5],
                'extoaiidsubfieldcode': CFG_BIBUPLOAD_EXTERNAL_OAIID_TAG[5:6],
                }
 
     def test_insert_the_same_extoaiid_record(self):
         """bibupload - EXTOAIID tag, refuse to insert the same EXTOAIID record"""
         # initialize bibupload mode:
         task_set_option('verbose', self.verbose)
         if self.verbose:
             print "test_insert_the_same_extoaiid_record() started"
         # insert record 1 first time:
         testrec_to_insert_first = self.xm_testrec1.replace('<controlfield tag="001">123456789</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='insert')
         inserted_xm = print_record(recid1, 'xm')
         inserted_hm = print_record(recid1, 'hm')
         # use real recID when comparing whether it worked:
         self.xm_testrec1 =  self.xm_testrec1.replace('123456789', str(recid1))
         self.hm_testrec1 =  self.hm_testrec1.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec1), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec1), '')
         # insert record 2 first time:
         testrec_to_insert_first = self.xm_testrec2.replace('<controlfield tag="001">987654321</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err2, recid2 = bibupload.bibupload(recs[0], opt_mode='insert')
         inserted_xm = print_record(recid2, 'xm')
         inserted_hm = print_record(recid2, 'hm')
         # use real recID when comparing whether it worked:
         self.xm_testrec2 =  self.xm_testrec2.replace('987654321', str(recid2))
         self.hm_testrec2 =  self.hm_testrec2.replace('987654321', str(recid2))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec2), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec2), '')
         # try to insert updated record 1, it should fail:
         recs = bibupload.xml_marc_to_records(self.xm_testrec1_to_update)
         err1_updated, recid1_updated = bibupload.bibupload(recs[0], opt_mode='insert')
         self.assertEqual(-1, recid1_updated)
         # delete test records
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid2)
         bibupload.wipe_out_record_from_all_tables(recid1_updated)
         if self.verbose:
             print "test_insert_the_same_extoaiid_record() finished"
 
     def test_insert_or_replace_the_same_extoaiid_record(self):
         """bibupload - EXTOAIID tag, allow to insert or replace the same EXTOAIID record"""
         # initialize bibupload mode:
         task_set_option('verbose', self.verbose)
         if self.verbose:
             print "test_insert_or_replace_the_same_extoaiid_record() started"
         # insert/replace record 1 first time:
         testrec_to_insert_first = self.xm_testrec1.replace('<controlfield tag="001">123456789</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='replace_or_insert')
         inserted_xm = print_record(recid1, 'xm')
         inserted_hm = print_record(recid1, 'hm')
         # use real recID in test buffers when comparing whether it worked:
         self.xm_testrec1 =  self.xm_testrec1.replace('123456789', str(recid1))
         self.hm_testrec1 =  self.hm_testrec1.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec1), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           self.hm_testrec1), '')
         # try to insert/replace updated record 1, it should be okay:
         recs = bibupload.xml_marc_to_records(self.xm_testrec1_to_update)
         err1_updated, recid1_updated = bibupload.bibupload(recs[0], opt_mode='replace_or_insert')
         inserted_xm = print_record(recid1_updated, 'xm')
         inserted_hm = print_record(recid1_updated, 'hm')
         self.assertEqual(recid1, recid1_updated)
         # use real recID in test buffers when comparing whether it worked:
         self.xm_testrec1_updated =  self.xm_testrec1_updated.replace('123456789', str(recid1))
         self.hm_testrec1_updated =  self.hm_testrec1_updated.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           self.xm_testrec1_updated), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           self.hm_testrec1_updated), '')
         # delete test records
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid1_updated)
         if self.verbose:
             print "test_insert_or_replace_the_same_extoaiid_record() finished"
 
     def test_replace_nonexisting_extoaiid_record(self):
         """bibupload - EXTOAIID tag, refuse to replace non-existing EXTOAIID record"""
         # initialize bibupload mode:
         task_set_option('verbose', self.verbose)
         if self.verbose:
             print "test_replace_nonexisting_extoaiid_record() started"
         # insert record 1 first time:
         testrec_to_insert_first = self.xm_testrec1.replace('<controlfield tag="001">123456789</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='replace_or_insert')
         inserted_xm = print_record(recid1, 'xm')
         inserted_hm = print_record(recid1, 'hm')
         # use real recID in test buffers when comparing whether it worked:
         self.xm_testrec1 =  self.xm_testrec1.replace('123456789', str(recid1))
         self.hm_testrec1 =  self.hm_testrec1.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec1), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec1), '')
         # try to replace record 2 it should fail:
         testrec_to_insert_first = self.xm_testrec2.replace('<controlfield tag="001">987654321</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err2, recid2 = bibupload.bibupload(recs[0], opt_mode='replace')
         self.assertEqual(-1, recid2)
         # delete test records
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid2)
         if self.verbose:
             print "test_replace_nonexisting_extoaiid_record() finished"
 
 class BibUploadRecordsWithOAIIDTest(unittest.TestCase):
     """Testing uploading of records that have OAI ID present."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """Initialize the MARCXML test records."""
         self.verbose = 0
         # Note that OAI fields are repeated but with different
         # subfields, this is to test whether bibupload would not
         # mistakenly pick up wrong values.
         self.xm_testrec1 = """
         <record>
          <controlfield tag="001">123456789</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 1</subfield>
          </datafield>
          <datafield tag="%(oaitag)s" ind1="%(oaiind1)s" ind2="%(oaiind2)s">
           <subfield code="%(oaisubfieldcode)s">oai:foo:1</subfield>
          </datafield>
          <datafield tag="%(oaitag)s" ind1="%(oaiind1)s" ind2="%(oaiind2)s">
           <subfield code="0">oai:foo:2</subfield>
          </datafield>
         </record>
         """ % {'oaitag': CFG_OAI_ID_FIELD[0:3],
                'oaiind1': CFG_OAI_ID_FIELD[3:4] != "_" and \
                           CFG_OAI_ID_FIELD[3:4] or " ",
                'oaiind2': CFG_OAI_ID_FIELD[4:5] != "_" and \
                           CFG_OAI_ID_FIELD[4:5] or " ",
                'oaisubfieldcode': CFG_OAI_ID_FIELD[5:6],
                }
         self.hm_testrec1 = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux 1
         %(oaitag)s%(oaiind1)s%(oaiind2)s $$%(oaisubfieldcode)soai:foo:1
         %(oaitag)s%(oaiind1)s%(oaiind2)s $$0oai:foo:2
         """ % {'oaitag': CFG_OAI_ID_FIELD[0:3],
                'oaiind1': CFG_OAI_ID_FIELD[3:4],
                'oaiind2': CFG_OAI_ID_FIELD[4:5],
                'oaisubfieldcode': CFG_OAI_ID_FIELD[5:6],
                }
         self.xm_testrec1_to_update = """
         <record>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 1 Updated</subfield>
          </datafield>
          <datafield tag="%(oaitag)s" ind1="%(oaiind1)s" ind2="%(oaiind2)s">
           <subfield code="%(oaisubfieldcode)s">oai:foo:1</subfield>
          </datafield>
          <datafield tag="%(oaitag)s" ind1="%(oaiind1)s" ind2="%(oaiind2)s">
           <subfield code="0">oai:foo:2</subfield>
          </datafield>
         </record>
         """ % {'oaitag': CFG_OAI_ID_FIELD[0:3],
                'oaiind1': CFG_OAI_ID_FIELD[3:4] != "_" and \
                           CFG_OAI_ID_FIELD[3:4] or " ",
                'oaiind2': CFG_OAI_ID_FIELD[4:5] != "_" and \
                           CFG_OAI_ID_FIELD[4:5] or " ",
                'oaisubfieldcode': CFG_OAI_ID_FIELD[5:6],
                }
         self.xm_testrec1_updated = """
         <record>
          <controlfield tag="001">123456789</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 1 Updated</subfield>
          </datafield>
          <datafield tag="%(oaitag)s" ind1="%(oaiind1)s" ind2="%(oaiind2)s">
           <subfield code="%(oaisubfieldcode)s">oai:foo:1</subfield>
          </datafield>
          <datafield tag="%(oaitag)s" ind1="%(oaiind1)s" ind2="%(oaiind2)s">
           <subfield code="0">oai:foo:2</subfield>
          </datafield>
         </record>
         """ % {'oaitag': CFG_OAI_ID_FIELD[0:3],
                'oaiind1': CFG_OAI_ID_FIELD[3:4] != "_" and \
                           CFG_OAI_ID_FIELD[3:4] or " ",
                'oaiind2': CFG_OAI_ID_FIELD[4:5] != "_" and \
                           CFG_OAI_ID_FIELD[4:5] or " ",
                'oaisubfieldcode': CFG_OAI_ID_FIELD[5:6],
                }
         self.hm_testrec1_updated = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux 1 Updated
         %(oaitag)s%(oaiind1)s%(oaiind2)s $$%(oaisubfieldcode)soai:foo:1
         %(oaitag)s%(oaiind1)s%(oaiind2)s $$0oai:foo:2
         """ % {'oaitag': CFG_OAI_ID_FIELD[0:3],
                'oaiind1': CFG_OAI_ID_FIELD[3:4],
                'oaiind2': CFG_OAI_ID_FIELD[4:5],
                'oaisubfieldcode': CFG_OAI_ID_FIELD[5:6],
                }
         self.xm_testrec2 = """
         <record>
          <controlfield tag="001">987654321</controlfield>
          <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Bar, Baz</subfield>
           <subfield code="u">Foo</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">On the quux and huux 2</subfield>
          </datafield>
          <datafield tag="%(oaitag)s" ind1="%(oaiind1)s" ind2="%(oaiind2)s">
           <subfield code="%(oaisubfieldcode)s">oai:foo:2</subfield>
          </datafield>
          <datafield tag="%(oaitag)s" ind1="%(oaiind1)s" ind2="%(oaiind2)s">
           <subfield code="0">oai:foo:1</subfield>
          </datafield>
         </record>
         """ % {'oaitag': CFG_OAI_ID_FIELD[0:3],
                'oaiind1': CFG_OAI_ID_FIELD[3:4] != "_" and \
                           CFG_OAI_ID_FIELD[3:4] or " ",
                'oaiind2': CFG_OAI_ID_FIELD[4:5] != "_" and \
                           CFG_OAI_ID_FIELD[4:5] or " ",
                'oaisubfieldcode': CFG_OAI_ID_FIELD[5:6],
                }
         self.hm_testrec2 = """
         001__ 987654321
         003__ SzGeCERN
         100__ $$aBar, Baz$$uFoo
         245__ $$aOn the quux and huux 2
         %(oaitag)s%(oaiind1)s%(oaiind2)s $$%(oaisubfieldcode)soai:foo:2
         %(oaitag)s%(oaiind1)s%(oaiind2)s $$0oai:foo:1
         """ % {'oaitag': CFG_OAI_ID_FIELD[0:3],
                'oaiind1': CFG_OAI_ID_FIELD[3:4],
                'oaiind2': CFG_OAI_ID_FIELD[4:5],
                'oaisubfieldcode': CFG_OAI_ID_FIELD[5:6],
                }
 
     def test_insert_the_same_oai_record(self):
         """bibupload - OAIID tag, refuse to insert the same OAI record"""
         task_set_option('verbose', self.verbose)
         # insert record 1 first time:
         testrec_to_insert_first = self.xm_testrec1.replace('<controlfield tag="001">123456789</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='insert')
         inserted_xm = print_record(recid1, 'xm')
         inserted_hm = print_record(recid1, 'hm')
         # use real recID when comparing whether it worked:
         self.xm_testrec1 =  self.xm_testrec1.replace('123456789', str(recid1))
         self.hm_testrec1 =  self.hm_testrec1.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec1), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec1), '')
         # insert record 2 first time:
         testrec_to_insert_first = self.xm_testrec2.replace('<controlfield tag="001">987654321</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err2, recid2 = bibupload.bibupload(recs[0], opt_mode='insert')
         inserted_xm = print_record(recid2, 'xm')
         inserted_hm = print_record(recid2, 'hm')
         # use real recID when comparing whether it worked:
         self.xm_testrec2 =  self.xm_testrec2.replace('987654321', str(recid2))
         self.hm_testrec2 =  self.hm_testrec2.replace('987654321', str(recid2))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec2), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec2), '')
         # try to insert updated record 1, it should fail:
         recs = bibupload.xml_marc_to_records(self.xm_testrec1_to_update)
         err1_updated, recid1_updated = bibupload.bibupload(recs[0], opt_mode='insert')
         self.assertEqual(-1, recid1_updated)
         # delete test records
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid2)
         bibupload.wipe_out_record_from_all_tables(recid1_updated)
 
     def test_insert_or_replace_the_same_oai_record(self):
         """bibupload - OAIID tag, allow to insert or replace the same OAI record"""
         # initialize bibupload mode:
         task_set_option('verbose', self.verbose)
         # insert/replace record 1 first time:
         testrec_to_insert_first = self.xm_testrec1.replace('<controlfield tag="001">123456789</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='replace_or_insert')
         inserted_xm = print_record(recid1, 'xm')
         inserted_hm = print_record(recid1, 'hm')
         # use real recID in test buffers when comparing whether it worked:
         self.xm_testrec1 =  self.xm_testrec1.replace('123456789', str(recid1))
         self.hm_testrec1 =  self.hm_testrec1.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec1), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec1), '')
         # try to insert/replace updated record 1, it should be okay:
         recs = bibupload.xml_marc_to_records(self.xm_testrec1_to_update)
         err1_updated, recid1_updated = bibupload.bibupload(recs[0], opt_mode='replace_or_insert')
         inserted_xm = print_record(recid1_updated, 'xm')
         inserted_hm = print_record(recid1_updated, 'hm')
         self.assertEqual(recid1, recid1_updated)
         # use real recID in test buffers when comparing whether it worked:
         self.xm_testrec1_updated =  self.xm_testrec1_updated.replace('123456789', str(recid1))
         self.hm_testrec1_updated =  self.hm_testrec1_updated.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           self.xm_testrec1_updated), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           self.hm_testrec1_updated), '')
         # delete test records
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid1_updated)
 
     def test_replace_nonexisting_oai_record(self):
         """bibupload - OAIID tag, refuse to replace non-existing OAI record"""
         task_set_option('verbose', self.verbose)
         # insert record 1 first time:
         testrec_to_insert_first = self.xm_testrec1.replace('<controlfield tag="001">123456789</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='replace_or_insert')
         inserted_xm = print_record(recid1, 'xm')
         inserted_hm = print_record(recid1, 'hm')
         # use real recID in test buffers when comparing whether it worked:
         self.xm_testrec1 =  self.xm_testrec1.replace('123456789', str(recid1))
         self.hm_testrec1 =  self.hm_testrec1.replace('123456789', str(recid1))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                            self.xm_testrec1), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                            self.hm_testrec1), '')
         # try to replace record 2 it should fail:
         testrec_to_insert_first = self.xm_testrec2.replace('<controlfield tag="001">987654321</controlfield>',
                                                            '')
         recs = bibupload.xml_marc_to_records(testrec_to_insert_first)
         err2, recid2 = bibupload.bibupload(recs[0], opt_mode='replace')
         self.assertEqual(-1, recid2)
         # delete test records
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid2)
 
 class BibUploadIndicatorsTest(unittest.TestCase):
     """
     Testing uploading of a MARCXML record with indicators having
     either blank space (as per MARC schema) or empty string value (old
     behaviour).
     """
 
     def setUp(self):
         """Initialize the MARCXML test record."""
         self.testrec1_xm = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
         </record>
         """
         self.testrec1_hm = """
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         """
         self.testrec2_xm = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1="" ind2="">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
         </record>
         """
         self.testrec2_hm = """
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         """
 
     def test_record_with_spaces_in_indicators(self):
         """bibupload - inserting MARCXML with spaces in indicators"""
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(self.testrec1_xm)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(remove_tag_001_from_xmbuffer(inserted_xm),
                                           self.testrec1_xm), '')
         self.assertEqual(compare_hmbuffers(remove_tag_001_from_hmbuffer(inserted_hm),
                                           self.testrec1_hm), '')
         bibupload.wipe_out_record_from_all_tables(recid)
 
     def test_record_with_no_spaces_in_indicators(self):
         """bibupload - inserting MARCXML with no spaces in indicators"""
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(self.testrec2_xm)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(remove_tag_001_from_xmbuffer(inserted_xm),
                                           self.testrec2_xm), '')
         self.assertEqual(compare_hmbuffers(remove_tag_001_from_hmbuffer(inserted_hm),
                                           self.testrec2_hm), '')
         bibupload.wipe_out_record_from_all_tables(recid)
 
 class BibUploadUpperLowerCaseTest(unittest.TestCase):
     """
     Testing treatment of similar records with only upper and lower
     case value differences in the bibxxx table.
     """
 
     def setUp(self):
         """Initialize the MARCXML test records."""
         self.testrec1_xm = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
         </record>
         """
         self.testrec1_hm = """
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         """
         self.testrec2_xm = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1="" ind2="">
           <subfield code="a">TeSt, JoHn</subfield>
           <subfield code="u">Test UniVeRsity</subfield>
          </datafield>
         </record>
         """
         self.testrec2_hm = """
         003__ SzGeCERN
         100__ $$aTeSt, JoHn$$uTest UniVeRsity
         """
 
     def test_record_with_upper_lower_case_letters(self):
         """bibupload - inserting similar MARCXML records with upper/lower case"""
         task_set_option('verbose', 0)
         # insert test record #1:
         recs = bibupload.xml_marc_to_records(self.testrec1_xm)
         err1, recid1 = bibupload.bibupload(recs[0], opt_mode='insert')
         recid1_inserted_xm = print_record(recid1, 'xm')
         recid1_inserted_hm = print_record(recid1, 'hm')
         # insert test record #2:
         recs = bibupload.xml_marc_to_records(self.testrec2_xm)
         err1, recid2 = bibupload.bibupload(recs[0], opt_mode='insert')
         recid2_inserted_xm = print_record(recid2, 'xm')
         recid2_inserted_hm = print_record(recid2, 'hm')
         # let us compare stuff now:
         self.assertEqual(compare_xmbuffers(remove_tag_001_from_xmbuffer(recid1_inserted_xm),
                                           self.testrec1_xm), '')
         self.assertEqual(compare_hmbuffers(remove_tag_001_from_hmbuffer(recid1_inserted_hm),
                                           self.testrec1_hm), '')
         self.assertEqual(compare_xmbuffers(remove_tag_001_from_xmbuffer(recid2_inserted_xm),
                                           self.testrec2_xm), '')
         self.assertEqual(compare_hmbuffers(remove_tag_001_from_hmbuffer(recid2_inserted_hm),
                                           self.testrec2_hm), '')
         # clean up after ourselves:
         bibupload.wipe_out_record_from_all_tables(recid1)
         bibupload.wipe_out_record_from_all_tables(recid2)
 
 class BibUploadStrongTagsTest(unittest.TestCase):
     """Testing treatment of strong tags and the replace mode."""
 
     def setUp(self):
         """Initialize the MARCXML test record."""
         self.testrec1_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, Jane</subfield>
           <subfield code="u">Test Institute</subfield>
          </datafield>
          <datafield tag="245" ind1=" " ind2=" ">
           <subfield code="a">Test title</subfield>
          </datafield>
          <datafield tag="%(strong_tag)s" ind1=" " ind2=" ">
           <subfield code="a">A value</subfield>
           <subfield code="b">Another value</subfield>
          </datafield>
         </record>
         """ % {'strong_tag': bibupload.CFG_BIBUPLOAD_STRONG_TAGS[0]}
         self.testrec1_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, Jane$$uTest Institute
         245__ $$aTest title
         %(strong_tag)s__ $$aA value$$bAnother value
         """ % {'strong_tag': bibupload.CFG_BIBUPLOAD_STRONG_TAGS[0]}
         self.testrec1_xm_to_replace = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, Joseph</subfield>
           <subfield code="u">Test Academy</subfield>
          </datafield>
         </record>
         """
         self.testrec1_replaced_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, Joseph</subfield>
           <subfield code="u">Test Academy</subfield>
          </datafield>
          <datafield tag="%(strong_tag)s" ind1=" " ind2=" ">
           <subfield code="a">A value</subfield>
           <subfield code="b">Another value</subfield>
          </datafield>
         </record>
         """ % {'strong_tag': bibupload.CFG_BIBUPLOAD_STRONG_TAGS[0]}
         self.testrec1_replaced_hm = """
         001__ 123456789
         100__ $$aTest, Joseph$$uTest Academy
         %(strong_tag)s__ $$aA value$$bAnother value
         """ % {'strong_tag': bibupload.CFG_BIBUPLOAD_STRONG_TAGS[0]}
         # insert test record:
         task_set_option('verbose', 0)
         test_record_xm = self.testrec1_xm.replace('<controlfield tag="001">123456789</controlfield>',
                                                   '')
         recs = bibupload.xml_marc_to_records(test_record_xm)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recID:
         self.testrec1_xm = self.testrec1_xm.replace('123456789', str(recid))
         self.testrec1_hm = self.testrec1_hm.replace('123456789', str(recid))
         self.testrec1_xm_to_replace = self.testrec1_xm_to_replace.replace('123456789', str(recid))
         self.testrec1_replaced_xm = self.testrec1_replaced_xm.replace('123456789', str(recid))
         self.testrec1_replaced_hm = self.testrec1_replaced_hm.replace('123456789', str(recid))
         # test of the inserted record:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm, self.testrec1_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm, self.testrec1_hm), '')
 
     def test_strong_tags_persistence(self):
         """bibupload - strong tags, persistence in replace mode"""
         # replace all metadata tags; will the strong tags be kept?
         recs = bibupload.xml_marc_to_records(self.testrec1_xm_to_replace)
         err, recid = bibupload.bibupload(recs[0], opt_mode='replace')
         replaced_xm = print_record(recid, 'xm')
         replaced_hm = print_record(recid, 'hm')
         # did it work?
         self.assertEqual(compare_xmbuffers(replaced_xm, self.testrec1_replaced_xm), '')
         self.assertEqual(compare_hmbuffers(replaced_hm, self.testrec1_replaced_hm), '')
         # clean up after ourselves:
         bibupload.wipe_out_record_from_all_tables(recid)
         return
 
 class BibUploadFFTModeTest(unittest.TestCase):
     """
     Testing treatment of fulltext file transfer import mode.
     """
 
     def _test_bibdoc_status(self, recid, docname, status):
         res = run_sql('SELECT bd.status FROM bibrec_bibdoc as bb JOIN bibdoc as bd ON bb.id_bibdoc = bd.id WHERE bb.id_bibrec = %s AND bd.docname = %s', (recid, docname))
         self.failUnless(res)
         self.assertEqual(status, res[0][0])
 
     def test_writing_rights(self):
         """bibupload - FFT has writing rights"""
         self.failUnless(bibupload.writing_rights_p())
 
     def test_simple_fft_insert(self):
         """bibupload - simple FFT insert"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
          </datafield>
         </record>
         """
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/cds.gif</subfield>
          </datafield>
         </record>
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/cds.gif
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/cds.gif" \
             % {'siteurl': CFG_SITE_URL}
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
         self.failUnless(try_url_download(testrec_expected_url))
         bibupload.wipe_out_record_from_all_tables(recid)
 
     def test_exotic_format_fft_append(self):
         """bibupload - exotic format FFT append"""
         # define the test case:
         testfile = os.path.join(CFG_TMPDIR, 'test.ps.Z')
         open(testfile, 'w').write('TEST')
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
         </record>
         """
         testrec_to_append = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">%s</subfield>
          </datafield>
         </record>
         """ % testfile
 
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/test.ps.Z</subfield>
          </datafield>
         </record>
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/test.ps.Z
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/test.ps.Z" \
                % {'siteurl': CFG_SITE_URL}
         testrec_expected_url2 = "%(siteurl)s/record/123456789/files/test?format=ps.Z" \
                % {'siteurl': CFG_SITE_URL}
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_to_append = testrec_to_append.replace('123456789',
                                                           str(recid))
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
         testrec_expected_url2 = testrec_expected_url.replace('123456789',
                                                           str(recid))
         recs = bibupload.xml_marc_to_records(testrec_to_append)
         err, recid = bibupload.bibupload(recs[0], opt_mode='append')
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
         self.assertEqual(urlopen(testrec_expected_url).read(), 'TEST')
         self.assertEqual(urlopen(testrec_expected_url2).read(), 'TEST')
         bibupload.wipe_out_record_from_all_tables(recid)
 
 
     def test_fft_check_md5_through_bibrecdoc_str(self):
         """bibupload - simple FFT insert, check md5 through BibRecDocs.str()"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">%s/img/head.gif</subfield>
          </datafield>
         </record>
         """ % CFG_SITE_URL
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
 
         original_md5 = md5(urlopen('%s/img/head.gif' % CFG_SITE_URL).read()).hexdigest()
 
         bibrec_str = str(BibRecDocs(int(recid)))
 
         md5_found = False
         for row in bibrec_str.split('\n'):
             if 'checksum' in row:
                 if original_md5 in row:
                     md5_found = True
 
         self.failUnless(md5_found)
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
 
     def test_detailed_fft_insert(self):
         """bibupload - detailed FFT insert"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="t">SuperMain</subfield>
           <subfield code="d">This is a description</subfield>
           <subfield code="z">This is a comment</subfield>
           <subfield code="n">CIDIESSE</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="t">SuperMain</subfield>
           <subfield code="f">.jpeg</subfield>
           <subfield code="d">This is a description</subfield>
           <subfield code="z">This is a second comment</subfield>
           <subfield code="n">CIDIESSE</subfield>
          </datafield>
         </record>
         """
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/CIDIESSE.gif</subfield>
           <subfield code="y">This is a description</subfield>
           <subfield code="z">This is a comment</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/CIDIESSE.jpeg</subfield>
           <subfield code="y">This is a description</subfield>
           <subfield code="z">This is a second comment</subfield>
          </datafield>
         </record>
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/CIDIESSE.gif$$yThis is a description$$zThis is a comment
         8564_ $$u%(siteurl)s/record/123456789/files/CIDIESSE.jpeg$$yThis is a description$$zThis is a second comment
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_url1 = "%(siteurl)s/record/123456789/files/CIDIESSE.gif" % {'siteurl': CFG_SITE_URL}
         testrec_expected_url2 = "%(siteurl)s/record/123456789/files/CIDIESSE.jpeg" % {'siteurl': CFG_SITE_URL}
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url1 = testrec_expected_url1.replace('123456789',
                                                           str(recid))
         testrec_expected_url2 = testrec_expected_url1.replace('123456789',
                                                           str(recid))
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
         self.failUnless(try_url_download(testrec_expected_url1))
         self.failUnless(try_url_download(testrec_expected_url2))
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
 
     def test_simple_fft_insert_with_restriction(self):
         """bibupload - simple FFT insert with restriction"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="r">thesis</subfield>
           <subfield code="x">http://cds.cern.ch/img/cds.gif</subfield>
          </datafield>
         </record>
         """
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/cds.gif</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="q">%(siteurl)s/record/123456789/files/icon-cds.gif</subfield>
           <subfield code="x">icon</subfield>
          </datafield>
         </record>
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/cds.gif
         8564_ $$q%(siteurl)s/record/123456789/files/icon-cds.gif$$xicon
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/cds.gif" \
             % {'siteurl': CFG_SITE_URL}
         testrec_expected_icon = "%(siteurl)s/record/123456789/files/icon-cds.gif" \
             % {'siteurl': CFG_SITE_URL}
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
         testrec_expected_icon = testrec_expected_icon.replace('123456789',
                                                           str(recid))
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         open_url = urlopen(testrec_expected_url)
         self.failUnless("This file is restricted" in open_url.read())
 
         open_icon = urlopen(testrec_expected_icon)
         restricted_icon = urlopen("%s/img/restricted.gif" % CFG_SITE_URL)
         self.failUnless(open_icon.read() == restricted_icon.read())
         bibupload.wipe_out_record_from_all_tables(recid)
 
     def test_simple_fft_insert_with_icon(self):
         """bibupload - simple FFT insert with icon"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="x">http://cds.cern.ch/img/cds.gif</subfield>
          </datafield>
         </record>
         """
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/cds.gif</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="q">%(siteurl)s/record/123456789/files/icon-cds.gif</subfield>
           <subfield code="x">icon</subfield>
          </datafield>
         </record>
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/cds.gif
         8564_ $$q%(siteurl)s/record/123456789/files/icon-cds.gif$$xicon
         """ % {'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/cds.gif" \
             % {'siteurl': CFG_SITE_URL}
         testrec_expected_icon = "%(siteurl)s/record/123456789/files/icon-cds.gif" \
             % {'siteurl': CFG_SITE_URL}
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
         testrec_expected_icon = testrec_expected_icon.replace('123456789',
                                                           str(recid))
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         self.failUnless(try_url_download(testrec_expected_url))
         self.failUnless(try_url_download(testrec_expected_icon))
         bibupload.wipe_out_record_from_all_tables(recid)
 
 
 
     def test_multiple_fft_insert(self):
         """bibupload - multiple FFT insert"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cdsweb.cern.ch/img/head.gif</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://doc.cern.ch/archive/electronic/hep-th/0101/0101001.pdf</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">%(prefix)s/var/tmp/demobibdata.xml</subfield>
          </datafield>
         </record>
         """ % { 'prefix': CFG_PREFIX }
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/0101001.pdf</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/cds.gif</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/demobibdata.xml</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/head.gif</subfield>
          </datafield>
         </record>
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/0101001.pdf
         8564_ $$u%(siteurl)s/record/123456789/files/cds.gif
         8564_ $$u%(siteurl)s/record/123456789/files/demobibdata.xml
         8564_ $$u%(siteurl)s/record/123456789/files/head.gif
         """ % { 'siteurl': CFG_SITE_URL}
         # insert test record:
         testrec_expected_urls = []
         for files in ('cds.gif', 'head.gif', '0101001.pdf', 'demobibdata.xml'):
             testrec_expected_urls.append('%(siteurl)s/record/123456789/files/%(files)s' % {'siteurl' : CFG_SITE_URL, 'files' : files})
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_urls = []
         for files in ('cds.gif', 'head.gif', '0101001.pdf', 'demobibdata.xml'):
             testrec_expected_urls.append('%(siteurl)s/record/%(recid)s/files/%(files)s' % {'siteurl' : CFG_SITE_URL, 'files' : files, 'recid' : recid})
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
 
         # FIXME: Next test has been commented out since, appearently, the
         # returned xml can have non predictable row order (but still correct)
         # Using only html marc output is fine because a value is represented
         # by a single row, so a row to row comparison can be employed.
 
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
         for url in testrec_expected_urls:
             self.failUnless(try_url_download(url))
 
         self._test_bibdoc_status(recid, 'head', '')
         self._test_bibdoc_status(recid, '0101001', '')
         self._test_bibdoc_status(recid, 'cds', '')
         self._test_bibdoc_status(recid, 'demobibdata', '')
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
     def test_simple_fft_correct(self):
         """bibupload - simple FFT correct"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
          </datafield>
         </record>
         """
         test_to_correct = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
          </datafield>
         </record>
         """
 
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/cds.gif</subfield>
          </datafield>
         </record>
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/cds.gif
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/patata.gif" \
             % {'siteurl': CFG_SITE_URL}
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
         test_to_correct = test_to_correct.replace('123456789',
                                                           str(recid))
         # correct test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_correct)
         bibupload.bibupload(recs[0], opt_mode='correct')
 
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.failUnless(try_url_download(testrec_expected_url))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         self._test_bibdoc_status(recid, 'cds', '')
 
         #print "\nRecid: " + str(recid) + "\n"
         #print testrec_expected_hm + "\n"
         #print print_record(recid, 'hm') + "\n"
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
 
     def test_detailed_fft_correct(self):
         """bibupload - detailed FFT correct"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="d">Try</subfield>
           <subfield code="z">Comment</subfield>
          </datafield>
         </record>
         """
         test_to_correct = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cdsweb.cern.ch/img/head.gif</subfield>
           <subfield code="n">cds</subfield>
           <subfield code="m">patata</subfield>
           <subfield code="d">Next Try</subfield>
           <subfield code="z">KEEP-OLD-VALUE</subfield>
          </datafield>
         </record>
         """
 
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/patata.gif</subfield>
           <subfield code="y">Next Try</subfield>
           <subfield code="z">Comment</subfield>
          </datafield>
         </record>
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/patata.gif$$yNext Try$$zComment
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/patata.gif" \
             % {'siteurl': CFG_SITE_URL}
 
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
 
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
 
         test_to_correct = test_to_correct.replace('123456789',
                                                           str(recid))
         # correct test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_correct)
         bibupload.bibupload(recs[0], opt_mode='correct')
 
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
 
         self.failUnless(try_url_download(testrec_expected_url))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         self._test_bibdoc_status(recid, 'patata', '')
 
         #print "\nRecid: " + str(recid) + "\n"
         #print testrec_expected_hm + "\n"
         #print print_record(recid, 'hm') + "\n"
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
     def test_no_url_fft_correct(self):
         """bibupload - no_url FFT correct"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="d">Try</subfield>
           <subfield code="z">Comment</subfield>
          </datafield>
         </record>
         """
         test_to_correct = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="n">cds</subfield>
           <subfield code="m">patata</subfield>
           <subfield code="f">.gif</subfield>
           <subfield code="d">KEEP-OLD-VALUE</subfield>
           <subfield code="z">Next Comment</subfield>
          </datafield>
         </record>
         """
 
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/patata.gif</subfield>
           <subfield code="y">Try</subfield>
           <subfield code="z">Next Comment</subfield>
          </datafield>
         </record>
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/patata.gif$$yTry$$zNext Comment
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/patata.gif" \
             % {'siteurl': CFG_SITE_URL}
 
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
 
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
 
         test_to_correct = test_to_correct.replace('123456789',
                                                           str(recid))
         # correct test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_correct)
         bibupload.bibupload(recs[0], opt_mode='correct')
 
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
 
         self.failUnless(try_url_download(testrec_expected_url))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         self._test_bibdoc_status(recid, 'patata', '')
 
         #print "\nRecid: " + str(recid) + "\n"
         #print testrec_expected_hm + "\n"
         #print print_record(recid, 'hm') + "\n"
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
     def test_new_icon_fft_append(self):
         """bibupload - new icon FFT append"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
         </record>
         """
         test_to_correct = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="n">cds</subfield>
           <subfield code="x">http://cds.cern.ch/img/cds.gif</subfield>
          </datafield>
         </record>
         """
 
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="q">%(siteurl)s/record/123456789/files/icon-cds.gif</subfield>
           <subfield code="x">icon</subfield>
          </datafield>
         </record>
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$q%(siteurl)s/record/123456789/files/icon-cds.gif$$xicon
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/icon-cds.gif" \
             % {'siteurl': CFG_SITE_URL}
 
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
 
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
 
         test_to_correct = test_to_correct.replace('123456789',
                                                           str(recid))
         # correct test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_correct)
         bibupload.bibupload(recs[0], opt_mode='append')
 
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
 
         self.failUnless(try_url_download(testrec_expected_url))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         self._test_bibdoc_status(recid, 'cds', '')
 
         #print "\nRecid: " + str(recid) + "\n"
         #print testrec_expected_hm + "\n"
         #print print_record(recid, 'hm') + "\n"
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
 
     def test_multiple_fft_correct(self):
         """bibupload - multiple FFT correct"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="d">Try</subfield>
           <subfield code="z">Comment</subfield>
           <subfield code="r">Restricted</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="f">.jpeg</subfield>
           <subfield code="d">Try jpeg</subfield>
           <subfield code="z">Comment jpeg</subfield>
           <subfield code="r">Restricted</subfield>
          </datafield>
         </record>
         """
         test_to_correct = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="m">patata</subfield>
           <subfield code="f">.gif</subfield>
           <subfield code="r">New restricted</subfield>
          </datafield>
         </record>
         """
 
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/patata.gif</subfield>
          </datafield>
         </record>
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/patata.gif
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/patata.gif" \
             % {'siteurl': CFG_SITE_URL}
 
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
 
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
 
         test_to_correct = test_to_correct.replace('123456789',
                                                           str(recid))
         # correct test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_correct)
         bibupload.bibupload(recs[0], opt_mode='correct')
 
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
 
         self.failUnless(try_url_download(testrec_expected_url))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         self._test_bibdoc_status(recid, 'patata', 'New restricted')
 
         #print "\nRecid: " + str(recid) + "\n"
         #print testrec_expected_hm + "\n"
         #print print_record(recid, 'hm') + "\n"
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
     def test_purge_fft_correct(self):
         """bibupload - purge FFT correct"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cdsweb.cern.ch/img/head.gif</subfield>
          </datafield>
         </record>
         """
         test_to_correct = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
          </datafield>
         </record>
         """
         test_to_purge = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">http://cds.cern.ch/img/cds.gif</subfield>
           <subfield code="t">PURGE</subfield>
          </datafield>
         </record>
         """
 
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/cds.gif</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/head.gif</subfield>
          </datafield>
         </record>
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/cds.gif
         8564_ $$u%(siteurl)s/record/123456789/files/head.gif
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/cds.gif" % { 'siteurl': CFG_SITE_URL}
 
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
         test_to_correct = test_to_correct.replace('123456789',
                                                           str(recid))
         test_to_purge = test_to_purge.replace('123456789',
                                                           str(recid))
         # correct test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_correct)
         bibupload.bibupload(recs[0], opt_mode='correct')
 
         # purge test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_purge)
         bibupload.bibupload(recs[0], opt_mode='correct')
 
 
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.failUnless(try_url_download(testrec_expected_url))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         self._test_bibdoc_status(recid, 'cds', '')
         self._test_bibdoc_status(recid, 'head', '')
 
         #print "\nRecid: " + str(recid) + "\n"
         #print testrec_expected_hm + "\n"
         #print print_record(recid, 'hm') + "\n"
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
     def test_revert_fft_correct(self):
         """bibupload - revert FFT correct"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">%s/img/iconpen.gif</subfield>
           <subfield code="n">cds</subfield>
          </datafield>
         </record>
         """ % CFG_SITE_URL
         test_to_correct = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">%s/img/head.gif</subfield>
           <subfield code="n">cds</subfield>
          </datafield>
         </record>
         """ % CFG_SITE_URL
         test_to_revert = """
         <record>
         <controlfield tag="001">123456789</controlfield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="n">cds</subfield>
           <subfield code="t">REVERT</subfield>
           <subfield code="v">1</subfield>
          </datafield>
         </record>
         """
 
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/cds.gif</subfield>
          </datafield>
         </record>
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/cds.gif
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/cds.gif" % { 'siteurl': CFG_SITE_URL}
 
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
         test_to_correct = test_to_correct.replace('123456789',
                                                           str(recid))
         test_to_revert = test_to_revert.replace('123456789',
                                                           str(recid))
         # correct test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_correct)
         bibupload.bibupload(recs[0], opt_mode='correct')
 
         # revert test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_revert)
         bibupload.bibupload(recs[0], opt_mode='correct')
 
 
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.failUnless(try_url_download(testrec_expected_url))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         self._test_bibdoc_status(recid, 'cds', '')
 
         expected_content_version1 = urlopen('%s/img/iconpen.gif' % CFG_SITE_URL).read()
         expected_content_version2 = urlopen('%s/img/head.gif' % CFG_SITE_URL).read()
         expected_content_version3 = expected_content_version1
 
         content_version1 = urlopen('%s/record/%s/files/cds.gif?version=1' % (CFG_SITE_URL, recid)).read()
         content_version2 = urlopen('%s/record/%s/files/cds.gif?version=2' % (CFG_SITE_URL, recid)).read()
         content_version3 = urlopen('%s/record/%s/files/cds.gif?version=3' % (CFG_SITE_URL, recid)).read()
 
         self.assertEqual(expected_content_version1, content_version1)
         self.assertEqual(expected_content_version2, content_version2)
         self.assertEqual(expected_content_version3, content_version3)
 
         #print "\nRecid: " + str(recid) + "\n"
         #print testrec_expected_hm + "\n"
         #print print_record(recid, 'hm') + "\n"
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
     def test_simple_fft_replace(self):
         """bibupload - simple FFT replace"""
         # define the test case:
         test_to_upload = """
         <record>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">%s/img/iconpen.gif</subfield>
           <subfield code="n">cds</subfield>
          </datafield>
         </record>
         """ % CFG_SITE_URL
         test_to_replace = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="FFT" ind1=" " ind2=" ">
           <subfield code="a">%s/img/head.gif</subfield>
          </datafield>
         </record>
         """ % CFG_SITE_URL
 
         testrec_expected_xm = """
         <record>
         <controlfield tag="001">123456789</controlfield>
         <controlfield tag="003">SzGeCERN</controlfield>
          <datafield tag="100" ind1=" " ind2=" ">
           <subfield code="a">Test, John</subfield>
           <subfield code="u">Test University</subfield>
          </datafield>
          <datafield tag="856" ind1="4" ind2=" ">
           <subfield code="u">%(siteurl)s/record/123456789/files/head.gif</subfield>
          </datafield>
         </record>
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_hm = """
         001__ 123456789
         003__ SzGeCERN
         100__ $$aTest, John$$uTest University
         8564_ $$u%(siteurl)s/record/123456789/files/head.gif
         """ % { 'siteurl': CFG_SITE_URL}
         testrec_expected_url = "%(siteurl)s/record/123456789/files/head.gif" % { 'siteurl': CFG_SITE_URL}
 
         # insert test record:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_upload)
         err, recid = bibupload.bibupload(recs[0], opt_mode='insert')
         # replace test buffers with real recid of inserted test record:
         testrec_expected_xm = testrec_expected_xm.replace('123456789',
                                                           str(recid))
         testrec_expected_hm = testrec_expected_hm.replace('123456789',
                                                           str(recid))
         testrec_expected_url = testrec_expected_url.replace('123456789',
                                                           str(recid))
         test_to_replace = test_to_replace.replace('123456789',
                                                           str(recid))
         # replace test record with new FFT:
         task_set_option('verbose', 0)
         recs = bibupload.xml_marc_to_records(test_to_replace)
         bibupload.bibupload(recs[0], opt_mode='replace')
 
         # compare expected results:
         inserted_xm = print_record(recid, 'xm')
         inserted_hm = print_record(recid, 'hm')
         self.failUnless(try_url_download(testrec_expected_url))
         self.assertEqual(compare_xmbuffers(inserted_xm,
                                           testrec_expected_xm), '')
         self.assertEqual(compare_hmbuffers(inserted_hm,
                                           testrec_expected_hm), '')
 
         expected_content_version = urlopen('%s/img/head.gif' % CFG_SITE_URL).read()
 
         content_version = urlopen('%s/record/%s/files/head.gif' % (CFG_SITE_URL, recid)).read()
 
         self.assertEqual(expected_content_version, content_version)
 
         #print "\nRecid: " + str(recid) + "\n"
         #print testrec_expected_hm + "\n"
         #print print_record(recid, 'hm') + "\n"
 
         bibupload.wipe_out_record_from_all_tables(recid)
 
 
-test_suite = make_test_suite(BibUploadInsertModeTest,
+TEST_SUITE = make_test_suite(BibUploadInsertModeTest,
                              BibUploadAppendModeTest,
                              BibUploadCorrectModeTest,
                              BibUploadReplaceModeTest,
                              BibUploadReferencesModeTest,
                              BibUploadRecordsWithSYSNOTest,
                              BibUploadRecordsWithEXTOAIIDTest,
                              BibUploadRecordsWithOAIIDTest,
                              BibUploadFMTModeTest,
                              BibUploadIndicatorsTest,
                              BibUploadUpperLowerCaseTest,
                              BibUploadStrongTagsTest,
                              BibUploadFFTModeTest)
 
-#test_suite = make_test_suite(BibUploadStrongTagsTest,)
+#TEST_SUITE = make_test_suite(BibUploadStrongTagsTest,)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/elmsubmit/lib/elmsubmit_tests.py b/modules/elmsubmit/lib/elmsubmit_tests.py
index 240d4358f..1f857c203 100644
--- a/modules/elmsubmit/lib/elmsubmit_tests.py
+++ b/modules/elmsubmit/lib/elmsubmit_tests.py
@@ -1,241 +1,238 @@
 # -*- coding: utf-8 -*-
 
 ## $Id$
 ## CDS Invenio elmsubmit unit tests.
 
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the elmsubmit."""
 
 __revision__ = "$Id$"
 
 import unittest
 import re
 import os
 import os.path
 from string import expandtabs, replace
-from invenio.config import CFG_TMPDIR
-import invenio.elmsubmit_config as elmsubmit_config
 import xml.dom.minidom
 
+from invenio.config import CFG_TMPDIR
+import invenio.elmsubmit_config as elmsubmit_config
 from invenio import elmsubmit
+from invenio.testutils import make_test_suite, run_test_suite
 
 class MarcTest(unittest.TestCase):
     """ elmsubmit - test for saniy """
     def test_simple_marc(self):
         """elmsubmit - parsing simple email"""
         try:
             f=open(os.path.join(CFG_TMPDIR, elmsubmit_config.CFG_ELMSUBMIT_FILES['test_case_1']),'r')
             email = f.read()
             f.close()
 
             # let's try to parse an example email and compare it with the appropriate marc xml
             x = elmsubmit.process_email(email)
             y  = """<record>
             <datafield tag ="245" ind1="" ind2="">
             <subfield code="a">something</subfield>
             </datafield>
             <datafield tag ="100" ind1="" ind2="">
             <subfield code="a">Simko, T</subfield>
             <subfield code="u">CERN</subfield>
             </datafield>
             </record>"""
 
             # in order to properly compare the marc files we have to remove the FFT node, it includes a random generated file path
 
             dom_x = xml.dom.minidom.parseString(x)
             datafields = dom_x.getElementsByTagName("datafield")
 
             #remove all the FFT datafields
             for node in datafields:
                 if (node.hasAttribute("tag") and  node.getAttribute("tag") == "FFT"):
                     node.parentNode.removeChild(node)
                     node.unlink()
 
             new_x = dom_x.toprettyxml("","\n")
 
             dom_y = xml.dom.minidom.parseString(y)
             new_y = dom_y.toprettyxml("","\n")
 
             # 'normalize' the two XML MARC files for the purpose of comparing
             new_x = expandtabs(new_x)
             new_y = expandtabs(new_y)
 
             new_x = new_x.replace(' ','')
             new_y = new_y.replace(' ','')
 
             new_x = new_x.replace('\n','')
             new_y = new_y.replace('\n','')
 
             # compare the two xml marcs
             self.assertEqual(new_x,new_y)
 
         except IOError:
             self.fail("WARNING: the test case file does not exist; test not run.")
 
     def test_complex_marc(self):
         """elmsubmit - parsing complex email with multiple fields"""
         try:
             f=open(os.path.join(CFG_TMPDIR, elmsubmit_config.CFG_ELMSUBMIT_FILES['test_case_2']),'r')
             email = f.read()
             f.close()
 
             # let's try to reproduce the demo XML MARC file by parsing it and printing it back:
             x = elmsubmit.process_email(email)
             y = """<record>
             <datafield tag ="245" ind1="" ind2="">
             <subfield code="a">something</subfield>
             </datafield>
             <datafield tag ="700" ind1="" ind2="">
             <subfield code="a">Le Meur, J Y</subfield>
             <subfield code="u">MIT</subfield>
             </datafield>
             <datafield tag ="700" ind1="" ind2="">
             <subfield code="a">Jedrzejek, K J</subfield>
             <subfield code="u">CERN2</subfield>
             </datafield>
             <datafield tag ="700" ind1="" ind2="">
             <subfield code="a">Favre, G</subfield>
             <subfield code="u">CERN3</subfield>
             </datafield>
             <datafield tag ="111" ind1="" ind2="">
             <subfield code="a">test11</subfield>
             <subfield code="c">test31</subfield>
             </datafield>
             <datafield tag ="111" ind1="" ind2="">
             <subfield code="a">test12</subfield>
             <subfield code="c">test32</subfield>
             </datafield>
             <datafield tag ="111" ind1="" ind2="">
             <subfield code="a">test13</subfield>
             <subfield code="c">test33</subfield>
             </datafield>
             <datafield tag ="111" ind1="" ind2="">
             <subfield code="b">test21</subfield>
             <subfield code="d">test41</subfield>
             </datafield>
             <datafield tag ="111" ind1="" ind2="">
             <subfield code="b">test22</subfield>
             <subfield code="d">test42</subfield>
             </datafield>
             <datafield tag ="111" ind1="" ind2="">
             <subfield code="a">test14</subfield>
             </datafield>
             <datafield tag ="111" ind1="" ind2="">
             <subfield code="e">test51</subfield>
             </datafield>
             <datafield tag ="111" ind1="" ind2="">
             <subfield code="e">test52</subfield>
             </datafield>
             <datafield tag ="100" ind1="" ind2="">
             <subfield code="a">Simko, T</subfield>
             <subfield code="u">CERN</subfield>
             </datafield>
             </record>"""
 
             # in order to properly compare the marc files we have to remove the FFT node, it includes a random generated file path
 
             dom_x = xml.dom.minidom.parseString(x)
             datafields = dom_x.getElementsByTagName("datafield")
 
             #remove all the FFT datafields
             for node in datafields:
                 if (node.hasAttribute("tag") and  node.getAttribute("tag") == "FFT"):
                     node.parentNode.removeChild(node)
                     node.unlink()
 
 
             new_x = dom_x.toprettyxml("","\n")
 
             dom_y = xml.dom.minidom.parseString(y)
             new_y = dom_y.toprettyxml("","\n")
             # 'normalize' the two XML MARC files for the purpose of comparing
             new_x = expandtabs(new_x)
             new_y = expandtabs(new_y)
 
             new_x = new_x.replace(' ','')
             new_y = new_y.replace(' ','')
 
             new_x = new_x.replace('\n','')
             new_y = new_y.replace('\n','')
 
             # compare the two xml marcs
             self.assertEqual(new_x,new_y)
         except IOError:
             self.fail("WARNING: the test case file does not exist; test not run.")
 
 class FileStorageTest(unittest.TestCase):
     """ testing proper storage of files """
     def test_read_text_files(self):
         """elmsubmit - reading text files"""
         try:
 
             f=open(os.path.join(CFG_TMPDIR, elmsubmit_config.CFG_ELMSUBMIT_FILES['test_case_2']),'r')
             email = f.read()
             f.close()
 
             # let's try to see if the files were properly stored:
             xml_marc = elmsubmit.process_email(email)
 
             dom = xml.dom.minidom.parseString(xml_marc)
             datafields = dom.getElementsByTagName("datafield")
 
             # get the file addresses
             file_list = []
 
             for node in datafields:
                 if (node.hasAttribute("tag") and  node.getAttribute("tag") == "FFT"):
                     children = node.childNodes
                     for child in children:
                         if (child.hasChildNodes()):
                             file_list.append(child.firstChild.nodeValue)
 
             f=open(file_list[0], 'r')
             x = f.read()
             f.close()
 
             x.lstrip()
             x.rstrip()
 
             y = """second attachment\n"""
 
             self.assertEqual(x,y)
 
             f=open(file_list[1], 'r')
             x = f.read()
             f.close()
 
             x.lstrip()
             x.rstrip()
 
             y = """some attachment\n"""
             self.assertEqual(x,y)
         except IOError:
             self.fail("WARNING: the test case file does not exist; test not run.")
 
-def create_test_suite():
-    """Return test suite for the elmsubmit module"""
-    return unittest.TestSuite((unittest.makeSuite(MarcTest,'test'), unittest.makeSuite(FileStorageTest,'test')))
-                              # unittest.makeSuite(BadInputTreatmentTest,'test'),
-                              # unittest.makeSuite(GettingFieldValuesTest,'test'),
-                              # unittest.makeSuite(AccentedUnicodeLettersTest,'test')))
+TEST_SUITE = make_test_suite(MarcTest,
+                             FileStorageTest,)
 
 if __name__ == '__main__':
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
 
diff --git a/modules/miscutil/bin/.cvsignore b/modules/miscutil/bin/.cvsignore
index 524d7a84e..d45b8a718 100644
--- a/modules/miscutil/bin/.cvsignore
+++ b/modules/miscutil/bin/.cvsignore
@@ -1,9 +1,7 @@
 Makefile
 Makefile.in
 z_*
 *.O
 *~
 dbexec
-testsuite
-regressiontestsuite
 inveniocfg
diff --git a/modules/miscutil/bin/Makefile.am b/modules/miscutil/bin/Makefile.am
index b7d04a774..9ceffec75 100644
--- a/modules/miscutil/bin/Makefile.am
+++ b/modules/miscutil/bin/Makefile.am
@@ -1,24 +1,24 @@
 ## $Id$
 
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
-bin_SCRIPTS = dbexec testsuite regressiontestsuite inveniocfg
+bin_SCRIPTS = dbexec inveniocfg
 
-EXTRA_DIST = dbexec.in testsuite.in regressiontestsuite.in inveniocfg.in
+EXTRA_DIST = dbexec.in inveniocfg.in
 
 CLEANFILES = *~ *.tmp
diff --git a/modules/miscutil/bin/regressiontestsuite.in b/modules/miscutil/bin/regressiontestsuite.in
deleted file mode 100644
index 08dc3c871..000000000
--- a/modules/miscutil/bin/regressiontestsuite.in
+++ /dev/null
@@ -1,81 +0,0 @@
-#!@PYTHON@
-## -*- mode: python; coding: utf-8; -*-
-##
-## $Id$
-##
-## This file is part of CDS Invenio.
-## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
-##
-## CDS Invenio is free software; you can redistribute it and/or
-## modify it under the terms of the GNU General Public License as
-## published by the Free Software Foundation; either version 2 of the
-## License, or (at your option) any later version.
-##
-## CDS Invenio is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
-## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-
-"""Run CDS Invenio regression test suite."""
-
-__revision__ = "$Id$"
-
-import getopt
-import sys
-import os
-import unittest
-
-import invenio
-from invenio import testutils
-
-def usage():
-    """Print usage info on standard error output."""
-    sys.stderr.write("Usage: %s [options]\n" % sys.argv[0])
-    sys.stderr.write("General options:\n")
-    sys.stderr.write("  -h, --help      \t\t Print this help.\n")
-    sys.stderr.write("  -V, --version   \t\t Print version information.\n")
-    sys.stderr.write("Description: run CDS Invenio regression test suite.\n")
-    return
-
-if __name__ == "__main__":
-
-    try:
-        opts, args = getopt.getopt(sys.argv[1:], "hV", ["help", "version", "yes-i-know"])
-    except getopt.GetoptError:
-        usage()
-        sys.exit(2)
-
-    for opt in opts:
-        if opt[0] in ("-V","--version"):
-            print __revision__
-            sys.exit(0)
-        elif opt[0] in ("-h","--help"):
-            usage()
-            sys.exit(0)
-
-    ## Okay, go on and harvest all the modules whose name ends in
-    ## 'regression_tests', and build up a complete suite to run from
-    ## that list, and run it.
-
-    test_modules = []
-
-    for candidate in os.listdir(os.path.dirname(invenio.__file__)):
-        base, ext = os.path.splitext(candidate)
-
-        if ext != '.py' or not base.endswith('regression_tests'):
-            continue
-
-        module = __import__('invenio.' + base, globals(), locals(), ['test_suite'])
-        test_modules.append(module.test_suite)
-
-    print "regressiontestsuite: detected %d regression test modules" % len(test_modules)
-    testutils.warn_user_about_tests()
-
-    complete_suite = unittest.TestSuite(test_modules)
-    unittest.TextTestRunner(verbosity=2).run(complete_suite)
-
-
diff --git a/modules/miscutil/bin/testsuite.in b/modules/miscutil/bin/testsuite.in
deleted file mode 100644
index 6304f88d0..000000000
--- a/modules/miscutil/bin/testsuite.in
+++ /dev/null
@@ -1,118 +0,0 @@
-#!@PYTHON@
-## -*- mode: python; coding: utf-8; -*-
-##
-## $Id$
-##
-## This file is part of CDS Invenio.
-## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
-##
-## CDS Invenio is free software; you can redistribute it and/or
-## modify it under the terms of the GNU General Public License as
-## published by the Free Software Foundation; either version 2 of the
-## License, or (at your option) any later version.
-##
-## CDS Invenio is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
-## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-
-"""Run CDS Invenio test suite."""
-
-__revision__ = "$Id$"
-
-import getopt
-import unittest
-import sys
-
-# we first import webinterface_tests to be sure to have the fake
-# Apache environment working:
-from invenio import webinterface_tests
-
-# now we import the rest:
-from invenio.config import CFG_VERSION
-from invenio import search_engine_tests
-from invenio import bibindex_engine_tests
-from invenio import bibindex_engine_stemmer_tests
-from invenio import bibrecord_tests
-from invenio import bibrank_citation_indexer_tests
-from invenio import bibrank_citation_searcher_tests
-from invenio import bibrank_downloads_indexer_tests
-from invenio import bibrank_record_sorter_tests
-from invenio import bibrank_tag_based_indexer_tests
-from invenio import oai_repository_tests
-from invenio import bibconvert_tests
-from invenio import errorlib_tests
-from invenio import elmsubmit_tests
-from invenio import bibformat_engine_tests
-from invenio import websearch_external_collections_getter_tests
-from invenio import webuser_tests
-from invenio import webgroup_tests
-from invenio import dbquery_tests
-from invenio import dateutils_tests
-from invenio import htmlutils_tests
-from invenio import access_control_firerole_tests
-from invenio import intbitset_tests
-from invenio import textutils_tests
-
-def usage():
-    """Print usage info on standard error output."""
-    sys.stderr.write("Usage: %s [options]\n" % sys.argv[0])
-    sys.stderr.write("General options:\n")
-    sys.stderr.write("  -h, --help      \t\t Print this help.\n")
-    sys.stderr.write("  -V, --version   \t\t Print version information.\n")
-    sys.stderr.write("Description: run CDS Invenio test suite.\n")
-    return
-
-def create_all_test_suites():
-    """Return all tests suites for all CDS Invenio modules."""
-    return unittest.TestSuite((search_engine_tests.create_test_suite(),
-                               bibindex_engine_tests.create_test_suite(),
-                               bibindex_engine_stemmer_tests.create_test_suite(),
-                               bibrecord_tests.create_test_suite(),
-                               bibrank_citation_indexer_tests.create_test_suite(),
-                               bibrank_citation_searcher_tests.create_test_suite(),
-                               bibrank_downloads_indexer_tests.create_test_suite(),
-                               bibrank_record_sorter_tests.create_test_suite(),
-                               bibrank_tag_based_indexer_tests.create_test_suite(),
-                               oai_repository_tests.create_test_suite(),
-                               bibconvert_tests.create_test_suite(),
-                               errorlib_tests.create_test_suite(),
-                               elmsubmit_tests.create_test_suite(),
-                               webinterface_tests.create_test_suite(),
-                               bibformat_engine_tests.create_test_suite(),
-                               websearch_external_collections_getter_tests.create_test_suite(),
-                               webuser_tests.create_test_suite(),
-                               webgroup_tests.create_test_suite(),
-                               dbquery_tests.create_test_suite(),
-                               dateutils_tests.create_test_suite(),
-                               htmlutils_tests.create_test_suite(),
-                               access_control_firerole_tests.create_test_suite(),
-                               intbitset_tests.create_test_suite(),
-                               textutils_tests.create_test_suite(),
-                               ))
-
-def print_info_line():
-    """Prints info line about tests to be executed."""
-    info_line = """CDS Invenio v%s test suite results:""" % CFG_VERSION
-    sys.stderr.write(info_line + "\n")
-    sys.stderr.write("=" * len(info_line) + "\n")
-
-if __name__ == "__main__":
-    try:
-        opts, args = getopt.getopt(sys.argv[1:], "hV", ["help", "version"])
-    except getopt.GetoptError:
-        usage()
-        sys.exit(2)
-    for opt in opts:
-        if opt[0] in ("-V","--version"):
-            print __revision__
-            sys.exit(0)
-        elif opt[0] in ("-h","--help"):
-            usage()
-            sys.exit(0)
-    print_info_line()
-    unittest.TextTestRunner(verbosity=2).run(create_all_test_suites())
diff --git a/modules/miscutil/lib/dateutils_tests.py b/modules/miscutil/lib/dateutils_tests.py
index 9dcd6e759..d29eddb76 100644
--- a/modules/miscutil/lib/dateutils_tests.py
+++ b/modules/miscutil/lib/dateutils_tests.py
@@ -1,106 +1,102 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for dateutils library."""
 
 __revision__ = "$Id$"
 
 import unittest
 import dateutils
 
+from invenio.testutils import make_test_suite, run_test_suite
+
 class ConvertFromDateCVSTest(unittest.TestCase):
     """
     Testing conversion of CVS dates.
     """
 
     def test_convert_good_cvsdate(self):
         """dateutils - conversion of good CVS dates"""
         # here we have to use '$' + 'Date...' here, otherwise the CVS
         # commit would erase this time format to put commit date:
         datecvs = "$" + "Date: 2006/09/21 10:07:22 $"
         datestruct_beginning_expected = (2006, 9, 21, 10, 7, 22)
         self.assertEqual(dateutils.convert_datecvs_to_datestruct(datecvs)[:6],
                          datestruct_beginning_expected)
 
         # here we have to use '$' + 'Date...' here, otherwise the CVS
         # commit would erase this time format to put commit date:
         datecvs = "$" + "Id: dateutils_tests.py,v 1.6 2007/02/14 18:33:02 tibor Exp $"
         datestruct_beginning_expected = (2007, 2, 14, 18, 33, 02)
         self.assertEqual(dateutils.convert_datecvs_to_datestruct(datecvs)[:6],
                          datestruct_beginning_expected)
 
     def test_convert_bad_cvsdate(self):
         """dateutils - conversion of bad CVS dates"""
         # here we have to use '$' + 'Date...' here, otherwise the CVS
         # commit would erase this time format to put commit date:
         datecvs = "$" + "Date: 2006/AA/21 10:07:22 $"
         datestruct_beginning_expected = (0, 0, 0, 0, 0, 0)
         self.assertEqual(dateutils.convert_datecvs_to_datestruct(datecvs)[:6],
                          datestruct_beginning_expected)
 
 class ConvertIntoDateGUITest(unittest.TestCase):
     """
     Testing conversion into dategui with various languages.
     """
 
     def test_convert_good_to_dategui_en(self):
         """dateutils - conversion of good text date into English GUI date"""
         datetext = "2006-07-16 18:36:01"
         dategui_en_expected = "16 Jul 2006, 18:36"
         dategui_en = dateutils.convert_datetext_to_dategui(datetext,
                                                            ln='en')
         self.assertEqual(dategui_en, dategui_en_expected)
 
     def test_convert_good_to_dategui_sk(self):
         """dateutils - conversion of good text date into Slovak GUI date"""
         datetext = "2006-07-16 18:36:01"
         dategui_sk_expected = "16 júl 2006, 18:36"
         dategui_sk = dateutils.convert_datetext_to_dategui(datetext,
                                                            ln='sk')
         self.assertEqual(dategui_sk, dategui_sk_expected)
 
     def test_convert_bad_to_dategui_en(self):
         """dateutils - conversion of bad text date into English GUI date"""
         datetext = "2006-02-AA 18:36:01"
         dategui_sk_expected = "N/A"
         dategui_sk = dateutils.convert_datetext_to_dategui(datetext,
                                                            ln='en')
         self.assertEqual(dategui_sk, dategui_sk_expected)
 
     def test_convert_bad_to_dategui_sk(self):
         """dateutils - conversion of bad text date into Slovak GUI date"""
         datetext = "2006-02-AA 18:36:01"
         dategui_sk_expected = "nepríst."
         dategui_sk = dateutils.convert_datetext_to_dategui(datetext,
                                                            ln='sk')
         self.assertEqual(dategui_sk, dategui_sk_expected)
 
-def create_test_suite():
-    """
-    Return test suite for the dateutils.
-    """
-    return unittest.TestSuite((unittest.makeSuite(ConvertFromDateCVSTest,
-                                                  'test'),
-                               unittest.makeSuite(ConvertIntoDateGUITest,
-                                                 'test')))
+TEST_SUITE = make_test_suite(ConvertFromDateCVSTest,
+                             ConvertIntoDateGUITest,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/miscutil/lib/dbquery_tests.py b/modules/miscutil/lib/dbquery_tests.py
index b4ff474a3..d09f0bc23 100644
--- a/modules/miscutil/lib/dbquery_tests.py
+++ b/modules/miscutil/lib/dbquery_tests.py
@@ -1,96 +1,93 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for dbquery library."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import dbquery
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TableUpdateTimesTest(unittest.TestCase):
     """Test functions related to the update_times of MySQL tables."""
 
     def _check_table_update_time(self, tablename):
         """Helper function to check update time of TABLENAME."""
         # detect MySQL version number:
         res = dbquery.run_sql("SELECT VERSION()")
         mysql_server_version = res[0][0]
         if mysql_server_version.startswith("5."):
             # MySQL-5 provides INFORMATION_SCHEMA:
             query = """SELECT UPDATE_TIME FROM INFORMATION_SCHEMA.TABLES
                         WHERE table_name='%s'""" % tablename
             tablename_update_time = str(dbquery.run_sql(query)[0][0])
         elif mysql_server_version.startswith("4.1"):
             # MySQL-4.1 has it on 12th position:
             query = """SHOW TABLE STATUS LIKE '%s'""" % tablename
             tablename_update_time = str(dbquery.run_sql(query)[0][12])
         elif mysql_server_version.startswith("4.0"):
             # MySQL-4.0 has it on 11th position:
             query = """SHOW TABLE STATUS LIKE '%s'""" % tablename
             tablename_update_time = str(dbquery.run_sql(query)[0][11])
         else:
             tablename_update_time = "MYSQL SERVER VERSION NOT DETECTED"
         # compare it with the one detected by the function:
         self.assertEqual(tablename_update_time,
                          dbquery.get_table_update_time(tablename))
 
     def test_single_table_update_time(self):
         """dbquery - single table (with indexes) update time detection"""
         # NOTE: this tests usual "long" branch of
         # get_table_update_time()
         self._check_table_update_time("collection")
 
     def test_empty_table_update_time(self):
         """dbquery - empty table (no indexes) update time detection"""
         # NOTE: this tests unusual "None" branch of
         # get_table_update_time()
         # create empty test table
         test_table = "tmpTESTTABLE123"
         dbquery.run_sql("CREATE TABLE IF NOT EXISTS %s (a INT)" % test_table)
         # run the test:
         self._check_table_update_time(test_table)
         # drop empty test table
         dbquery.run_sql("DROP TABLE %s" % test_table)
 
     def test_utf8_python_mysqldb_mysql_storage_chain(self):
         """dbquery - UTF-8 in Python<->MySQLdb<->MySQL storage chain"""
         # NOTE: This test test creates, uses and destroys a temporary
         # table called "test__invenio__utf8".
         beta_in_utf8 = "β" # Greek beta in UTF-8 is 0xCEB2
         dbquery.run_sql("CREATE TEMPORARY TABLE test__invenio__utf8 (x char(1), y varbinary(2)) DEFAULT CHARACTER SET utf8")
         dbquery.run_sql("INSERT INTO test__invenio__utf8 (x, y) VALUES (%s, %s)", (beta_in_utf8, beta_in_utf8))
         res = dbquery.run_sql("SELECT x,y,HEX(x),HEX(y),LENGTH(x),LENGTH(y),CHAR_LENGTH(x),CHAR_LENGTH(y) FROM test__invenio__utf8")
         self.assertEqual(res[0],
                          ('\xce\xb2', '\xce\xb2', 'CEB2', 'CEB2', 2L, 2L, 1L, 2L))
         dbquery.run_sql("DROP TEMPORARY TABLE test__invenio__utf8")
 
-def create_test_suite():
-    """Return test suite for the user handling."""
-    return unittest.TestSuite((
-        unittest.makeSuite(TableUpdateTimesTest,'test'),
-        ))
+TEST_SUITE = make_test_suite(TableUpdateTimesTest,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
 
diff --git a/modules/miscutil/lib/errorlib_regression_tests.py b/modules/miscutil/lib/errorlib_regression_tests.py
index 333506536..7744494c2 100644
--- a/modules/miscutil/lib/errorlib_regression_tests.py
+++ b/modules/miscutil/lib/errorlib_regression_tests.py
@@ -1,81 +1,81 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """errorlib Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 import os
 
 from invenio.errorlib import register_exception
 from invenio.config import CFG_SITE_URL, CFG_LOGDIR
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class ErrorlibWebPagesAvailabilityTest(unittest.TestCase):
     """Check errorlib web pages whether they are up or not."""
 
     def test_your_baskets_pages_availability(self):
         """errorlib - availability of error sending pages"""
 
         baseurl = CFG_SITE_URL + '/error/'
 
         _exports = ['', 'send']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
 class ErrorlibRegisterExceptionTest(unittest.TestCase):
     """Check errorlib register_exception functionality."""
 
     def test_simple_register_exception(self):
         """errorlib - simple usage of register_exception"""
         try:
             raise Exception('test-exception')
         except:
             result = register_exception()
         log_content = open(os.path.join(CFG_LOGDIR, 'invenio.err')).read()
         self.failUnless('test_simple_register_exception' in log_content)
         self.failUnless('test-exception' in log_content)
         self.assertEqual(1, result, "register_exception have not returned 1")
 
     def test_alert_admin_register_exception(self):
         """errorlib - alerting admin with register_exception"""
         text = 'test-exception that you should receive by email'
         try:
             raise Exception(text)
         except:
             result = register_exception(alert_admin=True)
         log_content = open(os.path.join(CFG_LOGDIR, 'invenio.err')).read()
         self.failUnless('test_alert_admin_register_exception' in log_content)
         self.failUnless(text in log_content)
         self.assertEqual(1, result, "register_exception have not returned 1")
 
-test_suite = make_test_suite(ErrorlibWebPagesAvailabilityTest,
+TEST_SUITE = make_test_suite(ErrorlibWebPagesAvailabilityTest,
                              ErrorlibRegisterExceptionTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/miscutil/lib/errorlib_tests.py b/modules/miscutil/lib/errorlib_tests.py
index 689efc341..57c1f459f 100644
--- a/modules/miscutil/lib/errorlib_tests.py
+++ b/modules/miscutil/lib/errorlib_tests.py
@@ -1,182 +1,178 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
-## 
+##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.  
+## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """ Test unit for the miscutil/errorlib module. """
 
 __revision__ = "$Id$"
 
 from invenio.errorlib import get_msg_associated_to_code, get_msgs_for_code_list
+from invenio.testutils import make_test_suite, run_test_suite
+
 import unittest
 
 class TestInternalErrorlibErrors(unittest.TestCase):
     """
     Class for testing!
     """
     messages = []
-    
+
     def test_correct_association(self):
         """errorlib - code association: correct code"""
         # correct input
         input_err_code = 'ERR_MISCUTIL_BAD_FILE_ARGUMENT_PASSED'
         (output_err_code, dummy) = get_msg_associated_to_code(input_err_code,
-                                                              'error') 
+                                                              'error')
         self.assertEqual(output_err_code, input_err_code)
 
     def test_no_module(self):
         """errorlib - code association: no <module>_config"""
         # no file module_config
         input_err_code ='ERR_BADMODULEIDENTIFIER_WITH_BAD_ERRORNAME'
         (output_err_code, dummy) = get_msg_associated_to_code(input_err_code,
                                                               'error')
         expected_output_err_code = 'ERR_MISCUTIL_IMPORT_ERROR'
         self.assertEqual(output_err_code, expected_output_err_code)
 
     def test_no_dictionary(self):
         """errorlib - code association: no error dictionary"""
         # file exists, but no dictionary
         input_err_code ='ERR_MISCUTIL_NODICTIONARY'
         (output_err_code, dummy) = get_msg_associated_to_code(input_err_code,
                                                               'nodict')
         expected_output_err_code = 'ERR_MISCUTIL_NO_DICT'
         self.assertEqual(output_err_code, expected_output_err_code)
 
     def test_no_identifier(self):
         """errorlib - code association: no identifier"""
         # identifier not in dictionary
         input_err_code ='ERR_MISCUTIL_IDENTIFIER_WONT_BE_FOUND_IN_DICTIONNARY'
         (output_err_code, dummy) = get_msg_associated_to_code(input_err_code,
                                                               'error')
         expected_output_err_code = 'ERR_MISCUTIL_NO_MESSAGE_IN_DICT'
         self.assertEqual(output_err_code, expected_output_err_code)
-        
+
     def test_not_an_error(self):
         """errorlib - code association: badly named error"""
         # identifier does not begin with ERR or WRN
         input_err_code = 'STRANGEERROR'
         (output_err_code, dummy) = get_msg_associated_to_code(input_err_code,
                                                               'error')
         expected_output_err_code = 'ERR_MISCUTIL_UNDEFINED_ERROR'
         self.assertEqual(output_err_code, expected_output_err_code)
-        
+
     def test_correct_arg_validation(self):
         """errorlib - single argument"""
         # displayable error
         error = 'ERR_MISCUTIL_BAD_FILE_ARGUMENT_PASSED'
         output_list = get_msgs_for_code_list((error, 'junk'))
         self.assertEqual(1, len(output_list))
         self.assertEqual(2, len(output_list[0]))
         self.assertEqual(error, output_list[0][0])
         self.messages.append(output_list[0][1])
 
     def test_correct_args_validation(self):
         """errorlib - multiple errors"""
         # displayable errors
         error = 'ERR_MISCUTIL_BAD_FILE_ARGUMENT_PASSED'
         output_list = get_msgs_for_code_list([(error, 'junk'), (error, 'junk')])
         self.assertEqual(2, len(output_list))
         self.assertEqual(2, len(output_list[0]))
         self.assertEqual(2, len(output_list[1]))
         self.assertEqual(error, output_list[0][0])
         self.assertEqual(error, output_list[1][0])
         # store error message for further tests
         self.messages.append(output_list[0][1])
         self.messages.append(output_list[1][1])
 
     def test_undefined_error(self):
         """errorlib - no underscore in error"""
         # undefined error
         error = 'ERRMISCUTIL'
         expected_error = 'ERR_MISCUTIL_UNDEFINED_ERROR'
         output_list = get_msgs_for_code_list([(error)])
         self.assertEqual(1, len(output_list))
         self.assertEqual(2, len(output_list[0]))
         self.assertEqual(expected_error, output_list[0][0])
         # store error messages for further tests
-        self.messages.append(output_list[0][1])               
+        self.messages.append(output_list[0][1])
 
     def test_too_many_arguments(self):
         """errorlib - arguments: too many arguments"""
         # too many arguments
         error = 'ERR_MISCUTIL_BAD_FILE_ARGUMENT_PASSED'
         other_error = 'ERR_MISCUTIL_TOO_MANY_ARGUMENT'
         output_list = get_msgs_for_code_list([(error, 'junk', 'junk', 'junk')])
         self.assertEqual(2, len(output_list))
         self.assertEqual(2, len(output_list[0]))
         self.assertEqual(2, len(output_list[1]))
         self.assertEqual(error, output_list[0][0])
         self.assertEqual(other_error, output_list[1][0])
         # store error messages for further tests
         self.messages.append(output_list[0][1])
         self.messages.append(output_list[1][1])
 
     def test_too_few_arguments(self):
         """errorlib - arguments: too few arguments"""
         # too few argument
         error = 'ERR_MISCUTIL_BAD_FILE_ARGUMENT_PASSED'
         other_error = 'ERR_MISCUTIL_TOO_FEW_ARGUMENT'
         output_list = get_msgs_for_code_list([(error)])
         self.assertEqual(2, len(output_list))
         self.assertEqual(2, len(output_list[0]))
         self.assertEqual(2, len(output_list[1]))
         self.assertEqual(error, output_list[0][0])
         self.assertEqual(other_error, output_list[1][0])
         # store error messages for further tests
         self.messages.append(output_list[0][1])
         self.messages.append(output_list[1][1])
 
     def test_bad_type(self):
         """errorlib - arguments: bad argument type"""
         # bad argument type
         error = 'ERR_MISCUTIL_DEBUG'
         other_error = 'ERR_MISCUTIL_BAD_ARGUMENT_TYPE'
         output_list = get_msgs_for_code_list([(error, 'should be an int')])
         self.assertEqual(2, len(output_list))
         self.assertEqual(2, len(output_list[0]))
         self.assertEqual(2, len(output_list[1]))
         self.assertEqual(error, output_list[0][0])
         self.assertEqual(other_error, output_list[1][0])
 
     # z because this function must execute lately for more interesting
     # results:
     def test_zsubstitution(self):
         """errorlib - arguments: every argument substituted"""
         # string replacement
         testmessages = reduce(lambda x, y: str(x) + str(y), self.messages)
         self.assertEqual(0, testmessages.count('%') - testmessages.count('%%'))
 
     # z because this function must also execute lately for more
     # interesting results:
     def test_zinternationalization(self):
         """errorlib - internationalization"""
         # string internationalization
         testmessages = reduce(lambda x, y: str(x) + str(y), self.messages)
         self.assertEqual(0, testmessages.count('_('))
-        
-def create_test_suite():
-    """
-    Return test suite for the search engine.
-    """
-    return unittest.TestSuite((unittest.makeSuite(\
-        TestInternalErrorlibErrors, 'test'),
-                               ))
+
+TEST_SUITE = make_test_suite(TestInternalErrorlibErrors,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/miscutil/lib/htmlutils_tests.py b/modules/miscutil/lib/htmlutils_tests.py
index 9c5903cf2..c2d034da3 100644
--- a/modules/miscutil/lib/htmlutils_tests.py
+++ b/modules/miscutil/lib/htmlutils_tests.py
@@ -1,92 +1,89 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.  
+## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for htmlutils library."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import dbquery
 from invenio.htmlutils import HTMLWasher
+from invenio.testutils import make_test_suite, run_test_suite
 
 class XSSEscapingTest(unittest.TestCase):
     """Test functions related to the prevention of XSS attacks."""
-    
+
     def __init__(self, methodName='test'):
         self.washer = HTMLWasher()
         unittest.TestCase.__init__(self, methodName)
-    
+
     def test_forbidden_formatting_tags(self):
         """htmlutils - washing of tags altering formatting of a page (e.g. </html>)"""
         test_str = """</html></body></div></pre>"""
         self.assertEqual(self.washer.wash(html_buffer=test_str),
                          '')
         self.assertEqual(self.washer.wash(html_buffer=test_str,
                                           render_unallowed_tags=True),
                          '&lt;/html&gt;&lt;/body&gt;&lt;/div&gt;&lt;/pre&gt;')
-                         
+
     def test_forbidden_script_tags(self):
         """htmlutils - washing of tags defining scripts (e.g. <script>)"""
         test_str = """<script>malicious_function();</script>"""
         self.assertEqual(self.washer.wash(html_buffer=test_str),
                          'malicious_function();')
         self.assertEqual(self.washer.wash(html_buffer=test_str,
                                           render_unallowed_tags=True),
                          '&lt;script&gt;malicious_function();&lt;/script&gt;')
-    
+
     def test_forbidden_attributes(self):
         """htmlutils - washing of forbidden attributes in allowed tags (e.g. onLoad)"""
         # onload
         test_str = """<p onload="javascript:malicious_functtion();">"""
-        self.assertEqual(self.washer.wash(html_buffer=test_str), '<p>') 
+        self.assertEqual(self.washer.wash(html_buffer=test_str), '<p>')
         # tricky: css calling a javascript
         test_str = """<p style="background: url('http://malicious_site.com/malicious_script.js');">"""
         self.assertEqual(self.washer.wash(html_buffer=test_str), '<p>')
 
     def test_fake_url(self):
         """htmlutils - washing of fake URLs which execute scripts"""
         test_str = """<a href="javascript:malicious_function();">link</a>"""
         self.assertEqual(self.washer.wash(html_buffer=test_str),
                          '<a href="">link</a>')
         # Pirates could encode ascii values, or use uppercase letters...
         test_str = """<a href="&#106;a&#118;asCRi&#112;t:malicious_function();">link</a>"""
         self.assertEqual(self.washer.wash(html_buffer=test_str),
                          '<a href="">link</a>')
         # MSIE treats 'java\ns\ncript:' the same way as 'javascript:'
         # Here we test with:
         # j
         #     avas
         #   crIPt :
         test_str = """<a href="&#106;\n    a&#118;as\n  crI&#80;t :malicious_function();">link</a>"""
         self.assertEqual(self.washer.wash(html_buffer=test_str),
                          '<a href="">link</a>')
-                                 
-def create_test_suite():
-    """Return test suite for the user handling."""
-    return unittest.TestSuite((
-        unittest.makeSuite(XSSEscapingTest,'test'),
-        ))
+
+TEST_SUITE = make_test_suite(XSSEscapingTest,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
 
diff --git a/modules/miscutil/lib/intbitset_tests.py b/modules/miscutil/lib/intbitset_tests.py
index 5e6d26c0b..cb172227b 100644
--- a/modules/miscutil/lib/intbitset_tests.py
+++ b/modules/miscutil/lib/intbitset_tests.py
@@ -1,395 +1,392 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the intbitset data structure."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.intbitset import intbitset
+from invenio.testutils import make_test_suite, run_test_suite
 
 try:
     set()
 except NameError:
     from sets import Set as set
 
 class IntBitSetTest(unittest.TestCase):
     """Test functions related to intbitset data structure."""
     def setUp(self):
         self.sets = [
             [10, 20],
             [10, 40],
             [60, 70],
             [60, 80],
             [10, 20, 60, 70],
             [10, 40, 60, 80],
             [1000],
             [10000],
             [23, 45, 67, 89, 110, 130, 174, 1002, 2132, 23434],
             [700, 2000],
         ]
         self.fncs_list = [
             (intbitset.__and__, set.__and__, int.__and__, False),
             (intbitset.__or__, set.__or__, int.__or__, False),
             (intbitset.__xor__, set.__xor__, int.__xor__, False),
             (intbitset.__sub__, set.__sub__, int.__sub__, False),
             (intbitset.__iand__, set.__iand__, int.__and__, True),
             (intbitset.__ior__, set.__ior__, int.__or__, True),
             (intbitset.__ixor__, set.__ixor__, int.__xor__, True),
             (intbitset.__isub__, set.__isub__, int.__sub__, True),
         ]
 
         self.cmp_list = [
             (intbitset.__eq__, set.__eq__, lambda x, y: cmp(x, y) == 0),
             (intbitset.__ge__, set.__ge__, lambda x, y: cmp(x, y) >= 0),
             (intbitset.__gt__, set.__gt__, lambda x, y: cmp(x, y) > 0),
             (intbitset.__le__, set.__le__, lambda x, y: cmp(x, y) <= 0),
             (intbitset.__lt__, set.__lt__, lambda x, y: cmp(x, y) < 0),
             (intbitset.__ne__, set.__ne__, lambda x, y: cmp(x, y) != 0),
         ]
 
     def _helper_sanity_test(self, intbitset1, msg=''):
         wordbitsize = intbitset1.get_wordbitsize()
         size1 = intbitset1.get_size()
         allocated1 = intbitset1.get_allocated()
         creator_list = intbitset1.extract_finite_list()
         up_to1 = creator_list and max(creator_list) or -1
         self.failUnless(up_to1 <= size1 * wordbitsize < allocated1 * wordbitsize, "up_to1=%s, size1=%s, allocated1=%s while testing %s during %s" % (up_to1, size1 * wordbitsize, allocated1 * wordbitsize, intbitset1, msg))
         tmp = intbitset(intbitset1.fastdump())
         size2 = tmp.get_size()
         allocated2 = tmp.get_allocated()
         creator_list = tmp.extract_finite_list()
         up_to2 = creator_list and max(creator_list) or -1
         self.failUnless(up_to2 <= size2 * wordbitsize < allocated2 * wordbitsize, "After serialization up_to2=%s, size2=%s, allocated2=%s while testing %s during %s" % (up_to2, size2 * wordbitsize, allocated2 * wordbitsize, intbitset1, msg))
 
 
     def _helper_test_via_fncs_list(self, fncs, intbitset1, intbitset2):
         orig1 = intbitset(intbitset1)
         orig2 = intbitset(intbitset2)
 
         msg = "Testing %s(%s, %s)" % (fncs[0].__name__, repr(intbitset1), repr(intbitset2))
 
         trailing1 = intbitset1.is_infinite()
         trailing2 = intbitset2.is_infinite()
 
         if fncs[3]:
             fncs[0](intbitset1, intbitset2)
             trailing1 = fncs[2](trailing1, trailing2) > 0
             up_to = intbitset1.extract_finite_list() and max(intbitset1.extract_finite_list()) or -1
         else:
             intbitset3 = fncs[0](intbitset1, intbitset2)
             trailing3 = fncs[2](trailing1, trailing2) > 0
             up_to = intbitset3.extract_finite_list() and max(intbitset3.extract_finite_list()) or -1
 
         set1 = set(orig1.extract_finite_list(up_to))
         set2 = set(orig2.extract_finite_list(up_to))
 
         if fncs[3]:
             fncs[1](set1, set2)
         else:
             set3 = fncs[1](set1, set2)
 
         self._helper_sanity_test(intbitset1, msg)
         self._helper_sanity_test(intbitset2, msg)
 
         if fncs[3]:
             self.assertEqual(set1 & set(intbitset1.extract_finite_list(up_to)), set(intbitset1.extract_finite_list(up_to)), "%s not equal to %s after executing %s(%s, %s)" % (set1, set(intbitset1.extract_finite_list(up_to)), fncs[0].__name__, repr(orig1), repr(orig2)))
             self.assertEqual(set1 | set(intbitset1.extract_finite_list(up_to)), set1, "%s not equal to %s after executing %s(%s, %s)" % (set1, set(intbitset1.extract_finite_list(up_to)), fncs[0].__name__, repr(orig1), repr(orig2)))
             self.assertEqual(trailing1, intbitset1.is_infinite(), "%s is not %s as it is supposed to be after executing %s(%s, %s)" % (intbitset1, trailing1 and 'infinite' or 'finite', fncs[0].__name__, repr(orig1), repr(orig2)))
         else:
             self._helper_sanity_test(intbitset3, msg)
             self.assertEqual(set3 & set(intbitset3.extract_finite_list(up_to)), set(intbitset3.extract_finite_list(up_to)), "%s not equal to %s after executing %s(%s, %s)" % (set3, set(intbitset3.extract_finite_list(up_to)), fncs[0].__name__, repr(orig1), repr(orig2)))
             self.assertEqual(set3 | set(intbitset3.extract_finite_list(up_to)), set3, "%s not equal to %s after executing %s(%s, %s)" % (set3, set(intbitset3.extract_finite_list(up_to)), fncs[0].__name__, repr(orig1), repr(orig2)))
             self.assertEqual(trailing3, intbitset3.is_infinite(), "%s is not %s as it is supposed to be after executing %s(%s, %s)" % (intbitset3, trailing3 and 'infinite' or 'finite', fncs[0].__name__, repr(orig1), repr(orig2)))
 
 
     def _helper_test_normal_set(self, fncs):
         for set1 in self.sets:
             for set2 in self.sets:
                 self._helper_test_via_fncs_list(fncs, intbitset(set1), intbitset(set2))
 
     def _helper_test_empty_set(self, fncs):
         for set1 in self.sets:
             self._helper_test_via_fncs_list(fncs, intbitset(set1), intbitset([]))
             self._helper_test_via_fncs_list(fncs, intbitset([]), intbitset(set1))
         self._helper_test_via_fncs_list(fncs, intbitset([]), intbitset([]))
 
     def _helper_test_inifinite_set(self, fncs):
         for set1 in self.sets:
             for set2 in self.sets:
                 self._helper_test_via_fncs_list(fncs, intbitset(set1), intbitset(set2, trailing_bits=True))
                 self._helper_test_via_fncs_list(fncs, intbitset(set1, trailing_bits=True), intbitset(set2))
                 self._helper_test_via_fncs_list(fncs, intbitset(set1, trailing_bits=True), intbitset(set2, trailing_bits=True))
 
     def _helper_test_infinite_vs_empty(self, fncs):
         for set1 in self.sets:
             self._helper_test_via_fncs_list(fncs, intbitset(set1, trailing_bits=True), intbitset([]))
             self._helper_test_via_fncs_list(fncs, intbitset([]), intbitset(set1, trailing_bits=True))
         self._helper_test_via_fncs_list(fncs, intbitset([]), intbitset(trailing_bits=True))
         self._helper_test_via_fncs_list(fncs, intbitset(trailing_bits=True), intbitset([]))
 
 
     def test_set_intersection(self):
         """intbitset - set intersection, normal set"""
         self._helper_test_normal_set(self.fncs_list[0])
 
     def test_set_intersection_empty(self):
         """intbitset - set intersection, empty set"""
         self._helper_test_empty_set(self.fncs_list[0])
 
     def test_set_intersection_infinite(self):
         """intbitset - set intersection, infinite set"""
         self._helper_test_inifinite_set(self.fncs_list[0])
 
     def test_set_intersection_infinite_empty(self):
         """intbitset - set intersection, infinite vs empty"""
         self._helper_test_infinite_vs_empty(self.fncs_list[0])
 
     def test_set_union(self):
         """intbitset - set union, normal set"""
         self._helper_test_normal_set(self.fncs_list[1])
 
     def test_set_union_empty(self):
         """intbitset - set union, empty set"""
         self._helper_test_empty_set(self.fncs_list[1])
 
     def test_set_union_infinite(self):
         """intbitset - set union, infinite set"""
         self._helper_test_inifinite_set(self.fncs_list[1])
 
     def test_set_union_infinite_empty(self):
         """intbitset - set union, infinite vs empty"""
         self._helper_test_infinite_vs_empty(self.fncs_list[1])
 
     def test_set_symmetric_difference(self):
         """intbitset - set symmetric difference, normal set"""
         self._helper_test_normal_set(self.fncs_list[2])
 
     def test_set_symmetric_difference_empty(self):
         """intbitset - set symmetric difference, empty set"""
         self._helper_test_empty_set(self.fncs_list[2])
 
     def test_set_symmetric_difference_infinite(self):
         """intbitset - set symmetric difference, infinite set"""
         self._helper_test_inifinite_set(self.fncs_list[2])
 
     def test_set_symmetric_difference_infinite_empty(self):
         """intbitset - set symmetric difference, infinite vs empty"""
         self._helper_test_infinite_vs_empty(self.fncs_list[2])
 
     def test_set_difference(self):
         """intbitset - set difference, normal set"""
         self._helper_test_normal_set(self.fncs_list[3])
 
     def test_set_difference_empty(self):
         """intbitset - set difference, empty set"""
         self._helper_test_empty_set(self.fncs_list[3])
 
     def test_set_difference_infinite(self):
         """intbitset - set difference, infinite set"""
         self._helper_test_inifinite_set(self.fncs_list[3])
 
     def test_set_difference_infinite_empty(self):
         """intbitset - set difference, infinite vs empty"""
         self._helper_test_infinite_vs_empty(self.fncs_list[3])
 
     def test_set_intersection_in_place(self):
         """intbitset - set intersection, normal set in place"""
         self._helper_test_normal_set(self.fncs_list[4])
 
     def test_set_intersection_empty_in_place(self):
         """intbitset - set intersection, empty set in place"""
         self._helper_test_empty_set(self.fncs_list[4])
 
     def test_set_intersection_infinite_in_place(self):
         """intbitset - set intersection, infinite set in place"""
         self._helper_test_inifinite_set(self.fncs_list[4])
 
     def test_set_intersection_infinite_empty_in_place(self):
         """intbitset - set intersection, infinite vs empty in place"""
         self._helper_test_infinite_vs_empty(self.fncs_list[4])
 
     def test_set_union_in_place(self):
         """intbitset - set union, normal set in place"""
         self._helper_test_normal_set(self.fncs_list[5])
 
     def test_set_union_empty_in_place(self):
         """intbitset - set union, empty set in place"""
         self._helper_test_empty_set(self.fncs_list[5])
 
     def test_set_union_infinite_in_place(self):
         """intbitset - set union, infinite set in place"""
         self._helper_test_inifinite_set(self.fncs_list[5])
 
     def test_set_union_infinite_empty_in_place(self):
         """intbitset - set union, infinite vs empty in place"""
         self._helper_test_infinite_vs_empty(self.fncs_list[5])
 
     def test_set_symmetric_difference_in_place(self):
         """intbitset - set symmetric difference, normal set in place"""
         self._helper_test_normal_set(self.fncs_list[6])
 
     def test_set_symmetric_difference_empty_in_place(self):
         """intbitset - set symmetric difference, empty set in place"""
         self._helper_test_empty_set(self.fncs_list[6])
 
     def test_set_symmetric_difference_infinite_in_place(self):
         """intbitset - set symmetric difference, infinite set in place"""
         self._helper_test_inifinite_set(self.fncs_list[6])
 
     def test_set_symmetric_difference_infinite_empty_in_place(self):
         """intbitset - set symmetric difference, infinite vs empty in place"""
         self._helper_test_infinite_vs_empty(self.fncs_list[6])
 
     def test_set_difference_in_place(self):
         """intbitset - set difference, normal set in place"""
         self._helper_test_normal_set(self.fncs_list[7])
 
     def test_set_difference_empty_in_place(self):
         """intbitset - set difference, empty set in place"""
         self._helper_test_empty_set(self.fncs_list[7])
 
     def test_set_difference_infinite_in_place(self):
         """intbitset - set difference, infinite set in place"""
         self._helper_test_inifinite_set(self.fncs_list[7])
 
     def test_set_difference_infinite_empty_in_place(self):
         """intbitset - set difference, infinite vs empty in place"""
         self._helper_test_infinite_vs_empty(self.fncs_list[7])
 
     def test_list_dump(self):
         """intbitset - list dump"""
         for set1 in self.sets + [[]]:
             self.assertEqual(list(intbitset(set1)), set1)
 
     def test_ascii_bit_dump(self):
         """intbitset - ascii bit dump"""
         for set1 in self.sets + [[]]:
             tot = 0
             count = 0
             for bit in intbitset(set1).strbits():
                 if bit == '0':
                     self.failIf(count in set1)
                 elif bit == '1':
                     self.failIf(count not in set1)
                     tot += 1
                 else:
                     self.fail()
                 count += 1
             self.assertEqual(tot, len(set1))
 
     def test_tuple_of_tuples(self):
         """intbitset - support tuple of tuples"""
         for set1 in self.sets + [[]]:
             tmp_tuple = tuple([(elem, ) for elem in set1])
             self.assertEqual(list(intbitset(set1)), list(intbitset(tmp_tuple)))
         for set1 in self.sets + [[]]:
             tmp_tuple = tuple([(elem, ) for elem in set1])
             self.assertEqual(intbitset(set1, trailing_bits=True), intbitset(tmp_tuple, trailing_bits=True))
 
     def test_marshalling(self):
         """intbitset - marshalling"""
         for set1 in self.sets + [[]]:
             self.assertEqual(intbitset(set1), intbitset().fastload((intbitset(set1).fastdump())))
         for set1 in self.sets + [[]]:
             self.assertEqual(intbitset(set1, trailing_bits=True), intbitset().fastload(intbitset(set1, trailing_bits=True).fastdump()))
         for set1 in self.sets + [[]]:
             self.assertEqual(intbitset(set1), intbitset().fastload((intbitset(set1).fastdump())))
         for set1 in self.sets + [[]]:
             self.assertEqual(intbitset(set1, trailing_bits=True), intbitset().fastload(intbitset(set1, trailing_bits=True).fastdump()))
 
     #def test_set_emptiness(self):
         #"""intbitset - tests for emptiness"""
         #map(lambda x, y: self.assertEqual(x.__nonzero__(), y, "%s is %s empty" % (x, not y and 'not' or '')), self.sets. self.emptiness)
 
     def test_set_clear(self):
         """intbitset - clearing"""
         for set1 in self.sets + [[]]:
             intbitset1 = intbitset(set1)
             intbitset1.clear()
             self.assertEqual(list(intbitset1), [])
             intbitset1 = intbitset(set1, trailing_bits=True)
             intbitset1.clear()
             self.assertEqual(list(intbitset1), [])
 
     def test_set_repr(self):
         """intbitset - Pythonic representation"""
         for set1 in self.sets + [[]]:
             intbitset1 = intbitset(set1)
             self.assertEqual(intbitset1, eval(repr(intbitset1)))
         for set1 in self.sets + [[]]:
             intbitset1 = intbitset(set1, trailing_bits=True)
             self.assertEqual(intbitset1, eval(repr(intbitset1)))
 
     def test_set_cmp(self):
         """intbitset - (non infinte) set comparison"""
         for set1 in self.sets + [[]]:
             for set2 in self.sets + [[]]:
                 for op in self.cmp_list:
                     self.assertEqual(op[0](intbitset(set1), intbitset(set2)), op[1](set(set1), set(set2)), "Error in comparing %s %s with comparing function %s" % (set1, set2, op[0].__name__))
 
 
     def test_set_update_with_signs(self):
         """intbitset - set update with signs"""
         dict1 = {10 : -1, 20 : 1, 23 : -1, 27 : 1, 33 : -1, 56 : 1, 70 : -1, 74 : 1}
         for set1 in self.sets + [[]]:
             intbitset1 = intbitset(set1)
             intbitset1.update_with_signs(dict1)
             up_to = max(dict1.keys() + set1)
             for i in xrange(up_to + 1):
                 if dict1.get(i, i in set1 and 1 or -1) == 1:
                     self.failUnless(i in intbitset1, "%s was not correctly updated from %s by %s" % (repr(intbitset1), repr(set1), repr(dict1)))
                 else:
                     self.failIf(i in intbitset1, "%s was not correctly updated from %s by %s" % (repr(intbitset1), repr(set1), repr(dict1)))
 
     def test_set_cloning(self):
         """intbitset - set cloning"""
         import copy
         for set1 in self.sets + [[]]:
             intbitset1 = intbitset(set1)
             intbitset2 = intbitset(intbitset1)
             intbitset3 = copy.deepcopy(intbitset2)
             self._helper_sanity_test(intbitset1)
             self._helper_sanity_test(intbitset2)
             self._helper_sanity_test(intbitset3)
             self.assertEqual(intbitset1, intbitset2)
             self.assertEqual(intbitset1, intbitset3)
 
         for set1 in self.sets + [[]]:
             intbitset1 = intbitset(set1, trailing_bits=True)
             intbitset2 = intbitset(intbitset1)
             intbitset3 = copy.deepcopy(intbitset2)
             self._helper_sanity_test(intbitset1)
             self._helper_sanity_test(intbitset2)
             self._helper_sanity_test(intbitset3)
             self.assertEqual(intbitset1, intbitset2)
             self.assertEqual(intbitset1, intbitset3)
 
-def create_test_suite():
-    """Return test suite for the intbitset data structure."""
-    return unittest.TestSuite((
-        unittest.makeSuite(IntBitSetTest, 'test'),
-        ))
+TEST_SUITE = make_test_suite(IntBitSetTest,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
diff --git a/modules/miscutil/lib/inveniocfg.py b/modules/miscutil/lib/inveniocfg.py
index cccda2eae..46d84df6a 100644
--- a/modules/miscutil/lib/inveniocfg.py
+++ b/modules/miscutil/lib/inveniocfg.py
@@ -1,957 +1,954 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """
 Invenio configuration and administration CLI tool.
 
 Usage: inveniocfg [options]
 
 General options:
    -h, --help               print this help
    -V, --version            print version number
 
 Options to finish your installation:
    --create-apache-conf     create Apache configuration files
    --create-tables          create DB tables for Invenio
    --drop-tables            drop DB tables of Invenio
 
 Options to set up and test a demo site:
    --create-demo-site       create demo site
    --load-demo-records      load demo records
    --remove-demo-records    remove demo records, keeping demo site
    --drop-demo-site         drop demo site configurations too
    --run-unit-tests         run unit test suite (need DB connectivity)
    --run-regression-tests   run regression test suite (need demo site)
 
 Options to update config files in situ:
    --update-all             perform all the update options
    --update-config-py       update config.py file from invenio.conf file
    --update-dbquery-py      update dbquery.py with DB credentials from invenio.conf
    --update-dbexec          update dbexec with DB credentials from invenio.conf
    --update-bibconvert-tpl  update bibconvert templates with CFG_SITE_URL from invenio.conf
 
 Options to update DB tables:
    --reset-all              perform all the reset options
    --reset-sitename         reset tables to take account of new CFG_SITE_NAME*
    --reset-siteadminemail   reset tables to take account of new CFG_SITE_ADMIN_EMAIL
    --reset-fieldnames       reset tables to take account of new I18N names from PO files
 
 Options to help the work:
    --list                   print names and values of all options from conf files
    --get <some-opt>         get value of a given option from conf files
    --conf-dir </some/path>  path to directory where invenio*.conf files are [optional]
    --detect-system-details  print system details such as Apache/Python/MySQL versions
 """
 
 __revision__ = "$Id$"
 
 from ConfigParser import ConfigParser
 import os
 import re
 import shutil
 import socket
 import sys
 import tempfile
 
 def print_usage():
     """Print help."""
     print __doc__
 
 def print_version():
     """Print version information."""
     print __revision__
 
 def run_command(cmd):
     """
     Run operating system command CMD (assumed to be washed already)
     and return tuple (exit status code, out stream, err stream).
     """
     cmd_out = ''
     cmd_err = ''
     file_cmd_out = tempfile.mkstemp("inveniocfg-cmd-out")[1]
     file_cmd_err = tempfile.mkstemp("inveniocfg-cmd-err")[1]
     cmd_exit_code = os.system("%s > %s 2> %s" % (cmd,
                                                  file_cmd_out,
                                                  file_cmd_err))
     if os.path.exists(file_cmd_out):
         cmd_out = open(file_cmd_out).read()
         os.remove(file_cmd_out)
     if os.path.exists(file_cmd_err):
         cmd_err = open(file_cmd_err).read()
         os.remove(file_cmd_err)
     return cmd_exit_code, cmd_out, cmd_err
 
 def convert_conf_option(option_name, option_value):
     """
     Convert conf option into Python config.py line, converting
     values to ints or strings as appropriate.
     """
 
     ## 1) convert option name to uppercase:
     option_name = option_name.upper()
 
     ## 2) convert option value to int or string:
     try:
         option_value = int(option_value)
     except ValueError:
         option_value = '"' + option_value + '"'
 
     ## 3a) special cases: regexps
     if option_name in ['CFG_BIBINDEX_CHARS_ALPHANUMERIC_SEPARATORS',
                        'CFG_BIBINDEX_CHARS_PUNCTUATION']:
         option_value = 'r"[' + option_value[1:-1] + ']"'
 
     ## 3b) special cases: True, False, None
     if option_value in ['"True"', '"False"', '"None"']:
         option_value = option_value[1:-1]
 
     ## 3c) special cases: dicts or lists
     if option_name in ['CFG_WEBSEARCH_FIELDS_CONVERT',
                        'CFG_WEBSEARCH_USE_JSMATH_FOR_FORMATS',
                        'CFG_WEBSUBMIT_ADDITIONAL_KNOWN_FILE_EXTENSIONS']:
         option_value = option_value[1:-1]
 
     ## 3d) special cases: CFG_SITE_LANGS
     if option_name == 'CFG_SITE_LANGS':
         out = "["
         for lang in option_value[1:-1].split(","):
             out += "'%s', " % lang
         out += "]"
         option_value = out
 
     ## 3e) special cases: multiline
     if option_name == 'CFG_OAI_IDENTIFY_DESCRIPTION':
         # make triple quotes
         option_value = '""' + option_value + '""'
 
     ## 3f) ignore some options:
     if option_name == 'CFG_SITE_NAME_INTL':
         # treated elsewhere
         return
 
     ## 4) finally, return output line:
     return '%s = %s' % (option_name, option_value)
 
 def cli_cmd_update_config_py(conf):
     """
     Update new config.py from conf options, keeping previous
     config.py in a backup copy.
     """
     print ">>> Going to update config.py..."
     ## location where config.py is:
     configpyfile = conf.get("Invenio", "CFG_PYLIBDIR") + \
                    os.sep + 'invenio' + os.sep + 'config.py'
     ## backup current config.py file:
     if os.path.exists(configpyfile):
         shutil.copy(configpyfile, configpyfile + '.OLD')
     ## here we go:
     fdesc = open(configpyfile, 'w')
     ## generate preamble:
     fdesc.write("# -*- coding: utf-8 -*-\n")
     fdesc.write("# DO NOT EDIT THIS FILE!  IT WAS AUTOMATICALLY GENERATED\n")
     fdesc.write("# FROM INVENIO.CONF BY EXECUTING:\n")
     fdesc.write("# " + " ".join(sys.argv) + "\n")
     ## special treatment for CFG_SITE_NAME_INTL options:
     fdesc.write("CFG_SITE_NAME_INTL = {}\n")
     for lang in conf.get("Invenio", "CFG_SITE_LANGS").split(","):
         fdesc.write("CFG_SITE_NAME_INTL['%s'] = \"%s\"\n" % (lang, conf.get("Invenio",
                                                                             "CFG_SITE_NAME_INTL_" + lang)))
     ## process all the options normally:
     for section in conf.sections():
         for option in conf.options(section):
             if not option.startswith('CFG_DATABASE_'):
                 # put all options except for db credentials into config.py
                 line_out = convert_conf_option(option, conf.get(section, option))
                 if line_out:
                     fdesc.write(line_out + "\n")
     ## generate postamble:
     fdesc.write("")
     fdesc.write("# END OF GENERATED FILE")
     ## we are done:
     fdesc.close()
     print "You may want to restart Apache now."
     print ">>> config.py updated successfully."
 
 def cli_cmd_update_dbquery_py(conf):
     """
     Update lib/dbquery.py file with DB parameters read from conf file.
     Note: this edits dbquery.py in situ, taking a backup first.
     Use only when you know what you are doing.
     """
     print ">>> Going to update dbquery.py..."
     ## location where dbquery.py is:
     dbquerypyfile = conf.get("Invenio", "CFG_PYLIBDIR") + \
                     os.sep + 'invenio' + os.sep + 'dbquery.py'
     ## backup current dbquery.py file:
     if os.path.exists(dbquerypyfile):
         shutil.copy(dbquerypyfile, dbquerypyfile + '.OLD')
     ## replace db parameters:
     out = ''
     for line in open(dbquerypyfile, 'r').readlines():
         match = re.search(r'^CFG_DATABASE_(HOST|NAME|USER|PASS)(\s*=\s*)\'.*\'$', line)
         if match:
             dbparam = 'CFG_DATABASE_' + match.group(1)
             out += "%s%s'%s'\n" % (dbparam, match.group(2),
                                    conf.get('Invenio', dbparam))
         else:
             out += line
     fdesc = open(dbquerypyfile, 'w')
     fdesc.write(out)
     fdesc.close()
     print "You may want to restart Apache now."
     print ">>> dbquery.py updated successfully."
 
 def cli_cmd_update_dbexec(conf):
     """
     Update bin/dbexec file with DB parameters read from conf file.
     Note: this edits dbexec in situ, taking a backup first.
     Use only when you know what you are doing.
     """
     print ">>> Going to update dbexec..."
     ## location where dbexec is:
     dbexecfile = conf.get("Invenio", "CFG_BINDIR") + \
                     os.sep + 'dbexec'
     ## backup current dbexec file:
     if os.path.exists(dbexecfile):
         shutil.copy(dbexecfile, dbexecfile + '.OLD')
     ## replace db parameters via sed:
     out = ''
     for line in open(dbexecfile, 'r').readlines():
         match = re.search(r'^CFG_DATABASE_(HOST|NAME|USER|PASS)(\s*=\s*)\'.*\'$', line)
         if match:
             dbparam = 'CFG_DATABASE_' + match.group(1)
             out += "%s%s'%s'\n" % (dbparam, match.group(2),
                                    conf.get("Invenio", dbparam))
         else:
             out += line
     fdesc = open(dbexecfile, 'w')
     fdesc.write(out)
     fdesc.close()
     print ">>> dbexec updated successfully."
 
 def cli_cmd_update_bibconvert_tpl(conf):
     """
     Update bibconvert/config/*.tpl files looking for 856
     http://.../record/ lines, replacing URL with CDSWEB taken from
     conf file.  Note: this edits tpl files in situ, taking a
     backup first.  Use only when you know what you are doing.
     """
     print ">>> Going to update bibconvert templates..."
     ## location where bibconvert/config/*.tpl are:
     tpldir = conf.get("Invenio", 'CFG_ETCDIR') + \
              os.sep + 'bibconvert' + os.sep + 'config'
     ## find all *.tpl files:
     for tplfilename in os.listdir(tpldir):
         if tplfilename.endswith(".tpl"):
             ## change tpl file:
             tplfile = tpldir + os.sep + tplfilename
             shutil.copy(tplfile, tplfile + '.OLD')
             out = ''
             for line in open(tplfile, 'r').readlines():
                 match = re.search(r'^(.*)http://.*?/record/(.*)$', line)
                 if match:
                     out += "%s%s/record/%s\n" % (match.group(1),
                                                  conf.get("Invenio", 'CFG_SITE_URL'),
                                                  match.group(2))
                 else:
                     out += line
             fdesc = open(tplfile, 'w')
             fdesc.write(out)
             fdesc.close()
     print ">>> bibconvert templates updated successfully."
 
 def cli_cmd_reset_sitename(conf):
     """
     Reset collection-related tables with new CFG_SITE_NAME and
     CFG_SITE_NAME_INTL* read from conf files.
     """
     print ">>> Going to reset CFG_SITE_NAME and CFG_SITE_NAME_INTL..."
     from invenio.dbquery import run_sql, IntegrityError
     # reset CFG_SITE_NAME:
     sitename = conf.get("Invenio", "CFG_SITE_NAME")
     try:
         run_sql("""INSERT INTO collection (id, name, dbquery, reclist, restricted) VALUES
                                           (1,%s,NULL,NULL,NULL)""", (sitename,))
     except IntegrityError:
         run_sql("""UPDATE collection SET name=%s WHERE id=1""", (sitename,))
     # reset CFG_SITE_NAME_INTL:
     for lang in conf.get("Invenio", "CFG_SITE_LANGS").split(","):
         sitename_lang = conf.get("Invenio", "CFG_SITE_NAME_INTL_" + lang)
         try:
             run_sql("""INSERT INTO collectionname (id_collection, ln, type, value) VALUES
                          (%s,%s,%s,%s)""", (1, lang, 'ln', sitename_lang))
         except IntegrityError:
             run_sql("""UPDATE collectionname SET value=%s
                         WHERE ln=%s AND id_collection=1 AND type='ln'""",
                     (sitename_lang, lang))
     print "You may want to restart Apache now."
     print ">>> CFG_SITE_NAME and CFG_SITE_NAME_INTL* reset successfully."
 
 def cli_cmd_reset_siteadminemail(conf):
     """
     Reset user-related tables with new CFG_SITE_ADMIN_EMAIL read from conf files.
     """
     print ">>> Going to reset CFG_SITE_ADMIN_EMAIL..."
     from invenio.dbquery import run_sql
     siteadminemail = conf.get("Invenio", "CFG_SITE_ADMIN_EMAIL")
     run_sql("DELETE FROM user WHERE id=1")
     run_sql("""INSERT INTO user (id, email, password, note, nickname) VALUES
                         (1, %s, AES_ENCRYPT(email, ''), 1, 'admin')""",
             (siteadminemail,))
     print "You may want to restart Apache now."
     print ">>> CFG_SITE_ADMIN_EMAIL reset successfully."
 
 def cli_cmd_reset_fieldnames(conf):
     """
     Reset I18N field names such as author, title, etc and other I18N
     ranking method names such as word similarity.  Their translations
     are taken from the PO files.
     """
     print ">>> Going to reset I18N field names..."
     from invenio.messages import gettext_set_language, language_list_long
     from invenio.dbquery import run_sql, IntegrityError
 
     ## get field id and name list:
     field_id_name_list = run_sql("SELECT id, name FROM field")
     ## get rankmethod id and name list:
     rankmethod_id_name_list = run_sql("SELECT id, name FROM rnkMETHOD")
     ## update names for every language:
     for lang, dummy in language_list_long():
         _ = gettext_set_language(lang)
         ## this list is put here in order for PO system to pick names
         ## suitable for translation
         field_name_names = {"any field": _("any field"),
                             "title": _("title"),
                             "author": _("author"),
                             "abstract": _("abstract"),
                             "keyword": _("keyword"),
                             "report number": _("report number"),
                             "subject": _("subject"),
                             "reference": _("reference"),
                             "fulltext": _("fulltext"),
                             "collection": _("collection"),
                             "division": _("division"),
                             "year": _("year"),
                             "experiment": _("experiment"),
                             "record ID": _("record ID")}
         ## update I18N names for every language:
         for (field_id, field_name) in field_id_name_list:
             if field_name_names.has_key(field_name):
                 try:
                     run_sql("""INSERT INTO fieldname (id_field,ln,type,value) VALUES
                                 (%s,%s,%s,%s)""", (field_id, lang, 'ln',
                                                 field_name_names[field_name]))
                 except IntegrityError:
                     run_sql("""UPDATE fieldname SET value=%s
                                 WHERE id_field=%s AND ln=%s AND type=%s""",
                             (field_name_names[field_name], field_id, lang, 'ln',))
         ## ditto for rank methods:
         rankmethod_name_names = {"wrd": _("word similarity"),
                                  "demo_jif": _("journal impact factor"),
                                  "citation": _("times cited"),}
         for (rankmethod_id, rankmethod_name) in rankmethod_id_name_list:
             try:
                 run_sql("""INSERT INTO rnkMETHODNAME (id_rnkMETHOD,ln,type,value) VALUES
                             (%s,%s,%s,%s)""", (rankmethod_id, lang, 'ln',
                                                rankmethod_name_names[rankmethod_name]))
             except IntegrityError:
                 run_sql("""UPDATE rnkMETHODNAME SET value=%s
                             WHERE id_rnkMETHOD=%s AND ln=%s AND type=%s""",
                         (rankmethod_name_names[rankmethod_name], rankmethod_id, lang, 'ln',))
 
     print ">>> I18N field names reset successfully."
 
 def test_db_connection():
     """
     Test DB connection, and if fails, advise user how to set it up.
     Useful to be called during table creation.
     """
     print "Testing DB connection...",
     from invenio.textutils import wrap_text_in_a_box
     from invenio.dbquery import run_sql, Error
 
     ## first, test connection to the DB server:
     try:
         run_sql("SHOW TABLES")
     except Error, err:
         from invenio.dbquery import CFG_DATABASE_HOST, CFG_DATABASE_NAME, \
              CFG_DATABASE_USER, CFG_DATABASE_PASS
         print wrap_text_in_a_box("""\
 DATABASE CONNECTIVITY ERROR %(errno)d: %(errmsg)s.\n
 
 Perhaps you need to set up database and connection rights?
 If yes, then please login as MySQL admin user and run the
 following commands now:
 
 
 $ mysql -h %(dbhost)s -u root -p mysql
 
 mysql> CREATE DATABASE %(dbname)s DEFAULT CHARACTER SET utf8;
 
 mysql> GRANT ALL PRIVILEGES ON %(dbname)s.*
 
        TO %(dbuser)s@%(webhost)s IDENTIFIED BY '%(dbpass)s';
 
 mysql> QUIT
 
 
 The values printed above were detected from your configuration.
 If they are not right, then please edit your invenio.conf file
 and rerun 'inveniocfg --update-all' first.
 
 
 If the problem is of different nature, then please inspect
 the above error message and fix the problem before continuing.""" % \
                                  {'errno': err.args[0],
                                   'errmsg': err.args[1],
                                   'dbname': CFG_DATABASE_NAME,
                                   'dbhost': CFG_DATABASE_HOST,
                                   'dbuser': CFG_DATABASE_USER,
                                   'dbpass': CFG_DATABASE_PASS,
                                   'webhost': CFG_DATABASE_HOST == 'localhost' and 'localhost' or os.popen('hostname -f', 'r').read().strip(),
                                   })
         sys.exit(1)
     print "ok"
 
     ## second, test insert/select of a Unicode string to detect
     ## possible Python/MySQL/MySQLdb mis-setup:
     print "Testing Python/MySQL/MySQLdb UTF-8 chain...",
     try:
         beta_in_utf8 = "β" # Greek beta in UTF-8 is 0xCEB2
         run_sql("CREATE TEMPORARY TABLE test__invenio__utf8 (x char(1), y varbinary(2)) DEFAULT CHARACTER SET utf8")
         run_sql("INSERT INTO test__invenio__utf8 (x, y) VALUES (%s, %s)", (beta_in_utf8, beta_in_utf8))
         res = run_sql("SELECT x,y,HEX(x),HEX(y),LENGTH(x),LENGTH(y),CHAR_LENGTH(x),CHAR_LENGTH(y) FROM test__invenio__utf8")
         assert res[0] == ('\xce\xb2', '\xce\xb2', 'CEB2', 'CEB2', 2L, 2L, 1L, 2L)
         run_sql("DROP TEMPORARY TABLE test__invenio__utf8")
     except Exception, err:
         print wrap_text_in_a_box("""\
 DATABASE RELATED ERROR %s\n
 
 A problem was detected with the UTF-8 treatment in the chain
 between the Python application, the MySQLdb connector, and
 the MySQL database. You may perhaps have installed older
 versions of some prerequisite packages?\n
 
 Please check the INSTALL file and please fix this problem
 before continuing.""" % err)
 
         sys.exit(1)
     print "ok"
 
 def cli_cmd_create_tables(conf):
     """Create and fill Invenio DB tables.  Useful for the installation process."""
     print ">>> Going to create and fill tables..."
     from invenio.config import CFG_PREFIX
     test_db_connection()
     for cmd in ["%s/bin/dbexec < %s/lib/sql/invenio/tabcreate.sql" % (CFG_PREFIX, CFG_PREFIX),
                 "%s/bin/dbexec < %s/lib/sql/invenio/tabfill.sql" % (CFG_PREFIX, CFG_PREFIX)]:
         if os.system(cmd):
             print "ERROR: failed execution of", cmd
             sys.exit(1)
     cli_cmd_reset_sitename(conf)
     cli_cmd_reset_siteadminemail(conf)
     cli_cmd_reset_fieldnames(conf)
     for cmd in ["%s/bin/webaccessadmin -u admin -c -a" % CFG_PREFIX]:
         if os.system(cmd):
             print "ERROR: failed execution of", cmd
             sys.exit(1)
     print ">>> Tables created and filled successfully."
 
 def cli_cmd_drop_tables(conf):
     """Drop Invenio DB tables.  Useful for the uninstallation process."""
     print ">>> Going to drop tables..."
     from invenio.config import CFG_PREFIX
     from invenio.textutils import wrap_text_in_a_box, wait_for_user
     if '--yes-i-know' not in sys.argv:
         wait_for_user(wrap_text_in_a_box("""\
 WARNING: You are going to destroy your database tables!\n
 
 Press Ctrl-C if you want to abort this action.\n
 Press ENTER to proceed with this action."""))
     cmd = "%s/bin/dbexec < %s/lib/sql/invenio/tabdrop.sql" % (CFG_PREFIX, CFG_PREFIX)
     if os.system(cmd):
         print "ERROR: failed execution of", cmd
         sys.exit(1)
     print ">>> Tables dropped successfully."
 
 def cli_cmd_create_demo_site(conf):
     """Create demo site.  Useful for testing purposes."""
     print ">>> Going to create demo site..."
     from invenio.config import CFG_PREFIX
     from invenio.dbquery import run_sql
     run_sql("TRUNCATE schTASK")
     for cmd in ["%s/bin/dbexec < %s/lib/sql/invenio/democfgdata.sql" % (CFG_PREFIX, CFG_PREFIX),
                 "%s/bin/webaccessadmin -u admin -c -r -D" % CFG_PREFIX,
                 "%s/bin/webcoll -u admin" % CFG_PREFIX,
                 "%s/bin/webcoll 1" % CFG_PREFIX,]:
         if os.system(cmd):
             print "ERROR: failed execution of", cmd
             sys.exit(1)
     print ">>> Demo site created successfully."
 
 def cli_cmd_load_demo_records(conf):
     """Load demo records.  Useful for testing purposes."""
     from invenio.config import CFG_PREFIX
     from invenio.dbquery import run_sql
     print ">>> Going to load demo records..."
     run_sql("TRUNCATE schTASK")
     for cmd in ["%s/bin/bibupload -i %s/var/tmp/demobibdata.xml" % (CFG_PREFIX, CFG_PREFIX),
                 "%s/bin/bibupload 1" % CFG_PREFIX,
                 "%s/bin/bibindex -u admin" % CFG_PREFIX,
                 "%s/bin/bibindex 2" % CFG_PREFIX,
                 "%s/bin/bibreformat -u admin -o HB" % CFG_PREFIX,
                 "%s/bin/bibreformat 3" % CFG_PREFIX,
                 "%s/bin/bibupload 4" % CFG_PREFIX,
                 "%s/bin/webcoll -u admin" % CFG_PREFIX,
                 "%s/bin/webcoll 5" % CFG_PREFIX,
                 "%s/bin/bibrank -u admin" % CFG_PREFIX,
                 "%s/bin/bibrank 6" % CFG_PREFIX,]:
         if os.system(cmd):
             print "ERROR: failed execution of", cmd
             sys.exit(1)
     print ">>> Demo records loaded successfully."
 
 def cli_cmd_remove_demo_records(conf):
     """Remove demo records.  Useful when you are finished testing."""
     print ">>> Going to remove demo records..."
     from invenio.config import CFG_PREFIX
     from invenio.dbquery import run_sql
     from invenio.textutils import wrap_text_in_a_box, wait_for_user
     if '--yes-i-know' not in sys.argv:
         wait_for_user(wrap_text_in_a_box("""\
 WARNING: You are going to destroy your records and documents!\n
 
 Press Ctrl-C if you want to abort this action.\n
 Press ENTER to proceed with this action."""))
     if os.path.exists(CFG_PREFIX + os.sep + 'var' + os.sep + 'data' + os.sep + 'files'):
         shutil.rmtree(CFG_PREFIX + os.sep + 'var' + os.sep + 'data' + os.sep + 'files')
     run_sql("TRUNCATE schTASK")
     for cmd in ["%s/bin/dbexec < %s/lib/sql/invenio/tabbibclean.sql" % (CFG_PREFIX, CFG_PREFIX),
                 "%s/bin/webcoll -u admin" % CFG_PREFIX,
                 "%s/bin/webcoll 1" % CFG_PREFIX,]:
         if os.system(cmd):
             print "ERROR: failed execution of", cmd
             sys.exit(1)
     print ">>> Demo records removed successfully."
 
 def cli_cmd_drop_demo_site(conf):
     """Drop demo site completely.  Useful when you are finished testing."""
     print ">>> Going to drop demo site..."
     from invenio.textutils import wrap_text_in_a_box, wait_for_user
     if '--yes-i-know' not in sys.argv:
         wait_for_user(wrap_text_in_a_box("""\
 WARNING: You are going to destroy your site and documents!\n
 
 Press Ctrl-C if you want to abort this action.\n
 Press ENTER to proceed with this action."""))
     cli_cmd_drop_tables(conf)
     cli_cmd_create_tables(conf)
     cli_cmd_remove_demo_records(conf)
     print ">>> Demo site dropped successfully."
 
 def cli_cmd_run_unit_tests(conf):
     """Run unit tests, usually on the working demo site."""
-    from invenio.config import CFG_PREFIX
-    os.system("%s/bin/testsuite" % CFG_PREFIX)
+    from invenio.testutils import build_and_run_unit_test_suite
+    build_and_run_unit_test_suite()
 
 def cli_cmd_run_regression_tests(conf):
     """Run regression tests, usually on the working demo site."""
-    from invenio.config import CFG_PREFIX
-    if '--yes-i-know' in sys.argv:
-        os.system("%s/bin/regressiontestsuite --yes-i-know" % CFG_PREFIX)
-    else:
-        os.system("%s/bin/regressiontestsuite" % CFG_PREFIX)
+    from invenio.testutils import build_and_run_regression_test_suite
+    build_and_run_regression_test_suite()
 
 def cli_cmd_create_apache_conf(conf):
     """
     Create Apache conf files for this site, keeping previous
     files in a backup copy.
     """
     print ">>> Going to create Apache conf files..."
     from invenio.textutils import wrap_text_in_a_box
     apache_conf_dir = conf.get("Invenio", 'CFG_ETCDIR') + \
                       os.sep + 'apache'
     if not os.path.exists(apache_conf_dir):
         os.mkdir(apache_conf_dir)
     apache_vhost_file = apache_conf_dir + os.sep + \
                             'invenio-apache-vhost.conf'
     apache_vhost_ssl_file = apache_conf_dir + os.sep + \
                              'invenio-apache-vhost-ssl.conf'
     apache_vhost_body = """\
 AddDefaultCharset UTF-8
 ServerSignature Off
 ServerTokens Prod
 NameVirtualHost *:80
 Listen 80
 <Files *.pyc>
    deny from all
 </Files>
 <Files *~>
    deny from all
 </Files>
 <VirtualHost *:80>
         ServerName %(servername)s
         ServerAlias %(serveralias)s
         ServerAdmin %(serveradmin)s
         DocumentRoot %(webdir)s
         <Directory %(webdir)s>
            Options FollowSymLinks MultiViews
            AllowOverride None
            Order allow,deny
            allow from all
         </Directory>
         ErrorLog %(logdir)s/apache.err
         LogLevel warn
         CustomLog %(logdir)s/apache.log combined
         DirectoryIndex index.en.html index.html
         <LocationMatch "^(/+$|/index|/collection|/record|/author|/search|/browse|/youraccount|/youralerts|/yourbaskets|/yourmessages|/yourgroups|/submit|/getfile|/comments|/error|/oai2d|/rss|/help|/journal|/openurl|/stats)">
            SetHandler python-program
            PythonHandler invenio.webinterface_layout
            PythonDebug On
         </LocationMatch>
         <Directory %(webdir)s>
            AddHandler python-program .py
            PythonHandler mod_python.publisher
            PythonDebug On
         </Directory>
 </VirtualHost>
 """ % {'servername': conf.get('Invenio', 'CFG_SITE_URL').replace("http://", ""),
        'serveralias': conf.get('Invenio', 'CFG_SITE_URL').replace("http://", "").split('.')[0],
        'serveradmin': conf.get('Invenio', 'CFG_SITE_ADMIN_EMAIL'),
        'webdir': conf.get('Invenio', 'CFG_WEBDIR'),
        'logdir': conf.get('Invenio', 'CFG_LOGDIR'),
        }
     apache_vhost_ssl_body = """\
 ServerSignature Off
 ServerTokens Prod
 Listen 443
 NameVirtualHost *:443
 #SSLCertificateFile /etc/apache2/ssl/apache.pem
 SSLCertificateFile /etc/apache2/ssl/server.crt
 SSLCertificateKeyFile /etc/apache2/ssl/server.key
 <Files *.pyc>
    deny from all
 </Files>
 <Files *~>
    deny from all
 </Files>
 <VirtualHost *:443>
         ServerName %(servername)s
         ServerAlias %(serveralias)s
         ServerAdmin %(serveradmin)s
         SSLEngine on
         DocumentRoot %(webdir)s
         <Directory %(webdir)s>
            Options FollowSymLinks MultiViews
            AllowOverride None
            Order allow,deny
            allow from all
         </Directory>
         ErrorLog %(logdir)s/apache-ssl.err
         LogLevel warn
         CustomLog %(logdir)s/apache-ssl.log combined
         DirectoryIndex index.en.html index.html
         <LocationMatch "^(/+$|/index|/collection|/record|/author|/search|/browse|/youraccount|/youralerts|/yourbaskets|/yourmessages|/yourgroups|/submit|/getfile|/comments|/error|/oai2d|/rss|/help|/journal|/openurl|/stats)">
            SetHandler python-program
            PythonHandler invenio.webinterface_layout
            PythonDebug On
         </LocationMatch>
         <Directory %(webdir)s>
            AddHandler python-program .py
            PythonHandler mod_python.publisher
            PythonDebug On
         </Directory>
 </VirtualHost>
 """ % {'servername': conf.get('Invenio', 'CFG_SITE_SECURE_URL').replace("https://", ""),
        'serveralias': conf.get('Invenio', 'CFG_SITE_SECURE_URL').replace("https://", "").split('.')[0],
        'serveradmin': conf.get('Invenio', 'CFG_SITE_ADMIN_EMAIL'),
        'webdir': conf.get('Invenio', 'CFG_WEBDIR'),
        'logdir': conf.get('Invenio', 'CFG_LOGDIR'),
        }
     # write HTTP vhost snippet:
     if os.path.exists(apache_vhost_file):
         shutil.copy(apache_vhost_file,
                     apache_vhost_file + '.OLD')
     fdesc = open(apache_vhost_file, 'w')
     fdesc.write(apache_vhost_body)
     fdesc.close()
     print "Created file", apache_vhost_file
     # write HTTPS vhost snippet:
     if conf.get('Invenio', 'CFG_SITE_SECURE_URL') != \
        conf.get('Invenio', 'CFG_SITE_URL'):
         if os.path.exists(apache_vhost_ssl_file):
             shutil.copy(apache_vhost_ssl_file,
                         apache_vhost_ssl_file + '.OLD')
         fdesc = open(apache_vhost_ssl_file, 'w')
         fdesc.write(apache_vhost_ssl_body)
         fdesc.close()
         print "Created file", apache_vhost_ssl_file
 
     print wrap_text_in_a_box("""\
 Apache virtual host configurations for your site have been
 created. You can check created files and put the following
 include statements in your httpd.conf:\n
 
 Include %s
 
 Include %s
     """ % (apache_vhost_file, apache_vhost_ssl_file))
     print ">>> Apache conf files created."
 
 def cli_cmd_get(conf, varname):
     """
     Return value of VARNAME read from CONF files.  Useful for
     third-party programs to access values of conf options such as
     CFG_PREFIX.  Return None if VARNAME is not found.
     """
     # do not pay attention to upper/lower case:
     varname = varname.lower()
     # do not pay attention to section names yet:
     all_options = {}
     for section in conf.sections():
         for option in conf.options(section):
             all_options[option] = conf.get(section, option)
     return  all_options.get(varname, None)
 
 def cli_cmd_list(conf):
     """
     Print a list of all conf options and values from CONF.
     """
     for section in conf.sections():
         for option in conf.options(section):
             print option, '=', conf.get(section, option)
 
 def _grep_version_from_executable(path_to_exec, version_regexp):
     """
     Try to detect a program version by digging into its binary
     PATH_TO_EXEC and looking for VERSION_REGEXP.  Return program
     version as a string.  Return empty string if not succeeded.
     """
     exec_version = ""
     if os.path.exists(path_to_exec):
         dummy1, cmd2_out, dummy2 = run_command("strings %s | grep %s" % \
                                                (path_to_exec, version_regexp))
         if cmd2_out:
             for cmd2_out_line in cmd2_out.split("\n"):
                 if len(cmd2_out_line) > len(exec_version):
                     # the longest the better
                     exec_version = cmd2_out_line
     return exec_version
 
 def detect_apache_version():
     """
     Try to detect Apache version by localizing httpd or apache
     executables and grepping inside binaries.  Return list of all
     found Apache versions and paths.  (For a given executable, the
     returned format is 'apache_version [apache_path]'.)  Return empty
     list if no success.
     """
     out = []
     dummy1, cmd_out, dummy2 = run_command("locate bin/httpd bin/apache")
     for apache in cmd_out.split("\n"):
         apache_version = _grep_version_from_executable(apache, '^Apache\/')
         if apache_version:
             out.append("%s [%s]" % (apache_version, apache))
     return out
 
 def detect_modpython_version():
     """
     Try to detect mod_python version, either from mod_python import or
     from grepping inside mod_python.so, like Apache.  Return list of
     all found mod_python versions and paths.  Return empty list if no
     success.
     """
     out = []
     try:
         from mod_python import version
         out.append(version)
     except ImportError:
         # try to detect via looking at mod_python.so:
         version = ""
         dummy1, cmd_out, dummy2 = run_command("locate /mod_python.so")
         for modpython in cmd_out.split("\n"):
             modpython_version = _grep_version_from_executable(modpython,
                                                               '^mod_python\/')
             if modpython_version:
                 out.append("%s [%s]" % (modpython_version, modpython))
     return out
 
 def cli_cmd_detect_system_details(conf):
     """
     Detect and print system details such as Apache/Python/MySQL
     versions etc.  Useful for debugging problems on various OS.
     """
     import MySQLdb
     print ">>> Going to detect system details..."
     print "* Hostname: " + socket.gethostname()
     print "* Invenio version: " + conf.get("Invenio", "CFG_VERSION")
     print "* Python version: " + sys.version.replace("\n", " ")
     print "* Apache version: " + ";\n                  ".join(detect_apache_version())
     print "* mod_python version: " + ";\n                  ".join(detect_modpython_version())
     print "* MySQLdb version: " + MySQLdb.__version__
     try:
         from invenio.dbquery import run_sql
         print "* MySQL version:"
         for key, val in run_sql("SHOW VARIABLES LIKE 'version%'") + \
                 run_sql("SHOW VARIABLES LIKE 'charact%'") + \
                 run_sql("SHOW VARIABLES LIKE 'collat%'"):
             if False:
                 print "    - %s: %s" % (key, val)
             elif key in ['version', 'character_set_connection',
                          'character_set_database',
                          'character_set_server',
                          'collation_connection', 'collation_database',
                          'collation_server']:
                 print "    - %s: %s" % (key, val)
     except ImportError:
         print "* ERROR: cannot import dbquery"
     print ">>> System details detected successfully."
 
 def main():
     """Main entry point."""
     conf = ConfigParser()
     if '--help' in sys.argv or \
        '-h' in sys.argv:
         print_usage()
     elif '--version' in sys.argv or \
          '-V' in sys.argv:
         print_version()
     else:
         confdir = None
         if '--conf-dir' in sys.argv:
             try:
                 confdir = sys.argv[sys.argv.index('--conf-dir') + 1]
             except IndexError:
                 pass # missing --conf-dir argument value
             if not os.path.exists(confdir):
                 print "ERROR: bad or missing --conf-dir option value."
                 sys.exit(1)
         else:
             ## try to detect path to conf dir (relative to this bin dir):
             confdir = re.sub(r'/bin$', '/etc', sys.path[0])
         ## read conf files:
         for conffile in [confdir + os.sep + 'invenio.conf',
                          confdir + os.sep + 'invenio-autotools.conf',
                          confdir + os.sep + 'invenio-local.conf',]:
             if os.path.exists(conffile):
                 conf.read(conffile)
             else:
                 if not conffile.endswith("invenio-local.conf"):
                     # invenio-local.conf is optional, otherwise stop
                     print "ERROR: Badly guessed conf file location", conffile
                     print "(Please use --conf-dir option.)"
                     sys.exit(1)
         ## decide what to do:
         done = False
         for opt_idx in range(0, len(sys.argv)):
             opt = sys.argv[opt_idx]
             if opt == '--conf-dir':
                 # already treated before, so skip silently:
                 pass
             elif opt == '--get':
                 try:
                     varname = sys.argv[opt_idx + 1]
                 except IndexError:
                     print "ERROR: bad or missing --get option value."
                     sys.exit(1)
                 if varname.startswith('-'):
                     print "ERROR: bad or missing --get option value."
                     sys.exit(1)
                 varvalue = cli_cmd_get(conf, varname)
                 if varvalue is not None:
                     print varvalue
                 else:
                     sys.exit(1)
                 done = True
             elif opt == '--list':
                 cli_cmd_list(conf)
                 done = True
             elif opt == '--detect-system-details':
                 cli_cmd_detect_system_details(conf)
                 done = True
             elif opt == '--create-tables':
                 cli_cmd_create_tables(conf)
                 done = True
             elif opt == '--drop-tables':
                 cli_cmd_drop_tables(conf)
                 done = True
             elif opt == '--create-demo-site':
                 cli_cmd_create_demo_site(conf)
                 done = True
             elif opt == '--load-demo-records':
                 cli_cmd_load_demo_records(conf)
                 done = True
             elif opt == '--remove-demo-records':
                 cli_cmd_remove_demo_records(conf)
                 done = True
             elif opt == '--drop-demo-site':
                 cli_cmd_drop_demo_site(conf)
                 done = True
             elif opt == '--run-unit-tests':
                 cli_cmd_run_unit_tests(conf)
                 done = True
             elif opt == '--run-regression-tests':
                 cli_cmd_run_regression_tests(conf)
                 done = True
             elif opt == '--update-all':
                 cli_cmd_update_config_py(conf)
                 cli_cmd_update_dbquery_py(conf)
                 cli_cmd_update_dbexec(conf)
                 cli_cmd_update_bibconvert_tpl(conf)
                 done = True
             elif opt == '--update-config-py':
                 cli_cmd_update_config_py(conf)
                 done = True
             elif opt == '--update-dbquery-py':
                 cli_cmd_update_dbquery_py(conf)
                 done = True
             elif opt == '--update-dbexec':
                 cli_cmd_update_dbexec(conf)
                 done = True
             elif opt == '--update-bibconvert-tpl':
                 cli_cmd_update_bibconvert_tpl(conf)
                 done = True
             elif opt == '--reset-all':
                 cli_cmd_reset_sitename(conf)
                 cli_cmd_reset_siteadminemail(conf)
                 cli_cmd_reset_fieldnames(conf)
                 done = True
             elif opt == '--reset-sitename':
                 cli_cmd_reset_sitename(conf)
                 done = True
             elif opt == '--reset-siteadminemail':
                 cli_cmd_reset_siteadminemail(conf)
                 done = True
             elif opt == '--reset-fieldnames':
                 cli_cmd_reset_fieldnames(conf)
                 done = True
             elif opt == '--create-apache-conf':
                 cli_cmd_create_apache_conf(conf)
                 done = True
             elif opt.startswith("-") and opt != '--yes-i-know':
                 print "ERROR: unknown option", opt
                 sys.exit(1)
         if not done:
             print """ERROR: Please specify a command.  Please see '--help'."""
             sys.exit(1)
 
 if __name__ == '__main__':
     main()
diff --git a/modules/miscutil/lib/testutils.py b/modules/miscutil/lib/testutils.py
index 768fc9b4d..2b11093ae 100644
--- a/modules/miscutil/lib/testutils.py
+++ b/modules/miscutil/lib/testutils.py
@@ -1,275 +1,317 @@
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 # pylint: disable-msg=E1102
 
 """
 Helper functions for building and running test suites.
 """
 
 __revision__ = "$Id$"
 
-# if verbose level is set to 9, many debugging messages will be
-# printed on stdout, so you may want to run:
-#   $ regressiontestsuite > /tmp/z.log
-# or even:
-#   $ regressiontestsuite > /tmp/z.log 2> /tmp/z.err
-
 CFG_TESTUTILS_VERBOSE = 1
 
+import os
 import string
 import sys
 import time
 import unittest
 
 from urllib import urlencode
 from itertools import chain, repeat
 
+import invenio
 from invenio.config import CFG_SITE_URL, CFG_SITE_SECURE_URL, CFG_LOGDIR
 from invenio.w3c_validator import w3c_validate, w3c_errors_to_str, CFG_TESTS_REQUIRE_HTML_VALIDATION
 
 def warn_user_about_tests():
     """ Put a standard warning about running tests that might modify
     user data"""
 
     # Provide a command line option to avoid having to type the
     # confirmation every time during development.
     if '--yes-i-know' in sys.argv:
         return
 
-
     sys.stderr.write("""\
 **********************************************************************
 **                                                                  **
 **  ***  I M P O R T A N T   W A R N I N G  ***                     **
 **                                                                  **
 ** The regression test suite needs to be run on a clean demo site   **
 ** that you can obtain by doing:                                    **
 **                                                                  **
 **    $ inveniocfg --drop-demo-site \                               **
 **                 --create-demo-site \                             **
 **                 --load-demo-records                              **
 **                                                                  **
 ** Note that DOING THE ABOVE WILL ERASE YOUR ENTIRE DATABASE.       **
 **                                                                  **
 ** In addition, due to the write nature of some of the tests,       **
 ** the demo DATABASE will be ALTERED WITH JUNK DATA, so that        **
 ** it is recommended to rebuild the demo site anew afterwards.      **
 **                                                                  **
 **********************************************************************
 
 Please confirm by typing "Yes, I know!": """)
 
     answer = raw_input('')
     if answer != 'Yes, I know!':
         sys.stderr.write("Aborted.\n")
         raise SystemExit(0)
 
     return
 
-def warn_user_about_tests_and_run(testsuite):
-    """ Convenience function to embed in test suites """
-    warn_user_about_tests()
-    unittest.TextTestRunner(verbosity=2).run(testsuite)
-
-
 def make_test_suite(*test_cases):
     """ Build up a test suite given separate test cases"""
-
     return unittest.TestSuite([unittest.makeSuite(case, 'test')
                                for case in test_cases])
 
+def run_test_suite(testsuite, warn_user=False):
+    """
+    Convenience function to embed in test suites.  Run given testsuite
+    and eventually ask for confirmation of warn_user is True.
+    """
+    if warn_user:
+        warn_user_about_tests()
+    unittest.TextTestRunner(verbosity=2).run(testsuite)
+
 def make_url(path, **kargs):
     """ Helper to generate an absolute invenio URL with query
     arguments"""
 
     url = CFG_SITE_URL + path
 
     if kargs:
         url += '?' + urlencode(kargs, doseq=True)
 
     return url
 
 def make_surl(path, **kargs):
     """ Helper to generate an absolute invenio Secure URL with query
     arguments"""
 
     url = CFG_SITE_SECURE_URL + path
 
     if kargs:
         url += '?' + urlencode(kargs, doseq=True)
 
     return url
 
 class InvenioTestUtilsBrowserException(Exception):
     """Helper exception for the regression test suite browser."""
     pass
 
 def test_web_page_existence(url):
     """
     Test whether URL exists and is well accessible.
     Return True or raise exception in case of problems.
     """
     import mechanize
     browser = mechanize.Browser()
     try:
         browser.open(url)
     except:
         raise
     return True
 
 def test_web_page_content(url,
                           username="guest",
                           password="",
                           expected_text="</html>",
                           expected_link_target=None,
                           expected_link_label=None,
                           require_validate_p=CFG_TESTS_REQUIRE_HTML_VALIDATION):
     """Test whether web page URL as seen by user USERNAME contains
        text EXPECTED_TEXT and, eventually, contains a link to
        EXPECTED_LINK_TARGET (if set) labelled EXPECTED_LINK_LABEL (if
        set).  The EXPECTED_TEXT is checked via substring matching, the
        EXPECTED_LINK_TARGET and EXPECTED_LINK_LABEL via exact string
        matching.
 
        EXPECTED_TEXT, EXPECTED_LINK_LABEL and EXPECTED_LINK_TARGET can
        either be strings or list of strings (in order to check multiple
        values inside same page).
 
        Before doing the tests, login as USERNAME with password
        PASSWORD.  E.g. interesting values for USERNAME are "guest" or
        "admin".
 
        Return empty list in case of problems, otherwise list of error
        messages that may have been encountered during processing of
        page.
     """
 
     if '--w3c-validate' in sys.argv:
         require_validate_p = True
         sys.stderr.write('Required validation\n')
 
     error_messages = []
     try:
         import mechanize
     except ImportError:
         return ['WARNING: Cannot import mechanize, test skipped.']
     browser = mechanize.Browser()
     try:
         # firstly login:
         if username == "guest":
             pass
         else:
             browser.open(CFG_SITE_SECURE_URL + "/youraccount/login")
             browser.select_form(nr=0)
             browser['p_un'] = username
             browser['p_pw'] = password
             browser.submit()
             username_account_page_body = browser.response().read()
             try:
                 string.index(username_account_page_body,
                              "You are logged in as %s." % username)
             except ValueError:
                 raise InvenioTestUtilsBrowserException, \
                       'ERROR: Cannot login as %s, test skipped.' % username
 
         # secondly read page body:
         browser.open(url)
         url_body = browser.response().read()
 
         # now test for EXPECTED_TEXT:
         # first normalize expected_text
         if isinstance(expected_text, str):
             expected_texts = [expected_text]
         else:
             expected_texts = expected_text
         # then test
         for cur_expected_text in expected_texts:
             try:
                 string.index(url_body, cur_expected_text)
             except ValueError:
                 raise InvenioTestUtilsBrowserException, \
                       'ERROR: Page %s (login %s) does not contain %s.' % \
                       (url, username, cur_expected_text)
 
         # now test for EXPECTED_LINK_TARGET and EXPECTED_LINK_LABEL:
         if expected_link_target or expected_link_label:
             # first normalize expected_link_target and expected_link_label
             if isinstance(expected_link_target, str) or \
                    expected_link_target is None:
                 expected_link_targets = [expected_link_target]
             else:
                 expected_link_targets = expected_link_target
             if isinstance(expected_link_label, str) or \
                    expected_link_label is None:
                 expected_link_labels = [expected_link_label]
             else:
                 expected_link_labels = expected_link_label
             max_links = max(len(expected_link_targets), len(expected_link_labels))
             expected_link_labels = chain(expected_link_labels, repeat(None))
             expected_link_targets = chain(expected_link_targets, repeat(None))
             # then test
             for dummy in range(0, max_links):
                 cur_expected_link_target = expected_link_targets.next()
                 cur_expected_link_label = expected_link_labels.next()
                 try:
                     browser.find_link(url=cur_expected_link_target,
                                       text=cur_expected_link_label)
                 except mechanize.LinkNotFoundError:
                     raise InvenioTestUtilsBrowserException, \
                           'ERROR: Page %s (login %s) does not contain link to %s entitled %s.' % \
                           (url, username, cur_expected_link_target, cur_expected_link_label)
 
         # now test for validation if required
         if require_validate_p:
             valid_p, errors, warnings = w3c_validate(url_body)
             if not valid_p:
                 error_text = 'ERROR: Page %s (login %s) does not validate:\n %s' % \
                                   (url, username, w3c_errors_to_str(errors, warnings))
                 open('%s/w3c-markup-validator.log' % CFG_LOGDIR, 'a').write(error_text)
                 raise InvenioTestUtilsBrowserException, error_text
 
 
     except mechanize.HTTPError, msg:
         error_messages.append('ERROR: Page %s (login %s) not accessible. %s' % \
                               (url, username, msg))
     except InvenioTestUtilsBrowserException, msg:
         error_messages.append('ERROR: Page %s (login %s) led to an error: %s.' % \
                               (url, username, msg))
 
     # logout after tests:
     browser.open(CFG_SITE_SECURE_URL + "/youraccount/logout")
 
     if CFG_TESTUTILS_VERBOSE >= 9:
         print "%s test_web_page_content(), tested page `%s', login `%s', expected text `%s', errors `%s'." % \
               (time.strftime("%Y-%m-%d %H:%M:%S -->", time.localtime()),
                url, username, expected_text,
                string.join(error_messages, ","))
 
     return error_messages
 
 def merge_error_messages(error_messages):
     """If the ERROR_MESSAGES list is non-empty, merge them and return nicely
        formatted string suitable for printing.  Otherwise return empty
        string.
     """
     out = ""
     if error_messages:
         out = "\n*** " + string.join(error_messages, "\n*** ")
     return out
+
+def build_and_run_unit_test_suite():
+    """
+    Detect all Invenio modules with names ending by '*_tests.py' (and
+    not '_regression_tests.py'), build a complete test suite of them,
+    and run it.  Called by 'inveniocfg --run-unit-tests'.
+    """
+
+    test_modules = []
+
+    for candidate in os.listdir(os.path.dirname(invenio.__file__)):
+        base, ext = os.path.splitext(candidate)
+
+        if ext != '.py' or not (base.endswith('_tests') and not \
+                                base.endswith('_regression_tests')):
+            continue
+
+        module = __import__('invenio.' + base, globals(), locals(), ['TEST_SUITE'])
+        test_modules.append(module.TEST_SUITE)
+
+    complete_suite = unittest.TestSuite(test_modules)
+    unittest.TextTestRunner(verbosity=2).run(complete_suite)
+
+def build_and_run_regression_test_suite():
+    """
+    Detect all Invenio modules with names ending by
+    '*_regression_tests.py', build a complete test suite of them, and
+    run it.  Called by 'inveniocfg --run-regression-tests'.
+    """
+
+    test_modules = []
+
+    for candidate in os.listdir(os.path.dirname(invenio.__file__)):
+        base, ext = os.path.splitext(candidate)
+
+        if ext != '.py' or not base.endswith('_regression_tests'):
+            continue
+
+        module = __import__('invenio.' + base, globals(), locals(), ['TEST_SUITE'])
+        test_modules.append(module.TEST_SUITE)
+
+    warn_user_about_tests()
+
+    complete_suite = unittest.TestSuite(test_modules)
+    unittest.TextTestRunner(verbosity=2).run(complete_suite)
diff --git a/modules/miscutil/lib/testutils_regression_tests.py b/modules/miscutil/lib/testutils_regression_tests.py
index ee24fa42d..90084d1a4 100644
--- a/modules/miscutil/lib/testutils_regression_tests.py
+++ b/modules/miscutil/lib/testutils_regression_tests.py
@@ -1,95 +1,95 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """TestUtils Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content
 
 class TestFunctionTestWebPageContent(unittest.TestCase):
     """Check browser test_web_page_content() function."""
 
     def test_twpc_username_arg(self):
         """testutils - test_web_page_content() and username arguments"""
         # should login as admin without password:
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL,
                                                username="admin",
                                                expected_text="</html>"))
         # should not login as admin with password:
         errmsgs = test_web_page_content(CFG_SITE_URL,
                                         username="admin",
                                         password="foo",
                                         expected_text="</html>")
         if errmsgs[0].find("ERROR: Cannot login as admin, test skipped.") > -1:
             pass
         else:
             self.fail("Should not be able to login as admin with foo password.")
         return
 
     def test_twpc_expected_text_arg(self):
         """testutils - test_web_page_content() and expected_text argument"""
         # should find HTML in an HTML page:
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + "/search?p=ellis",
                                                expected_text="</html>"))
         # should not find HTML tag in an XML page:
         errmsgs = test_web_page_content(CFG_SITE_URL + "/search?p=ellis&of=xm")
         if errmsgs[0].find(" does not contain </html>") > -1:
             pass
         else:
             self.fail("Should not find </html> in an XML page.")
         return
 
     def test_twpc_expected_link_arg(self):
         """testutils - test_web_page_content() and expected_link argument"""
         # should find link to ALEPH:
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL,
                               expected_link_target=CFG_SITE_URL+"/collection/ALEPH"))
         # should find link entitled ISOLDE:
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL,
                               expected_link_label="ISOLDE"))
         # should find link to ISOLDE entitled ISOLDE:
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL,
                               expected_link_target=CFG_SITE_URL+"/collection/ISOLDE",
                               expected_link_label="ISOLDE"))
         # should not find link to ALEPH entitled ISOLDE:
         errmsgs = test_web_page_content(CFG_SITE_URL,
                               expected_link_target=CFG_SITE_URL+"/collection/ALEPH",
                               expected_link_label="ISOLDE")
         if errmsgs[0].find(" does not contain link to ") > -1:
             pass
         else:
             self.fail("Should not find link to ALEPH entitled ISOLDE.")
         return
 
-test_suite = make_test_suite(TestFunctionTestWebPageContent)
+TEST_SUITE = make_test_suite(TestFunctionTestWebPageContent)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/miscutil/lib/textutils_tests.py b/modules/miscutil/lib/textutils_tests.py
index d87abb5c3..ce3f8e3a6 100644
--- a/modules/miscutil/lib/textutils_tests.py
+++ b/modules/miscutil/lib/textutils_tests.py
@@ -1,202 +1,199 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the textutils library."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.textutils import wrap_text_in_a_box
+from invenio.testutils import make_test_suite, run_test_suite
 
 class WrapTextInABoxTest(unittest.TestCase):
     """Test functions related to wrap_text_in_a_box function."""
 
     def test_plain_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box plain."""
         result = """
 **********************************************
 ** foo bar                                  **
 **********************************************
 """
         self.assertEqual(wrap_text_in_a_box('foo bar'), result)
 
     def test_empty_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box empty."""
         result = """
 **********************************************
 **********************************************
 """
         self.assertEqual(wrap_text_in_a_box(), result)
 
     def test_with_title_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box with title."""
         result = """
 **********************************************
 ** a Title!                                 **
 ** **************************************** **
 ** foo bar                                  **
 **********************************************
 """
         self.assertEqual(wrap_text_in_a_box('foo bar', title='a Title!'), result)
 
     def test_multiline_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box multiline."""
         result = """
 **********************************************
 ** foo bar                                  **
 **********************************************
 """
         self.assertEqual(wrap_text_in_a_box('foo\n bar'), result)
 
     def test_real_multiline_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box real multiline."""
         result = """
 **********************************************
 ** foo                                      **
 ** bar                                      **
 **********************************************
 """
         self.assertEqual(wrap_text_in_a_box('foo\n\nbar'), result)
 
     def test_real_no_width_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box no width."""
         result = """
 ************
 ** foobar **
 ************
 """
         self.assertEqual(wrap_text_in_a_box('foobar', min_col=0), result)
 
     def test_real_nothing_at_all_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box nothing at all."""
         result = """
 ******
 ******
 """
         self.assertEqual(wrap_text_in_a_box(min_col=0), result)
 
     def test_real_squared_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box squared style."""
         result = """
 +--------+
 | foobar |
 +--------+
 """
         self.assertEqual(wrap_text_in_a_box('foobar', style='squared', min_col=0), result)
 
     def test_indented_text_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box indented text."""
         text = """
     def test_real_squared_wrap_text_in_a_box(self):\n
         \"""wrap_text_in_a_box - squared style.\"""\n
         result = \"""\n
 +--------+\n
 | foobar |\n
 +--------+
 \"""
 """
         result = """
 ******************************
 **     def test_real_square **
 **     d_wrap_text_in_a_box **
 **     (self):              **
 **         \"""wrap_text_in_ **
 **         a_box - squared  **
 **         style.\"""        **
 **         result = \"""     **
 ** +--------+               **
 ** | foobar |               **
 ** +--------+\"""            **
 ******************************
 """
         self.assertEqual(wrap_text_in_a_box(text, min_col=0, max_col=30, break_long=True), result)
 
     def test_single_new_line_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box single new line."""
         result = """
 **********************************************
 ** ciao come và?                            **
 **********************************************
 """
         self.assertEqual(wrap_text_in_a_box("ciao\ncome và?"), result)
 
 
     def test_indented_box_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box indented box."""
         result = """
     **********************************************
     ** foobar                                   **
     **********************************************
 """
         self.assertEqual(wrap_text_in_a_box('foobar', tab_num=1), result)
 
     def test_real_conclusion_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box conclusion."""
         result = """----------------------------------------
 foobar                                  \n"""
         self.assertEqual(wrap_text_in_a_box('foobar', style='conclusion'), result)
 
     def test_real_longtext_wrap_text_in_a_box(self):
         """textutils - wrap_text_in_a_box long text."""
         text = """CDS Invenio (formerly CDSware), the integrated digital library system, is a suite of applications which provides the framework and tools for building and managing an autonomous digital library server. The software is readily available to anyone, as it is free software, licensed under the GNU General Public Licence (GPL). The technology offered by the software covers all aspects of digital library management. It complies with the Open Archives Initiative metadata harvesting protocol (OAI-PMH) and uses MARC 21 as its underlying bibliographic standard. Its flexibility and performance make it a comprehensive solution for the management of document repositories of moderate to large size.
 
 CDS Invenio is developed by, maintained by, and used at, the CERN Document Server. At CERN, CDS Invenio manages over 500 collections of data, consisting of over 800,000 bibliographic records, covering preprints, articles, books, journals, photographs, and more. Besides CERN, CDS Invenio is currently installed and in use by over a dozen scientific institutions worldwide (see the Demo page for details)
 
 If you would like to try it out yourself, please feel free to download our latest version. If you have any questions about the product or our support service, do not hesitate to check out CDS Invenio mailing list archives or to contact us."""
 
         result = """
 ************************************************************************
 ** CDS Invenio (formerly CDSware), the integrated digital library     **
 ** system, is a suite of applications which provides the framework    **
 ** and tools for building and managing an autonomous digital library  **
 ** server. The software is readily available to anyone, as it is free **
 ** software, licensed under the GNU General Public Licence (GPL). The **
 ** technology offered by the software covers all aspects of digital   **
 ** library management. It complies with the Open Archives Initiative  **
 ** metadata harvesting protocol (OAI-PMH) and uses MARC 21 as its     **
 ** underlying bibliographic standard. Its flexibility and performance **
 ** make it a comprehensive solution for the management of document    **
 ** repositories of moderate to large size.                            **
 ** CDS Invenio is developed by, maintained by, and used at, the CERN  **
 ** Document Server. At CERN, CDS Invenio manages over 500 collections **
 ** of data, consisting of over 800,000 bibliographic records,         **
 ** covering preprints, articles, books, journals, photographs, and    **
 ** more. Besides CERN, CDS Invenio is currently installed and in use  **
 ** by over a dozen scientific institutions worldwide (see the Demo    **
 ** page for details)                                                  **
 ** If you would like to try it out yourself, please feel free to      **
 ** download our latest version. If you have any questions about the   **
 ** product or our support service, do not hesitate to check out CDS   **
 ** Invenio mailing list archives or to contact us.                    **
 ************************************************************************
 """
         self.assertEqual(wrap_text_in_a_box(text), result)
 
-def create_test_suite():
-    """Return test suite for the wrap_text_in_a_box function."""
-    return unittest.TestSuite((
-        unittest.makeSuite(WrapTextInABoxTest, 'test'),
-        ))
+TEST_SUITE = make_test_suite(WrapTextInABoxTest,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
diff --git a/modules/webaccess/lib/access_control_firerole_tests.py b/modules/webaccess/lib/access_control_firerole_tests.py
index 3723ee3d9..76be81206 100644
--- a/modules/webaccess/lib/access_control_firerole_tests.py
+++ b/modules/webaccess/lib/access_control_firerole_tests.py
@@ -1,143 +1,141 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the access_control_firerole library."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.access_control_firerole import compile_role_definition, \
     serialize, deserialize, acc_firerole_check_user
 from invenio.access_control_config import InvenioWebAccessFireroleError, \
         CFG_ACC_EMPTY_ROLE_DEFINITION_SER
+from invenio.testutils import make_test_suite, run_test_suite
 
 class AccessControlFireRoleTest(unittest.TestCase):
     """Test functions related to the firewall like role definitions."""
 
     def setUp(self):
         """setting up helper variables for tests"""
         self.user_info = {'email' : 'foo.bar@cern.ch',
             'group' : ['patata', 'cetriolo'], 'remote_ip' : '127.0.0.1'}
 
     def test_compile_role_definition_empty(self):
         """firerole - compiling empty role definitions"""
         self.assertEqual(compile_role_definition(None),
             deserialize(CFG_ACC_EMPTY_ROLE_DEFINITION_SER))
 
     def test_compile_role_definition_allow_any(self):
         """firerole - compiling allow any role definitions"""
         self.failUnless(serialize(compile_role_definition("allow any")))
 
     def test_compile_role_definition_deny_any(self):
         """firerole - compiling deny any role definitions"""
         self.failUnless(serialize(compile_role_definition("deny any")))
 
     def test_compile_role_definition_literal_field(self):
         """firerole - compiling literal field role definitions"""
         self.failUnless(serialize(compile_role_definition(
             "allow email 'cds.support@cern.ch'")))
 
     def test_compile_role_definition_not(self):
         """firerole - compiling not role definitions"""
         self.failUnless(serialize(compile_role_definition(
             "allow not email 'cds.support@cern.ch'")))
 
     def test_compile_role_definition_group_field(self):
         """firerole - compiling group field role definitions"""
         self.failUnless(serialize(compile_role_definition(
             "allow groups 'patata'")))
 
     def test_compile_role_definition_regexp_field(self):
         """firerole - compiling regexp field role definitions"""
         self.failUnless(serialize(compile_role_definition(
             "allow email /.*@cern.ch/")))
 
     def test_compile_role_definition_literal_list(self):
         """firerole - compiling literal list role definitions"""
         self.failUnless(serialize(compile_role_definition(
             "allow email 'cds.support@cern.ch', 'foo.bar@cern.ch'")))
 
     def test_compile_role_definition_more_rows(self):
         """firerole - compiling more rows role definitions"""
         self.failUnless(serialize(compile_role_definition(
             "allow email /.*@cern.ch/\nallow groups 'patata' "
             "# a comment\ndeny any")))
 
     def test_compile_role_definition_complex(self):
         """firerole - compiling complex role definitions"""
         self.failUnless(serialize(compile_role_definition(
             "allow email /.*@cern.ch/\nallow groups 'patata' "
             "# a comment\ndeny remote_ip '127.0.0.0/24'\ndeny any")))
 
     def test_compile_role_definition_wrong(self):
         """firerole - compiling wrong role definitions"""
         self.assertRaises(InvenioWebAccessFireroleError,
             compile_role_definition, "allow al")
         self.assertRaises(InvenioWebAccessFireroleError,
             compile_role_definition, "fgdfglk  g fgk")
 
     def test_deserialize(self):
         """firerole - deserializing"""
         self.assertEqual(compile_role_definition("allow any"),
             (True, False, ()))
 
     def test_firerole_literal_email(self):
         """firerole - firerole core testing literal email matching"""
         self.failUnless(acc_firerole_check_user(self.user_info,
             compile_role_definition("allow email 'cds.support@cern.ch',"
                 "'foo.bar@cern.ch'\ndeny any")))
 
     def test_firerole_regexp_email(self):
         """firerole - firerole core testing regexp email matching"""
         self.failUnless(acc_firerole_check_user(self.user_info,
             compile_role_definition("allow email /.*@cern.ch/\ndeny any")))
 
     def test_firerole_literal_group(self):
         """firerole - firerole core testing literal group matching"""
         self.failUnless(acc_firerole_check_user(self.user_info,
             compile_role_definition("allow groups 'patata'\ndeny any")))
 
     def test_firerole_ip_mask(self):
         """firerole - firerole core testing ip mask matching"""
         self.failUnless(acc_firerole_check_user(self.user_info,
             compile_role_definition("allow remote_ip '127.0.0.0/24'"
                 "\ndeny any")))
 
     def test_firerole_non_existant_group(self):
         """firerole - firerole core testing non existant group matching"""
         self.failIf(acc_firerole_check_user(self.user_info,
             compile_role_definition("allow groups 'patat'\ndeny any")))
 
     def test_firerole_empty(self):
         """firerole - firerole core testing empty matching"""
         self.assertEqual(False, acc_firerole_check_user(self.user_info,
             compile_role_definition(None)))
 
-def create_test_suite():
-    """Return test suite for the user handling."""
-    return unittest.TestSuite((unittest.makeSuite(
-        AccessControlFireRoleTest,'test'),))
+TEST_SUITE = make_test_suite(AccessControlFireRoleTest,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
 
diff --git a/modules/webaccess/lib/external_authentication_cern_tests.py b/modules/webaccess/lib/external_authentication_cern_tests.py
index c45ed8ddc..546a506ba 100644
--- a/modules/webaccess/lib/external_authentication_cern_tests.py
+++ b/modules/webaccess/lib/external_authentication_cern_tests.py
@@ -1,67 +1,66 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the user handling library."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import external_authentication_cern as cern
+from invenio.testutils import make_test_suite, run_test_suite
 
 class ExternalAuthenticationCernTest(unittest.TestCase):
     """Test functions related to the CERN authentication."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """setting up helper variables for tests"""
         self.username, self.userpwd, self.useremail = \
                 open('demopwd.cfg', 'r').readline().strip().split(':', 2)
         self.cern = cern.ExternalAuthCern()
 
     def test_auth_user_ok(self):
-        """external CERN - authorizing user through CERN system: should pass"""
+        """external authentication CERN - authorizing user through CERN system: should pass"""
         self.assertEqual(self.cern.auth_user(self.username, self.userpwd), \
                 self.useremail)
 
     def test_auth_user_fail(self):
-        """external CERN - authorizing user through CERN system: should fail"""
+        """external authentication CERN - authorizing user through CERN system: should fail"""
         self.assertEqual(self.cern.auth_user('patata', 'patata'), None)
 
     def test_fetch_user_groups_membership(self):
-        """external CERN - fetching user group membership at CERN"""
+        """external authentication CERN - fetching user group membership at CERN"""
         self.assertNotEqual(self.cern.fetch_user_groups_membership(self.useremail, self.userpwd), 0)
         self.assertEqual(self.cern.fetch_user_groups_membership('patata', 'patata'), {})
 
     def test_fetch_user_preferences(self):
-        """external CERN - fetching user setting from CERN"""
+        """external authentication CERN - fetching user setting from CERN"""
         self.assertEqual(self.cern.fetch_user_preferences(self.username, self.userpwd)['email'], self.useremail)
         #self.assertRaises(KeyError, self.cern.fetch_user_preferences('patata', 'patata')['email'])
 
-def create_test_suite():
-    """Return test suite for the user handling."""
-    return unittest.TestSuite((unittest.makeSuite(
-        ExternalAuthenticationCernTest,'test'),))
+# FIXME: the above tests not plugged into global unit test suite
+TEST_SUITE = make_test_suite() # ExternalAuthenticationCernTest,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
 
diff --git a/modules/webaccess/lib/webaccess_regression_tests.py b/modules/webaccess/lib/webaccess_regression_tests.py
index df8294662..6d7d59d1d 100644
--- a/modules/webaccess/lib/webaccess_regression_tests.py
+++ b/modules/webaccess/lib/webaccess_regression_tests.py
@@ -1,69 +1,69 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebAccess Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class WebAccessWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebAccess web pages whether they are up or not."""
 
     def test_webaccess_admin_interface_availability(self):
         """webaccess - availability of WebAccess Admin interface pages"""
 
         baseurl = CFG_SITE_URL + '/admin/webaccess/webaccessadmin.py/'
 
         _exports = ['', 'delegate_startarea', 'manageaccounts']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'Authorization failure'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_webaccess_admin_guide_availability(self):
         """webaccess - availability of WebAccess Admin guide pages"""
 
         url = CFG_SITE_URL + '/help/admin/webaccess-admin-guide'
         error_messages = test_web_page_content(url,
                                                expected_text="WebAccess Admin Guide")
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(WebAccessWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(WebAccessWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/webalert/lib/webalert_regression_tests.py b/modules/webalert/lib/webalert_regression_tests.py
index d7c470110..aa90c78cb 100644
--- a/modules/webalert/lib/webalert_regression_tests.py
+++ b/modules/webalert/lib/webalert_regression_tests.py
@@ -1,53 +1,53 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.  
+## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebAlert Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class WebAlertWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebAlert web pages whether they are up or not."""
 
     def test_your_alerts_pages_availability(self):
-        """webalert - availability of Your Alerts pages""" 
+        """webalert - availability of Your Alerts pages"""
 
         baseurl = CFG_SITE_URL + '/youralerts/'
 
         _exports = ['', 'display', 'input', 'modify', 'list', 'add',
                     'update', 'remove']
-        
+
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(WebAlertWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(WebAlertWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/webbasket/lib/webbasket_regression_tests.py b/modules/webbasket/lib/webbasket_regression_tests.py
index f5ec111bc..c4d8cdbd9 100644
--- a/modules/webbasket/lib/webbasket_regression_tests.py
+++ b/modules/webbasket/lib/webbasket_regression_tests.py
@@ -1,201 +1,201 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebBasket Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 import mechanize
 import re
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, make_url, make_surl, merge_error_messages
 
 class WebBasketWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebBasket web pages whether they are up or not."""
 
     def test_your_baskets_pages_availability(self):
         """webbasket - availability of Your Baskets pages"""
 
         baseurl = CFG_SITE_URL + '/yourbaskets/'
 
         _exports = ['', 'display', 'display_item', 'write_comment',
                     'save_comment', 'delete_comment', 'add', 'delete',
                     'modify', 'edit', 'create_basket', 'display_public',
                     'list_public_baskets', 'unsubscribe', 'subscribe']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
 class WebBasketRecordsAdditionTest(unittest.TestCase):
     """Test addition of records to webbasket"""
 
     def _login(self, browser, user, password):
         """Log the user in an existing browser using his password"""
 
         browser.open(make_surl('/youraccount/login'))
         browser.select_form(nr=0)
         browser['p_un'] = user
         browser['p_pw'] = password
         browser.submit()
 
     def _perform_search(self, browser, search_criteria):
         """Perform search in an existing browser using the specified criteria.
         Calling the method is equal of typing the criteria in the search box
         and pressing the 'search' button."""
 
         # open the search page that in our case is the default page
         browser.open(make_url('/'))
 
         # perform search
         browser.select_form(name = 'search')
         browser['p'] = search_criteria
         browser.submit(name = 'action_search')
 
     def _select_records_for_adding_to_basket(self, browser, records):
         """Calling this method is is equal of selecting records from
         the search results and pressing 'ADD TO BASKET' button.
 
         browser - the browser object where the selection takes place.
         It is supposed that the browser contains form with search results.
 
         records - list of numbers (first record is 0) indicating
         whisch records to be selected from the search results.  """
 
         # select the proper form containing the check boxes for marking the records
         browser.select_form(nr = 2)
 
         # select the records
         control = browser.find_control('recid')
 
         for current_record in records:
             control.items[current_record].selected = True
 
         # press 'ADD TO BASKET' button
         browser.submit();
 
     def _create_new_basket_and_add_records(self, browser, basket_name, topic_name):
         """creates a new basket. After submiting the form for basket creation
         the records will be automaticaly added to the basket. """
 
         browser.select_form(name = 'add_to_basket')
         browser['new_basket_name'] = basket_name
         browser['new_topic_name'] = topic_name
         browser.submit()
 
     def _delete_basket(self, browser):
         """deletes the first basket in the list of baskets on Display baskets page"""
 
         # go to Display baskets page
         browser.open(make_surl('/yourbaskets/display?ln=en'))
 
         # click Edit basket link
         browser.follow_link(text_regex=re.compile('.*Edit basket', re.I))
 
         # click Delete basket button on the page
         browser.select_form(name = 'edit')
         browser.submit(name = 'delete')
 
         # answer yes to the question "Are you sure..."
         browser.select_form(name = 'validate')
         browser.submit()
 
     def _check_basket_content(self, browser, expected_texts):
         """goes to the baskets page and checks the content for a specified text.
 
         expected_texts is a list of strings containing text that is we expect
         to be shown on the page."""
 
         browser.open(make_surl('/yourbaskets/display?ln=en'))
         url_body = browser.response().read()
 
         for current_expected_text in expected_texts:
             if current_expected_text not in url_body:
                 self.fail('Expects to find ' + current_expected_text + ' in the basket')
 
     def _add_records_into_new_basket(self, browser, basket_name, topic_name):
         """perform a search and add records into new basket"""
 
         self._perform_search(browser, 'ellis')
         self._select_records_for_adding_to_basket(browser, [0, 6])
         self._create_new_basket_and_add_records(browser, basket_name, topic_name)
 
 
     def _add_records_to_basket_and_check_content(self, browser):
         """add records to basket and check content of baskets page for
         expexted strings """
 
         self._add_records_into_new_basket(browser, basket_name = 'Test Basket', topic_name = 'Test Topic')
 
         expected_texts = ['Test Topic', 'Test Basket', '2 records',
                           'Thermal conductivity of dense quark matter and cooling of stars',
                           'The total cross section for the production of heavy quarks in hadronic collisions']
         self._check_basket_content(browser, expected_texts)
 
     def test_records_addition_as_guest_user(self):
         """webbasket - addition of records as guest"""
 
         browser = mechanize.Browser()
         self._add_records_to_basket_and_check_content(browser)
 
     def test_records_addition_as_registered_user(self):
         """webbasket - addition of records as registered user"""
 
         browser = mechanize.Browser()
         self._login(browser, 'jekyll', 'j123ekyll')
 
         self._add_records_to_basket_and_check_content(browser)
 
         self._delete_basket(browser)
 
     def test_adding_records_into_new_basket_twice(self):
         """webbasket - test adding records in new basket after second addition """
 
         browser = mechanize.Browser()
         self._login(browser, 'jekyll', 'j123ekyll')
 
         # add twice records into the same basket, creating the basket every time
         self._add_records_into_new_basket(browser, basket_name = 'New Basket', topic_name = 'New Topic')
         self._add_records_into_new_basket(browser, basket_name = 'New Basket2', topic_name = 'New Topic2')
 
         url_body = browser.response().read()
 
         error_message = "Error: Sorry, you don't have sufficient rights on this basket"
 
         if(error_message in url_body):
             self._delete_basket(browser)
             self._delete_basket(browser)
             self.fail('Does not expect to find message "' + error_message + ' after creating twice the same basket.')
 
         self._delete_basket(browser)
         self._delete_basket(browser)
 
 
-test_suite = make_test_suite(WebBasketWebPagesAvailabilityTest, WebBasketRecordsAdditionTest)
+TEST_SUITE = make_test_suite(WebBasketWebPagesAvailabilityTest, WebBasketRecordsAdditionTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/webcomment/lib/webcomment_regression_tests.py b/modules/webcomment/lib/webcomment_regression_tests.py
index ad31b672e..a6646ad0c 100644
--- a/modules/webcomment/lib/webcomment_regression_tests.py
+++ b/modules/webcomment/lib/webcomment_regression_tests.py
@@ -1,86 +1,86 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebComment Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class WebCommentWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebComment web pages whether they are up or not."""
 
     def test_your_baskets_pages_availability(self):
         """webcomment - availability of comments pages"""
 
         baseurl = CFG_SITE_URL + '/record/10/comments/'
 
         _exports = ['', 'display', 'add', 'vote', 'report']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_webcomment_admin_interface_availability(self):
         """webcomment - availability of WebComment Admin interface pages"""
 
         baseurl = CFG_SITE_URL + '/admin/webcomment/webcommentadmin.py/'
 
         _exports = ['', 'comments', 'delete', 'users']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'Authorization failure'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_webcomment_admin_guide_availability(self):
         """webcomment - availability of WebComment Admin Guide"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/admin/webcomment-admin-guide',
                                                expected_text="WebComment Admin Guide"))
         return
 
     def test_webcomment_mini_review_availability(self):
         """webcomment - availability of mini-review panel on detailed record page"""
         url = CFG_SITE_URL + '/record/12'
         error_messages = test_web_page_content(url,
                                                expected_text="(Not yet reviewed)")
 
-test_suite = make_test_suite(WebCommentWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(WebCommentWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/webcomment/lib/webcomment_tests.py b/modules/webcomment/lib/webcomment_tests.py
index 96a23fbc4..70362638b 100644
--- a/modules/webcomment/lib/webcomment_tests.py
+++ b/modules/webcomment/lib/webcomment_tests.py
@@ -1,28 +1,34 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
-##                                              
+##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import webcomment
+from invenio.testutils import make_test_suite, run_test_suite
 
 # FIXME: Implement me!
+
+TEST_SUITE = make_test_suite()
+
+if __name__ == "__main__":
+    run_test_suite(TEST_SUITE)
diff --git a/modules/webhelp/web/hacking/test-suite.webdoc b/modules/webhelp/web/hacking/test-suite.webdoc
index e4b58df4e..fe82d0b5e 100644
--- a/modules/webhelp/web/hacking/test-suite.webdoc
+++ b/modules/webhelp/web/hacking/test-suite.webdoc
@@ -1,518 +1,488 @@
 ## $Id$
 
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 <!-- WebDoc-Page-Title: Test Suite Strategy -->
 <!-- WebDoc-Page-Navtrail: <a class="navtrail" href="<CFG_SITE_URL>/help/hacking">Hacking CDS Invenio</a> -->
 <!-- WebDoc-Page-Revision: $Id$ -->
 
 <h2>Contents</h2>
 <strong>1. <a href="#1">General considerations</a></strong><br />
 <strong>2. <a href="#2">Unit testing</a></strong><br />
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.1 <a href="#2.1">Unit testing philosophy</a><br />
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.2 <a href="#2.2">Writing unit tests</a><br />
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.3 <a href="#2.3">Running unit tests</a><br />
 <strong>3. <a href="#3">Regression testing</a></strong><br />
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.1 <a href="#3.1">Regression testing philosophy</a><br />
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.2 <a href="#3.2">Writing regression tests</a><br />
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.3 <a href="#3.3">Running regression tests</a><br />
 <strong>4. <a href="#4">Conclusions</a></strong><br />
 <strong>5. <a href="#5">Additional information</a></strong><br />
 
 <a name="1"></a><h2>1. General considerations</h2>
 
 <p>This documents presents guidelines for unit testing and regression
 testing homogenisation throughout all CDS Invenio modules.
 
 <p>Testing is an important coding activity.  Most authors believe that
 writing test cases should take between 10% and 30% of the project
 time.  But, even with such a large fraction, don't put too much belief
 on such a testing.  It cannot find bugs that aren't tested for.  So,
 while testing is an important activity inherent to safe software
 development practices, it cannot become a substitute for pro-active
 bug hunting, source code inspection, and bugfree-driven development
 approach from the start.
 
 <p>Testing should happen alongside with coding.  If you write a
 function, immediately load it into your toplevel, evaluate its
 definition, and call it for a couple of arguments to make sure the
 function works as expected.  If not, then change the function
 definition, re-evaluate it, re-call it, etc.  Dynamic languages with
 interactive toplevel such as Common Lisp or Python makes this easy for
 you.  Dynamic redefinition capabilities (full in Common Lisp, partial
 in Python) are very programmer-friendly in this respect.  If your test
 cases are interesting to be kept, then keep them in a test file.
 (It's almost all the time a good idea to store them in the test file,
 since you cannot predict whether you won't want to change something in
 the future.)  We'll see below how to store your tests in a test file.
 
 <p>When testing, it is nice to know some rules of thumb, like: check
 your edge cases (e.g. null array), check atypical input values
 (e.g. laaarge array instead of typically 5-6 elements only), check
 your termination conditions, ask whether your arguments have already
 been safe-proofed or whether it is in your mandate to check them,
 write a test case for each `if-else' branch of the code to explore all
 the possibilites, etc.  Another interesting rule of thumb is the bug
 frequency distribution.  Experience has shown that the bugs tend to
 cluster.  If you discover a bug, there are chances that other bugs are
 in the neighborhood.  The famous 80/20 rule of thumb applies here too:
 about 80% of bugs are located in about 20% of the code.  Another rule
 of thumb: if you find a bug caused by some coding practice pattern
 thay may be used elsewhere too, look and fix other pattern instances.
 </p>
 
 <p>In a nutshell, the best advice to write bug-free code is: <em>think
 ahead</em>.  Try to prepare in advance for unusual usage scenarios, to
 foresee problems before they happen.  Don't rely on typical input and
 typical usage scenarios.  Things have a tendency to become atypical
 one day.  Recall that testing is necessary, but not sufficient, to
 write good code.  Therefore, think ahead!
 </p>
 
 <a name="2"></a><h2>2. Unit testing</h2>
 
 <a name="2.1"></a><h3>2.1 Unit testing philosophy</h3>
 
 <p>Core functionality, such as the hit set intersection for the search
 engine, or the text input manipulating functions of the BibConvert
 language, should come with a couple of test cases to assure proper
 behaviour of the core functionality.  The test cases should cover
 typical input (e.g. hit set corresponding to the query for ``ellis''),
 as well as the edge cases (e.g. empty/full hit set) and other unusual
 situations (e.g. non-UTF-8 accented input for BibConvert functions to
 test a situation of different number of bytes per char).
 </p>
 
 <p>The test cases should be written for most important core
 functionality.  Not every function or class in the code is to be
 throughly tested.  Common sense will tell.
 </p>
 
 <p>Unit test cases are free of side-effects.  Users should be able to
 run them on production database without any harm to their data.  This
 is because the tests test ``units'' of the code, not the application
 as such.  If the behaviour of the function you would like to test
 depends on the status of the database, or some other parameters that
 cannot be passed to the function itself, the unit testing framework is
 not suitable for this kind of situation and you should use the
 regression testing framework instead (see below).
 </p>
 
 <p>For more information on Pythonic unit testing, see the
 documentation to the unittest module at <a
 href="http://docs.python.org/lib/module-unittest.html">http://docs.python.org/lib/module-unittest.html</a>.
 For a tutorial, see for example <a
 href="http://diveintopython.org/unit_testing/">http://diveintopython.org/unit_testing/</a>.
 </p>
 
 <a name="2.2"></a><h3>2.2 Writing unit tests</h3>
 
 <p>Each core file that is located in the lib directory (such as the
 <code>webbasketlib.py</code> in the example above) should come with a
 testing file where the test cases are stored.  The test file is to be
 named identically as the lib file it tests, but with the suffix
 <code>_tests</code> (in our example,
 <code>webbasketlib_tests.py</code>).
 </p>
 
 <p>The test cases are written using Pythonic unittest TestCase class.
 An example for testing search engine query parameter washing function:
 <blockquote>
 <pre>
 $ cat /opt/cds-invenio/lib/python/invenio/search_engine_tests.py
 [...]
 import search_engine
 import unittest
 
 class TestWashQueryParameters(unittest.TestCase):
     """Test for washing of search query parameters."""
 
     def test_wash_url_argument(self):
         """search engine washing of URL arguments"""
         self.assertEqual(1, search_engine.wash_url_argument(['1'],'int'))
         self.assertEqual("1", search_engine.wash_url_argument(['1'],'str'))
         self.assertEqual(['1'], search_engine.wash_url_argument(['1'],'list'))
         self.assertEqual(0, search_engine.wash_url_argument('ellis','int'))
         self.assertEqual("ellis", search_engine.wash_url_argument('ellis','str'))
         self.assertEqual(["ellis"], search_engine.wash_url_argument('ellis','list'))
         self.assertEqual(0, search_engine.wash_url_argument(['ellis'],'int'))
         self.assertEqual("ellis", search_engine.wash_url_argument(['ellis'],'str'))
         self.assertEqual(["ellis"], search_engine.wash_url_argument(['ellis'],'list'))
 [...]
 </pre>
 </blockquote>
 </p>
 
 <p>In addition, each test file is supposed to define a
-<code>create_test_suite()</code> function that will return test suite
-with all the tests available in this file:
+<code>TEST_SUITE</code> variable that will return test suite with all
+the tests available in this file:
 
 <blockquote>
 <pre>
 $ cat /opt/cds-invenio/lib/python/invenio/search_engine_tests.py
 [...]
-def create_test_suite():
-    """Return test suite for the search engine."""
-    return unittest.TestSuite((unittest.makeSuite(TestWashQueryParameters,'test'),
-                               unittest.makeSuite(TestStripAccents,'test')))
-[...]
-</pre>
-</blockquote>
-</p>
-
-<p>This will enable us to later include this file into
-<code>testsuite</code> executable:
-
-<blockquote>
-<pre>
-$ cat ~/src/cds-invenio/modules/miscutil/bin/testsuite.in
-[...]
-from invenio import search_engine_tests
-    from invenio import bibindex_engine_tests
-
-def create_all_test_suites():
-    """Return all tests suites for all CDS Invenio modules."""
-    return unittest.TestSuite((search_engine_tests.create_test_suite(),
-                               bibindex_engine_tests.create_test_suite()))
+TEST_SUITE = make_test_suite(TestWashQueryParameters,
+                             TestStripAccents,
+                             TestQueryParser,)
 [...]
 </pre>
 </blockquote>
 </p>
 
 <p>In this way, all the test cases defined in the file
 <code>search_engine_tests.py</code> will be executed when the global
 <code>testcase</code> executable is called.
 
 <p>Note that it may be time-consuming to run all the tests in one go.
 If you are interested in running tests only on a certain file (say
 <code>search_engine_tests.py</code>), then launch:
 
 <blockquote>
 <pre>
 $ python /opt/cds-invenio/lib/python/invenio/search_engine_tests.py
 </pre>
 </blockquote>
 </p>
 
 <p>For full-scale examples, you may follow
 <code>search_engine_tests.py<code> and other <code>_tests.py</code>
 files in the source distribution.
 </p>
 
 <a name="2.3"></a><h3>2.3 Running unit tests</h3>
 
-<p>CDS Invenio test suite can be run in the source directory:
-
-<blockquote>
-<pre>
-$ make test
-</pre>
-</blockquote>
-
-or anytime after the installation:
+<p>CDS Invenio test suite can be run at any time via:
 
 <blockquote>
 <pre>
-$ /opt/cds-invenio/bin/testsuite
+$ /opt/cds-invenio/bin/inveniocfg --run-unit-tests
 </pre>
 </blockquote>
 
-The ``testsuite'' executable will run all available unit tests
-provided with CDS Invenio.
+This command will run all available unit tests provided with CDS
+Invenio.
 </p>
 
 <p>The informative output is of the form:
 
 <blockquote>
 <pre>
-$ make test
 CDS Invenio v0.3.2.20040519 test suite results:
 ===========================================
 search engine washing of query patterns ... ok
 search engine washing of URL arguments ... ok
 search engine stripping of accented letters ... ok
 bibindex engine list union ... ok
 
 ----------------------------------------------------------------------
 Ran 4 tests in 0.121s
 
 OK
 </pre>
 </blockquote>
 
 In case of problems you will see failures like:
 
 <blockquote>
 <pre>
 CDS Invenio v0.3.2.20040519 test suite results:
 ===========================================
 search engine washing of query patterns ... FAIL
 search engine washing of URL arguments ... ok
 search engine stripping of accented letters ... ok
 bibindex engine list union ... ok
 
 ======================================================================
 FAIL: search engine washing of query patterns
 ----------------------------------------------------------------------
 Traceback (most recent call last):
   File "/opt/cds-invenio/lib/python/invenio/search_engine_tests.py", line 25, in test_wash_pattern
     self.assertEqual("ell*", search_engine.wash_pattern('ell*'))
   File "/usr/lib/python2.3/unittest.py", line 302, in failUnlessEqual
     raise self.failureException, \
 AssertionError: 'ell*' != 'ell'
 
 ----------------------------------------------------------------------
 Ran 4 tests in 0.091s
 
 FAILED (failures=1)
 </pre>
 </blockquote>
 </p>
 
 <p>The test suite compliance should be checked before each CVS commit.
 (And, obviously, double-checked before each CDS Invenio release.)
 </p>
 
 <a name="3"></a><h2>3. Regression testing</h2>
 
 <a name="3.1"></a><h3>3.1 Regression testing philosophy</h3>
 
 <p>In addition to the above-mentioned unit testing of important
 functions, a regression testing should ensure that the overall
 application functionality is behaving well and is not altered by code
 changes.  This is especially important if a bug had been previously
 found.  Then a regression test case should be written to assure that
 it will never reappear.  (It also helps to scan the neighborhood of
 the bug, or the whole codebase for occurrences of the same kind of
 bug, see the 80/20 thumb rule cited above.)
 </p>
 
 <p>Moreover, the regression test suite should be used when the
 functionality of the item we would like to test depends on
 extra-parametrical status, such as the database content.  Also, the
 regression framework is suitable for testing the web pages overall
 behaviour.  (In extreme programming, the regression testing is called
 <em>acceptance testing</em>, the name that evolved from previous
 <em>functionality testing</em>.)
 </p>
 
 <p>Within the framework of the regression test suite, we have liberty
 to alter database content, unlike that of the unit testing framework.
 We can also simulate the web browser in order to test web
 applications.
 </p>
 
 <p>As an example of a regression test, we can test whether the web
 pages are alive; whether searching for Ellis in the demo site produces
 indeed 12 records; whether searching for aoeuidhtns produces no hits
 but the box of nearest terms, and with which content; whether
 accessing the Theses collection page search prompts an Apache password
 prompt; whether the admin interface is really accessible only to
 admins or also to guests, etc.
 </p>
 
 <p>For more information on regression testing, see for example <a
 href="http://c2.com/cgi/wiki?RegressionTesting">http://c2.com/cgi/wiki?RegressionTesting</a>.
 </p>
 
 <a name="3.2"></a><h3>3.2 Writing regression tests</h3>
 
 <p>Regression tests are written per application (or sub-module) in
 files named like <code>websearch_regression_tests.py</code> or
 <code>websubmitadmin_regression_tests.py</code>.
 </p>
 
 <p>When writing regression tests, you can assume that the site is in
 the fresh demo mode (Atlantis Institute of Fictive Science).  You can
 also safely write not only database-read-only tests, but you can also
 safely insert/update/delete into/from the database whatever values you
 need for testing.  Users are warned prior to running the regression
 test suite about its possibly destructive side-effects. (See below.)
 Therefore you can create users, create user groups, attach users to
 groups to test the group joining process etc, as needed.
 </p>
 
 <p>For testing web pages using GET arguments, you can take advantage
 of the following helper function:
 
 <blockquote>
 <pre>
 $ cat /opt/cds-invenio/lib/python/invenio/testutils.py
 [...]
 def test_web_page_content(url, username="guest", expected_text="</html>"):
     """Test whether web page URL as seen by user USERNAME contains
        text EXPECTED_TEXT.  Before doing the tests, login as USERNAME.
        (E.g. interesting values are "guest" or "admin".)
 
        Return empty list in case of problems, otherwise list of error
        messages that may have been encountered during processing of
        page.
     """
 </pre>
 </blockquote>
 
 For example you can test whether admins can access WebSearch Admin
 interface but guests cannot:
 
 <blockquote>
 <pre>
 test_web_page_content(CFG_SITE_URL + '/admin/websearch/websearchadmin.py',
                       username='admin')
 
 test_web_page_content(CFG_SITE_URL + '/admin/websearch/websearchadmin.py',
                       username='guest',
                       expected_text='Authorization failure')
 </pre>
 </blockquote>
 
 or you can test whether searching for aoeuidhtns produces nearest
 terms box:
 
 <blockquote>
 <pre>
 test_web_page_content(CFG_SITE_URL + '/search?p=aoeuidhtns',
                       expected_text='Nearest terms in any collection are')
 </pre>
 </blockquote>
 </p>
 
 <p>For testing web pages using POST argumens or for other more
 advanced testing you should use directly <code>mechanize</code> Python
 module that simulates the browser.  It can post forms, follow links,
 go back to previous pages, etc.  An example of how to test the login
 page functionality:
 
 <blockquote>
 <pre>
 browser = mechanize.Browser()
 browser.open(CFG_SITE_SECURE_URL + "/youraccount/login")
 browser.select_form(nr=0)
 browser['p_un'] = 'userfoo'
 browser['p_pw'] = 'passbar'
 browser.submit()
 username_account_page_body = browser.response().read()
 try:
     string.index(username_account_page_body,
                  "You are logged in as userfoo.")
 except ValueError:
     self.fail('ERROR: Cannot login as userfoo.')
 </pre>
 </blockquote>
 
 <p>For full-scale examples, you may follow
 <code>websearch_regression_tests.py<code> and other
 <code>_regression_tests.py</code> files in the source distribution.
 </p>
 
 <a name="3.3"></a><h3>3.3 Running regression test suite</h3>
 
 <p>The regression test suite can be run by invoking:
 
 <blockquote>
 <pre>
-$ /opt/cds-invenio/bin/regressiontestsuite
+$ /opt/cds-invenio/bin/inveniocfg --run-regression-tests
 </pre>
 </blockquote>
 
 similarly to the unit test suite cited above.  The notable exception
 when compared to running the unit test suite is:
 </p>
 
 <ul>
 
-<li><code>regressiontestsuite</code> script assumes the site to be in
-    demo mode (Atlantis Institute of Fictive Science)
+<li>we assume the site to be in demo mode (Atlantis Institute of
+    Fictive Science)
 
-<li><code>regressiontestsuite</code> will pollute the database with
-    test data as it sees fit for the regression testing purposes.
+<li>we shall pollute the database with test data as it seems fit for
+    the regression testing purposes.
 
 </ul>
 
 <p>
 Therefore beware, <strong>running regression test suite requires clean
 demo site and may destroy your data forever</strong>.  The user is
 warned about this prior to running the suite and is given a chance to
 abort the process:
 
 
 <blockquote>
 <pre>
-$ /opt/cds-invenio/bin/regressiontestsuite
-regressiontestsuite: detected 19 regression test modules
+$ /opt/cds-invenio/bin/inveniocfg --run-regression-tests
 **********************************************************************
 **                                                                  **
 **  ***  I M P O R T A N T   W A R N I N G  ***                     **
 **                                                                  **
 ** The regression test suite needs to be run on a clean demo site   **
 ** that you can obtain by doing:                                    **
 **                                                                  **
 **    $ inveniocfg --drop-demo-site \                               **
 **                 --create-demo-site \                             **
 **                 --load-demo-records                              **
 **                                                                  **
 ** Note that DOING THE ABOVE WILL ERASE YOUR ENTIRE DATABASE.       **
 **                                                                  **
 ** (In addition, due to the write nature of some of the tests,      **
 ** the demo database may be altered with junk data, so that         **
 ** it is recommended to rebuild the demo site anew afterwards.)     **
 **                                                                  **
 **********************************************************************
 
 Please confirm by typing "Yes, I know!": NO
 Aborted.
 </pre>
 </blockquote>
 </p>
 
 <p>If you choose to continue, the regression test suite will produce
 the output similar to the unit test suite that was discussed
 previously.
 </p>
 
 <a name="4"></a><h2>4. Conclusions</h2>
 
 <p>A uniform testing technique and two test suites (unit test suite,
 regression test suite) were discussed.  Each programmer should plan to
 write the test code alongside the core code development to test the
 building blocks of his/her code (unit tests) as well as the overall
 application behaviour (regression tests).  The guidelines were given
 how to do so.
 </p>
 
 <a name="5"></a><h2>5. Additional information</h2>
 
 <dl>
 <dt>More information can be found on the URLs mentioned above:
 <dd>
 <pre>
 <a href="http://c2.com/cgi/wiki?UnitTest">http://c2.com/cgi/wiki?UnitTest</a>
 <a href="http://c2.com/cgi/wiki?RegressionTesting">http://c2.com/cgi/wiki?RegressionTesting</a>
 <a href="http://docs.python.org/lib/module-unittest.html">http://docs.python.org/lib/module-unittest.html</a>
 <a href="http://diveintopython.org/unit_testing/">http://diveintopython.org/unit_testing/</a>
 <a href="http://wwwsearch.sourceforge.net/mechanize/">http://wwwsearch.sourceforge.net/mechanize/</a>
 </pre>
 </dl>
 
 <dl>
 <dt>and elsewhere:
 <dd>
 <pre>
 Steve McConnell: "Code Complete"
 FIXME: list of other interesting references, like Kent Beck papers, etc
 </pre>
 </dl>
diff --git a/modules/webmessage/lib/webmessage_regression_tests.py b/modules/webmessage/lib/webmessage_regression_tests.py
index bf3dcbf65..a70d72c13 100644
--- a/modules/webmessage/lib/webmessage_regression_tests.py
+++ b/modules/webmessage/lib/webmessage_regression_tests.py
@@ -1,53 +1,53 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.  
+## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebMessage Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class WebMessageWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebMessage web pages whether they are up or not."""
 
     def test_your_baskets_pages_availability(self):
-        """webmessage - availability of Your Messages pages""" 
+        """webmessage - availability of Your Messages pages"""
 
         baseurl = CFG_SITE_URL + '/yourmessages/'
 
         _exports = ['', 'display', 'write', 'send', 'delete', 'delete_all',
                     'display_msg']
-        
+
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(WebMessageWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(WebMessageWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/websearch/lib/search_engine_tests.py b/modules/websearch/lib/search_engine_tests.py
index 521def779..92365f435 100644
--- a/modules/websearch/lib/search_engine_tests.py
+++ b/modules/websearch/lib/search_engine_tests.py
@@ -1,241 +1,239 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the search engine."""
 
 __revision__ = \
     "$Id$"
 
 import unittest
 
 from invenio import search_engine
+from invenio.testutils import make_test_suite, run_test_suite
 
 class TestWashQueryParameters(unittest.TestCase):
     """Test for washing of search query parameters."""
 
     def test_wash_url_argument(self):
         """search engine - washing of URL arguments"""
         self.assertEqual(1,
                          search_engine.wash_url_argument(['1'], 'int'))
         self.assertEqual("1",
                          search_engine.wash_url_argument(['1'], 'str'))
         self.assertEqual(['1'],
                          search_engine.wash_url_argument(['1'], 'list'))
         self.assertEqual(0,
                          search_engine.wash_url_argument('ellis', 'int'))
         self.assertEqual("ellis",
                          search_engine.wash_url_argument('ellis', 'str'))
         self.assertEqual(["ellis"],
                          search_engine.wash_url_argument('ellis', 'list'))
         self.assertEqual(0,
                          search_engine.wash_url_argument(['ellis'], 'int'))
         self.assertEqual("ellis",
                          search_engine.wash_url_argument(['ellis'], 'str'))
         self.assertEqual(["ellis"],
                          search_engine.wash_url_argument(['ellis'], 'list'))
 
     def test_wash_pattern(self):
         """search engine - washing of query patterns"""
         self.assertEqual("Ellis, J", search_engine.wash_pattern('Ellis, J'))
         self.assertEqual("ell", search_engine.wash_pattern('ell*'))
 
     def test_wash_dates_from_tuples(self):
         """search engine - washing of date arguments from (year,month,day) tuples"""
         self.assertEqual(search_engine.wash_dates(d1y=1980, d1m=1, d1d=28, d2y=2003, d2m=2, d2d=3),
                          ('1980-01-28 00:00:00', '2003-02-03 00:00:00'))
         self.assertEqual(search_engine.wash_dates(d1y=1980, d1m=0, d1d=28, d2y=2003, d2m=2, d2d=0),
                          ('1980-01-28 00:00:00', '2003-02-31 00:00:00'))
 
     def test_wash_dates_from_datetexts(self):
         """search engine - washing of date arguments from datetext strings"""
         self.assertEqual(search_engine.wash_dates(d1="1980-01-28 01:02:03", d2="1980-01-29 12:34:56"),
                          ('1980-01-28 01:02:03', '1980-01-29 12:34:56'))
         self.assertEqual(search_engine.wash_dates(d1="1980-01-28 01:02:03"),
                          ('1980-01-28 01:02:03', '9999-12-31 00:00:00'))
         self.assertEqual(search_engine.wash_dates(d2="1980-01-29 12:34:56"),
                          ('0000-01-01 00:00:00', '1980-01-29 12:34:56'))
 
     def test_wash_dates_from_both(self):
         """search engine - washing of date arguments from both datetext strings and (year,month,day) tuples"""
         # datetext mode takes precedence, d1* should be ignored
         self.assertEqual(search_engine.wash_dates(d1="1980-01-28 01:02:03", d1y=1980, d1m=1, d1d=28),
                          ('1980-01-28 01:02:03', '9999-12-31 00:00:00'))
         # datetext mode takes precedence, d2 missing, d2* should be ignored
         self.assertEqual(search_engine.wash_dates(d1="1980-01-28 01:02:03", d2y=2003, d2m=2, d2d=3),
                          ('1980-01-28 01:02:03', '2003-02-03 00:00:00'))
 
 class TestStripAccents(unittest.TestCase):
     """Test for handling of UTF-8 accents."""
 
     def test_strip_accents(self):
         """search engine - stripping of accented letters"""
         self.assertEqual("memememe",
                          search_engine.strip_accents('mémêmëmè'))
         self.assertEqual("MEMEMEME",
                          search_engine.strip_accents('MÉMÊMËMÈ'))
 
 class TestQueryParser(unittest.TestCase):
     """Test of search pattern (or query) parser."""
 
     def _check(self, p, f, m, result_wanted):
         "Internal checking function calling create_basic_search_units."
         result_obtained = search_engine.create_basic_search_units(None, p, f, m)
         assert result_obtained == result_wanted, \
                'obtained %s instead of %s' % (repr(result_obtained),
                                               repr(result_wanted))
         return
 
     def test_parsing_single_word_query(self):
         "search engine - parsing single word queries"
         self._check('word', '', None, [['+', 'word', '', 'w']])
 
     def test_parsing_single_word_with_boolean_operators(self):
         "search engine - parsing single word queries"
         self._check('+word', '', None, [['+', 'word', '', 'w']])
         self._check('-word', '', None, [['-', 'word', '', 'w']])
         self._check('|word', '', None, [['|', 'word', '', 'w']])
 
     def test_parsing_single_word_in_field(self):
         "search engine - parsing single word queries in a logical field"
         self._check('word', 'title', None, [['+', 'word', 'title', 'w']])
 
     def test_parsing_single_word_in_tag(self):
         "search engine - parsing single word queries in a physical tag"
         self._check('word', '500', None, [['+', 'word', '500', 'a']])
 
     def test_parsing_query_with_commas(self):
         "search engine - parsing queries with commas"
         self._check('word,word', 'title', None,
                     [['+', 'word,word', 'title', 'a']])
 
     def test_parsing_exact_phrase_query(self):
         "search engine - parsing exact phrase"
         self._check('"the word"', 'title', None,
                     [['+', 'the word', 'title', 'a']])
 
     def test_parsing_exact_phrase_query_unbalanced(self):
         "search engine - parsing unbalanced exact phrase"
         self._check('"the word', 'title', None,
                     [['+', '"the', 'title', 'w'],
                      ['+', 'word', 'title', 'w']])
 
     def test_parsing_exact_phrase_query_in_any_field(self):
         "search engine - parsing exact phrase in any field"
         self._check('"the word"', '', None,
                     [['+', 'the word', 'anyfield', 'a']])
 
     def test_parsing_partial_phrase_query(self):
         "search engine - parsing partial phrase"
         self._check("'the word'", 'title', None,
                     [['+', '%the word%', 'title', 'a']])
 
     def test_parsing_partial_phrase_query_unbalanced(self):
         "search engine - parsing unbalanced partial phrase"
         self._check("'the word", 'title', None,
                     [['+', "'the", 'title', 'w'],
                      ['+', "word", 'title', 'w']])
     def test_parsing_partial_phrase_query_in_any_field(self):
         "search engine - parsing partial phrase in any field"
         self._check("'the word'", '', None,
                     [['+', "'the", '', 'w'],
                      ['+', "word'", '', 'w']])
 
     def test_parsing_regexp_query(self):
         "search engine - parsing regex matches"
         self._check("/the word/", 'title', None,
                     [['+', 'the word', 'title', 'r']])
 
     def test_parsing_regexp_query_unbalanced(self):
         "search engine - parsing unbalanced regexp"
         self._check("/the word", 'title', None,
                     [['+', '/the', 'title', 'w'],
                      ['+', 'word', 'title', 'w']])
 
     def test_parsing_regexp_query_in_any_field(self):
         "search engine - parsing regexp searches in any field"
         self._check("/the word/", '', None,
                     [['+', "/the", '', 'w'],
                      ['+', "word/", '', 'w']])
 
     def test_parsing_boolean_query(self):
         "search engine - parsing boolean query with several words"
         self._check("muon kaon ellis cern", '', None,
                     [['+', 'muon', '', 'w'],
                      ['+', 'kaon', '', 'w'],
                      ['+', 'ellis', '', 'w'],
                      ['+', 'cern', '', 'w']])
 
     def test_parsing_boolean_query_with_word_operators(self):
         "search engine - parsing boolean query with word operators"
         self._check("muon and kaon or ellis not cern", '', None,
                     [['+', 'muon', '', 'w'],
                      ['+', 'kaon', '', 'w'],
                      ['|', 'ellis', '', 'w'],
                      ['-', 'cern', '', 'w']])
 
     def test_parsing_boolean_query_with_symbol_operators(self):
         "search engine - parsing boolean query with symbol operators"
         self._check("muon +kaon |ellis -cern", '', None,
                     [['+', 'muon', '', 'w'],
                      ['+', 'kaon', '', 'w'],
                      ['|', 'ellis', '', 'w'],
                      ['-', 'cern', '', 'w']])
 
     def test_parsing_boolean_query_with_symbol_operators_and_spaces(self):
         "search engine - parsing boolean query with operators and spaces"
         self._check("muon + kaon | ellis - cern", '', None,
                     [['+', 'muon', '', 'w'],
                      ['+', 'kaon', '', 'w'],
                      ['|', 'ellis', '', 'w'],
                      ['-', 'cern', '', 'w']])
 
     def test_parsing_boolean_query_with_symbol_operators_and_no_spaces(self):
         "search engine - parsing boolean query with operators and no spaces"
         self._check("muon+kaon|ellis-cern", '', None,
                     [['+', 'muon+kaon|ellis-cern', '', 'w']])
 
     def test_parsing_combined_structured_query(self):
         "search engine - parsing combined structured query"
         self._check("title:muon author:ellis", '', None,
                     [['+', 'muon', 'title', 'w'],
                      ['+', 'ellis', 'author', 'w']])
 
     def test_parsing_structured_regexp_query(self):
         "search engine - parsing structured regexp query"
         self._check("title:/(one|two)/", '', None,
                     [['+', '(one|two)', 'title', 'r']])
 
     def test_parsing_combined_structured_query_in_a_field(self):
         "search engine - parsing structured query in a field"
         self._check("title:muon author:ellis", 'abstract', None,
                     [['+', 'muon', 'title', 'w'],
                      ['+', 'ellis', 'author', 'w']])
 
 
-def create_test_suite():
-    """Return test suite for the search engine."""
-    return unittest.TestSuite((unittest.makeSuite(TestWashQueryParameters,
-                                                  'test'),
-                               unittest.makeSuite(TestStripAccents, 'test'),
-                               unittest.makeSuite(TestQueryParser, 'test')))
+TEST_SUITE = make_test_suite(TestWashQueryParameters,
+                             TestStripAccents,
+                             TestQueryParser,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/websearch/lib/websearch_external_collections_getter_tests.py b/modules/websearch/lib/websearch_external_collections_getter_tests.py
index a1adffe3c..b15d43e78 100644
--- a/modules/websearch/lib/websearch_external_collections_getter_tests.py
+++ b/modules/websearch/lib/websearch_external_collections_getter_tests.py
@@ -1,73 +1,72 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Testing functions for the page getter module.
 """
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.websearch_external_collections_getter import HTTPAsyncPageGetter, async_download
+from invenio.testutils import make_test_suite, run_test_suite
 
 class AsyncDownloadTest(unittest.TestCase):
     """Test suite for websearch_external_collections_*"""
 
     def test_async_download(self):
         """websearch_external_collections_getter - asynchronous download"""
 
         ## Test various cases for the async_download function:
         ##   - test 1 working page: cdsware
         ##   - test 1 unresolvable name: rjfreijoiregjreoijgoirg.fr
         ##   - test 1 bad IP: 1.2.3.4
         ## Return the list of errors.
         checks = [
             {'url': 'http://cdsware.cern.ch/invenio/index.html', 'content': '<title>CDS Invenio: Overview</title>'},
             {'url': 'http://rjfreijoiregjreoijgoirg.fr'},
             {'url': 'http://1.2.3.4/'} ]
 
         def finished(pagegetter, check, current_time):
             """Function called when a page is received."""
             is_ok = pagegetter.status is not None
 
             if check.has_key('content') and is_ok:
                 is_ok = pagegetter.data.find(check['content']) > 0
 
             check['result'] = is_ok == check.has_key('content')
 
         pagegetters = [HTTPAsyncPageGetter(check['url']) for check in checks]
         finished_list = async_download(pagegetters, finished, checks, 20)
 
         for (finished, check) in zip(finished_list, checks):
             if not finished:
                 check['result'] = not check.has_key('content')
 
         errors = [check for check in checks if not check['result']]
 
         self.assertEqual(errors, [])
 
-def create_test_suite():
-    """Return test suite for the external collection tests."""
-    return unittest.TestSuite((unittest.makeSuite(AsyncDownloadTest, 'test'),))
+TEST_SUITE = make_test_suite(AsyncDownloadTest,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
diff --git a/modules/websearch/lib/websearch_external_collections_tests.py b/modules/websearch/lib/websearch_external_collections_tests.py
index 05e8c8040..e9c4a3b32 100644
--- a/modules/websearch/lib/websearch_external_collections_tests.py
+++ b/modules/websearch/lib/websearch_external_collections_tests.py
@@ -1,100 +1,100 @@
 # -*- coding: utf-8 -*-
 ## $Id$
 
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Testing functions for the external collections search.
 
-   More tests of the page getter module can be done with 
+   More tests of the page getter module can be done with
        websearch_external_collections_getter_tests.py
 """
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.websearch_external_collections_searcher import external_collections_dictionary
 from invenio.websearch_external_collections_getter import HTTPAsyncPageGetter, async_download
+from invenio.testutils import make_test_suite, run_test_suite
 
 def download_and_parse():
-    """Try to make a query that always return results on all search engines. 
+    """Try to make a query that always return results on all search engines.
     Check that a page is well returned and that the result can be parsed.
 
     This test is not included in the general test suite.
 
     This test give false positive if any of the external server is non working or too slow.
     """
     test = [['+', 'ieee', '', 'w']]
     errors = []
 
     external_collections = external_collections_dictionary.values()
     urls = [engine.build_search_url(test) for engine in external_collections]
     pagegetters = [HTTPAsyncPageGetter(url) for url in urls]
     dummy = async_download(pagegetters, None, None, 30)
 
     for (page, engine, url) in zip(pagegetters, external_collections, urls):
         if not url:
             errors.append("Unable to build url for : " + engine.name)
             continue
         if len(page.data) == 0:
             errors.append("Zero sized page with : " + engine.name)
             continue
         if engine.parser:
             results = engine.parser.parse_and_get_results(page.data)
             num_results = engine.parser.parse_num_results()
             if len(results) == 0:
                 errors.append("Unable to parse results for : " + engine.name)
                 continue
             if not num_results:
                 errors.append("Unable to parse (None returned) number of results for : " + engine.name)
             try:
                 num_results = int(num_results)
             except:
                 errors.append("Unable to parse (not a number) number of results for : " + engine.name)
 
     return errors
 
 def build_search_urls_test():
     """Build some classical urls from basic_search_units."""
     print "Testing external_search_engines build_search_url functions."
     tests = [ [['+', 'ellis', 'author', 'w'], ['+', 'unification', 'title', 'w'],
             ['-', 'Ross', 'author', 'w'], ['+', 'large', '', 'w'], ['-', 'helloworld', '', 'w']],
         [['+', 'ellis', 'author', 'w'], ['+', 'unification', 'title', 'w']],
         [['+', 'ellis', 'author', 'w']],
         [['-', 'Ross', 'author', 'w']] ]
     for engine in external_collections_dictionary.values():
         print engine.name
         for test in tests:
             url = engine.build_search_url(test)
             print "    Url: " + str(url)
 
-class TestSuite(unittest.TestCase):
-    """Test suite for websearch_external_collections_*"""
+class ExtCollTests(unittest.TestCase):
+    """Test cases for websearch_external_collections_*"""
 
     def test_download_and_parse(self):
         """websearch_external_collections - download_and_parse (not reliable, see docstring)"""
         self.assertEqual([], download_and_parse())
 
-def create_test_suite():
-    """Return test suite for the external collection tests."""
-    return unittest.TestSuite((unittest.makeSuite(TestSuite, 'test')))
+# FIXME: the above tests not plugged into global unit test suite
+TEST_SUITE = make_test_suite() #ExtCollTests,)
 
 if __name__ == "__main__":
     build_search_urls_test()
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
diff --git a/modules/websearch/lib/websearch_regression_tests.py b/modules/websearch/lib/websearch_regression_tests.py
index 0db264504..02f196450 100644
--- a/modules/websearch/lib/websearch_regression_tests.py
+++ b/modules/websearch/lib/websearch_regression_tests.py
@@ -1,1196 +1,1196 @@
 # -*- coding: utf-8 -*-
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 # pylint: disable-msg=C0301
 # pylint: disable-msg=E1102
 
 """WebSearch module regression tests."""
 
 __revision__ = "$Id$"
 
 import unittest
 import re
 import urlparse, cgi
 from sets import Set
 
 from mechanize import Browser, LinkNotFoundError, HTTPError
 
 from invenio.config import CFG_SITE_URL, CFG_SITE_NAME, CFG_SITE_LANG
 from invenio.testutils import make_test_suite, \
-                              warn_user_about_tests_and_run, \
+                              run_test_suite, \
                               make_url, test_web_page_content, \
                               merge_error_messages
 from invenio.urlutils import same_urls_p
 from invenio.search_engine import perform_request_search
 
 def parse_url(url):
     parts = urlparse.urlparse(url)
     query = cgi.parse_qs(parts[4], True)
 
     return parts[2].split('/')[1:], query
 
 class WebSearchWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebSearch web pages whether they are up or not."""
 
     def test_search_interface_pages_availability(self):
         """websearch - availability of search interface pages"""
 
         baseurl = CFG_SITE_URL + '/'
 
         _exports = ['', 'collection/Poetry', 'collection/Poetry?as=1']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_search_results_pages_availability(self):
         """websearch - availability of search results pages"""
 
         baseurl = CFG_SITE_URL + '/search'
 
         _exports = ['', '?c=Poetry', '?p=ellis', '/cache', '/log']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_search_detailed_record_pages_availability(self):
         """websearch - availability of search detailed record pages"""
 
         baseurl = CFG_SITE_URL + '/record/'
 
         _exports = ['', '1', '1/', '1/files', '1/files/']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_browse_results_pages_availability(self):
         """websearch - availability of browse results pages"""
 
         baseurl = CFG_SITE_URL + '/search'
 
         _exports = ['?p=ellis&f=author&action_browse=Browse']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_help_page_availability(self):
         """websearch - availability of Help Central page"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help',
                                                expected_text="Help Central"))
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/?ln=fr',
                                                expected_text="Centre d'aide"))
 
     def test_search_tips_page_availability(self):
         """websearch - availability of Search Tips"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/search-tips',
                                                expected_text="Search Tips"))
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/search-tips?ln=fr',
                                                expected_text="Conseils de recherche"))
 
     def test_search_guide_page_availability(self):
         """websearch - availability of Search Guide"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/search-guide',
                                                expected_text="Search Guide"))
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/search-guide?ln=fr',
                                                expected_text="Guide de recherche"))
 
 class WebSearchTestLegacyURLs(unittest.TestCase):
 
     """ Check that the application still responds to legacy URLs for
     navigating, searching and browsing."""
 
     def test_legacy_collections(self):
         """ websearch - collections handle legacy urls """
 
         browser = Browser()
 
         def check(legacy, new, browser=browser):
             browser.open(legacy)
             got = browser.geturl()
 
             self.failUnless(same_urls_p(got, new), got)
 
         # Use the root URL unless we need more
         check(make_url('/', c=CFG_SITE_NAME),
               make_url('/', ln=CFG_SITE_LANG))
 
         # Other collections are redirected in the /collection area
         check(make_url('/', c='Poetry'),
               make_url('/collection/Poetry', ln=CFG_SITE_LANG))
 
         # Drop unnecessary arguments, like ln and as (when they are
         # the default value)
         check(make_url('/', c='Poetry', as=0),
               make_url('/collection/Poetry', ln=CFG_SITE_LANG))
 
         # Otherwise, keep them
         check(make_url('/', c='Poetry', as=1),
               make_url('/collection/Poetry', as=1, ln=CFG_SITE_LANG))
 
         # Support the /index.py addressing too
         check(make_url('/index.py', c='Poetry'),
               make_url('/collection/Poetry', ln=CFG_SITE_LANG))
 
 
     def test_legacy_search(self):
         """ websearch - search queries handle legacy urls """
 
         browser = Browser()
 
         def check(legacy, new, browser=browser):
             browser.open(legacy)
             got = browser.geturl()
 
             self.failUnless(same_urls_p(got, new), got)
 
         # /search.py is redirected on /search
         # Note that `as' is a reserved word in Python 2.5
         check(make_url('/search.py', p='nuclear') + 'as=1',
               make_url('/search', p='nuclear') + 'as=1')
 
         # direct recid searches are redirected to /record
         check(make_url('/search.py', recid=1, ln='es'),
               make_url('/record/1', ln='es'))
 
     def test_legacy_search_help_link(self):
         """websearch - legacy Search Help page link"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/search/index.en.html',
                                                expected_text="Help Central"))
 
     def test_legacy_search_tips_link(self):
         """websearch - legacy Search Tips page link"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/search/tips.fr.html',
                                                expected_text="Conseils de recherche"))
 
     def test_legacy_search_guide_link(self):
         """websearch - legacy Search Guide page link"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/search/guide.en.html',
                                                expected_text="Search Guide"))
 
 class WebSearchTestRecord(unittest.TestCase):
     """ Check the interface of the /record results """
 
     def test_format_links(self):
         """ websearch - check format links for records """
 
         browser = Browser()
 
         # We open the record in all known HTML formats
         for hformat in ('hd', 'hx', 'hm'):
             browser.open(make_url('/record/1', of=hformat))
 
             if hformat == 'hd':
                 # hd format should have a link to the following
                 # formats
                 for oformat in ('hx', 'hm', 'xm', 'xd'):
                     target = make_url('/record/1/export/%s' % oformat)
                     try:
                         browser.find_link(url=target)
                     except LinkNotFoundError:
                         self.fail('link %r should be in page' % target)
             else:
                 # non-hd HTML formats should have a link back to
                 # the main detailed record
                  target = make_url('/record/1')
                  try:
                      browser.find_link(url=target)
                  except LinkNotFoundError:
                      self.fail('link %r should be in page' % target)
 
         return
 
 
 class WebSearchTestCollections(unittest.TestCase):
 
     def test_traversal_links(self):
         """ websearch - traverse all the publications of a collection """
 
         browser = Browser()
 
         try:
             for as in (0, 1):
                 browser.open(make_url('/collection/Preprints', as=as))
 
                 for jrec in (11, 21, 11, 27):
                     args = {'jrec': jrec, 'cc': 'Preprints'}
                     if as:
                         args['as'] = as
 
                     url = make_url('/search', **args)
                     try:
                         browser.follow_link(url=url)
                     except LinkNotFoundError:
                         args['ln'] = CFG_SITE_LANG
                         url = make_url('/search', **args)
                         browser.follow_link(url=url)
 
         except LinkNotFoundError:
             self.fail('no link %r in %r' % (url, browser.geturl()))
 
     def test_collections_links(self):
         """ websearch - enter in collections and subcollections """
 
         browser = Browser()
 
         def tryfollow(url):
             cur = browser.geturl()
             body = browser.response().read()
             try:
                 browser.follow_link(url=url)
             except LinkNotFoundError:
                 print body
                 self.fail("in %r: could not find %r" % (
                     cur, url))
             return
 
         for as in (0, 1):
             if as:
                 kargs = {'as': 1}
             else:
                 kargs = {}
 
             kargs['ln'] = CFG_SITE_LANG
 
             # We navigate from immediate son to immediate son...
             browser.open(make_url('/', **kargs))
             tryfollow(make_url('/collection/Articles%20%26%20Preprints',
                                **kargs))
             tryfollow(make_url('/collection/Articles', **kargs))
 
             # But we can also jump to a grandson immediately
             browser.back()
             browser.back()
             tryfollow(make_url('/collection/ALEPH', **kargs))
 
         return
 
     def test_records_links(self):
         """ websearch - check the links toward records in leaf collections """
 
         browser = Browser()
         browser.open(make_url('/collection/Preprints'))
 
         def harvest():
 
             """ Parse all the links in the page, and check that for
             each link to a detailed record, we also have the
             corresponding link to the similar records."""
 
             records = Set()
             similar = Set()
 
             for link in browser.links():
                 path, q = parse_url(link.url)
 
                 if not path:
                     continue
 
                 if path[0] == 'record':
                     records.add(int(path[1]))
                     continue
 
                 if path[0] == 'search':
                     if not q.get('rm') == ['wrd']:
                         continue
 
                     recid = q['p'][0].split(':')[1]
                     similar.add(int(recid))
 
             self.failUnlessEqual(records, similar)
 
             return records
 
         # We must have 10 links to the corresponding /records
         found = harvest()
         self.failUnlessEqual(len(found), 10)
 
         # When clicking on the "Search" button, we must also have
         # these 10 links on the records.
         browser.select_form(name="search")
         browser.submit()
 
         found = harvest()
         self.failUnlessEqual(len(found), 10)
         return
 
 
 class WebSearchTestBrowse(unittest.TestCase):
 
     def test_browse_field(self):
         """ websearch - check that browsing works """
 
         browser = Browser()
         browser.open(make_url('/'))
 
         browser.select_form(name='search')
         browser['f'] = ['title']
         browser.submit(name='action_browse')
 
         def collect():
             # We'll get a few links to search for the actual hits, plus a
             # link to the following results.
             res = []
             for link in browser.links(url_regex=re.compile(CFG_SITE_URL +
                                                            r'/search\?')):
                 if link.text == 'Advanced Search':
                     continue
 
                 dummy, q = parse_url(link.url)
                 res.append((link, q))
 
             return res
 
         # if we follow the last link, we should get another
         # batch. There is an overlap of one item.
         batch_1 = collect()
 
         browser.follow_link(link=batch_1[-1][0])
 
         batch_2 = collect()
 
         # FIXME: we cannot compare the whole query, as the collection
         # set is not equal
         self.failUnlessEqual(batch_1[-2][1]['p'], batch_2[0][1]['p'])
 
 class WebSearchTestOpenURL(unittest.TestCase):
 
     def test_isbn_01(self):
         """ websearch - isbn query via OpenURL 0.1"""
 
         browser = Browser()
 
         # We do a precise search in an isolated collection
         browser.open(make_url('/openurl', isbn='0387940758'))
 
         dummy, current_q = parse_url(browser.geturl())
 
         self.failUnlessEqual(current_q, {
             'sc' : ['1'],
             'p' : ['isbn:"0387940758"'],
             'of' : ['hd']
         })
 
     def test_isbn_10_rft_id(self):
         """ websearch - isbn query via OpenURL 1.0 - rft_id"""
 
         browser = Browser()
 
         # We do a precise search in an isolated collection
         browser.open(make_url('/openurl', rft_id='urn:ISBN:0387940758'))
 
         dummy, current_q = parse_url(browser.geturl())
 
         self.failUnlessEqual(current_q, {
             'sc' : ['1'],
             'p' : ['isbn:"0387940758"'],
             'of' : ['hd']
         })
 
     def test_isbn_10(self):
         """ websearch - isbn query via OpenURL 1.0"""
 
         browser = Browser()
 
         # We do a precise search in an isolated collection
         browser.open(make_url('/openurl?rft.isbn=0387940758'))
 
         dummy, current_q = parse_url(browser.geturl())
 
         self.failUnlessEqual(current_q, {
             'sc' : ['1'],
             'p' : ['isbn:"0387940758"'],
             'of' : ['hd']
         })
 
 
 class WebSearchTestSearch(unittest.TestCase):
 
     def test_hits_in_other_collection(self):
         """ websearch - check extension of a query to the home collection """
 
         browser = Browser()
 
         # We do a precise search in an isolated collection
         browser.open(make_url('/collection/ISOLDE', ln='en'))
 
         browser.select_form(name='search')
         browser['f'] = ['author']
         browser['p'] = 'matsubara'
         browser.submit()
 
         dummy, current_q = parse_url(browser.geturl())
 
         link = browser.find_link(text_regex=re.compile('.*hit', re.I))
         dummy, target_q = parse_url(link.url)
 
         # the target query should be the current query without any c
         # or cc specified.
         for f in ('cc', 'c', 'action_search', 'ln'):
             if f in current_q:
                 del current_q[f]
 
         self.failUnlessEqual(current_q, target_q)
 
     def test_nearest_terms(self):
         """ websearch - provide a list of nearest terms """
 
         browser = Browser()
         browser.open(make_url(''))
 
         # Search something weird
         browser.select_form(name='search')
         browser['p'] = 'gronf'
         browser.submit()
 
         dummy, original = parse_url(browser.geturl())
 
         for to_drop in ('cc', 'action_search', 'f'):
             if to_drop in original:
                 del original[to_drop]
 
         if 'ln' not in original:
             original['ln'] = [CFG_SITE_LANG]
 
         # we should get a few searches back, which are identical
         # except for the p field being substituted (and the cc field
         # being dropped).
         if 'cc' in original:
             del original['cc']
 
         for link in browser.links(url_regex=re.compile(CFG_SITE_URL + r'/search\?')):
             if link.text == 'Advanced Search':
                 continue
 
             dummy, target = parse_url(link.url)
 
             if 'ln' not in target:
                 target['ln'] = [CFG_SITE_LANG]
 
             original['p'] = [link.text]
             self.failUnlessEqual(original, target)
 
         return
 
     def test_switch_to_simple_search(self):
         """ websearch - switch to simple search """
 
         browser = Browser()
         browser.open(make_url('/collection/ISOLDE', as=1))
 
         browser.select_form(name='search')
         browser['p1'] = 'tandem'
         browser['f1'] = ['title']
         browser.submit()
 
         browser.follow_link(text='Simple Search')
 
         dummy, q = parse_url(browser.geturl())
 
         self.failUnlessEqual(q, {'cc': ['ISOLDE'],
                                  'p': ['tandem'],
                                  'f': ['title']})
 
     def test_switch_to_advanced_search(self):
         """ websearch - switch to advanced search """
 
         browser = Browser()
         browser.open(make_url('/collection/ISOLDE'))
 
         browser.select_form(name='search')
         browser['p'] = 'tandem'
         browser['f'] = ['title']
         browser.submit()
 
         browser.follow_link(text='Advanced Search')
 
         dummy, q = parse_url(browser.geturl())
 
         self.failUnlessEqual(q, {'cc': ['ISOLDE'],
                                  'p1': ['tandem'],
                                  'f1': ['title'],
                                  'as': ['1']})
 
     def test_no_boolean_hits(self):
         """ websearch - check the 'no boolean hits' proposed links """
 
         browser = Browser()
         browser.open(make_url(''))
 
         browser.select_form(name='search')
         browser['p'] = 'quasinormal muon'
         browser.submit()
 
         dummy, q = parse_url(browser.geturl())
 
         for to_drop in ('cc', 'action_search', 'f'):
             if to_drop in q:
                 del q[to_drop]
 
         for bsu in ('quasinormal', 'muon'):
             l = browser.find_link(text=bsu)
             q['p'] = bsu
             if 'ln' in q:
                 del q['ln']
 
             if not same_urls_p(l.url, make_url('/search', **q)):
                 self.fail(repr((l.url, make_url('/search', **q))))
 
     def test_similar_authors(self):
         """ websearch - test similar authors box """
 
         browser = Browser()
         browser.open(make_url(''))
 
         browser.select_form(name='search')
         browser['p'] = 'Ellis, R K'
         browser['f'] = ['author']
         browser.submit()
 
         l = browser.find_link(text="Ellis, R S")
         self.failUnless(same_urls_p(l.url, make_url('/search',
                                                     p="Ellis, R S",
                                                     f='author')))
 
 class WebSearchNearestTermsTest(unittest.TestCase):
     """Check various alternatives of searches leading to the nearest
     terms box."""
 
     def test_nearest_terms_box_in_okay_query(self):
         """ websearch - no nearest terms box for a successful query """
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=ellis',
                                                expected_text="jump to record"))
 
     def test_nearest_terms_box_in_unsuccessful_simple_query(self):
         """ websearch - nearest terms box for unsuccessful simple query """
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=ellisz',
                                                expected_text="Nearest terms in any collection are",
                                                expected_link_target=CFG_SITE_URL+"/search?p=embed",
                                                expected_link_label='embed'))
 
     def test_nearest_terms_box_in_unsuccessful_structured_query(self):
         """ websearch - nearest terms box for unsuccessful structured query """
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=ellisz&f=author',
                                                expected_text="Nearest terms in any collection are",
                                                expected_link_target=CFG_SITE_URL+"/search?p=fabbro&f=author",
                                                expected_link_label='fabbro'))
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=author%3Aellisz',
                                                expected_text="Nearest terms in any collection are",
                                                expected_link_target=CFG_SITE_URL+"/search?p=author%3Afabbro",
                                                expected_link_label='fabbro'))
 
     def test_nearest_terms_box_in_unsuccessful_phrase_query(self):
         """ websearch - nearest terms box for unsuccessful phrase query """
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=author%3A%22Ellis%2C+Z%22',
                                                expected_text="Nearest terms in any collection are",
                                                expected_link_target=CFG_SITE_URL+"/search?p=author%3A%22Enqvist%2C+K%22",
                                                expected_link_label='Enqvist, K'))
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=%22ellisz%22&f=author',
                                                expected_text="Nearest terms in any collection are",
                                                expected_link_target=CFG_SITE_URL+"/search?p=%22Enqvist%2C+K%22&f=author",
                                                expected_link_label='Enqvist, K'))
 
     def test_nearest_terms_box_in_unsuccessful_boolean_query(self):
         """ websearch - nearest terms box for unsuccessful boolean query """
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=title%3Aellisz+author%3Aellisz',
                                                expected_text="Nearest terms in any collection are",
                                                expected_link_target=CFG_SITE_URL+"/search?p=title%3Aenergie+author%3Aellisz",
                                                expected_link_label='energie'))
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=title%3Aenergie+author%3Aenergie',
                                                expected_text="Nearest terms in any collection are",
                                                expected_link_target=CFG_SITE_URL+"/search?p=title%3Aenergie+author%3Aenqvist",
                                                expected_link_label='enqvist'))
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=title%3Aellisz+author%3Aellisz&f=keyword',
                                                expected_text="Nearest terms in any collection are",
                                                expected_link_target=CFG_SITE_URL+"/search?p=title%3Aenergie+author%3Aellisz&f=keyword",
                                                expected_link_label='energie'))
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=title%3Aenergie+author%3Aenergie&f=keyword',
                                                expected_text="Nearest terms in any collection are",
                                                expected_link_target=CFG_SITE_URL+"/search?p=title%3Aenergie+author%3Aenqvist&f=keyword",
                                                expected_link_label='enqvist'))
 
 class WebSearchBooleanQueryTest(unittest.TestCase):
     """Check various boolean queries."""
 
     def test_successful_boolean_query(self):
         """ websearch - successful boolean query """
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=ellis+muon',
                                                expected_text="records found",
                                                expected_link_label="Detailed record"))
 
     def test_unsuccessful_boolean_query_where_all_individual_terms_match(self):
         """ websearch - unsuccessful boolean query where all individual terms match """
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=ellis+muon+letter',
                                                expected_text="Boolean query returned no hits. Please combine your search terms differently."))
 
 class WebSearchAuthorQueryTest(unittest.TestCase):
     """Check various author-related queries."""
 
     def test_propose_similar_author_names_box(self):
         """ websearch - propose similar author names box """
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=Ellis%2C+R&f=author',
                                                expected_text="See also: similar author names",
                                                expected_link_target=CFG_SITE_URL+"/search?p=Ellis%2C+R+K&f=author",
                                                expected_link_label="Ellis, R K"))
 
     def test_do_not_propose_similar_author_names_box(self):
         """ websearch - do not propose similar author names box """
         errmsgs = test_web_page_content(CFG_SITE_URL + '/search?p=author%3A%22Ellis%2C+R%22',
                                         expected_link_target=CFG_SITE_URL+"/search?p=Ellis%2C+R+K&f=author",
                                         expected_link_label="Ellis, R K")
         if errmsgs[0].find("does not contain link to") > -1:
             pass
         else:
             self.fail("Should not propose similar author names box.")
         return
 
 class WebSearchSearchEnginePythonAPITest(unittest.TestCase):
     """Check typical search engine Python API calls on the demo data."""
 
     def test_search_engine_python_api_for_failed_query(self):
         """websearch - search engine Python API for failed query"""
         self.assertEqual([],
                          perform_request_search(p='aoeuidhtns'))
 
     def test_search_engine_python_api_for_successful_query(self):
         """websearch - search engine Python API for successful query"""
         self.assertEqual([8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 47],
                          perform_request_search(p='ellis'))
 
     def test_search_engine_python_api_for_existing_record(self):
         """websearch - search engine Python API for existing record"""
         self.assertEqual([8],
                          perform_request_search(recid=8))
 
     def test_search_engine_python_api_for_nonexisting_record(self):
         """websearch - search engine Python API for non-existing record"""
         self.assertEqual([],
                          perform_request_search(recid=1234567809))
 
     def test_search_engine_python_api_for_nonexisting_collection(self):
         """websearch - search engine Python API for non-existing collection"""
         self.assertEqual([],
                          perform_request_search(c='Foo'))
 
     def test_search_engine_python_api_for_range_of_records(self):
         """websearch - search engine Python API for range of records"""
         self.assertEqual([1, 2, 3, 4, 5, 6, 7, 8, 9],
                          perform_request_search(recid=1, recidb=10))
 
 class WebSearchSearchEngineWebAPITest(unittest.TestCase):
     """Check typical search engine Web API calls on the demo data."""
 
     def test_search_engine_web_api_for_failed_query(self):
         """websearch - search engine Web API for failed query"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=aoeuidhtns&of=id',
                                                expected_text="[]"))
 
 
     def test_search_engine_web_api_for_successful_query(self):
         """websearch - search engine Web API for successful query"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=ellis&of=id',
                                                expected_text="[8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 47]"))
 
     def test_search_engine_web_api_for_existing_record(self):
         """websearch - search engine Web API for existing record"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?recid=8&of=id',
                                                expected_text="[8]"))
 
     def test_search_engine_web_api_for_nonexisting_record(self):
         """websearch - search engine Web API for non-existing record"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?recid=123456789&of=id',
                                                expected_text="[]"))
 
     def test_search_engine_web_api_for_nonexisting_collection(self):
         """websearch - search engine Web API for non-existing collection"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?c=Foo&of=id',
                                                expected_text="[]"))
 
     def test_search_engine_web_api_for_range_of_records(self):
         """websearch - search engine Web API for range of records"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?recid=1&recidb=10&of=id',
                                                expected_text="[1, 2, 3, 4, 5, 6, 7, 8, 9]"))
 
 class WebSearchRestrictedCollectionTest(unittest.TestCase):
     """Test of the restricted Theses collection behaviour."""
 
     def test_restricted_collection_interface_page(self):
         """websearch - restricted collection interface page body"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/collection/Theses',
                                                expected_text="The contents of this collection is restricted."))
 
     def test_restricted_search_as_anonymous_guest(self):
         """websearch - restricted collection not searchable by anonymous guest"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/search?c=Theses')
         response = browser.response().read()
         if response.find("If you think you have right to access it, please authenticate yourself.") > -1:
             pass
         else:
             self.fail("Oops, searching restricted collection without password should have redirected to login dialog.")
         return
 
     def test_restricted_search_as_authorized_person(self):
         """websearch - restricted collection searchable by authorized person"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/search?c=Theses')
         browser.select_form(nr=0)
         browser['p_un'] = 'jekyll'
         browser['p_pw'] = 'j123ekyll'
         browser.submit()
         if browser.response().read().find("records found") > -1:
             pass
         else:
             self.fail("Oops, Dr. Jekyll should be able to search Theses collection.")
 
     def test_restricted_search_as_unauthorized_person(self):
         """websearch - restricted collection not searchable by unauthorized person"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/search?c=Theses')
         browser.select_form(nr=0)
         browser['p_un'] = 'hyde'
         browser['p_pw'] = 'h123yde'
         browser.submit()
         # Mr. Hyde should not be able to connect:
         if browser.response().read().find("You are not authorized") <= -1:
             # if we got here, things are broken:
             self.fail("Oops, Mr.Hyde should not be able to search Theses collection.")
 
     def test_restricted_detailed_record_page_as_anonymous_guest(self):
         """websearch - restricted detailed record page not accessible to guests"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/record/35')
         if browser.response().read().find("You can use your nickname or your email address to login.") > -1:
             pass
         else:
             self.fail("Oops, searching restricted collection without password should have redirected to login dialog.")
         return
 
     def test_restricted_detailed_record_page_as_authorized_person(self):
         """websearch - restricted detailed record page accessible to authorized person"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/youraccount/login')
         browser.select_form(nr=0)
         browser['p_un'] = 'jekyll'
         browser['p_pw'] = 'j123ekyll'
         browser.submit()
         browser.open(CFG_SITE_URL + '/record/35')
         # Dr. Jekyll should be able to connect
         # (add the pw to the whole CFG_SITE_URL because we shall be
         # redirected to '/reordrestricted/'):
         if browser.response().read().find("A High-performance Video Browsing System") > -1:
             pass
         else:
             self.fail("Oops, Dr. Jekyll should be able to access restricted detailed record page.")
 
     def test_restricted_detailed_record_page_as_unauthorized_person(self):
         """websearch - restricted detailed record page not accessible to unauthorized person"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/youraccount/login')
         browser.select_form(nr=0)
         browser['p_un'] = 'hyde'
         browser['p_pw'] = 'h123yde'
         browser.submit()
         browser.open(CFG_SITE_URL + '/record/35')
         # Mr. Hyde should not be able to connect:
         if browser.response().read().find('You are not authorized') <= -1:
             # if we got here, things are broken:
             self.fail("Oops, Mr.Hyde should not be able to access restricted detailed record page.")
 
 class WebSearchRSSFeedServiceTest(unittest.TestCase):
     """Test of the RSS feed service."""
 
     def test_rss_feed_service(self):
         """websearch - RSS feed service"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/rss',
                                                expected_text='<rss version="2.0">'))
 
 class WebSearchXSSVulnerabilityTest(unittest.TestCase):
     """Test possible XSS vulnerabilities of the search engine."""
 
     def test_xss_in_collection_interface_page(self):
         """websearch - no XSS vulnerability in collection interface pages"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/?c=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E',
                                                expected_text='Collection &amp;lt;SCRIPT&amp;gt;alert("XSS");&amp;lt;/SCRIPT&amp;gt; Not Found'))
 
     def test_xss_in_collection_search_page(self):
         """websearch - no XSS vulnerability in collection search pages"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?c=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E',
                                                expected_text='Collection &lt;SCRIPT&gt;alert("XSS");&lt;/SCRIPT&gt; Not Found'))
 
     def test_xss_in_simple_search(self):
         """websearch - no XSS vulnerability in simple search"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E',
                                                expected_text='Search term <em>&lt;SCRIPT&gt;alert("XSS");&lt;/SCRIPT&gt;</em> did not match any record.'))
 
     def test_xss_in_structured_search(self):
         """websearch - no XSS vulnerability in structured search"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E&f=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E',
                                                expected_text='Search term <em>&lt;SCRIPT&gt;alert("XSS");&lt;/SCRIPT&gt;</em> inside index <em>&lt;SCRIPT&gt;alert("XSS");&lt;/SCRIPT&gt;</em> did not match any record.'))
 
 
     def test_xss_in_advanced_search(self):
         """websearch - no XSS vulnerability in advanced search"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?as=1&p1=ellis&f1=author&op1=a&p2=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E&f2=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E',
                                                expected_text='Search term <em>&lt;SCRIPT&gt;alert("XSS");&lt;/SCRIPT&gt;</em> inside index <em>&lt;SCRIPT&gt;alert("XSS");&lt;/SCRIPT&gt;</em> did not match any record.'))
 
 
 
     def test_xss_in_browse(self):
         """websearch - no XSS vulnerability in browse"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E&f=%3CSCRIPT%3Ealert%28%22XSS%22%29%3B%3C%2FSCRIPT%3E&action_browse=Browse',
                                                expected_text='&lt;SCRIPT&gt;alert("XSS");&lt;/SCRIPT&gt;'))
 
 class WebSearchResultsOverview(unittest.TestCase):
     """Test of the search results page's Results overview box and links."""
 
     def test_results_overview_split_off(self):
         """websearch - results overview box when split by collection is off"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/search?p=of&sc=0')
         body = browser.response().read()
         if body.find("Results overview") > -1:
             self.fail("Oops, when split by collection is off, "
                       "results overview should not be present.")
         if body.find('<a name="1"></a>') == -1:
             self.fail("Oops, when split by collection is off, "
                       "Atlantis collection should be found.")
         if body.find('<a name="15"></a>') > -1:
             self.fail("Oops, when split by collection is off, "
                       "Multimedia & Arts should not be found.")
         try:
             browser.find_link(url='#15')
             self.fail("Oops, when split by collection is off, "
                       "a link to Multimedia & Arts should not be found.")
         except LinkNotFoundError:
             pass
 
     def test_results_overview_split_on(self):
         """websearch - results overview box when split by collection is on"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/search?p=of&sc=1')
         body = browser.response().read()
         if body.find("Results overview") == -1:
             self.fail("Oops, when split by collection is on, "
                       "results overview should be present.")
         if body.find('<a name="Atlantis%20Institute%20of%20Fictive%20Science"></a>') > -1:
             self.fail("Oops, when split by collection is on, "
                       "Atlantis collection should not be found.")
         if body.find('<a name="15"></a>') == -1:
             self.fail("Oops, when split by collection is on, "
                       "Multimedia & Arts should be found.")
         try:
             browser.find_link(url='#15')
         except LinkNotFoundError:
             self.fail("Oops, when split by collection is on, "
                       "a link to Multimedia & Arts should be found.")
 
 class WebSearchSortResultsTest(unittest.TestCase):
     """Test of the search results page's sorting capability."""
 
     def test_sort_results_default(self):
         """websearch - search results sorting, default method"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=cern&rg=1',
                                                expected_text="[hep-th/9809057]"))
 
     def test_sort_results_ascending(self):
         """websearch - search results sorting, ascending field"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=cern&rg=1&sf=reportnumber&so=a',
                                                expected_text="ISOLTRAP"))
 
     def test_sort_results_descending(self):
         """websearch - search results sorting, descending field"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=cern&rg=1&sf=reportnumber&so=d',
                                                expected_text="SCAN-9605071"))
 
     def test_sort_results_sort_pattern(self):
         """websearch - search results sorting, preferential sort pattern"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=cern&rg=1&sf=reportnumber&so=d&sp=cern',
                                                expected_text="CERN-TH-4036"))
 
 class WebSearchSearchResultsXML(unittest.TestCase):
     """Test search results in various output"""
 
     def test_search_results_xm_output_split_on(self):
         """ websearch - check document element of search results in xm output (split by collection on)"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/search?sc=1&of=xm')
         body = browser.response().read()
 
         num_doc_element = body.count("<collection "
                                      "xmlns=\"http://www.loc.gov/MARC21/slim\">")
         if num_doc_element == 0:
             self.fail("Oops, no document element <collection "
                       "xmlns=\"http://www.loc.gov/MARC21/slim\">"
                       "found in search results.")
         elif num_doc_element > 1:
             self.fail("Oops, multiple document elements <collection> "
                       "found in search results.")
 
         num_doc_element = body.count("</collection>")
         if num_doc_element == 0:
             self.fail("Oops, no document element </collection> "
                       "found in search results.")
         elif num_doc_element > 1:
             self.fail("Oops, multiple document elements </collection> "
                       "found in search results.")
 
 
     def test_search_results_xm_output_split_off(self):
         """ websearch - check document element of search results in xm output (split by collection off)"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/search?sc=0&of=xm')
         body = browser.response().read()
 
         num_doc_element = body.count("<collection "
                                      "xmlns=\"http://www.loc.gov/MARC21/slim\">")
         if num_doc_element == 0:
             self.fail("Oops, no document element <collection "
                       "xmlns=\"http://www.loc.gov/MARC21/slim\">"
                       "found in search results.")
         elif num_doc_element > 1:
             self.fail("Oops, multiple document elements <collection> "
                       "found in search results.")
 
         num_doc_element = body.count("</collection>")
         if num_doc_element == 0:
             self.fail("Oops, no document element </collection> "
                       "found in search results.")
         elif num_doc_element > 1:
             self.fail("Oops, multiple document elements </collection> "
                       "found in search results.")
 
     def test_search_results_xd_output_split_on(self):
         """ websearch - check document element of search results in xd output (split by collection on)"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/search?sc=1&of=xd')
         body = browser.response().read()
 
         num_doc_element = body.count("<collection")
         if num_doc_element == 0:
             self.fail("Oops, no document element <collection "
                       "xmlns=\"http://www.loc.gov/MARC21/slim\">"
                       "found in search results.")
         elif num_doc_element > 1:
             self.fail("Oops, multiple document elements <collection> "
                       "found in search results.")
 
         num_doc_element = body.count("</collection>")
         if num_doc_element == 0:
             self.fail("Oops, no document element </collection> "
                       "found in search results.")
         elif num_doc_element > 1:
             self.fail("Oops, multiple document elements </collection> "
                       "found in search results.")
 
 
     def test_search_results_xd_output_split_off(self):
         """ websearch - check document element of search results in xd output (split by collection off)"""
         browser = Browser()
         browser.open(CFG_SITE_URL + '/search?sc=0&of=xd')
         body = browser.response().read()
 
         num_doc_element = body.count("<collection>")
         if num_doc_element == 0:
             self.fail("Oops, no document element <collection "
                       "xmlns=\"http://www.loc.gov/MARC21/slim\">"
                       "found in search results.")
         elif num_doc_element > 1:
             self.fail("Oops, multiple document elements <collection> "
                       "found in search results.")
 
         num_doc_element = body.count("</collection>")
         if num_doc_element == 0:
             self.fail("Oops, no document element </collection> "
                       "found in search results.")
         elif num_doc_element > 1:
             self.fail("Oops, multiple document elements </collection> "
                       "found in search results.")
 
 class WebSearchUnicodeQueryTest(unittest.TestCase):
     """Test of the search results for queries containing Unicode characters."""
 
     def test_unicode_word_query(self):
         """websearch - Unicode word query"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?of=id&p=title%3A%CE%99%CE%B8%CE%AC%CE%BA%CE%B7',
                                                expected_text="[76]"))
 
     def test_unicode_word_query_not_found_term(self):
         """websearch - Unicode word query, not found term"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?p=title%3A%CE%99%CE%B8',
                                                expected_text="ιθάκη"))
 
     def test_unicode_exact_phrase_query(self):
         """websearch - Unicode exact phrase query"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?of=id&p=title%3A%22%CE%99%CE%B8%CE%AC%CE%BA%CE%B7%22',
                                                expected_text="[76]"))
 
     def test_unicode_partial_phrase_query(self):
         """websearch - Unicode partial phrase query"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?of=id&p=title%3A%27%CE%B7%27',
                                                expected_text="[76]"))
 
     def test_unicode_regexp_query(self):
         """websearch - Unicode regexp query"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?of=id&p=title%3A%2F%CE%B7%2F',
                                                expected_text="[76]"))
 
 class WebSearchMARCQueryTest(unittest.TestCase):
     """Test of the search results for queries containing physical MARC tags."""
 
     def test_single_marc_tag_exact_phrase_query(self):
         """websearch - single MARC tag, exact phrase query (100__a)"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?of=id&p=100__a%3A%22Ellis%2C+J%22',
                                                expected_text="[9, 14, 18]"))
 
     def test_single_marc_tag_partial_phrase_query(self):
         """websearch - single MARC tag, partial phrase query (245__b)"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?of=id&p=245__b%3A%27and%27',
                                                expected_text="[28]"))
 
     def test_many_marc_tags_partial_phrase_query(self):
         """websearch - many MARC tags, partial phrase query (245)"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?of=id&p=245%3A%27and%27',
                                                expected_text="[1, 8, 9, 14, 15, 20, 22, 24, 28, 33, 47, 48, 49, 51, 53, 64, 69, 71, 79, 82, 83, 85, 91]"))
 
     def test_single_marc_tag_regexp_query(self):
         """websearch - single MARC tag, regexp query"""
         # NOTE: regexp queries for physical MARC tags (e.g. 245:/and/)
         # are not treated by the search engine by purpose.  But maybe
         # we should support them?!
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?of=id&p=245%3A%2Fand%2F',
                                                expected_text="[]"))
 
 class WebSearchExtSysnoQueryTest(unittest.TestCase):
     """Test of queries using external system numbers."""
 
     def test_existing_sysno_html_output(self):
         """websearch - external sysno query, existing sysno, HTML output"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?sysno=000289446CER',
                                                expected_text="The wall of the cave"))
 
     def test_existing_sysno_id_output(self):
         """websearch - external sysno query, existing sysno, ID output"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?sysno=000289446CER&of=id',
                                                expected_text="[95]"))
 
 
     def test_nonexisting_sysno_html_output(self):
         """websearch - external sysno query, non-existing sysno, HTML output"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?sysno=000289446CERRRR',
                                                expected_text="Requested record does not seem to exist."))
 
     def test_nonexisting_sysno_id_output(self):
         """websearch - external sysno query, non-existing sysno, ID output"""
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/search?sysno=000289446CERRRR&of=id',
                                                expected_text="[]"))
 
-test_suite = make_test_suite(WebSearchWebPagesAvailabilityTest,
+TEST_SUITE = make_test_suite(WebSearchWebPagesAvailabilityTest,
                              WebSearchTestSearch,
                              WebSearchTestBrowse,
                              WebSearchTestOpenURL,
                              WebSearchTestCollections,
                              WebSearchTestRecord,
                              WebSearchTestLegacyURLs,
                              WebSearchNearestTermsTest,
                              WebSearchBooleanQueryTest,
                              WebSearchAuthorQueryTest,
                              WebSearchSearchEnginePythonAPITest,
                              WebSearchSearchEngineWebAPITest,
                              WebSearchRestrictedCollectionTest,
                              WebSearchRSSFeedServiceTest,
                              WebSearchXSSVulnerabilityTest,
                              WebSearchResultsOverview,
                              WebSearchSortResultsTest,
                              WebSearchSearchResultsXML,
                              WebSearchUnicodeQueryTest,
                              WebSearchMARCQueryTest,
                              WebSearchExtSysnoQueryTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
 
diff --git a/modules/websearch/lib/websearchadmin_regression_tests.py b/modules/websearch/lib/websearchadmin_regression_tests.py
index ec295a93e..0aca25cfd 100644
--- a/modules/websearch/lib/websearchadmin_regression_tests.py
+++ b/modules/websearch/lib/websearchadmin_regression_tests.py
@@ -1,75 +1,75 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebSearch Admin Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class WebSearchAdminWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebSearch Admin web pages whether they are up or not."""
 
     def test_websearch_admin_interface_pages_availability(self):
         """websearchadmin - availability of WebSearch Admin interface pages"""
 
         baseurl = CFG_SITE_URL + '/admin/websearch/websearchadmin.py'
 
         _exports = ['',
                     '?mtype=perform_showall',
                     '?mtype=perform_addcollection',
                     '?mtype=perform_addcollectiontotree',
                     '?mtype=perform_modifycollectiontree',
                     '?mtype=perform_checkwebcollstatus',
                     '?mtype=perform_checkcollectionstatus',]
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'Authorization failure'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_websearch_admin_guide_availability(self):
         """websearchadmin - availability of WebSearch Admin guide pages"""
 
         url = CFG_SITE_URL + '/help/admin/websearch-admin-guide'
         error_messages = test_web_page_content(url,
                                                expected_text="WebSearch Admin Guide")
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(WebSearchAdminWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(WebSearchAdminWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/websession/lib/webgroup_regression_tests.py b/modules/websession/lib/webgroup_regression_tests.py
index 9676f89e1..10fa81152 100644
--- a/modules/websession/lib/webgroup_regression_tests.py
+++ b/modules/websession/lib/webgroup_regression_tests.py
@@ -1,201 +1,201 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 # pylint: disable-msg=E1102
 
 """Unit tests for the user handling library."""
 
 __revision__ = "$Id$"
 
 from mechanize import Browser
 from invenio.config import CFG_SITE_SECURE_URL, CFG_SITE_ADMIN_EMAIL
 
 from invenio.dbquery import run_sql
 from invenio.webgroup import synchronize_external_groups, synchronize_all_external_groups
 from invenio.webgroup_dblayer import get_external_groups, get_all_login_method_groups
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 import unittest
 
 class WebGroupTest(unittest.TestCase):
     """Test functions related to the Apache authentication."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """setting up helper variables for tests"""
         self.email = 'ciccio@pasticcio.it'
         self.pwd = '123'
         self.login_method = 'PATATA'
         self.uid = run_sql("""INSERT INTO user (email, password) VALUES (%s, AES_ENCRYPT(email,%s))""", (self.email, self.pwd, ))
         self.uid = int(self.uid)
 
         self.email2 = 'ghero@boll.ch'
         self.pwd2 = '1234'
         self.uid2 = run_sql("""INSERT INTO user (email, password) VALUES (%s, AES_ENCRYPT(email,%s))""", (self.email2, self.pwd2, ))
         self.uid2 = int(self.uid2)
 
         self.goodgroup = 'bla'
         self.badgroup = 'blo'
         self.goodid = run_sql("""INSERT INTO usergroup(name, description, join_policy, login_method)
             VALUES (%s, %s, 'VE', 'INTERNAL')""", (self.goodgroup, self.goodgroup))
         self.badid = run_sql("""INSERT INTO usergroup(name, description, join_policy, login_method)
             VALUES (%s, %s, 'VE', 'INTERNAL')""", (self.badgroup, self.badgroup))
         run_sql("""INSERT INTO user_usergroup(id_user, id_usergroup, user_status, user_status_date)
             VALUES (1, %s, 'M', NOW())""", (self.goodid, ))
 
 
     def test_synchronize_external_groups(self):
         """webgroup - synchronizing one user external groups"""
         synchronize_external_groups(self.uid, {'group1' : 'descr1', 'group2' : 'descr2'}, self.login_method)
         groups = get_external_groups(self.uid)
         groups_names = [name[1] for name in groups]
         self.failUnless('group1' in groups_names)
         self.failUnless('group2' in groups_names)
         synchronize_external_groups(self.uid, {'group1' : 'descr1', 'group2' : 'descr2'}, self.login_method)
         groups = get_external_groups(self.uid)
         groups_names = [name[1] for name in groups]
         self.failUnless('group1' in groups_names)
         self.failUnless('group2' in groups_names)
         self.failUnless(len(groups_names) == 2)
         synchronize_external_groups(self.uid, {'group1' : 'descr1', 'group3' : 'descr2'}, self.login_method)
         groups = get_external_groups(self.uid)
         groups_names = [name[1] for name in groups]
         self.failUnless('group1' in groups_names)
         self.failUnless('group3' in groups_names)
         self.failUnless(len(groups_names) == 2)
         synchronize_external_groups(self.uid, {}, self.login_method)
         groups = get_external_groups(self.uid)
         groups_names = [name[1] for name in groups]
         self.failUnless(len(groups_names) == 0)
 
     def test_synchronize_all_external_groups(self):
         """webgroup - synchronizing all external groups"""
         synchronize_all_external_groups({'group1' : ('descr1', [self.email, self.email2])}, self.login_method)
         groups = get_external_groups(self.uid2)
         self.assertEqual(len(groups), 1)
         synchronize_all_external_groups({'group2' : ('descr1', [self.email, self.email2])}, self.login_method)
         groups = get_external_groups(self.uid2)
         self.assertEqual(len(groups), 1)
         self.assertEqual(groups[0][1], 'group2')
         self.assertEqual(groups[0][2], 'descr1')
         synchronize_all_external_groups({'group2' : ('descr2', [self.email])}, self.login_method)
         groups = get_external_groups(self.uid)
         self.assertEqual(groups[0][2], 'descr2')
         groups = get_external_groups(self.uid)
         self.assertEqual(len(groups), 1)
         self.assertEqual(groups[0][1], 'group2')
         groups = get_external_groups(self.uid2)
         self.assertEqual(len(groups), 0)
         synchronize_all_external_groups({}, self.login_method)
         groups = get_external_groups(self.uid2)
         self.assertEqual(len(groups), 0)
         groups = get_all_login_method_groups(self.login_method)
         self.failIf(groups)
 
     def test_external_groups_visibility_groupspage(self):
         """webgroup - external group visibility in groups page"""
         browser = Browser()
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/login")
         browser.select_form(nr=0)
         browser['p_un'] = 'admin'
         browser['p_pw'] = ''
         browser.submit()
 
         expected_response = "You are logged in as admin"
         login_response_body = browser.response().read()
         try:
             login_response_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, login_response_body))
 
         browser.open(CFG_SITE_SECURE_URL + "/yourgroups/display")
         expected_response = self.goodgroup
         groups_body = browser.response().read()
         try:
             groups_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                     (expected_response, groups_body))
 
         not_expected_response = self.badgroup
         try:
             groups_body.index(not_expected_response)
         except ValueError:
             pass
         else:
             self.fail("Not expected to see %s, got %s." % \
                     (not_expected_response, groups_body))
 
     def test_external_groups_visibility_messagespage(self):
         """webgroup - external group visibility in messages page"""
         browser = Browser()
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/login")
         browser.select_form(nr=0)
         browser['p_un'] = 'admin'
         browser['p_pw'] = ''
         browser.submit()
 
         expected_response = "You are logged in as admin"
         login_response_body = browser.response().read()
         try:
             login_response_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, login_response_body))
 
         browser.open(CFG_SITE_SECURE_URL + "/yourmessages/write")
         browser.select_form(nr=0)
         browser['search_pattern'] = 'b'
         browser.submit(name='search_group')
 
         expected_response = self.goodgroup
         groups_body = browser.response().read()
         try:
             groups_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                     (expected_response, groups_body))
 
         not_expected_response = self.badgroup
         try:
             groups_body.index(not_expected_response)
         except ValueError:
             pass
         else:
             self.fail("Not expected to see %s, got %s." % \
                     (not_expected_response, groups_body))
 
 
 
     def tearDown(self):
         run_sql("""DELETE FROM user WHERE email=%s""", (self.email,))
         run_sql("""DELETE FROM user WHERE email=%s""", (self.email2,))
         run_sql("""DELETE FROM usergroup WHERE login_method=%s""", (self.login_method,))
         run_sql("""DELETE FROM user_usergroup WHERE id_user=%s""", (self.uid, ))
         run_sql("""DELETE FROM user_usergroup WHERE id_user=%s""", (self.uid2, ))
         run_sql("""DELETE FROM usergroup WHERE name=%s OR name=%s""", (self.goodgroup, self.badgroup,))
         run_sql("""DELETE FROM user_usergroup WHERE id_usergroup=%s OR id_usergroup=%s""", (self.goodid, self.badid,))
 
-test_suite = make_test_suite(WebGroupTest)
+TEST_SUITE = make_test_suite(WebGroupTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/websession/lib/webgroup_tests.py b/modules/websession/lib/webgroup_tests.py
index ff383434f..82b790043 100644
--- a/modules/websession/lib/webgroup_tests.py
+++ b/modules/websession/lib/webgroup_tests.py
@@ -1,56 +1,53 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
-"""Unit tests for the user handling library."""
+"""Unit tests for the group handling library."""
 
 __revision__ = "$Id$"
 
 import unittest
+from invenio.testutils import make_test_suite, run_test_suite
 
 # Compatibility stuff for python 2.3. Warning: don't use fancy methods!
 try:
     set
 except NameError:
     from sets import Set
     set = Set
 
 class WebGroupTests(unittest.TestCase):
     """Test functions related to the WebGroup usage."""
 
     def test_set(self):
         """webgroup - test fancy usage of set (differences among Python versions)"""
         # These should succeed:
         self.failUnless(set([1,2,3]))
         self.assertEqual(set([1,2,3]) - set([3,4,5]), set([1,2]))
         self.assertEqual(set([1,2,3,3]), set([1,2,3]))
         self.assertEqual(set([1,2,3]), set([3,2,1]))
         self.assertEqual(set([1,2,3]) & set([2,3,4]), set([2,3]))
         self.assertEqual(set([1,2,3]) | set([2,3,4]), set([1,2,3,4]))
         self.assertEqual(set([1,2,3]), set([3,2,1]))
 
-def create_test_suite():
-    """Return test suite for the user handling."""
-    return unittest.TestSuite((unittest.makeSuite(
-        WebGroupTests,'test'),
-                               ))
+TEST_SUITE = make_test_suite(WebGroupTests,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/websession/lib/websession_regression_tests.py b/modules/websession/lib/websession_regression_tests.py
index 0e647571a..eda2cfb63 100644
--- a/modules/websession/lib/websession_regression_tests.py
+++ b/modules/websession/lib/websession_regression_tests.py
@@ -1,116 +1,116 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 # pylint: disable-msg=E1102
 
 """WebSession Regression Test Suite."""
 
 __revision__ = \
     "$Id$"
 
 import unittest
 
 from mechanize import Browser
 from invenio.config import CFG_SITE_SECURE_URL, CFG_SITE_ADMIN_EMAIL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 from invenio.dbquery import run_sql
 
 class WebSessionWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebSession web pages whether they are up or not."""
 
     def test_your_account_pages_availability(self):
         """websession - availability of Your Account pages"""
 
         baseurl = CFG_SITE_SECURE_URL + '/youraccount/'
 
         _exports = ['', 'edit', 'change', 'lost', 'display',
                     'send_email', 'youradminactivities',
                     'delete', 'logout', 'login', 'register']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_your_groups_pages_availability(self):
         """websession - availability of Your Groups pages"""
 
         baseurl = CFG_SITE_SECURE_URL + '/yourgroups/'
 
         _exports = ['', 'display', 'create', 'join', 'leave', 'edit', 'members']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
 class WebSessionLostYourPasswordTest(unittest.TestCase):
     """Test Lost Your Passwords functionality."""
 
     def test_lost_your_password_for_internal_accounts(self):
         """websession - sending lost password for internal admin account"""
 
         try_with_account = CFG_SITE_ADMIN_EMAIL
 
         # click on "send lost password" for CFG_SITE_ADMIN_EMAIL internal account
         browser = Browser()
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/lost")
         browser.select_form(nr=0)
         browser['p_email'] = try_with_account
         try:
             browser.submit()
         except Exception, e:
             # Restore the admin password (send_email set it to random number)
             run_sql("UPDATE user SET password=AES_ENCRYPT(email, '')"
                 "WHERE id=1")
             self.fail("Obtained %s: probably the email server is not installed "
                 "correctly." % e)
 
 
 
         # verify the response:
         expected_response = "Okay, a password reset link has been emailed to " + \
                             try_with_account
         lost_password_response_body = browser.response().read()
         try:
             lost_password_response_body.index(expected_response)
         except ValueError:
             # Restore the admin password (send_email set it to random number)
             run_sql("UPDATE user SET password=AES_ENCRYPT(email, '')"
                 "WHERE id=1")
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, lost_password_response_body))
 
     def tearDown(self):
         # Restore the admin password (send_email set it to random number)
         run_sql("UPDATE user SET password=AES_ENCRYPT(email, '')"
             "WHERE id=1")
 
-test_suite = make_test_suite(WebSessionWebPagesAvailabilityTest,
+TEST_SUITE = make_test_suite(WebSessionWebPagesAvailabilityTest,
                              WebSessionLostYourPasswordTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/websession/lib/webuser_regression_tests.py b/modules/websession/lib/webuser_regression_tests.py
index 33097140f..a6c390da5 100644
--- a/modules/websession/lib/webuser_regression_tests.py
+++ b/modules/websession/lib/webuser_regression_tests.py
@@ -1,279 +1,279 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 # pylint: disable-msg=E1102
 
 """WebSession Regression Test Suite."""
 
 __revision__ = \
     "$Id$"
 
 import unittest
 
 from mechanize import Browser
 
 from invenio.dbquery import run_sql
 from invenio.config import CFG_SITE_SECURE_URL, CFG_SITE_ADMIN_EMAIL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class WebSessionYourSettingsTest(unittest.TestCase):
     """Check WebSession web pages whether they are up or not."""
 
     def tearDown(self):
         run_sql('DELETE FROM user WHERE email="foo@cds.cern.ch"')
         run_sql('DELETE FROM user WHERE email="FOO@cds.cern.ch"')
 
     def test_password_setting(self):
         """webuser - check password settings"""
         browser = Browser()
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/login")
         browser.select_form(nr=0)
         browser['p_un'] = 'admin'
         browser['p_pw'] = ''
         browser.submit()
 
         expected_response = "You are logged in as admin"
         login_response_body = browser.response().read()
         try:
             login_response_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, login_response_body))
 
         # Going to set new password from "" to "123"
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/edit")
         browser.select_form(name="edit_password")
         browser['old_password'] = ""
         browser['password'] = "123"
         browser['password2'] = "123"
         browser.submit()
         expected_response = "Password successfully edited"
         change_password_body = browser.response().read()
         try:
             change_password_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                     (expected_response, change_password_body))
 
         # Going to set a wrong old password
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/edit")
         browser.select_form(name="edit_password")
         browser['old_password'] = "321"
         browser['password'] = "123"
         browser['password2'] = "123"
         browser.submit()
         expected_response = "Wrong old password inserted"
         change_password_body = browser.response().read()
         try:
             change_password_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                     (expected_response, change_password_body))
 
         # Going to put different new passwords
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/edit")
         browser.select_form(name="edit_password")
         browser['old_password'] = "123"
         browser['password'] = "123"
         browser['password2'] = "321"
         browser.submit()
         expected_response = "Both passwords must match"
         change_password_body = browser.response().read()
         try:
             change_password_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                     (expected_response, change_password_body))
 
         # Reset the situation
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/edit")
         browser.select_form(name="edit_password")
         browser['old_password'] = "123"
         browser['password'] = ""
         browser['password2'] = ""
         browser.submit()
         expected_response = "Password successfully edited"
         change_password_body = browser.response().read()
         try:
             change_password_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                     (expected_response, change_password_body))
 
     def test_email_caseless(self):
         """webuser - check email caseless"""
         browser = Browser()
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/register")
         browser.select_form(nr=0)
         browser['p_email'] = 'foo@cds.cern.ch'
         browser['p_nickname'] = 'foobar'
         browser['p_pw'] = ''
         browser['p_pw2'] = ''
         browser.submit()
 
         expected_response = "Account created"
         login_response_body = browser.response().read()
         try:
             login_response_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, login_response_body))
 
 
         browser = Browser()
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/register")
         browser.select_form(nr=0)
         browser['p_email'] = 'foo@cds.cern.ch'
         browser['p_nickname'] = 'foobar2'
         browser['p_pw'] = ''
         browser['p_pw2'] = ''
         browser.submit()
 
         expected_response = "Registration failure"
         login_response_body = browser.response().read()
         try:
             login_response_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, login_response_body))
 
         browser = Browser()
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/register")
         browser.select_form(nr=0)
         browser['p_email'] = 'FOO@cds.cern.ch'
         browser['p_nickname'] = 'foobar2'
         browser['p_pw'] = ''
         browser['p_pw2'] = ''
         browser.submit()
 
         expected_response = "Registration failure"
         login_response_body = browser.response().read()
         try:
             login_response_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, login_response_body))
 
     def test_select_records_per_group(self):
         """webuser - test of user preferences setting"""
 
         # logging in as admin
         browser = Browser()
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/login")
         browser.select_form(nr=0)
         browser['p_un'] = 'admin'
         browser['p_pw'] = ''
         browser.submit()
 
         expected_response = "You are logged in as admin"
         login_response_body = browser.response().read()
         try:
             login_response_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, login_response_body))
 
         # Going to edit page and setting records per group to 20
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/edit")
         browser.select_form(name="edit_websearch_settings")
         browser['group_records'] = ["20"]
         browser.submit()
 
         expected_response = "User settings saved correctly"
         changed_settings_body = browser.response().read()
         try:
             changed_settings_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, changed_settings_body))
 
         # Going to the search page, making an empty search
         browser.open(CFG_SITE_SECURE_URL)
         browser.select_form(nr=0)
         browser.submit()
         expected_response = "1 - 20"
         records_found_body = browser.response().read()
         try:
             records_found_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, records_found_body))
 
         # Going again to edit and setting records per group back to 10
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/edit")
         browser.select_form(name="edit_websearch_settings")
         browser['group_records'] = ["10"]
         browser.submit()
 
         expected_response = "User settings saved correctly"
         changed_settings_body = browser.response().read()
         try:
             changed_settings_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, changed_settings_body))
 
         # Logging out!
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/logout")
         expected_response = "You are no longer recognized"
         logout_response_body = browser.response().read()
         try:
             logout_response_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, logout_response_body))
 
         # Logging in again
         browser.open(CFG_SITE_SECURE_URL + "/youraccount/login")
         browser.select_form(nr=0)
         browser['p_un'] = 'admin'
         browser['p_pw'] = ''
         browser.submit()
 
         expected_response = "You are logged in as admin"
         login_response_body = browser.response().read()
         try:
             login_response_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, login_response_body))
 
         # Let's go to search and check that the setting is still there
         browser.open(CFG_SITE_SECURE_URL)
         browser.select_form(nr=0)
         browser.submit()
         expected_response = "1 - 10"
         records_found_body = browser.response().read()
         try:
             records_found_body.index(expected_response)
         except ValueError:
             self.fail("Expected to see %s, got %s." % \
                       (expected_response, records_found_body))
 
         return
 
 
 
-test_suite = make_test_suite(WebSessionYourSettingsTest)
+TEST_SUITE = make_test_suite(WebSessionYourSettingsTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/websession/lib/webuser_tests.py b/modules/websession/lib/webuser_tests.py
index 2d25db087..8ab63e46b 100644
--- a/modules/websession/lib/webuser_tests.py
+++ b/modules/websession/lib/webuser_tests.py
@@ -1,92 +1,89 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the user handling library."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio import webuser
+from invenio.testutils import make_test_suite, run_test_suite
 
 class ApacheAuthenticationTests(unittest.TestCase):
     """Test functions related to the Apache authentication."""
 
     def setUp(self):
         # pylint: disable-msg=C0103
         """setting up helper variables for tests"""
         self.apache_password_file = "demo-site-apache-user-passwords"
         self.apache_group_file = "demo-site-apache-user-groups"
 
     def test_auth_apache_user_p(self):
         """webuser - apache user password checking"""
         # These should succeed:
         self.assertEqual(True,
                          webuser.auth_apache_user_p('jekyll', 'j123ekyll',
                                                     self.apache_password_file))
         self.assertEqual(True,
                          webuser.auth_apache_user_p('hyde', 'h123yde',
                                                     self.apache_password_file))
         # Note: the following one should succeed even though the real
         # password is different, because crypt() looks at first 8
         # chars only:
         self.assertEqual(True,
                          webuser.auth_apache_user_p('jekyll', 'j123ekylx',
                                                     self.apache_password_file))
         # Now some attempts that should fail:
         self.assertEqual(False,
                          webuser.auth_apache_user_p('jekyll', '',
                                                     self.apache_password_file))
         self.assertEqual(False,
                          webuser.auth_apache_user_p('jekyll', 'h123yde',
                                                     self.apache_password_file))
         self.assertEqual(False,
                          webuser.auth_apache_user_p('jekyll', 'aoeuidhtns',
                                                     self.apache_password_file))
         self.assertEqual(False,
                          webuser.auth_apache_user_p('aoeui', '',
                                                     self.apache_password_file))
         self.assertEqual(False,
                          webuser.auth_apache_user_p('aoeui', 'h123yde',
                                                     self.apache_password_file))
         self.assertEqual(False,
                          webuser.auth_apache_user_p('aoeui', 'dhtns',
                                                     self.apache_password_file))
 
     def test_auth_apache_user_in_groups(self):
         """webuser - apache user group membership checking"""
         self.assertEqual(['theses'],
           webuser.auth_apache_user_in_groups('jekyll', self.apache_group_file))
         self.assertEqual([],
           webuser.auth_apache_user_in_groups('hyde', self.apache_group_file))
         self.assertEqual([],
           webuser.auth_apache_user_in_groups('aoeui', self.apache_group_file))
 
-def create_test_suite():
-    """Return test suite for the user handling."""
-    return unittest.TestSuite((unittest.makeSuite(
-        ApacheAuthenticationTests,'test'),
-                               ))
+TEST_SUITE = make_test_suite(ApacheAuthenticationTests,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
 
 
diff --git a/modules/webstyle/lib/webinterface_tests.py b/modules/webstyle/lib/webinterface_tests.py
index 2a80734dd..990c26ef4 100644
--- a/modules/webstyle/lib/webinterface_tests.py
+++ b/modules/webstyle/lib/webinterface_tests.py
@@ -1,139 +1,139 @@
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """Unit tests for the webinterface module."""
 
 __revision__ = "$Id$"
 
 import unittest, sys, cgi
 
+from invenio.testutils import make_test_suite, run_test_suite
+
 # SLIPPERY SLOPE AHEAD
 #
 # Trick mod_python into believing there is already an _apache module
 # available, which is used only for its parse_qs functions anyway.
 #
 # This must be done early, as many imports somehow end up importing
 # apache in turn, which makes the trick useless.
 
 class _FakeApache(object):
 
     SERVER_RETURN = 'RETURN'
 
     def __init__(self):
         self.table = None
         self.log_error = None
         self.table = None
         self.config_tree = None
         self.server_root = None
         self.mpm_query = None
         self.exists_config_define = None
         self.stat = None
         self.AP_CONN_UNKNOWN = None
         self.AP_CONN_CLOSE = None
         self.AP_CONN_KEEPALIVE = None
         self.APR_NOFILE = None
         self.APR_REG = None
         self.APR_DIR = None
         self.APR_CHR = None
         self.APR_BLK = None
         self.APR_PIPE = None
         self.APR_LNK = None
         self.APR_SOCK = None
         self.APR_UNKFILE = None
 
     def parse_qs(self, *args, **kargs):
         return cgi.parse_qs(*args, **kargs)
 
     def parse_qsl(self, *args, **kargs):
         return cgi.parse_qsl(*args, **kargs)
 
 class _FakeReq(object):
 
     def __init__(self, q):
         self.args = q
         self.method = "GET"
         return
 
 _current_module = sys.modules.get('mod_python._apache')
 
 sys.modules['mod_python._apache'] = _FakeApache()
 
 from mod_python.util import FieldStorage
 
 if _current_module:
     sys.modules['mod_python._apache'] = _current_module
 else:
     del sys.modules['mod_python._apache']
 
 
 # --------------------------------------------------
 
 from invenio import webinterface_handler
 from invenio.config import CFG_SITE_LANG
 
 
 class TestWashArgs(unittest.TestCase):
     """webinterface - Test for washing of URL query arguments"""
 
     def _check(self, query, default, expected):
         req = _FakeReq(query)
         form = FieldStorage(req, keep_blank_values=True)
         result = webinterface_handler.wash_urlargd(form, default)
 
         if not 'ln' in expected:
             expected['ln'] = CFG_SITE_LANG
 
         self.failUnlessEqual(result, expected)
 
     def test_single_string(self):
         """ webinterface - check retrieval of a single string field """
 
         default = {'c': (str, 'default')}
 
         self._check('c=Test1', default, {'c': 'Test1'})
         self._check('d=Test1', default, {'c': 'default'})
         self._check('c=Test1&c=Test2', default, {'c': 'Test1'})
 
     def test_string_list(self):
         """ webinterface - check retrieval of a list of values """
 
         default = {'c': (list, ['default'])}
 
         self._check('c=Test1', default, {'c': ['Test1']})
         self._check('c=Test1&c=Test2', default, {'c': ['Test1', 'Test2']})
         self._check('d=Test1', default, {'c': ['default']})
 
     def test_int_casting(self):
         """ webinterface - check casting into an int. """
 
         default = {'jrec': (int, -1)}
 
         self._check('jrec=12', default, {'jrec': 12})
         self._check('jrec=', default, {'jrec': -1})
         self._check('jrec=foo', default, {'jrec': -1})
         self._check('jrec=foo&jrec=1', default, {'jrec': -1})
         self._check('jrec=12&jrec=foo', default, {'jrec': 12})
 
 
-def create_test_suite():
-    """Return test suite for the search engine."""
-    return unittest.TestSuite((unittest.makeSuite(TestWashArgs),))
+TEST_SUITE = make_test_suite(TestWashArgs,)
 
 if __name__ == "__main__":
-    unittest.TextTestRunner(verbosity=2).run(create_test_suite())
+    run_test_suite(TEST_SUITE)
diff --git a/modules/websubmit/lib/websubmit_regression_tests.py b/modules/websubmit/lib/websubmit_regression_tests.py
index 39dc2459e..9c9deda63 100644
--- a/modules/websubmit/lib/websubmit_regression_tests.py
+++ b/modules/websubmit/lib/websubmit_regression_tests.py
@@ -1,106 +1,106 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebSubmit Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class WebSubmitWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebSubmit web pages whether they are up or not."""
 
     def test_submission_pages_availability(self):
         """websubmit - availability of submission pages"""
 
         baseurl = CFG_SITE_URL + '/submit/'
 
         _exports = ['', 'direct']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_publiline_pages_availability(self):
         """websubmit - availability of approval pages"""
 
         baseurl = CFG_SITE_URL
 
         _exports = ['/approve.py', '/publiline.py',
                     '/yourapprovals.py']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_your_submissions_pages_availability(self):
         """websubmit - availability of Your Submissions pages"""
 
         baseurl = CFG_SITE_URL
 
         _exports = ['/yoursubmissions.py']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             error_messages.extend(test_web_page_content(url))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_help_page_availability(self):
         """websubmit - availability of WebSubmit help page"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/submit-guide',
                                                expected_text="Submit Guide"))
 
 class WebSubmitTestLegacyURLs(unittest.TestCase):
     """ Check that the application still responds to legacy URLs"""
 
     def test_legacy_help_page_link(self):
         """websubmit - legacy Submit Guide page link"""
 	self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/submit',
                                                expected_text="Submit Guide"))
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/submit/',
                                                expected_text="Submit Guide"))
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/submit/index.en.html',
                                               expected_text="Submit Guide"))
         self.assertEqual([],
                          test_web_page_content(CFG_SITE_URL + '/help/submit/access.en.html',
                                               expected_text="Submit Guide"))
 
-test_suite = make_test_suite(WebSubmitWebPagesAvailabilityTest,
+TEST_SUITE = make_test_suite(WebSubmitWebPagesAvailabilityTest,
                              WebSubmitTestLegacyURLs)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/modules/websubmit/lib/websubmitadmin_regression_tests.py b/modules/websubmit/lib/websubmitadmin_regression_tests.py
index beda97c58..34589ae6e 100644
--- a/modules/websubmit/lib/websubmitadmin_regression_tests.py
+++ b/modules/websubmit/lib/websubmitadmin_regression_tests.py
@@ -1,71 +1,71 @@
 # -*- coding: utf-8 -*-
 ##
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
 """WebSubmit Admin Regression Test Suite."""
 
 __revision__ = "$Id$"
 
 import unittest
 
 from invenio.config import CFG_SITE_URL
-from invenio.testutils import make_test_suite, warn_user_about_tests_and_run, \
+from invenio.testutils import make_test_suite, run_test_suite, \
                               test_web_page_content, merge_error_messages
 
 class WebSubmitAdminWebPagesAvailabilityTest(unittest.TestCase):
     """Check WebSubmit Admin web pages whether they are up or not."""
 
     def test_websubmit_admin_interface_pages_availability(self):
         """websubmitadmin - availability of WebSubmit Admin interface pages"""
 
         baseurl = CFG_SITE_URL + '/admin/websubmit/websubmitadmin.py/'
 
         _exports = ['', 'showall', 'doctypelist', 'doctypeadd',
                     'doctyperemove', 'actionlist', 'jschecklist',
                     'elementlist', 'functionlist']
 
         error_messages = []
         for url in [baseurl + page for page in _exports]:
             # first try as guest:
             error_messages.extend(test_web_page_content(url,
                                                         username='guest',
                                                         expected_text=
                                                         'Authorization failure'))
             # then try as admin:
             error_messages.extend(test_web_page_content(url,
                                                         username='admin'))
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
     def test_websubmit_admin_guide_availability(self):
         """websubmitadmin - availability of WebSubmit Admin guide pages"""
 
         url = CFG_SITE_URL + '/help/admin/websubmit-admin-guide'
         error_messages = test_web_page_content(url,
                                                expected_text="WebSubmit Admin Guide")
         if error_messages:
             self.fail(merge_error_messages(error_messages))
         return
 
-test_suite = make_test_suite(WebSubmitAdminWebPagesAvailabilityTest)
+TEST_SUITE = make_test_suite(WebSubmitAdminWebPagesAvailabilityTest)
 
 if __name__ == "__main__":
-    warn_user_about_tests_and_run(test_suite)
+    run_test_suite(TEST_SUITE, warn_user=True)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2cf052c57..faaa7f478 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,239 +1,238 @@
 ## $Id$
 ##
 ## This file is part of CDS Invenio.
 ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 CERN.
 ##
 ## CDS Invenio is free software; you can redistribute it and/or
 ## modify it under the terms of the GNU General Public License as
 ## published by the Free Software Foundation; either version 2 of the
 ## License, or (at your option) any later version.
 ##
 ## CDS Invenio is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 ## General Public License for more details.
 ##
 ## You should have received a copy of the GNU General Public License
 ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc.,
 ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 #
 # List of source files which contain translatable strings.
 #
 modules/webhelp/web/help-central.webdoc
 modules/webhelp/web/admin/admin.webdoc
 modules/websearch/doc/search-tips.webdoc
 modules/websearch/doc/search-guide.webdoc
 modules/websearch/doc/admin/websearch-admin-guide.webdoc
 modules/websubmit/doc/submit-guide.webdoc
 modules/websubmit/doc/admin/websubmit-admin-guide.webdoc
 modules/bibedit/doc/admin/bibedit-admin-guide.webdoc
 modules/bibupload/doc/admin/bibupload-admin-guide.webdoc
 modules/bibformat/doc/admin/bibformat-admin-guide.webdoc
 modules/bibharvest/doc/admin/bibharvest-admin-guide.webdoc
 modules/webmessage/doc/admin/webmessage-admin-guide.webdoc
 modules/webalert/doc/admin/webalert-admin-guide.webdoc
 modules/bibclassify/doc/admin/bibclassify-admin-guide.webdoc
 modules/bibmatch/doc/admin/bibmatch-admin-guide.webdoc
 modules/bibconvert/doc/admin/bibconvert-admin-guide.webdoc
 modules/bibsched/doc/admin/bibsched-admin-guide.webdoc
 modules/bibrank/doc/admin/bibrank-admin-guide.webdoc
 modules/webstat/doc/admin/webstat-admin-guide.webdoc
 modules/bibindex/doc/admin/bibindex-admin-guide.webdoc
 modules/webbasket/doc/admin/webbasket-admin-guide.webdoc
 modules/webcomment/doc/admin/webcomment-admin-guide.webdoc
 modules/websession/doc/admin/websession-admin-guide.webdoc
 modules/webstyle/doc/admin/webstyle-admin-guide.webdoc
 modules/elmsubmit/doc/admin/elmsubmit-admin-guide.webdoc
 modules/bibformat/etc/format_templates/Default_HTML_files.bft
 modules/bibformat/etc/format_templates/Default_HTML_actions.bft
 modules/bibconvert/bin/bibconvert.in
 modules/bibconvert/lib/bibconvert.py
 modules/bibconvert/lib/bibconvert_tests.py
 modules/bibedit/bin/refextract.in
 modules/bibedit/bin/xmlmarclint.in
 modules/bibedit/lib/bibedit_templates.py
 modules/bibedit/lib/bibrecord_config.py
 modules/bibedit/lib/bibrecord.py
 modules/bibedit/lib/bibrecord_tests.py
 modules/bibedit/lib/refextract_config.py
 modules/bibedit/lib/refextract.py
 modules/bibedit/web/admin/bibeditadmin.py
 modules/bibformat/bin/bibreformat.in
 modules/bibformat/lib/bibformat_templates.py
 modules/bibformat/lib/bibformatadminlib.py
 modules/bibformat/lib/elements/bfe_authors.py
 modules/bibformat/web/admin/bibformatadmin.py
 modules/bibharvest/bin/bibharvest.in
 modules/bibharvest/bin/oaiharvest.in
 modules/bibharvest/lib/bibharvestadminlib.py
 modules/bibharvest/lib/bibharvest_templates.py
 modules/bibharvest/lib/oaiharvestlib.py
 modules/bibharvest/lib/oai_repository_config.py
 modules/bibharvest/lib/oai_repository.py
 modules/bibharvest/lib/oai_repository_tests.py
 modules/bibharvest/web/admin/bibharvestadmin.py
 modules/bibindex/bin/bibindex.in
 modules/bibindex/bin/bibstat.in
 modules/bibindex/lib/bibindexadminlib.py
 modules/bibindex/lib/bibindex_engine_config.py
 modules/bibindex/lib/bibindex_engine.py
 modules/bibindex/lib/bibindex_engine_stemmer.py
 modules/bibindex/lib/bibindex_engine_stemmer_tests.py
 modules/bibindex/lib/bibindex_engine_stopwords.py
 modules/bibindex/lib/bibindex_engine_tests.py
 modules/bibindex/web/admin/bibindexadmin.py
 modules/bibrank/bin/bibrankgkb.in
 modules/bibrank/bin/bibrank.in
 modules/bibrank/lib/bibrankadminlib.py
 modules/bibrank/lib/bibrank_citation_grapher.py
 modules/bibrank/lib/bibrank_citation_indexer.py
 modules/bibrank/lib/bibrank_citation_indexer_tests.py
 modules/bibrank/lib/bibrank_citation_searcher.py
 modules/bibrank/lib/bibrank_citation_searcher_tests.py
 modules/bibrank/lib/bibrank_downloads_grapher.py
 modules/bibrank/lib/bibrank_downloads_indexer.py
 modules/bibrank/lib/bibrank_downloads_indexer_tests.py
 modules/bibrank/lib/bibrank_downloads_similarity.py
 modules/bibrank/lib/bibrank_grapher.py
 modules/bibrank/lib/bibrank_record_sorter.py
 modules/bibrank/lib/bibrank_record_sorter_tests.py
 modules/bibrank/lib/bibrank_tag_based_indexer.py
 modules/bibrank/lib/bibrank_tag_based_indexer_tests.py
 modules/bibrank/lib/bibrank_word_indexer.py
 modules/bibrank/web/admin/bibrankadmin.py
 modules/bibsched/bin/bibsched.in
 modules/bibsched/bin/bibtaskex.in
 modules/elmsubmit/bin/elmsubmit.in
 modules/elmsubmit/lib/elmsubmit_enriched2txt.py
 modules/elmsubmit/lib/elmsubmit_EZArchive.py
 modules/elmsubmit/lib/elmsubmit_EZEmail.py
 modules/elmsubmit/lib/elmsubmit_field_validation.py
 modules/elmsubmit/lib/elmsubmit_filename_generator.py
 modules/elmsubmit/lib/elmsubmit_html2txt.py
 modules/elmsubmit/lib/elmsubmit_misc.py
 modules/elmsubmit/lib/elmsubmit.py
 modules/elmsubmit/lib/elmsubmit_richtext2txt.py
 modules/elmsubmit/lib/elmsubmit_submission_parser.py
 modules/elmsubmit/lib/myhtmlentitydefs.py
 modules/miscutil/bin/dbexec.in
-modules/miscutil/bin/testsuite.in
 modules/miscutil/lib/dateutils.py
 modules/miscutil/lib/errorlib.py
 modules/miscutil/lib/errorlib_tests.py
 modules/miscutil/lib/errorlib_webinterface.py
 modules/miscutil/lib/__init__.py
 modules/miscutil/lib/inveniocfg.py
 modules/miscutil/lib/miscutil_config.py
 modules/miscutil/lib/mailutils.py
 modules/miscutil/lib/messages.py
 modules/miscutil/lib/textutils.py
 modules/webaccess/bin/authaction.in
 modules/webaccess/bin/webaccessadmin.in
 modules/webaccess/lib/access_control_admin.py
 modules/webaccess/lib/access_control_config.py
 modules/webaccess/lib/access_control_engine.py
 modules/webaccess/lib/external_authentication.py
 modules/webaccess/lib/webaccessadmin_lib.py
 modules/webaccess/web/admin/webaccessadmin.py
 modules/webalert/bin/alertengine.in
 modules/webalert/lib/alert_engine.py
 modules/webalert/lib/htmlparser.py
 modules/webalert/lib/webalert.py
 modules/webalert/lib/webalert_templates.py
 modules/webalert/lib/webalert_webinterface.py
 modules/webbasket/lib/webbasket.py
 modules/webbasket/lib/webbasket_config.py
 modules/webbasket/lib/webbasket_templates.py
 modules/webbasket/lib/webbasket_webinterface.py
 modules/webcomment/lib/webcommentadminlib.py
 modules/webcomment/lib/webcomment_config.py
 modules/webcomment/lib/webcomment.py
 modules/webcomment/lib/webcomment_templates.py
 modules/webcomment/lib/webcomment_tests.py
 modules/webcomment/lib/webcomment_webinterface.py
 modules/webcomment/web/admin/webcommentadmin.py
 modules/webmessage/bin/webmessageadmin.in
 modules/webmessage/lib/webmessage_config.py
 modules/webmessage/lib/webmessage_dblayer.py
 modules/webmessage/lib/webmessage_mailutils.py
 modules/webmessage/lib/webmessage.py
 modules/webmessage/lib/webmessage_templates.py
 modules/webmessage/lib/webmessage_webinterface.py
 modules/websearch/bin/webcoll.in
 modules/websearch/lib/search_engine_config.py
 modules/websearch/lib/search_engine.py
 modules/websearch/lib/search_engine_tests.py
 modules/websearch/lib/websearchadminlib.py
 modules/websearch/lib/websearch_templates.py
 modules/websearch/lib/websearch_webinterface.py
 modules/websearch/lib/websearch_external_collections.py
 modules/websearch/lib/websearch_external_collections_templates.py
 modules/websearch/lib/websearch_webcoll.py
 modules/websearch/web/admin/websearchadmin.py
 modules/websession/bin/inveniogc.in
 modules/websession/lib/session.py
 modules/websession/lib/webaccount.py
 modules/websession/lib/websession.py
 modules/websession/lib/websession_templates.py
 modules/websession/lib/webuser.py
 modules/websession/lib/websession_webinterface.py
 modules/websession/lib/webgroup_dblayer.py 
 modules/websession/lib/webgroup.py
 modules/websession/lib/websession_config.py
 modules/webstat/bin/webstat.in
 modules/webstyle/lib/template.py
 modules/webstyle/lib/webpage.py
 modules/webstyle/lib/webstyle_templates.py
 modules/webstyle/lib/webdoc.py
 modules/webstyle/lib/webdoc_webinterface.py
 modules/websubmit/bin/thumbmaker.in
 modules/websubmit/lib/file.py
 modules/websubmit/lib/functions/Add_Files.py
 modules/websubmit/lib/functions/CaseEDS.py
 modules/websubmit/lib/functions/Create_Modify_Interface.py
 modules/websubmit/lib/functions/Create_Recid.py
 modules/websubmit/lib/functions/Finish_Submission.py
 modules/websubmit/lib/functions/Format_Record.py
 modules/websubmit/lib/functions/Get_Info.py
 modules/websubmit/lib/functions/Get_Report_Number.py
 modules/websubmit/lib/functions/Get_Sysno.py
 modules/websubmit/lib/functions/Insert_Modify_Record.py
 modules/websubmit/lib/functions/Insert_Record.py
 modules/websubmit/lib/functions/Is_Original_Submitter.py
 modules/websubmit/lib/functions/Is_Referee.py
 modules/websubmit/lib/functions/Mail_Submitter.py
 modules/websubmit/lib/functions/Make_Modify_Record.py
 modules/websubmit/lib/functions/Make_Record.py
 modules/websubmit/lib/functions/Move_Files_Archive.py
 modules/websubmit/lib/functions/Move_From_Pending.py
 modules/websubmit/lib/functions/Move_to_Done.py
 modules/websubmit/lib/functions/Move_to_Pending.py
 modules/websubmit/lib/functions/Print_Success_APP.py
 modules/websubmit/lib/functions/Print_Success_DEL.py
 modules/websubmit/lib/functions/Print_Success_MBI.py
 modules/websubmit/lib/functions/Print_Success.py
 modules/websubmit/lib/functions/Print_Success_SRV.py
 modules/websubmit/lib/functions/Report_Number_Generation.py
 modules/websubmit/lib/functions/Retrieve_Data.py
 modules/websubmit/lib/functions/Send_APP_Mail.py
 modules/websubmit/lib/functions/Send_Approval_Request.py
 modules/websubmit/lib/functions/Send_Modify_Mail.py
 modules/websubmit/lib/functions/Send_SRV_Mail.py
 modules/websubmit/lib/functions/Test_Status.py
 modules/websubmit/lib/functions/Update_Approval_DB.py
 modules/websubmit/lib/functions/Upload_Files.py
 modules/websubmit/lib/websubmit_config.py
 modules/websubmit/lib/websubmit_engine.py
 modules/websubmit/lib/websubmit_templates.py
 modules/websubmit/lib/websubmit_webinterface.py
 modules/websubmit/lib/websubmitadmin_config.py
 modules/websubmit/lib/websubmitadmin_engine.py
 modules/websubmit/web/admin/referees.py
 modules/websubmit/web/approve.py
 modules/websubmit/web/publiline.py
 modules/websubmit/web/yourapprovals.py
 modules/websubmit/web/yoursubmissions.py
 modules/websubmit/web/admin/websubmitadmin.py
 modules/webjournal/lib/webjournal_utils.py
 modules/webjournal/lib/webjournal_templates.py
 modules/webjournal/lib/webjournal_config.py