fab-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Fab-user] SNIPPETs: fab autotest


From: Phlip
Subject: [Fab-user] SNIPPETs: fab autotest
Date: Fri, 29 Jan 2010 10:38:40 -0800

For Fab:

Below my sig are two fabfile.py examples. One lets you run this:

   fab autotest:'fab report'

Without the argument, it runs fab test. This lets you use a broken editor (like, in my humble opinion, nearly all of them!) that can't trigger tests each time you change the source and hit Save.

With the argument, it runs whatever you like. If you had a fabfile with a target of /report/, it could process a report and raise this in a browser. This would let you fine tune the report's aesthetic details.

The next script, test, runs a Django command line to test a project - but with a twist. An important goal of testing, with finite processor speed, is "incremental testing", where the test runner only runs important test suites, and disregards the unimportant ones. (Running the GrandWazoo test batch is a job for a build server, such as CruiseControl.)

So test() calls _three_most_recently_changed_applications(), which finds all the local tests.py files, sorts them by modification time, and pulls off the top three.

I suspect Django then runs the tests in the order specified on its manage.py command line, so in theory the most recently changed test suite would run first. This would be a great benefit for TDD, so that when you predict an error message you can get to it quickly.

(A future version of my fab scripts will solve Django's truly miserable problem with slow test database fixtures!)

Feel free to suggest improvements...

--
  Phlip
  http://penbird.tumblr.com/

def autotest(cmd='fab test', sleep=1):
    """
    spin until you change a file, then run the tests

    It considers the fabfile.py directory as the project root directory, then
    monitors changes in any inner python files.

    Usage:

       fab autotest

    This is based on Jeff Winkler's nosy script.
    """

    def we_like(f):
        return f.endswith('.py') or f.endswith('.html') or f.endswith('.json')

    def checkSum():
        '''
        Return a long which can be used to know if any .py files have changed.
        Looks in all project's subdirectory.
        '''

        def hash_stat(file):
            from stat import ST_SIZE, ST_MTIME
            stats = os.stat(file)
            return stats[ST_SIZE] + stats[ST_MTIME]

        hash_ = 0
        base = os.path.dirname(fabfile.__file__)

        for zone in (base, base + '/webcube/', base + '/simplecart/'):
            for root, dirs, files in os.walk(zone):
                # We are only interested int python, json, & html files
                files = [os.path.join(root, f) for f in files if we_like(f)]
                hash_ += sum(map(hash_stat, files))

        return hash_

    val = 0

    while(True):
        actual_val = checkSum()

        if val != actual_val:
            val = actual_val
            os.system(cmd)

        time.sleep(sleep)

def _three_most_recently_changed_applications():
    import os
    import glob

    fyles = glob.glob('*/tests.py') + glob.glob('*/tests/*.py')

    def by_time(a, b):  return int(os.stat(b).st_mtime - os.stat(a).st_mtime)
    fyles.sort(by_time)
    applications = [ fyle.split('/')[0] for fyle in fyles ]
    return ' '.join(applications[:3])

def _get_test_settings():
    test_settings = 'settings'
    if os.path.exists('test_settings.py'):           test_settings = 'test_settings'
    if os.path.exists('settings/test_settings.py'):  test_settings = 'settings.test_settings'
    if os.path.exists('settings/test.py'):           test_settings = 'settings.test'
    return test_settings

def test(extra=''):
    'run the short test batch for this project'

    test_settings = _get_test_settings()
    whut = _three_most_recently_changed_applications()

    _sh( 'python manage.py test --settings=%s --verbosity=0 %s %s' %
                                    (test_settings,       whut, extra) )


reply via email to

[Prev in Thread] Current Thread [Next in Thread]