diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/commands/autobuild.py jhbuild/jhbuild/commands/autobuild.py
--- /home/prash/jhbuild/jhbuild/commands/autobuild.py	2006-05-17 17:33:28.000000000 +0530
+++ jhbuild/jhbuild/commands/autobuild.py	2006-07-28 23:16:32.000000000 +0530
@@ -22,6 +22,7 @@
 from jhbuild.errors import UsageError
 from jhbuild.commands.base import Command, register_command
 import jhbuild.frontends
+import os
 
 class cmd_autobuild(Command):
     '''Distributed tinderbox for jhbuild'''
@@ -55,7 +56,8 @@
 
         config.autobuild_report_url = None
         config.verbose = False
-
+        config.noxvfb = False # For running GUI test cases `testmodule'
+        
         if options.autogen:
             config.alwaysautogen = True
         if options.clean:
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/commands/base.py jhbuild/jhbuild/commands/base.py
--- /home/prash/jhbuild/jhbuild/commands/base.py	2006-05-24 11:07:27.000000000 +0530
+++ jhbuild/jhbuild/commands/base.py	2006-06-20 19:52:46.000000000 +0530
@@ -133,6 +133,9 @@
             make_option('-D', metavar='DATE-SPEC',
                         action='store', dest='sticky_date', default=None,
                         help='set a sticky date when checking out modules'),
+            make_option('-x', '--no-xvfb',
+                        action='store_true', dest='noxvfb', default=False,
+                        help='Run tests in real X and not in Xvfb')
             ])
 
     def run(self, config, options, args):
@@ -146,6 +149,8 @@
             config.skip += item.split(',')
         if options.sticky_date is not None:
             config.sticky_date = options.sticky_date
+        if options.noxvfb is not None:
+            config.noxvfb = options.noxvfb
 
         module_set = jhbuild.moduleset.load(config)
         module_list = module_set.get_module_list(args or config.modules,
@@ -183,6 +188,9 @@
             make_option('-D', metavar='DATE-SPEC',
                         action='store', dest='sticky_date', default=None,
                         help='set a sticky date when checking out modules'),
+            make_option('-x', '--no-xvfb',
+                        action='store_true', dest='noxvfb', default=False,
+                        help='Run tests in real X and not in Xvfb')
             ])
 
     def run(self, config, options, args):
@@ -194,6 +202,8 @@
             config.nonetwork = True
         if options.sticky_date is not None:
             config.sticky_date = options.sticky_date
+        if options.noxvfb is not None:
+            config.noxvfb = options.noxvfb
 
         module_set = jhbuild.moduleset.load(config)
         try:
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/commands/test.py jhbuild/jhbuild/commands/test.py
--- /home/prash/jhbuild/jhbuild/commands/test.py	1970-01-01 05:30:00.000000000 +0530
+++ jhbuild/jhbuild/commands/test.py	2006-07-28 22:49:19.000000000 +0530
@@ -0,0 +1,90 @@
+# jhbuild - a build script for GNOME 1.x and 2.x
+# Copyright (C) 2001-2006  James Henstridge
+#
+#   test.py: Contains the GUI test command
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+from optparse import make_option
+
+from jhbuild.errors import UsageError
+from jhbuild.commands.base import Command, register_command
+import jhbuild.frontends
+
+class cmd_test(Command):
+    """Runs test scripts on the given modules"""
+
+    name = 'test'
+    usage_args = '[modules ... ]'
+
+    def __init__(self):
+        Command.__init__(self, [
+            make_option('-a', '--autogen',
+                        action='store_true', dest='autogen', default=False,
+                        help='always run autogen.sh'),
+            make_option('-c', '--clean',
+                        action='store_true', dest='clean', default=False,
+                        help='run make clean before make'),
+            make_option('-n', '--no-network',
+                        action='store_true', dest='nonetwork', default=False,
+                        help='skip version control update'),
+            make_option('-s', '--skip', metavar='MODULES',
+                        action='append', dest='skip', default=[],
+                        help='treat the given modules as up to date'),
+            make_option('-t', '--start-at', metavar='MODULE',
+                        action='store', dest='startat', default=None,
+                        help='start building at the given module'),
+            make_option('-D', metavar='DATE-SPEC',
+                        action='store', dest='sticky_date', default=None,
+                        help='set a sticky date when checking out modules'),
+            make_option('-x', '--no-xvfb',
+                        action='store_true', dest='noxvfb', default=False,
+                        help='Run tests in real X and not in Xvfb')
+            ])
+    
+    def run (self, config, options, args):
+        if options.autogen:
+            config.alwaysautogen = True
+        if options.clean:
+            config.makeclean = True
+        if options.nonetwork:
+            config.nonetwork = True
+        for item in options.skip:
+            config.skip += item.split(',')
+        if options.sticky_date is not None:
+            config.sticky_date = options.sticky_date
+        if options.noxvfb is not None:
+            config.noxvfb = options.noxvfb
+            #By default run GUI tests in an Xvfb environment
+            
+        if args  == None:
+            args = []
+
+        module_set = jhbuild.moduleset.load_tests (config)
+        module_list = module_set.get_test_module_list(args, config.skip)
+
+        # remove modules upto startat
+        if options.startat:
+            while module_list and module_list[0].name != options.startat:
+                del module_list[0]
+            if not module_list:
+                raise FatalError('%s not in module list' % options.startat)
+
+        # test the modules
+        test = jhbuild.frontends.get_buildscript(config, module_list)
+        test.build()
+        #end test here
+
+register_command(cmd_test)
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/commands/tinderbox.py jhbuild/jhbuild/commands/tinderbox.py
--- /home/prash/jhbuild/jhbuild/commands/tinderbox.py	2006-05-16 07:49:54.000000000 +0530
+++ jhbuild/jhbuild/commands/tinderbox.py	2006-07-28 23:17:03.000000000 +0530
@@ -21,7 +21,7 @@
 
 from jhbuild.errors import UsageError
 from jhbuild.commands import Command, register_command
-import jhbuild.frontends
+import jhbuild.frontends, os
 
 
 class cmd_tinderbox(Command):
@@ -57,7 +57,8 @@
 
     def run(self, config, options, args):
         config.buildscript = 'tinderbox'
-
+        config.noxvfb = False
+        
         if options.autogen:
             config.alwaysautogen = True
         if options.clean:
@@ -88,5 +89,4 @@
 
         build = jhbuild.frontends.get_buildscript(config, module_list)
         build.build()
-
 register_command(cmd_tinderbox)
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/config.py jhbuild/jhbuild/config.py
--- /home/prash/jhbuild/jhbuild/config.py	2006-06-19 19:37:25.000000000 +0530
+++ jhbuild/jhbuild/config.py	2006-07-06 17:52:56.000000000 +0530
@@ -29,7 +29,7 @@
 
 _known_keys = [ 'moduleset', 'modules', 'skip', 'prefix',
                 'checkoutroot', 'buildroot', 'autogenargs', 'makeargs',
-                'repos', 'branches',
+                'repos', 'branches', 'xvfbargs',
                 'builddir_pattern', 'module_autogenargs', 'module_makeargs',
                 'interact', 'buildscript', 'nonetwork',
                 'alwaysautogen', 'nobuild', 'makeclean', 'makecheck',
@@ -183,3 +183,10 @@
                 if x.find('libgdkxft.so') >= 0:
                     valarr.remove(x)
             os.environ['LD_PRELOAD'] = ' '.join(valarr)
+
+
+        # For getting rid of verbose output for LDTP tests
+        if os.environ.has_key('LDTP_DEBUG'):
+            del os.environ['LDTP_DEBUG']
+        if not os.environ.has_key('GNOME_ACCESSIBILITY') or os.environ['GNOME_ACCESSIBILITY'] != 1:
+            os.environ['GNOME_ACCESSIBILITY'] = '1'
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/frontends/autobuild.py jhbuild/jhbuild/frontends/autobuild.py
--- /home/prash/jhbuild/jhbuild/frontends/autobuild.py	2006-07-25 22:12:07.000000000 +0530
+++ jhbuild/jhbuild/frontends/autobuild.py	2006-07-28 23:17:48.000000000 +0530
@@ -33,6 +33,7 @@
 
 from tinderbox import get_distro
 from terminal import TerminalBuildScript, trayicon, t_bold, t_reset
+import jhbuild.moduleset
 
 def escape(string):
     return string.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
@@ -84,6 +85,7 @@
         self.server = None
         self.modulefp = None
         self.phasefp = None
+        self.modules = {}
 
         # cleanup environment
         os.environ['TERM'] = 'dumb'
@@ -244,6 +246,14 @@
     def end_phase(self, module, state, error):
         log = fix_encoding(self.phasefp.getvalue())
         self.phasefp = None
+
+        if state == 'test':
+            if self.modules == {}:
+                self.modules = jhbuild.moduleset.load_tests(self.config)
+
+            if module in self.modules.modules.keys() \
+                   and self.modules.modules[module].test_type == 'ldtp':
+                self._upload_logfile(module)
         self.server.end_phase(self.build_id, module, state, compress_data(log), error)
 
     def handle_error(self, module, state, nextstate, error, altstates):
@@ -251,5 +261,16 @@
         print 'handle error!'
         return 'fail'
 
+    def _upload_logfile (self, module):
+        test_module = self.modules.modules[module]
+        src_dir =  test_module.get_srcdir()
+        if not os.path.exists (os.path.join(src_dir,'run.xml')):
+            return
+        logfile = test_module.get_ldtp_log_file (os.path.join(src_dir,'run.xml'))
+        if not os.path.exists (logfile):
+            return
+        log = open (logfile, 'r')
+        self.server.attach_file (self.build_id, module, 'test', 'LDTP Log File', compress_data(log.read()), 'application/x-ldtp+xml')
+
 
 BUILD_SCRIPT = AutobuildBuildScript
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/frontends/terminal.py jhbuild/jhbuild/frontends/terminal.py
--- /home/prash/jhbuild/jhbuild/frontends/terminal.py	2006-05-18 16:04:13.000000000 +0530
+++ jhbuild/jhbuild/frontends/terminal.py	2006-06-20 10:43:23.000000000 +0530
@@ -56,7 +56,7 @@
     'configure':      'configure.png',
     #'clean':          'clean.png',
     'build':          'build.png',
-    #'check':          'check.png',
+    'check':          'check.png',
     'install':        'install.png',
     }
 
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/frontends/tinderbox.py jhbuild/jhbuild/frontends/tinderbox.py
--- /home/prash/jhbuild/jhbuild/frontends/tinderbox.py	2006-06-14 15:32:38.000000000 +0530
+++ jhbuild/jhbuild/frontends/tinderbox.py	2006-07-20 22:03:41.000000000 +0530
@@ -137,7 +137,7 @@
     return None
 
 def escape(string):
-    return string.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
+    return string.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;').replace('\n','<br/>').replace('\t','&nbsp;&nbsp;&nbsp;&nbsp;')
 
 class TinderboxBuildScript(buildscript.BuildScript):
     def __init__(self, config, module_list):
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/main.py jhbuild/jhbuild/main.py
--- /home/prash/jhbuild/jhbuild/main.py	2006-05-16 07:49:54.000000000 +0530
+++ jhbuild/jhbuild/main.py	2006-06-20 10:35:59.000000000 +0530
@@ -34,6 +34,7 @@
         ('updateone', 'update a fixed set of modules'),
         ('list', 'list what modules would be built'),
         ('info', 'prints information about modules'),
+        ('test', 'Runs LDTP/Dogtail tests on the respective modules'),
         ('tinderbox', 'build non-interactively with logging'),
         ('gui', 'build targets from a gui app'),
         ('run', 'run a command in the build environment'),
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/modtypes/autotools.py jhbuild/jhbuild/modtypes/autotools.py
--- /home/prash/jhbuild/jhbuild/modtypes/autotools.py	2006-06-23 13:17:53.000000000 +0530
+++ jhbuild/jhbuild/modtypes/autotools.py	2006-07-28 22:59:00.000000000 +0530
@@ -52,7 +52,7 @@
         self.supports_non_srcdir_builds = supports_non_srcdir_builds
         self.autogen_sh = autogen_sh
 
-    def get_srcdir(self, buildscript):
+    def get_srcdir(self, buildscript=None):
         return self.branch.srcdir
 
     def get_builddir(self, buildscript):
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/modtypes/testmodule.py jhbuild/jhbuild/modtypes/testmodule.py
--- /home/prash/jhbuild/jhbuild/modtypes/testmodule.py	1970-01-01 05:30:00.000000000 +0530
+++ jhbuild/jhbuild/modtypes/testmodule.py	2006-08-07 14:04:22.000000000 +0530
@@ -0,0 +1,363 @@
+# jhbuild - a build script for GNOME 1.x and 2.x
+# Copyright (C) 2001-2006  James Henstridge
+#
+#   testmodule.py: testmodule type definitions.
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+__metaclass__ = type
+
+import os, time, signal, sys, subprocess, random
+
+from jhbuild.errors import FatalError, CommandError, BuildStateError
+from jhbuild.modtypes import \
+     Package, get_dependencies, get_branch, register_module_type
+from jhbuild.modtypes.autotools import AutogenModule
+
+from xml.dom.minidom import parse
+
+__all__ = [ 'TestModule' ]
+__test_types__ = [ 'ldtp' , 'dogtail' ]
+
+class TestModule (Package):
+    type = 'test'
+    
+    STATE_CHECKOUT       = 'checkout'
+    STATE_FORCE_CHECKOUT = 'force_checkout'
+    STATE_TEST           = 'test'
+    unexpected_exit      = -1
+    
+    def __init__(self, name, branch, test_type, dependencies=[], after=[], tested_pkgs=[]):
+        Package.__init__(self, name)
+        self.branch       = branch
+        self.test_type    = test_type
+        self.dependencies = dependencies
+        self.after        = after
+        self.tested_pkgs  = tested_pkgs
+
+    def get_srcdir(self, buildscript=None):
+        return self.branch.srcdir
+
+    def get_revision(self):
+        return self.branch.branchname
+
+    def do_start(self, testscript):
+        testdir = testscript.config.buildroot
+        if not testscript.config.nonetwork: # normal start state
+            return (self.STATE_CHECKOUT, None, None)
+        else:
+            return (self.STATE_TEST, None, None)
+
+    def do_checkout(self, testscript):
+        srcdir = self.get_srcdir(testscript)
+        testscript.set_action('Checking out', self)
+        try:
+            self.branch.checkout(testscript)
+        except CommandError:
+            succeeded = False
+        else:
+            succeeded = True
+
+        nextstate = self.STATE_TEST
+        # did the checkout succeed?
+        if succeeded and os.path.exists(srcdir):
+            return (nextstate, None, None)
+        else:
+            return (nextstate, 'could not update module',
+                    [self.STATE_FORCE_CHECKOUT])
+        
+    def do_force_checkout(self, testscript):
+        testscript.set_action ('Checking out', self)
+        nextstate = self.STATE_TEST
+        try:
+            self.branch.force_checkout(testscript)
+        except CommandError:
+            return (nextstate, 'could not checkout module',
+                    [self.STATE_FORCE_CHECKOUT])
+        else:
+            return (nextstate, None, None)
+
+    def _get_display (self):
+        # get free display
+        servernum = 99
+        list_of_files = os.walk ('/tmp').next()[2]
+        while True:
+            if '.X'+str(servernum)+'-lock' not in list_of_files:
+                break
+            servernum += 1
+        return str(servernum)
+
+    def _set_xauth (self, servernum):
+        # create auth file
+        paths = os.environ.get('PATH').split(':')
+        flag = False
+        for path in paths:
+            if os.path.exists (os.path.join (path,'xauth')):
+                flag = True
+                break
+        if not flag or os.path.exists (os.path.join('/tmp','jhbuild.'+str(os.getpid()))):
+            return ''
+
+        try:
+            os.mkdir (os.path.join('/tmp','jhbuild.'+str(os.getpid())))
+            new_xauth = os.path.join('/tmp','jhbuild.'+str(os.getpid()),'Xauthority')
+            tmp_file = open (new_xauth, 'w')
+            tmp_file.close ()
+            os.system ('xauth -f "%s" add ":%s" "." "%s"' % (new_xauth, \
+                                                             servernum, \
+                                                             str(random.random())[2:]))
+        except OSError:
+            return ''
+        return new_xauth
+    
+    def do_test (self, testscript):
+        method = getattr (self, 'do_'+self.test_type+'_test')
+        nextstate = self.STATE_DONE
+
+        testscript.set_action ('Testing',self)
+        if not testscript.config.noxvfb:
+            # start Xvfb
+            old_display = os.environ.get ('DISPLAY')
+            old_xauth   = os.environ.get ('XAUTHORITY')
+            xvfb_pid = self._start_xvfb(testscript.config.xvfbargs)
+            if xvfb_pid == self.unexpected_exit:
+                return (nextstate, 'Unable to start Xvfb',[])
+
+        status,error = method (testscript)
+        
+        if not testscript.config.noxvfb:
+            # kill Xvfb if it has been started
+            self._stop_xvfb(xvfb_pid)
+            if old_display:
+                os.environ['DISPLAY'] = old_display
+            else:
+                os.unsetenv ('DISPLAY')
+            if old_xauth:
+                os.environ['XAUTHORITY'] = old_xauth
+            else:
+                os.unsetenv ('XAUTHORITY')
+                
+        if status !=0:
+            return (nextstate, error,[])
+        testscript.message (error)
+        return (nextstate, None, None)
+
+    def get_ldtp_log_file (self, filename):
+        # <ldtp>
+        # |
+        # -- <logfile>filename</logfile>
+        run_file = parse (filename)
+        return run_file.getElementsByTagName ('ldtp')[0].getElementsByTagName ('logfile')[0].childNodes[0].data
+
+    def _get_ldtp_info (self, node):
+        infos = []
+        errors = []
+        warnings = []
+        causes = []
+        for info in node.getElementsByTagName ('info'):
+            for child in info.childNodes:
+                infos.append (child.data)
+        for cause in node.getElementsByTagName ('cause'):
+            for child in cause.childNodes:
+                causes.append (child.data)
+        for error in node.getElementsByTagName ('error'):
+            for child in error.childNodes:
+                errors.append (child.data)
+        for warning in node.getElementsByTagName ('warning'):
+            for child in warning.childNodes:
+                warnings.append (child.data)
+        return infos, errors, causes, warnings
+        
+    def _check_ldtp_log_file (self, logfile):
+        log_file = parse (logfile)
+        ldtp_node = log_file.getElementsByTagName ('ldtp')[0]
+
+        groups = []
+        for group in ldtp_node.getElementsByTagName ('group'):
+            scr = []
+            for script in group.getElementsByTagName ('script'):
+                tests = {}
+                for test in script.getElementsByTagName ('test'):
+                    test_name = test.getAttribute('name')
+                    
+                    pass_status = test.getElementsByTagName ('pass')[0].childNodes[0].data
+                    infos, errors, causes, warnings = self. _get_ldtp_info (test)
+                    tests [test_name] = {'pass':pass_status, 'info':infos,
+                                         'error':errors, 'cause':causes,
+                                         'warning':warnings}
+                infos, errors, causes, warnings = self. _get_ldtp_info (script)
+                scr.append ({'tests':tests, 'info':infos, 'error':errors,
+                            'cause':causes, 'warning':warnings})
+            groupstatus = group.getElementsByTagName ('groupstatus')[0].childNodes[0].data
+            groups.append ({'script':scr, 'groupstatus':groupstatus})
+        return groups
+
+    def check_groups (self, groups):
+        group_num = 1
+        flag = False
+        status = ''
+        for group in groups:
+            status +=  'In Group #' + str(group_num) + ' ('+group['groupstatus'] + ')\n'
+            for script in group['script']:
+                for test in script['tests'].keys():
+                    status += 'Test \''+test+'\' '
+                    if script['tests'][test]['pass'] == '0': # failed
+                        status += 'failed\n\tErrors'
+                        for error in script['tests'][test]['error']:
+                            status += ', '
+                            status += error
+
+                        status += '\n\tCauses'
+                        for cause in script['tests'][test]['cause']:
+                            status += ', '
+                            status += cause
+
+                        status += '\n\tWarnings'
+                        for warning in script['tests'][test]['warning']:
+                            status += ', '
+                            status += warning
+
+                        status += '\n\tInfos'
+                        for info in script['tests'][test]['info']:
+                            status += ', '
+                            status += info                        
+                    else:
+                        status += 'passed'
+                    status += '\n'
+            group_num += 1
+            if self._check_ldtp_group_status (group['groupstatus']):
+                flag = True
+        return flag, status
+    
+    def _check_ldtp_group_status (self, status):
+        status = status.split()
+        if status[0] != status [-1]:
+            return True
+        return False
+
+    def _start_xvfb(self, xvfbargs):
+        new_display = self._get_display()
+        new_xauth   = self._set_xauth (new_display)
+        if new_xauth == '':
+            return self.unexpected_exit
+
+        os.environ['DISPLAY'] = ':'+new_display
+        os.environ['XAUTHORITY'] = new_xauth
+        try:
+            xvfb = subprocess.Popen (['Xvfb',':'+new_display] + xvfbargs.split(),\
+                                     shell=False)
+            self.screennum = new_display
+            self.xauth = new_xauth
+        except OSError:
+            return self.unexpected_exit
+        
+        time.sleep(2) #allow Xvfb to start
+        if xvfb.poll() != None:
+            return self.unexpected_exit
+        return xvfb.pid
+
+    def _stop_xvfb (self, xvfb_pid):
+        os.kill (xvfb_pid, signal.SIGINT)
+        os.system ('xauth remove ":'+self.screennum+'"')
+        os.system ('rm -r '+os.path.split(self.xauth)[0])
+            
+    def _start_ldtp (self):
+        try:
+            ldtp = subprocess.Popen ('ldtp', shell=False)
+        except OSError:
+            return self.unexpected_exit
+        time.sleep (1)
+        if ldtp.poll() != None:
+            return self.unexpected_exit
+        return ldtp.pid
+    
+    def do_ldtp_test (self, testscript):
+        src_dir = self.get_srcdir (testscript)
+        old_debug = os.getenv ('LDTP_DEBUG')
+        if old_debug != None:
+            del os.environ ['LDTP_DEBUG']
+
+        ldtp_pid = self._start_ldtp()
+        if ldtp_pid  == self.unexpected_exit:
+            return ldtp_pid, 'Unable to start ldtp server'
+
+        try:
+            if testscript.config.noxvfb:
+                testscript.execute ('ldtprunner run.xml',cwd=src_dir)
+            else:
+                testscript.execute ('ldtprunner run.xml',cwd=src_dir,extra_env={'DISPLAY':':'+self.screennum})
+        except CommandError, e:
+            os.kill (ldtp_pid, signal.SIGINT)
+            if e.returncode == 32512:        # ldtprunner not installed
+                return e.returncode, 'ldtprunner not available'
+            return e.returncode, 'error during running of test'
+        os.kill (ldtp_pid, signal.SIGINT)
+        
+        if old_debug != None:
+            os.environ ['LDTP_DEBUG'] = old_debug
+        
+        log_file = self.get_ldtp_log_file (os.path.join (src_dir,'run.xml'))
+        try:
+            groups = self._check_ldtp_log_file (log_file)
+            flag, status = self.check_groups (groups)
+            if flag:
+                return self.unexpected_exit, status
+        except:
+             return self.unexpected_exit,'malformed log file'
+        return 0, status
+
+    def do_dogtail_test (self, testscript):
+        src_dir = self.get_srcdir (testscript)
+        test_cases = []
+        failed = False
+        all_files = os.listdir (src_dir)
+        for file in all_files:
+            if file[-3:] == '.py':
+                test_cases.append (file)
+
+        status = ''
+        for test_case in test_cases:
+            try:
+                testscript.execute ('python '+test_case, cwd=src_dir, extra_env={'DISPLAY':':'+self.screenum})
+            except CommandError, e:
+                if e.returncode != 0:
+                    status += test_case+' Failed\n'
+                    failed = True
+        if failed:
+            return self.unexpected_exit, status
+        return 0, status
+
+
+def get_tested_packages (node):
+    tested_pkgs = []
+    for tested_module in node.getElementsByTagName ('testedmodules'):
+        for mod in tested_module.getElementsByTagName ('tested'):
+            tested_pkgs.append (mod.getAttribute ('package'))
+    return tested_pkgs
+
+def parse_testmodule (node, config, repositories, default_repo):
+    id = node.getAttribute('id')
+    test_type = node.getAttribute ('type')
+    if test_type not in __test_types__:
+        # FIXME: create an error here
+        pass
+
+    dependencies, after = get_dependencies(node)
+    branch = get_branch(node, repositories, default_repo)
+    tested_pkgs = get_tested_packages (node)
+    return TestModule (id, branch, test_type, dependencies=dependencies,
+                       after=after, tested_pkgs=tested_pkgs)
+                                   
+register_module_type('testmodule', parse_testmodule)
diff -Naur -x install-check -x CVS /home/prash/jhbuild/jhbuild/moduleset.py jhbuild/jhbuild/moduleset.py
--- /home/prash/jhbuild/jhbuild/moduleset.py	2006-05-15 11:07:11.000000000 +0530
+++ jhbuild/jhbuild/moduleset.py	2006-06-20 19:56:02.000000000 +0530
@@ -33,8 +33,9 @@
 from jhbuild import modtypes
 from jhbuild.versioncontrol import get_repo_type
 from jhbuild.utils import httpcache
+from jhbuild.modtypes import testmodule
 
-__all__ = [ 'load' ]
+__all__ = [ 'load','load_tests' ]
 
 class ModuleSet:
     def __init__(self):
@@ -118,6 +119,16 @@
     
     def get_full_module_list(self, skip=[]):
         return self.get_module_list(self.modules.keys(), skip=skip)
+
+    def get_test_module_list (self, seed, skip=[]):
+        test_modules = []
+        if seed == []:
+            return
+        for mod in self.modules.values():
+            for test_app in seed:
+                if test_app in mod.tested_pkgs:
+                    test_modules.append(mod)
+        return test_modules
     
     def write_dot(self, modules=None, fp=sys.stdout):
         from jhbuild.modtypes import MetaModule
@@ -173,6 +184,14 @@
         ms.modules.update(_parse_module_set(config, uri).modules)
     return ms
 
+def load_tests (config, uri=None):
+    ms = load (config, uri)
+    ms_tests = ModuleSet()
+    for app, module in ms.modules.iteritems():
+        if module.__class__ == testmodule.TestModule:
+            ms_tests.modules[app] = module
+    return ms_tests
+
 def _child_elements(parent):
     for node in parent.childNodes:
         if node.nodeType == node.ELEMENT_NODE:
diff -Naur -x install-check -x CVS /home/prash/jhbuild/modulesets/gnome-2.14.modules jhbuild/modulesets/gnome-2.14.modules
--- /home/prash/jhbuild/modulesets/gnome-2.14.modules	2006-07-25 17:58:49.000000000 +0530
+++ jhbuild/modulesets/gnome-2.14.modules	2006-07-27 22:38:00.000000000 +0530
@@ -45,6 +45,8 @@
   <repository type="cvs" name="openh323.sf.net"
      cvsroot=":pserver:anonymous@openh323.cvs.sourceforge.net:/cvsroot/openh323"
      password="" />
+  <repository type="cvs" name="ldtp.freedesktop.org"
+     cvsroot=":pserver:anoncvs@cvs.freedesktop.org:/cvs/ldtp" password="" />
 
   <tarball id="scrollkeeper" version="0.3.14" supports-non-srcdir-builds="no">
     <source href="http://easynews.dl.sourceforge.net/sourceforge/scrollkeeper/scrollkeeper-0.3.14.tar.gz"
@@ -2011,4 +2013,12 @@
       <dep package="gnonlin"/>
     </dependencies>
   </autotools>
+  <autotools id="ldtp">
+    <branch repo="ldtp.freedesktop.org" module="ldtp"/>
+    <dependencies>
+      <dep package="at-spi"/>
+      <dep package="libgnomeui"/>
+      <dep package="atk"/>
+    </dependencies>
+  </autotools>	
 </moduleset>
diff -Naur -x install-check -x CVS /home/prash/jhbuild/modulesets/gnome-2.14-test.modules jhbuild/modulesets/gnome-2.14-test.modules
--- /home/prash/jhbuild/modulesets/gnome-2.14-test.modules	1970-01-01 05:30:00.000000000 +0530
+++ jhbuild/modulesets/gnome-2.14-test.modules	2006-06-20 11:47:59.000000000 +0530
@@ -0,0 +1,29 @@
+<?xml version="1.0"?><!--*- mode: nxml -*-->
+<?xml-stylesheet type="text/xsl" href="moduleset.xsl"?>
+<moduleset>
+  <include href="gnome-2.14.modules" />
+  <repository type="cvs" name="ldtp.freedesktop.org"
+     cvsroot=":pserver:anoncvs@cvs.freedesktop.org:/cvs/ldtp" 
+     password="" />
+
+  <testmodule id="ldtp-gedit-test" type="ldtp">
+    <branch repo="ldtp.freedesktop.org" module="pyautosuite/gedit" revision="gnome-2-14"/>
+    <dependencies>
+      <dep package="ldtp"/>
+      <dep package="gedit"/>
+    </dependencies>
+    <testedmodules>
+      <tested package="gedit"/>
+    </testedmodules>
+  </testmodule>
+  <testmodule id="ldtp-gnome-dictionary-test" type="ldtp">
+    <branch repo="ldtp.freedesktop.org" module="pyautosuite/gnome-dictionary" revision="gnome-2-14"/>
+    <dependencies>
+      <dep package="ldtp"/>
+      <dep package="gnome-utils"/>
+    </dependencies>
+    <testedmodules>
+      <tested package="gnome-utils"/>
+    </testedmodules>
+  </testmodule>
+</moduleset>
