Skip to content

Commit

Permalink
Improve test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
Whit Morriss committed Jul 30, 2011
1 parent 1daa770 commit c0dc19c
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 40 deletions.
19 changes: 12 additions & 7 deletions strap/bootstrap.py
@@ -1,11 +1,16 @@
import argparse
import commands
import os
import sys
def main():
pass

def call_subprocess(*args, **kw):
pass

def main():
class Logger(object):
"""
I am the main yak
Faux logger object
"""
pass
def __init__(*args, **kw):
pass

@staticmethod
def level_for_integer(*args):
pass
5 changes: 3 additions & 2 deletions strap/default_bootstrap.py
@@ -1,10 +1,11 @@
"""
This code gets inserted into the virtualenv generated bootstrap
Text inserted into the virtualenv generated bootstrap
`Strap` is a protocol stub. Define your own `Strap` to extend
"""
from extender import BootstrapExtender



class Strap(BootstrapExtender):
"""
The `BootstrapExtender` class does all the work here. This class
Expand Down
51 changes: 30 additions & 21 deletions strap/extender.py
Expand Up @@ -4,44 +4,44 @@


class BootstrapExtender(object):
"""
Extension base class, included in the executable bundle. State bag
for virtualenv hook functions. Basically some reach arounds to
help deal with wrapping virtualenv from the inside.
"""

def __init__(self, location, use_distribute=True):
self.location = location
self.use_distribute = use_distribute

_subprocess = False

@property
def subprocess(self):
if not self._subprocess:
from bootstrap import call_subprocess
self._subprocess = call_subprocess
return self._subprocess

def __init__(self, location, use_distribute=True):
self.location = location
self.use_distribute = use_distribute

@property
def bundle(self):
# assumes Extender lives in root of pybundle
return path(self.location).parent

@property
def workon_home(self):
venv = os.environ.get('WORKON_HOME')
if venv:
return path(venv)
return None
## @property
## def workon_home(self):
# feature is coming
## venv = os.environ.get('WORKON_HOME')
## if venv:
## return path(venv)
## return None

@property
def virtualenv(self):
venv = os.environ.get('VIRTUAL_ENV')
if venv:
return path(venv)
return None

def modify_parser(self, optparse_parser):
"""
Override this method to manipulate the default optparse
instance
"""
pass

def extend_parser(self, optparse_parser):
"""
As extend_parser is run before any other hook, we can use it
Expand All @@ -62,6 +62,10 @@ def setup_logger_global(self, options):
verbosity = options.verbose - options.quiet
bootstrap.logger = bootstrap.Logger([(bootstrap.Logger.level_for_integer(2-verbosity), sys.stdout)])

def after_install(self, options, home_dir):
self.subprocess("pip install -E %s %s" %(home_dir, self.location))
self.build_hook(options, home_dir)

def adjust_options(self, options, args):
"""
Override to adjust options and args
Expand All @@ -73,7 +77,12 @@ def build_hook(self, options, home_dir):
Override this hook to add build steps
"""
pass

def modify_parser(self, optparse_parser):
"""
Override this method to manipulate the default optparse
instance
"""
pass

def after_install(self, options, home_dir):
self.subprocess("pip install -E %s %s" %(home_dir, self.location))
self.build_hook(options, home_dir)

16 changes: 9 additions & 7 deletions strap/factory.py
@@ -1,7 +1,7 @@
from fabric.api import local
from path import path
from strap.resolver import DottedNameResolver
import argparse
import commands
import inspect
import logging
import sys
Expand All @@ -26,15 +26,13 @@ def __init__(self, extra_text, bundle_name, requirements_file, modules=default_m
self.requirements_file = requirements_file
self.modules = modules



@staticmethod
def argparser(*args, **kw):
parser = argparse.ArgumentParser(description='This is STRAP')
parser.add_argument('bundle_name', action="store")
parser.add_argument('-e', action="store", dest="extra_text", default='strap.default_bootstrap')
parser.add_argument('-r', action="store", dest="requirements_file",
default=None, required=True)
parser.add_argument('bundle_name', action="store", required=True)
return parser.parse_args(*args, **kw)

def append_to_zip(self, bundle_path):
Expand All @@ -47,11 +45,16 @@ def append_to_zip(self, bundle_path):
if mod is not None:
bundle.writestr(mod_name, inspect.getsource(mod))
else:
logger.error("%s does not return a module" %spec)
#@@ negative test
logger.error("%s does not return a module", spec)
bundle.writestr('bootstrap.py', virtualenv.create_bootstrap_script(self.extra_text))

def create_bundle(self):
local('pip bundle -r %s %s' %(self.requirements_file, self.bundle_name))
(stat, out) = commands.getstatusoutput('pip bundle -r %s %s' %(self.requirements_file, self.bundle_name))
if stat != 0:
#@@ negative test
logger.error("%s\n", out)
sys.exit(stat)
return path('.').abspath() / self.bundle_name

@staticmethod
Expand All @@ -73,7 +76,6 @@ def resolve_extra_text(et):
return path(inspect.getsourcefile(module)).text()
return et # just a string


@property
def extra_text(self):
et = getattr(self, '_extra_text', None)
Expand Down
77 changes: 77 additions & 0 deletions strap/tests/test_building_blocks.py
@@ -0,0 +1,77 @@
from mock import Mock
from mock import patch
from path import path
import unittest


class TestBootstrapExtender(unittest.TestCase):
"""
The extender object is injected into the generated bootstrap. We
test it's basic organs here.
"""
def _make_one(self, location='/here', dist=True):
from strap import extender
return extender.BootstrapExtender(location, dist)

def test_subprocess_prop(self):
"""
Subproc property outside of a true bootstrap should be a noop.
"""
be = self._make_one()
assert be.subprocess.__module__ == 'strap.bootstrap'
assert be.subprocess() is None

def test_bundle_prop(self):
be = self._make_one('tests/testreq.txt')
assert be.bundle.abspath().name == 'tests', be.bundle.name

def test_virtualenv_prop(self):
"""
should always be run in an env and always return a path object
"""
be = self._make_one()
assert isinstance(be.virtualenv, path), be.virtualenv

def test_stubs(self):
be = self._make_one()
assert be.modify_parser(None) is None
assert be.adjust_options(None, None) is None
assert be.build_hook(None, None) is None

@patch('sys.exit')
def test_extendparser(self, exit_mock):
be = self._make_one()
parser = Mock()
arg_ret = Mock()
parser.parse_args = Mock(return_value=(arg_ret, None))
arg_ret.verbose = 1
arg_ret.quiet = 1
assert be.extend_parser(parser) is None
assert exit_mock.call_args[0][0] == 0

@patch('strap.extender.BootstrapExtender.build_hook')
@patch('strap.extender.BootstrapExtender.subprocess')
def test_afterinstall(self, subproc_mock, bh_mock):
be = self._make_one()
be.after_install("options", "homedir")
assert subproc_mock
assert bh_mock

def test_bootstrap_dummy():
from strap import bootstrap
assert bootstrap.main() is None


def test_hook_protocol_stub():
"""
These are stubs, should take the right number of args and do
nothing.
"""
from strap import default_bootstrap
strap = default_bootstrap.Strap('here')
assert strap.modify_parser(None) is None
assert strap.adjust_options(None, None) is None
assert strap.build_hook(None, None) is None



23 changes: 20 additions & 3 deletions strap/tests/test_strapfactory.py
@@ -1,4 +1,5 @@
from itertools import count
from mock import patch
from path import path
import commands
import inspect
Expand Down Expand Up @@ -37,7 +38,6 @@ class TestStrapFactory(unittest.TestCase):
"""
Test the main class
"""

counter = count()

def _makeone(self, et='print "Wheeeeeeee"', bundle=None, reqfile=path(__file__).dirname() / 'testreq.txt'):
Expand All @@ -47,11 +47,26 @@ def _makeone(self, et='print "Wheeeeeeee"', bundle=None, reqfile=path(__file__).
bundle = td / 'test_bundle-%s.pybundle' %next(self.counter)
return StrapFactory(et, bundle, reqfile)

@patch('argparse.ArgumentParser.add_argument')
@patch('argparse.ArgumentParser.parse_args')
def test_argparser(self, parse_mock, add_mock):
factory = self._makeone()
blah = factory.argparser()
assert blah
assert parse_mock.call_args_list == [((), {})]
assert set(x[0][0] for x in add_mock.call_args_list) == set(['-h', 'bundle_name', '-e', '-r'])

def test_init(self):
factory = self._makeone('','','')
assert factory

def test_createbundle(self):

@patch('sys.exit')
def test_createbundle(self, exit_mock):
factory = self._makeone(reqfile='idonotexist')
factory.create_bundle()
exit_mock.assert_called_once_with(256)

def test_createbundle_fail(self):
factory = self._makeone()
rp = factory.create_bundle()
assert rp.exists(), "%s does not exist." %rp
Expand All @@ -74,6 +89,7 @@ def test_bundle_has_bootstrap(self):
import bootstrap
for func in ('extend_parser', 'adjust_options', 'after_install'):
assert hasattr(bootstrap, func), "No function %s in %s: %s" %(func, bootstrap, dir(bootstrap))
del sys.path[0]

def test_bundle_exec(self):
env = os.environ['VIRTUAL_ENV']
Expand All @@ -82,6 +98,7 @@ def test_bundle_exec(self):
(stat, out) = commands.getstatusoutput('%s/bin/python %s' %(env, factory.run()))
assert out.find('Successfully installed dummycode') != -1, out





0 comments on commit c0dc19c

Please sign in to comment.