From f5aaf25aa473f82cdb3bf7633f7a4d93e69784c6 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Sun, 16 Jun 2013 16:24:15 -0400 Subject: [PATCH] Use testr and flake8. Change-Id: I748a0f54416ca540153ed5a9e7edfff739acaaea --- .gitignore | 1 + .testr.conf | 4 ++++ devstack-vm-check.py | 2 ++ devstack-vm-delete.py | 1 + devstack-vm-threshold.py | 5 ++--- myjenkins.py | 19 ++++++++++--------- sshclient.py | 3 +-- tests/__init__.py | 0 tests/test_vmdatabase.py | 30 +++++++++++++++++------------- tools/test-requires | 16 +++++++++------- tox.ini | 15 ++++++++++++--- utils.py | 11 +++++++++++ 12 files changed, 70 insertions(+), 37 deletions(-) create mode 100644 .testr.conf create mode 100644 tests/__init__.py diff --git a/.gitignore b/.gitignore index 77307d5a..5c1baa98 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ nosetests.xml .DS_Store build/ dist/ +.testrepository diff --git a/.testr.conf b/.testr.conf new file mode 100644 index 00000000..55ecb776 --- /dev/null +++ b/.testr.conf @@ -0,0 +1,4 @@ +[DEFAULT] +test_command=${PYTHON:-python} -m subunit.run discover -t . ./tests $LISTOPT $IDOPTION +test_id_option=--load-list $IDFILE +test_list_option=--list diff --git a/devstack-vm-check.py b/devstack-vm-check.py index a3ed1b54..0e9c2188 100755 --- a/devstack-vm-check.py +++ b/devstack-vm-check.py @@ -35,6 +35,7 @@ DEVSTACK_GATE_SECURE_CONFIG = os.environ.get('DEVSTACK_GATE_SECURE_CONFIG', '~/devstack-gate-secure.conf')) SKIP_DEVSTACK_GATE_JENKINS = os.environ.get('SKIP_DEVSTACK_GATE_JENKINS', None) + def check_machine(jenkins, machine): utils.log.debug("Check ID: %s" % machine.id) @@ -54,6 +55,7 @@ def check_machine(jenkins, machine): machine.delete() + def main(): db = vmdatabase.VMDatabase() diff --git a/devstack-vm-delete.py b/devstack-vm-delete.py index 6d3501b3..d27206ce 100755 --- a/devstack-vm-delete.py +++ b/devstack-vm-delete.py @@ -36,6 +36,7 @@ UPSTREAM_JOB_NAME=os.environ.get('UPSTREAM_JOB_NAME', '') UPSTREAM_BRANCH=os.environ.get('UPSTREAM_BRANCH', '') BUILD_URL=os.environ.get('BUILD_URL', '') + def main(): db = vmdatabase.VMDatabase() diff --git a/devstack-vm-threshold.py b/devstack-vm-threshold.py index 66cea24e..83c9c812 100755 --- a/devstack-vm-threshold.py +++ b/devstack-vm-threshold.py @@ -31,8 +31,7 @@ def main(threshold, stat_file): for provider in db.getProviders(): for base_image in provider.base_images: - ready_nodes = [x for x in base_image.machines \ - if x.state == ready] + ready_nodes = [x for x in base_image.machines if x.state == ready] ready_count = len(ready_nodes) set_vm_state(ready_count, stat_file) @@ -55,7 +54,7 @@ def usage(msg=None): stream = sys.stderr else: stream = sys.stdout - stream.write("usage: %s [-h] -t threshold [-f stat-file]\n" \ + stream.write("usage: %s [-h] -t threshold [-f stat-file]\n" % os.path.basename(sys.argv[0])) if msg: stream.write("\nERROR: " + msg + "\n") diff --git a/myjenkins.py b/myjenkins.py index cb27c779..0e142ea6 100644 --- a/myjenkins.py +++ b/myjenkins.py @@ -7,11 +7,12 @@ from jenkins import JenkinsException, NODE_TYPE, CREATE_NODE TOGGLE_OFFLINE = '/computer/%(name)s/toggleOffline?offlineMessage=%(msg)s' CONFIG_NODE = '/computer/%(name)s/config.xml' + class Jenkins(jenkins.Jenkins): def disable_node(self, name, msg=''): ''' Disable a node - + @param name: Jenkins node name @type name: str @param msg: Offline message @@ -25,7 +26,7 @@ class Jenkins(jenkins.Jenkins): def enable_node(self, name): ''' Enable a node - + @param name: Jenkins node name @type name: str ''' @@ -38,7 +39,7 @@ class Jenkins(jenkins.Jenkins): def get_node_config(self, name): ''' Get the configuration for a node. - + :param name: Jenkins node name, ``str`` ''' get_config_url = self.server + CONFIG_NODE%locals() @@ -47,7 +48,7 @@ class Jenkins(jenkins.Jenkins): def reconfig_node(self, name, config_xml): ''' Change the configuration for an existing node. - + :param name: Jenkins node name, ``str`` :param config_xml: New XML configuration, ``str`` ''' @@ -68,7 +69,7 @@ class Jenkins(jenkins.Jenkins): @param remoteFS: Remote filesystem location to use @type remoteFS: str @param labels: Labels to associate with node - @type labels: str + @type labels: str @param exclusive: Use this node for tied jobs only @type exclusive: boolean @param launcher: The launch method for the slave @@ -78,7 +79,7 @@ class Jenkins(jenkins.Jenkins): ''' if self.node_exists(name): raise JenkinsException('node[%s] already exists'%(name)) - + mode = 'NORMAL' if exclusive: mode = 'EXCLUSIVE' @@ -87,7 +88,7 @@ class Jenkins(jenkins.Jenkins): #hudson.slaves.CommandLauncher #hudson.os.windows.ManagedWindowsServiceLauncher launcher_params['stapler-class'] = launcher - + inner_params = { 'name' : name, 'nodeDescription' : nodeDescription, @@ -100,13 +101,13 @@ class Jenkins(jenkins.Jenkins): 'nodeProperties' : { 'stapler-class-bag' : 'true' }, 'launcher' : launcher_params } - + params = { 'name' : name, 'type' : NODE_TYPE, 'json' : json.dumps(inner_params) } - + self.jenkins_open(urllib2.Request(self.server + CREATE_NODE%urllib.urlencode(params))) if not self.node_exists(name): diff --git a/sshclient.py b/sshclient.py index 421f4eaf..ed7a20ac 100644 --- a/sshclient.py +++ b/sshclient.py @@ -21,6 +21,7 @@ import paramiko import sys + class SSHClient(object): def __init__(self, ip, username, password=None, pkey=None): client = paramiko.SSHClient() @@ -47,5 +48,3 @@ class SSHClient(object): ftp = self.client.open_sftp() ftp.put(source, dest) ftp.close() - - diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_vmdatabase.py b/tests/test_vmdatabase.py index 315cf50f..995c8cdb 100644 --- a/tests/test_vmdatabase.py +++ b/tests/test_vmdatabase.py @@ -18,13 +18,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import unittest -import vmdatabase import time -class testVMDatabase(unittest.TestCase): +import testtools +from testtools import content + +import vmdatabase + + +class TestVMDatabase(testtools.TestCase): def setUp(self): + super(TestVMDatabase, self).setUp() self.db = vmdatabase.VMDatabase(':memory:') def test_add_provider(self): @@ -41,7 +46,7 @@ class testVMDatabase(unittest.TestCase): def test_add_base_image(self): self.test_add_provider() - + provider = self.db.getProvider('rackspace') base_image1 = provider.newBaseImage('oneiric', 1) base_image2 = provider.newBaseImage('precise', 2) @@ -54,13 +59,13 @@ class testVMDatabase(unittest.TestCase): self.test_add_base_image() provider = self.db.getProvider('rackspace') base_image1 = provider.getBaseImage('oneiric') - base_image2 = provider.getBaseImage('precise') + base_image2 = provider.getBaseImage('precise') snapshot_image1 = base_image1.newSnapshotImage('oneiric-1331683549', 1331683549, 201, 301) snapshot_image2 = base_image2.newSnapshotImage('precise-1331683549', 1331683549, 202, 301) hp_provider = self.db.getProvider('hpcloud') hp_base_image1 = hp_provider.getBaseImage('oneiric') - hp_base_image2 = hp_provider.getBaseImage('precise') + hp_base_image2 = hp_provider.getBaseImage('precise') hp_snapshot_image1 = hp_base_image1.newSnapshotImage('oneiric-1331683549', 1331929410, 211, 311) hp_snapshot_image2 = hp_base_image2.newSnapshotImage('precise-1331683549', 1331929410, 212, 311) @@ -79,7 +84,7 @@ class testVMDatabase(unittest.TestCase): assert(snapshot_image1 == base_image1.current_snapshot) assert(snapshot_image2 == base_image2.current_snapshot) - snapshot_image2_latest = base_image2.newSnapshotImage('precise-1331683550', + snapshot_image2_latest = base_image2.newSnapshotImage('precise-1331683550', 1331683550, 203, 303) assert(base_image1.current_snapshot) assert(base_image2.current_snapshot) @@ -195,25 +200,25 @@ class testVMDatabase(unittest.TestCase): assert(len(hp_provider.ready_machines)==2) machine = self.db.getMachineForUse('oneiric') - print 'got machine', machine.name + self.addDetail('machine name', content.text_content(machine.name)) assert(len(rs_provider.ready_machines)==1) assert(len(hp_provider.ready_machines)==2) assert(machine==machine1) machine = self.db.getMachineForUse('oneiric') - print 'got machine', machine.name + self.addDetail('machine name', content.text_content(machine.name)) assert(len(rs_provider.ready_machines)==1) assert(len(hp_provider.ready_machines)==1) assert(machine==hp_machine1) machine = self.db.getMachineForUse('precise') - print 'got machine', machine.name + self.addDetail('machine name', content.text_content(machine.name)) assert(len(rs_provider.ready_machines)==1) assert(len(hp_provider.ready_machines)==0) assert(machine==hp_machine2) machine = self.db.getMachineForUse('precise') - print 'got machine', machine.name + self.addDetail('machine name', content.text_content(machine.name)) assert(len(rs_provider.ready_machines)==0) assert(len(hp_provider.ready_machines)==0) assert(machine==machine2) @@ -223,7 +228,7 @@ class testVMDatabase(unittest.TestCase): self.db.print_state() machine = self.db.getMachineForUse('oneiric') - print 'got machine', machine.name + self.addDetail('machine name', content.text_content(machine.name)) result = machine.newResult('test-job', 82, 1234, 1) time.sleep(2) result.setResult(vmdatabase.RESULT_SUCCESS) @@ -245,4 +250,3 @@ class testVMDatabase(unittest.TestCase): assert(result.gerrit_patchset_number == 1) else: assert(len(base_image.results)==0) - diff --git a/tools/test-requires b/tools/test-requires index 32f5acc1..ce5788a9 100644 --- a/tools/test-requires +++ b/tools/test-requires @@ -1,8 +1,10 @@ # Testing -coverage # computes code coverage percentages -mox # mock object framework -nose # for test discovery and console feedback -nosexcover -pylint # static code analysis -pep8==0.6.1 # checks for PEP8 code style compliance -unittest2 # backport of unittest lib in python 2.7 + +# Install bounded pep8/pyflakes first, then let flake8 install +hacking>=0.5.3,<0.6 + +coverage>=3.6 +discover +python-subunit +testrepository>=0.0.13 +testtools>=0.9.27 diff --git a/tox.ini b/tox.ini index 6aac8c9c..130aa6f1 100644 --- a/tox.ini +++ b/tox.ini @@ -2,11 +2,20 @@ envlist = py26,py27,pep8 [testenv] +setenv = VIRTUAL_ENV={envdir} deps = -r{toxinidir}/tools/pip-requires -r{toxinidir}/tools/test-requires -commands = nosetests {posargs} +commands = + python setup.py testr --slowest --testr-args='{posargs}' [testenv:pep8] -deps = pep8 -commands = pep8 --count --repeat --show-source --exclude=.tox setup.py . +commands = flake8 +[testenv:cover] +commands = + python setup.py testr --coverage + +[flake8] +exclude = .git,.tox,dist,*egg,build,v1_0 +show-source = True +ignore = E12,E2,E501,F,H diff --git a/utils.py b/utils.py index bc22f407..679cefa2 100644 --- a/utils.py +++ b/utils.py @@ -39,6 +39,7 @@ handler = logging.handlers.SysLogHandler(address = '/dev/log') handler.setFormatter(logging.Formatter("devstack-gate: %(message)s")) log.addHandler(handler) + def iterate_timeout(max_seconds, purpose): start = time.time() count = 0 @@ -71,6 +72,8 @@ def get_client(provider): return client extension_cache = {} + + def get_extensions(client): global extension_cache cache = extension_cache.get(client) @@ -84,11 +87,13 @@ def get_extensions(client): extension_cache[client] = extensions return extensions + def get_flavor(client, min_ram): flavors = [f for f in client.flavors.list() if f.ram >= min_ram] flavors.sort(lambda a, b: cmp(a.ram, b.ram)) return flavors[0] + def get_public_ip(server, version=4): if 'os-floating-ips' in get_extensions(server.manager.api): print 'using floating ips' @@ -109,6 +114,7 @@ def get_public_ip(server, version=4): return addr['addr'] return None + def add_public_ip(server): ip = server.manager.api.floating_ips.create() print "created floating ip", ip @@ -125,12 +131,14 @@ def add_public_ip(server): print 'ip has been added' return + def add_keypair(client, name): key = paramiko.RSAKey.generate(2048) public_key = key.get_name() + ' ' + key.get_base64() kp = client.keypairs.create(name, public_key) return key, kp + def wait_for_resource(wait_resource): last_progress = None last_status = None @@ -154,6 +162,7 @@ def wait_for_resource(wait_resource): if resource.status == 'ACTIVE': return resource + def ssh_connect(ip, username, connect_kwargs={}, timeout=60): # HPcloud may return errno 111 for about 30 seconds after adding the IP for count in iterate_timeout(timeout, "ssh access"): @@ -168,6 +177,7 @@ def ssh_connect(ip, username, connect_kwargs={}, timeout=60): return client return None + def delete_server(server): try: if 'os-floating-ips' in get_extensions(server.manager.api): @@ -191,6 +201,7 @@ def delete_server(server): print "Deleting server", server.id server.delete() + def update_stats(provider): state_names = { vmdatabase.BUILDING: 'building',