Use testr and flake8.

Change-Id: I748a0f54416ca540153ed5a9e7edfff739acaaea
This commit is contained in:
Monty Taylor 2013-06-16 16:24:15 -04:00
parent 7cb7093b2e
commit f5aaf25aa4
12 changed files with 70 additions and 37 deletions

1
.gitignore vendored
View File

@ -16,3 +16,4 @@ nosetests.xml
.DS_Store .DS_Store
build/ build/
dist/ dist/
.testrepository

4
.testr.conf Normal file
View File

@ -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

View File

@ -35,6 +35,7 @@ DEVSTACK_GATE_SECURE_CONFIG = os.environ.get('DEVSTACK_GATE_SECURE_CONFIG',
'~/devstack-gate-secure.conf')) '~/devstack-gate-secure.conf'))
SKIP_DEVSTACK_GATE_JENKINS = os.environ.get('SKIP_DEVSTACK_GATE_JENKINS', None) SKIP_DEVSTACK_GATE_JENKINS = os.environ.get('SKIP_DEVSTACK_GATE_JENKINS', None)
def check_machine(jenkins, machine): def check_machine(jenkins, machine):
utils.log.debug("Check ID: %s" % machine.id) utils.log.debug("Check ID: %s" % machine.id)
@ -54,6 +55,7 @@ def check_machine(jenkins, machine):
machine.delete() machine.delete()
def main(): def main():
db = vmdatabase.VMDatabase() db = vmdatabase.VMDatabase()

View File

@ -36,6 +36,7 @@ UPSTREAM_JOB_NAME=os.environ.get('UPSTREAM_JOB_NAME', '')
UPSTREAM_BRANCH=os.environ.get('UPSTREAM_BRANCH', '') UPSTREAM_BRANCH=os.environ.get('UPSTREAM_BRANCH', '')
BUILD_URL=os.environ.get('BUILD_URL', '') BUILD_URL=os.environ.get('BUILD_URL', '')
def main(): def main():
db = vmdatabase.VMDatabase() db = vmdatabase.VMDatabase()

View File

@ -31,8 +31,7 @@ def main(threshold, stat_file):
for provider in db.getProviders(): for provider in db.getProviders():
for base_image in provider.base_images: for base_image in provider.base_images:
ready_nodes = [x for x in base_image.machines \ ready_nodes = [x for x in base_image.machines if x.state == ready]
if x.state == ready]
ready_count = len(ready_nodes) ready_count = len(ready_nodes)
set_vm_state(ready_count, stat_file) set_vm_state(ready_count, stat_file)
@ -55,7 +54,7 @@ def usage(msg=None):
stream = sys.stderr stream = sys.stderr
else: else:
stream = sys.stdout 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])) % os.path.basename(sys.argv[0]))
if msg: if msg:
stream.write("\nERROR: " + msg + "\n") stream.write("\nERROR: " + msg + "\n")

View File

@ -7,11 +7,12 @@ from jenkins import JenkinsException, NODE_TYPE, CREATE_NODE
TOGGLE_OFFLINE = '/computer/%(name)s/toggleOffline?offlineMessage=%(msg)s' TOGGLE_OFFLINE = '/computer/%(name)s/toggleOffline?offlineMessage=%(msg)s'
CONFIG_NODE = '/computer/%(name)s/config.xml' CONFIG_NODE = '/computer/%(name)s/config.xml'
class Jenkins(jenkins.Jenkins): class Jenkins(jenkins.Jenkins):
def disable_node(self, name, msg=''): def disable_node(self, name, msg=''):
''' '''
Disable a node Disable a node
@param name: Jenkins node name @param name: Jenkins node name
@type name: str @type name: str
@param msg: Offline message @param msg: Offline message
@ -25,7 +26,7 @@ class Jenkins(jenkins.Jenkins):
def enable_node(self, name): def enable_node(self, name):
''' '''
Enable a node Enable a node
@param name: Jenkins node name @param name: Jenkins node name
@type name: str @type name: str
''' '''
@ -38,7 +39,7 @@ class Jenkins(jenkins.Jenkins):
def get_node_config(self, name): def get_node_config(self, name):
''' '''
Get the configuration for a node. Get the configuration for a node.
:param name: Jenkins node name, ``str`` :param name: Jenkins node name, ``str``
''' '''
get_config_url = self.server + CONFIG_NODE%locals() get_config_url = self.server + CONFIG_NODE%locals()
@ -47,7 +48,7 @@ class Jenkins(jenkins.Jenkins):
def reconfig_node(self, name, config_xml): def reconfig_node(self, name, config_xml):
''' '''
Change the configuration for an existing node. Change the configuration for an existing node.
:param name: Jenkins node name, ``str`` :param name: Jenkins node name, ``str``
:param config_xml: New XML configuration, ``str`` :param config_xml: New XML configuration, ``str``
''' '''
@ -68,7 +69,7 @@ class Jenkins(jenkins.Jenkins):
@param remoteFS: Remote filesystem location to use @param remoteFS: Remote filesystem location to use
@type remoteFS: str @type remoteFS: str
@param labels: Labels to associate with node @param labels: Labels to associate with node
@type labels: str @type labels: str
@param exclusive: Use this node for tied jobs only @param exclusive: Use this node for tied jobs only
@type exclusive: boolean @type exclusive: boolean
@param launcher: The launch method for the slave @param launcher: The launch method for the slave
@ -78,7 +79,7 @@ class Jenkins(jenkins.Jenkins):
''' '''
if self.node_exists(name): if self.node_exists(name):
raise JenkinsException('node[%s] already exists'%(name)) raise JenkinsException('node[%s] already exists'%(name))
mode = 'NORMAL' mode = 'NORMAL'
if exclusive: if exclusive:
mode = 'EXCLUSIVE' mode = 'EXCLUSIVE'
@ -87,7 +88,7 @@ class Jenkins(jenkins.Jenkins):
#hudson.slaves.CommandLauncher #hudson.slaves.CommandLauncher
#hudson.os.windows.ManagedWindowsServiceLauncher #hudson.os.windows.ManagedWindowsServiceLauncher
launcher_params['stapler-class'] = launcher launcher_params['stapler-class'] = launcher
inner_params = { inner_params = {
'name' : name, 'name' : name,
'nodeDescription' : nodeDescription, 'nodeDescription' : nodeDescription,
@ -100,13 +101,13 @@ class Jenkins(jenkins.Jenkins):
'nodeProperties' : { 'stapler-class-bag' : 'true' }, 'nodeProperties' : { 'stapler-class-bag' : 'true' },
'launcher' : launcher_params 'launcher' : launcher_params
} }
params = { params = {
'name' : name, 'name' : name,
'type' : NODE_TYPE, 'type' : NODE_TYPE,
'json' : json.dumps(inner_params) 'json' : json.dumps(inner_params)
} }
self.jenkins_open(urllib2.Request(self.server + CREATE_NODE%urllib.urlencode(params))) self.jenkins_open(urllib2.Request(self.server + CREATE_NODE%urllib.urlencode(params)))
if not self.node_exists(name): if not self.node_exists(name):

View File

@ -21,6 +21,7 @@
import paramiko import paramiko
import sys import sys
class SSHClient(object): class SSHClient(object):
def __init__(self, ip, username, password=None, pkey=None): def __init__(self, ip, username, password=None, pkey=None):
client = paramiko.SSHClient() client = paramiko.SSHClient()
@ -47,5 +48,3 @@ class SSHClient(object):
ftp = self.client.open_sftp() ftp = self.client.open_sftp()
ftp.put(source, dest) ftp.put(source, dest)
ftp.close() ftp.close()

0
tests/__init__.py Normal file
View File

View File

@ -18,13 +18,18 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import unittest
import vmdatabase
import time import time
class testVMDatabase(unittest.TestCase): import testtools
from testtools import content
import vmdatabase
class TestVMDatabase(testtools.TestCase):
def setUp(self): def setUp(self):
super(TestVMDatabase, self).setUp()
self.db = vmdatabase.VMDatabase(':memory:') self.db = vmdatabase.VMDatabase(':memory:')
def test_add_provider(self): def test_add_provider(self):
@ -41,7 +46,7 @@ class testVMDatabase(unittest.TestCase):
def test_add_base_image(self): def test_add_base_image(self):
self.test_add_provider() self.test_add_provider()
provider = self.db.getProvider('rackspace') provider = self.db.getProvider('rackspace')
base_image1 = provider.newBaseImage('oneiric', 1) base_image1 = provider.newBaseImage('oneiric', 1)
base_image2 = provider.newBaseImage('precise', 2) base_image2 = provider.newBaseImage('precise', 2)
@ -54,13 +59,13 @@ class testVMDatabase(unittest.TestCase):
self.test_add_base_image() self.test_add_base_image()
provider = self.db.getProvider('rackspace') provider = self.db.getProvider('rackspace')
base_image1 = provider.getBaseImage('oneiric') 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_image1 = base_image1.newSnapshotImage('oneiric-1331683549', 1331683549, 201, 301)
snapshot_image2 = base_image2.newSnapshotImage('precise-1331683549', 1331683549, 202, 301) snapshot_image2 = base_image2.newSnapshotImage('precise-1331683549', 1331683549, 202, 301)
hp_provider = self.db.getProvider('hpcloud') hp_provider = self.db.getProvider('hpcloud')
hp_base_image1 = hp_provider.getBaseImage('oneiric') 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_image1 = hp_base_image1.newSnapshotImage('oneiric-1331683549', 1331929410, 211, 311)
hp_snapshot_image2 = hp_base_image2.newSnapshotImage('precise-1331683549', 1331929410, 212, 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_image1 == base_image1.current_snapshot)
assert(snapshot_image2 == base_image2.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) 1331683550, 203, 303)
assert(base_image1.current_snapshot) assert(base_image1.current_snapshot)
assert(base_image2.current_snapshot) assert(base_image2.current_snapshot)
@ -195,25 +200,25 @@ class testVMDatabase(unittest.TestCase):
assert(len(hp_provider.ready_machines)==2) assert(len(hp_provider.ready_machines)==2)
machine = self.db.getMachineForUse('oneiric') 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(rs_provider.ready_machines)==1)
assert(len(hp_provider.ready_machines)==2) assert(len(hp_provider.ready_machines)==2)
assert(machine==machine1) assert(machine==machine1)
machine = self.db.getMachineForUse('oneiric') 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(rs_provider.ready_machines)==1)
assert(len(hp_provider.ready_machines)==1) assert(len(hp_provider.ready_machines)==1)
assert(machine==hp_machine1) assert(machine==hp_machine1)
machine = self.db.getMachineForUse('precise') 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(rs_provider.ready_machines)==1)
assert(len(hp_provider.ready_machines)==0) assert(len(hp_provider.ready_machines)==0)
assert(machine==hp_machine2) assert(machine==hp_machine2)
machine = self.db.getMachineForUse('precise') 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(rs_provider.ready_machines)==0)
assert(len(hp_provider.ready_machines)==0) assert(len(hp_provider.ready_machines)==0)
assert(machine==machine2) assert(machine==machine2)
@ -223,7 +228,7 @@ class testVMDatabase(unittest.TestCase):
self.db.print_state() self.db.print_state()
machine = self.db.getMachineForUse('oneiric') 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) result = machine.newResult('test-job', 82, 1234, 1)
time.sleep(2) time.sleep(2)
result.setResult(vmdatabase.RESULT_SUCCESS) result.setResult(vmdatabase.RESULT_SUCCESS)
@ -245,4 +250,3 @@ class testVMDatabase(unittest.TestCase):
assert(result.gerrit_patchset_number == 1) assert(result.gerrit_patchset_number == 1)
else: else:
assert(len(base_image.results)==0) assert(len(base_image.results)==0)

View File

@ -1,8 +1,10 @@
# Testing # Testing
coverage # computes code coverage percentages
mox # mock object framework # Install bounded pep8/pyflakes first, then let flake8 install
nose # for test discovery and console feedback hacking>=0.5.3,<0.6
nosexcover
pylint # static code analysis coverage>=3.6
pep8==0.6.1 # checks for PEP8 code style compliance discover
unittest2 # backport of unittest lib in python 2.7 python-subunit
testrepository>=0.0.13
testtools>=0.9.27

15
tox.ini
View File

@ -2,11 +2,20 @@
envlist = py26,py27,pep8 envlist = py26,py27,pep8
[testenv] [testenv]
setenv = VIRTUAL_ENV={envdir}
deps = -r{toxinidir}/tools/pip-requires deps = -r{toxinidir}/tools/pip-requires
-r{toxinidir}/tools/test-requires -r{toxinidir}/tools/test-requires
commands = nosetests {posargs} commands =
python setup.py testr --slowest --testr-args='{posargs}'
[testenv:pep8] [testenv:pep8]
deps = pep8 commands = flake8
commands = pep8 --count --repeat --show-source --exclude=.tox setup.py .
[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

View File

@ -39,6 +39,7 @@ handler = logging.handlers.SysLogHandler(address = '/dev/log')
handler.setFormatter(logging.Formatter("devstack-gate: %(message)s")) handler.setFormatter(logging.Formatter("devstack-gate: %(message)s"))
log.addHandler(handler) log.addHandler(handler)
def iterate_timeout(max_seconds, purpose): def iterate_timeout(max_seconds, purpose):
start = time.time() start = time.time()
count = 0 count = 0
@ -71,6 +72,8 @@ def get_client(provider):
return client return client
extension_cache = {} extension_cache = {}
def get_extensions(client): def get_extensions(client):
global extension_cache global extension_cache
cache = extension_cache.get(client) cache = extension_cache.get(client)
@ -84,11 +87,13 @@ def get_extensions(client):
extension_cache[client] = extensions extension_cache[client] = extensions
return extensions return extensions
def get_flavor(client, min_ram): def get_flavor(client, min_ram):
flavors = [f for f in client.flavors.list() if f.ram >= 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)) flavors.sort(lambda a, b: cmp(a.ram, b.ram))
return flavors[0] return flavors[0]
def get_public_ip(server, version=4): def get_public_ip(server, version=4):
if 'os-floating-ips' in get_extensions(server.manager.api): if 'os-floating-ips' in get_extensions(server.manager.api):
print 'using floating ips' print 'using floating ips'
@ -109,6 +114,7 @@ def get_public_ip(server, version=4):
return addr['addr'] return addr['addr']
return None return None
def add_public_ip(server): def add_public_ip(server):
ip = server.manager.api.floating_ips.create() ip = server.manager.api.floating_ips.create()
print "created floating ip", ip print "created floating ip", ip
@ -125,12 +131,14 @@ def add_public_ip(server):
print 'ip has been added' print 'ip has been added'
return return
def add_keypair(client, name): def add_keypair(client, name):
key = paramiko.RSAKey.generate(2048) key = paramiko.RSAKey.generate(2048)
public_key = key.get_name() + ' ' + key.get_base64() public_key = key.get_name() + ' ' + key.get_base64()
kp = client.keypairs.create(name, public_key) kp = client.keypairs.create(name, public_key)
return key, kp return key, kp
def wait_for_resource(wait_resource): def wait_for_resource(wait_resource):
last_progress = None last_progress = None
last_status = None last_status = None
@ -154,6 +162,7 @@ def wait_for_resource(wait_resource):
if resource.status == 'ACTIVE': if resource.status == 'ACTIVE':
return resource return resource
def ssh_connect(ip, username, connect_kwargs={}, timeout=60): def ssh_connect(ip, username, connect_kwargs={}, timeout=60):
# HPcloud may return errno 111 for about 30 seconds after adding the IP # HPcloud may return errno 111 for about 30 seconds after adding the IP
for count in iterate_timeout(timeout, "ssh access"): for count in iterate_timeout(timeout, "ssh access"):
@ -168,6 +177,7 @@ def ssh_connect(ip, username, connect_kwargs={}, timeout=60):
return client return client
return None return None
def delete_server(server): def delete_server(server):
try: try:
if 'os-floating-ips' in get_extensions(server.manager.api): if 'os-floating-ips' in get_extensions(server.manager.api):
@ -191,6 +201,7 @@ def delete_server(server):
print "Deleting server", server.id print "Deleting server", server.id
server.delete() server.delete()
def update_stats(provider): def update_stats(provider):
state_names = { state_names = {
vmdatabase.BUILDING: 'building', vmdatabase.BUILDING: 'building',