[PATCH 1/2] move RollbackContext from tests/utils to src/kimchi/rollbackcontext

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> Then kimchi source code can make use of it Also add src/kimchi/rollbackcontext.py in dist list Signed-off-by: Zhou Zheng Sheng <zhshzhou@linux.vnet.ibm.com> Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/Makefile.am | 59 +++++++++++++++++------------------ src/kimchi/rollbackcontext.py | 71 +++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 25 +++++++-------- tests/test_rest.py | 3 +- tests/utils.py | 45 --------------------------- 5 files changed, 116 insertions(+), 87 deletions(-) create mode 100644 src/kimchi/rollbackcontext.py diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 47a3bd2..2f05ab7 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -21,35 +21,36 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA kimchi_PYTHON = \ - asynctask.py \ - auth.py \ - controller.py \ - disks.py \ - distroloader.py \ - exception.py \ - __init__.py \ - isoinfo.py \ - netinfo.py \ - network.py \ - networkxml.py \ - mockmodel.py \ - model.py \ - objectstore.py \ - osinfo.py \ - root.py \ - scan.py \ - screenshot.py \ - server.py \ - sslcert.py \ - template.py \ - vmtemplate.py \ - vnc.py \ - websocket.py \ - websockify.py \ - xmlutils.py \ - utils.py \ - cachebust.py \ - featuretests.py + __init__.py \ + asynctask.py \ + auth.py \ + cachebust.py \ + controller.py \ + disks.py \ + distroloader.py \ + exception.py \ + featuretests.py \ + isoinfo.py \ + mockmodel.py \ + model.py \ + netinfo.py \ + network.py \ + networkxml.py \ + objectstore.py \ + osinfo.py \ + rollbackcontext.py \ + root.py \ + scan.py \ + screenshot.py \ + server.py \ + sslcert.py \ + template.py \ + utils.py \ + vmtemplate.py \ + vnc.py \ + websocket.py \ + websockify.py \ + xmlutils.py nodist_kimchi_PYTHON = config.py diff --git a/src/kimchi/rollbackcontext.py b/src/kimchi/rollbackcontext.py new file mode 100644 index 0000000..2afd114 --- /dev/null +++ b/src/kimchi/rollbackcontext.py @@ -0,0 +1,71 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@linux.vnet.ibm.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import sys + + +class RollbackContext(object): + ''' + A context manager for recording and playing rollback. + The first exception will be remembered and re-raised after rollback + + Sample usage: + with RollbackContext() as rollback: + step1() + rollback.prependDefer(lambda: undo step1) + def undoStep2(arg): pass + step2() + rollback.prependDefer(undoStep2, arg) + ''' + def __init__(self, *args): + self._finally = [] + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + firstException = exc_value + + for undo, args, kwargs in self._finally: + try: + undo(*args, **kwargs) + except Exception as e: + # keep the earliest exception info + if not firstException: + firstException = e + # keep the original traceback info + traceback = sys.exc_info()[2] + + # re-raise the earliest exception + if firstException is not None: + if type(firstException) is str: + sys.stderr.write(firstException) + else: + raise firstException, None, traceback + + def defer(self, func, *args, **kwargs): + self._finally.append((func, args, kwargs)) + + def prependDefer(self, func, *args, **kwargs): + self._finally.insert(0, (func, args, kwargs)) diff --git a/tests/test_model.py b/tests/test_model.py index e19364f..7ecd8c6 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -38,6 +38,7 @@ import utils from kimchi import netinfo from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.exception import NotFoundError, OperationFailed +from kimchi.rollbackcontext import RollbackContext class ModelTests(unittest.TestCase): @@ -72,7 +73,7 @@ class ModelTests(unittest.TestCase): def test_vm_lifecycle(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': []} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -97,7 +98,7 @@ class ModelTests(unittest.TestCase): def test_vm_storage_provisioning(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': [{'size': 1}]} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -115,7 +116,7 @@ class ModelTests(unittest.TestCase): def test_storagepool(self): inst = kimchi.model.Model('qemu:///system', self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images' name = 'test-pool' if not os.path.exists(path): @@ -168,7 +169,7 @@ class ModelTests(unittest.TestCase): def test_storagevolume(self): inst = kimchi.model.Model('qemu:///system', self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images' pool = 'test-pool' vol = 'test-volume.img' @@ -223,7 +224,7 @@ class ModelTests(unittest.TestCase): def test_template_storage_customise(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images' pool = 'test-pool' if not os.path.exists(path): @@ -295,7 +296,7 @@ class ModelTests(unittest.TestCase): orig_params = {'name': 'test', 'memory': '1024', 'cpus': '1'} inst.templates_create(orig_params) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params_1 = {'name': 'kimchi-vm1', 'template': '/templates/test'} params_2 = {'name': 'kimchi-vm2', 'template': '/templates/test'} inst.vms_create(params_1) @@ -326,7 +327,7 @@ class ModelTests(unittest.TestCase): def test_network(self): inst = kimchi.model.Model('qemu:///system', self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: name = 'test-network' networks = inst.networks_get_list() @@ -480,7 +481,7 @@ class ModelTests(unittest.TestCase): def test_delete_running_vm(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': u'test', 'disks': []} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -501,7 +502,7 @@ class ModelTests(unittest.TestCase): def test_vm_list_sorted(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': []} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -517,7 +518,7 @@ class ModelTests(unittest.TestCase): def test_use_test_host(self): inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': [], 'storagepool': '/storagepools/default-pool', 'domain': 'test', @@ -546,7 +547,7 @@ class ModelTests(unittest.TestCase): inst.debugreport_delete(namePrefix + '*') except NotFoundError: pass - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: report_list = inst.debugreports_get_list() self.assertFalse(reportName in report_list) try: @@ -617,7 +618,7 @@ class ModelTests(unittest.TestCase): @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_deep_scan(self): inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images/tmpdir' if not os.path.exists(path): os.makedirs(path) diff --git a/tests/test_rest.py b/tests/test_rest.py index 73946c0..1b7312f 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -33,8 +33,9 @@ from functools import partial import kimchi.mockmodel import kimchi.server from kimchi.asynctask import AsyncTask +from kimchi.rollbackcontext import RollbackContext from utils import fake_user, get_free_port, https_request, patch_auth, request -from utils import RollbackContext, run_server +from utils import run_server test_server = None diff --git a/tests/utils.py b/tests/utils.py index a7596e8..960e0be 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -140,51 +140,6 @@ def https_request(host, port, path, data=None, method='GET', headers=None): return _request(conn, path, data, method, headers) -class RollbackContext(object): - ''' - A context manager for recording and playing rollback. - The first exception will be remembered and re-raised after rollback - - Sample usage: - with RollbackContext() as rollback: - step1() - rollback.prependDefer(lambda: undo step1) - def undoStep2(arg): pass - step2() - rollback.prependDefer(undoStep2, arg) - ''' - def __init__(self, *args): - self._finally = [] - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - firstException = exc_value - - for undo, args, kwargs in self._finally: - try: - undo(*args, **kwargs) - except Exception as e: - # keep the earliest exception info - if not firstException: - firstException = e - # keep the original traceback info - traceback = sys.exc_info()[2] - - # re-raise the earliest exception - if firstException is not None: - if type(firstException) is str: - sys.stderr.write(firstException) - else: - raise firstException, None, traceback - - def defer(self, func, *args, **kwargs): - self._finally.append((func, args, kwargs)) - - def prependDefer(self, func, *args, **kwargs): - self._finally.insert(0, (func, args, kwargs)) - def patch_auth(): """ Override the authenticate function with a simple test against an -- 1.8.4.2

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> Touch 4 files when move RollbackContext Fix pep8 on these 4 files Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- Makefile.am | 10 +++++-- tests/test_model.py | 83 +++++++++++++++++++++++++++++++++-------------------- tests/test_rest.py | 70 ++++++++++++++++++++++++-------------------- tests/utils.py | 14 ++++++--- 4 files changed, 108 insertions(+), 69 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0fd92c8..8a29923 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,17 +38,21 @@ EXTRA_DIST = \ # When fixing a file to conform with pep8, add it to the WL here. # So it will be checked from now on. PEP8_WHITELIST = \ + plugins/__init__.py \ + plugins/sample/__init__.py \ + plugins/sample/model.py \ src/kimchi/asynctask.py \ src/kimchi/auth.py \ src/kimchi/cachebust.py \ src/kimchi/config.py.in \ src/kimchi/disks.py \ + src/kimchi/rollbackcontext.py \ src/kimchi/root.py \ src/kimchi/server.py \ - plugins/__init__.py \ - plugins/sample/__init__.py \ - plugins/sample/model.py \ + tests/test_model.py \ tests/test_plugin.py \ + tests/test_rest.py \ + tests/utils.py \ $(NULL) check-local: diff --git a/tests/test_model.py b/tests/test_model.py index 7ecd8c6..c03cc3f 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -19,7 +19,7 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import os import platform @@ -149,12 +149,13 @@ class ModelTests(unittest.TestCase): self.assertEquals('active', poolinfo['state']) autostart = poolinfo['autostart'] - ori_params = {'autostart': True} if autostart else {'autostart': False} + ori_params = {'autostart': + True} if autostart else {'autostart': False} for i in [True, False]: params = {'autostart': i} inst.storagepool_update(name, params) rollback.prependDefer(inst.storagepool_update, name, - ori_params) + ori_params) poolinfo = inst.storagepool_lookup(name) self.assertEquals(i, poolinfo['autostart']) inst.storagepool_update(name, ori_params) @@ -182,7 +183,8 @@ class ModelTests(unittest.TestCase): inst.storagepools_create(args) rollback.prependDefer(inst.storagepool_delete, pool) - self.assertRaises(InvalidOperation, inst.storagevolumes_get_list, pool) + self.assertRaises(InvalidOperation, inst.storagevolumes_get_list, + pool) poolinfo = inst.storagepool_lookup(pool) self.assertEquals(0, poolinfo['nr_volumes']) # Activate the pool before adding any volume @@ -235,7 +237,8 @@ class ModelTests(unittest.TestCase): rollback.prependDefer(inst.template_delete, 'test') params = {'storagepool': '/storagepools/test-pool'} - self.assertRaises(InvalidParameter, inst.template_update, 'test', params) + self.assertRaises(InvalidParameter, inst.template_update, + 'test', params) args = {'name': pool, 'path': path, @@ -258,7 +261,8 @@ class ModelTests(unittest.TestCase): self.assertTrue(os.access(disk_path, os.F_OK)) def test_template_create(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) # Test non-exist path raises InvalidParameter params = {'name': 'test', 'cdrom': '/non-exsitent.iso'} @@ -270,7 +274,8 @@ class ModelTests(unittest.TestCase): @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_template_update(self): - inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('qemu:///system', + objstore_loc=self.tmp_store) orig_params = {'name': 'test', 'memory': '1024', 'cpus': '1'} inst.templates_create(orig_params) @@ -291,7 +296,8 @@ class ModelTests(unittest.TestCase): self.assertEquals(params[key], info[key]) def test_vm_edit(self): - inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('qemu:///system', + objstore_loc=self.tmp_store) orig_params = {'name': 'test', 'memory': '1024', 'cpus': '1'} inst.templates_create(orig_params) @@ -314,11 +320,13 @@ class ModelTests(unittest.TestCase): self.assertEquals('running', info['state']) params = {'name': 'new-vm'} - self.assertRaises(InvalidParameter, inst.vm_update, 'kimchi-vm1', params) + self.assertRaises(InvalidParameter, inst.vm_update, + 'kimchi-vm1', params) inst.vm_stop('kimchi-vm1') params = {'name': 'new-vm'} - self.assertRaises(OperationFailed, inst.vm_update, 'kimchi-vm1', {'name': 'kimchi-vm2'}) + self.assertRaises(OperationFailed, inst.vm_update, + 'kimchi-vm1', {'name': 'kimchi-vm2'}) inst.vm_update('kimchi-vm1', params) self.assertEquals(info['uuid'], inst.vm_lookup('new-vm')['uuid']) rollback.prependDefer(inst.vm_delete, 'new-vm') @@ -427,7 +435,8 @@ class ModelTests(unittest.TestCase): self.assertEquals(10, len(store._connections.keys())) def test_get_interfaces(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) expected_ifaces = netinfo.all_favored_interfaces() ifaces = inst.interfaces_get_list() self.assertEquals(len(expected_ifaces), len(ifaces)) @@ -456,7 +465,8 @@ class ModelTests(unittest.TestCase): except: cb("Exception raised", False) - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) taskid = inst.add_task('', quick_op, 'Hello') self._wait_task(inst, taskid) self.assertEquals(1, taskid) @@ -464,17 +474,19 @@ class ModelTests(unittest.TestCase): self.assertEquals('Hello', inst.task_lookup(taskid)['message']) taskid = inst.add_task('', long_op, - {'delay': 3, 'result': False, - 'message': 'It was not meant to be'}) + {'delay': 3, 'result': False, + 'message': 'It was not meant to be'}) self.assertEquals(2, taskid) self.assertEquals('running', inst.task_lookup(taskid)['status']) self.assertEquals('OK', inst.task_lookup(taskid)['message']) self._wait_task(inst, taskid) self.assertEquals('failed', inst.task_lookup(taskid)['status']) - self.assertEquals('It was not meant to be', inst.task_lookup(taskid)['message']) + self.assertEquals('It was not meant to be', + inst.task_lookup(taskid)['message']) taskid = inst.add_task('', abnormal_op, {}) self._wait_task(inst, taskid) - self.assertEquals('Exception raised', inst.task_lookup(taskid)['message']) + self.assertEquals('Exception raised', + inst.task_lookup(taskid)['message']) self.assertEquals('failed', inst.task_lookup(taskid)['status']) @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') @@ -516,18 +528,20 @@ class ModelTests(unittest.TestCase): self.assertEquals(vms, sorted(vms, key=unicode.lower)) def test_use_test_host(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) with RollbackContext() as rollback: params = {'name': 'test', 'disks': [], - 'storagepool': '/storagepools/default-pool', - 'domain': 'test', - 'arch': 'i686'} + 'storagepool': '/storagepools/default-pool', + 'domain': 'test', + 'arch': 'i686'} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') - params = {'name': 'kimchi-vm', 'template': '/templates/test',} + params = {'name': 'kimchi-vm', + 'template': '/templates/test'} inst.vms_create(params) rollback.prependDefer(inst.vm_delete, 'kimchi-vm') @@ -537,7 +551,8 @@ class ModelTests(unittest.TestCase): @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_debug_reports(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) namePrefix = 'unitTestReport' # sosreport always deletes unsual letters like '-' and '_' in the # generated report file name. @@ -555,9 +570,11 @@ class ModelTests(unittest.TestCase): rollback.prependDefer(inst.debugreport_delete, reportName) taskid = task['id'] self._wait_task(inst, taskid, 60) - self.assertEquals('finished', inst.task_lookup(taskid)['status'], - "It is not necessary an error. You may need to increase the " - "timeout number in _wait_task()") + self.assertEquals('finished', + inst.task_lookup(taskid)['status'], + "It is not necessary an error. " + "You may need to increase the " + "timeout number in _wait_task()") report_list = inst.debugreports_get_list() self.assertTrue(reportName in report_list) except OperationFailed, e: @@ -570,7 +587,8 @@ class ModelTests(unittest.TestCase): time.sleep(1) def test_get_distros(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) distros = inst._get_distros() for distro in distros.values(): self.assertIn('name', distro) @@ -580,7 +598,8 @@ class ModelTests(unittest.TestCase): @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_get_hostinfo(self): - inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('qemu:///system', + objstore_loc=self.tmp_store) info = inst.host_lookup() distro, version, codename = platform.linux_distribution() self.assertIn('cpu', info) @@ -617,15 +636,17 @@ class ModelTests(unittest.TestCase): @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_deep_scan(self): - inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('qemu:///system', + objstore_loc=self.tmp_store) with RollbackContext() as rollback: path = '/tmp/kimchi-images/tmpdir' if not os.path.exists(path): os.makedirs(path) - iso_gen.construct_fake_iso('/tmp/kimchi-images/tmpdir/ubuntu12.04.iso', - True, '12.04', 'ubuntu') + iso_gen.construct_fake_iso('/tmp/kimchi-images/tmpdir/' + 'ubuntu12.04.iso', True, + '12.04', 'ubuntu') iso_gen.construct_fake_iso('/tmp/kimchi-images/sles10.iso', - True, '10', 'sles') + True, '10', 'sles') args = {'name': 'kimchi-scanning-pool', 'path': '/tmp/kimchi-images', diff --git a/tests/test_rest.py b/tests/test_rest.py index 1b7312f..e626d2f 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -18,7 +18,7 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import base64 import json @@ -32,7 +32,6 @@ from functools import partial import kimchi.mockmodel import kimchi.server -from kimchi.asynctask import AsyncTask from kimchi.rollbackcontext import RollbackContext from utils import fake_user, get_free_port, https_request, patch_auth, request from utils import run_server @@ -134,12 +133,12 @@ class RestTests(unittest.TestCase): resp = self.request("/", headers={'Accept': 'text/html'}) self.assertTrue('<!doctype html>' in resp.read().lower()) - resp = self.request("/", - headers={'Accept': 'application/json, text/html'}) + resp = self.request("/", headers={'Accept': + 'application/json, text/html'}) self.assertValidJSON(resp.read()) - resp = self.request("/", - headers={'Accept': 'text/html, application/json'}) + resp = self.request("/", headers={'Accept': + 'text/html, application/json'}) self.assertValidJSON(resp.read()) h = {'Accept': 'text/plain'} @@ -212,7 +211,7 @@ class RestTests(unittest.TestCase): # Create a Template req = json.dumps({'name': 'test', 'disks': [{'size': 1}], 'icon': 'images/icon-debian.png', - 'cdrom': '/nonexistent.iso'}) + 'cdrom': '/nonexistent.iso'}) resp = self.request('/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -303,7 +302,7 @@ class RestTests(unittest.TestCase): def test_template_customise_storage(self): req = json.dumps({'name': 'test', 'cdrom': '/nonexistent.iso', - 'disks': [{'size': 1}]}) + 'disks': [{'size': 1}]}) resp = self.request('/templates', req, 'POST') self.assertEquals(201, resp.status) @@ -437,7 +436,8 @@ class RestTests(unittest.TestCase): self.assertEquals(201, resp.status) # Verify the storage pool - storagepool = json.loads(self.request('/storagepools/test-pool').read()) + storagepool = json.loads( + self.request('/storagepools/test-pool').read()) self.assertEquals('inactive', storagepool['state']) if storagepool['type'] == 'dir': self.assertEquals(True, storagepool['autostart']) @@ -446,12 +446,14 @@ class RestTests(unittest.TestCase): # activate the storage pool resp = self.request('/storagepools/test-pool/activate', '{}', 'POST') - storagepool = json.loads(self.request('/storagepools/test-pool').read()) + storagepool = json.loads( + self.request('/storagepools/test-pool').read()) self.assertEquals('active', storagepool['state']) # Deactivate the storage pool resp = self.request('/storagepools/test-pool/deactivate', '{}', 'POST') - storagepool = json.loads(self.request('/storagepools/test-pool').read()) + storagepool = json.loads( + self.request('/storagepools/test-pool').read()) self.assertEquals('inactive', storagepool['state']) # Set autostart flag of the storage pool @@ -460,7 +462,7 @@ class RestTests(unittest.TestCase): req = json.dumps(t) resp = self.request('/storagepools/test-pool', req, 'PUT') storagepool = json.loads( - self.request('/storagepools/test-pool').read()) + self.request('/storagepools/test-pool').read()) self.assertEquals(autostart, storagepool['autostart']) # Delete the storage pool @@ -477,7 +479,8 @@ class RestTests(unittest.TestCase): resp = self.request('/storagepools/pool-1/activate', '{}', 'POST') self.assertEquals(200, resp.status) - nr_vols = json.loads(self.request('/storagepools/pool-1').read())['nr_volumes'] + nr_vols = json.loads( + self.request('/storagepools/pool-1').read())['nr_volumes'] self.assertEquals(0, nr_vols) # Now add a couple of storage volumes to the mock model @@ -489,10 +492,11 @@ class RestTests(unittest.TestCase): 'type': 'disk', 'format': 'raw'}) resp = self.request('/storagepools/pool-1/storagevolumes', - req, 'POST') + req, 'POST') self.assertEquals(201, resp.status) - nr_vols = json.loads(self.request('/storagepools/pool-1').read())['nr_volumes'] + nr_vols = json.loads( + self.request('/storagepools/pool-1').read())['nr_volumes'] self.assertEquals(5, nr_vols) resp = self.request('/storagepools/pool-1/storagevolumes') storagevolumes = json.loads(resp.read()) @@ -502,7 +506,8 @@ class RestTests(unittest.TestCase): storagevolume = json.loads(resp.read()) self.assertEquals('volume-1', storagevolume['name']) self.assertEquals('raw', storagevolume['format']) - self.assertEquals('/var/lib/libvirt/images/volume-1', storagevolume['path']) + self.assertEquals('/var/lib/libvirt/images/volume-1', + storagevolume['path']) # Now remove the StoragePool from mock model self._delete_pool('pool-1') @@ -516,11 +521,13 @@ class RestTests(unittest.TestCase): 'allocation': 512, 'type': 'disk', 'format': 'raw'}) - resp = self.request('/storagepools/pool-2/storagevolumes/', req, 'POST') + resp = self.request('/storagepools/pool-2/storagevolumes/', + req, 'POST') self.assertEquals(400, resp.status) resp = self.request('/storagepools/pool-2/activate', '{}', 'POST') self.assertEquals(200, resp.status) - resp = self.request('/storagepools/pool-2/storagevolumes/', req, 'POST') + resp = self.request('/storagepools/pool-2/storagevolumes/', + req, 'POST') self.assertEquals(201, resp.status) # Verify the storage volume @@ -545,7 +552,7 @@ class RestTests(unittest.TestCase): # Delete the storage volume resp = self.request('/storagepools/pool-2/storagevolumes/test-volume', - '{}', 'DELETE') + '{}', 'DELETE') self.assertEquals(204, resp.status) # Now remove the StoragePool from mock model @@ -561,7 +568,8 @@ class RestTests(unittest.TestCase): self.assertEquals(201, resp.status) # Verify the storage pool - storagepool = json.loads(self.request('/storagepools/%s' % name).read()) + storagepool = json.loads(self.request('/storagepools/%s' + % name).read()) self.assertEquals('inactive', storagepool['state']) return name @@ -572,8 +580,8 @@ class RestTests(unittest.TestCase): def test_templates(self): def verify_template(t, res): - for field in ('name', 'os_distro', - 'os_version', 'memory', 'cpus', 'storagepool'): + for field in ('name', 'os_distro', 'os_version', + 'memory', 'cpus', 'storagepool'): self.assertEquals(t[field], res[field]) resp = self.request('/templates') @@ -700,15 +708,17 @@ class RestTests(unittest.TestCase): '/storagepools/kimchi_isos/storagevolumes/').read())[0] self.assertEquals('pool-3-fedora.iso', storagevolume['name']) self.assertEquals('iso', storagevolume['format']) - self.assertEquals('/var/lib/libvirt/images/fedora.iso',storagevolume['path']) + self.assertEquals('/var/lib/libvirt/images/fedora.iso', + storagevolume['path']) self.assertEquals(1024 << 20, storagevolume['capacity']) self.assertEquals(1024 << 20, storagevolume['allocation']) self.assertEquals('17', storagevolume['os_version']) - self.assertEquals('fedora',storagevolume['os_distro']) - self.assertEquals(True,storagevolume['bootable']) + self.assertEquals('fedora', storagevolume['os_distro']) + self.assertEquals(True, storagevolume['bootable']) # Create a template - # In real model os distro/version can be omitted as we will scan the iso + # In real model os distro/version can be omitted + # as we will scan the iso req = json.dumps({'name': 'test', 'cdrom': storagevolume['path'], 'os_distro': storagevolume['os_distro'], @@ -724,8 +734,8 @@ class RestTests(unittest.TestCase): self.assertEquals(1024, t['memory']) # Deactivate or destroy scan pool return 405 - resp = self.request('/storagepools/kimchi_isos/storagevolumes/deactivate', - '{}', 'POST') + resp = self.request('/storagepools/kimchi_isos/storagevolumes' + '/deactivate', '{}', 'POST') self.assertEquals(405, resp.status) resp = self.request('/storagepools/kimchi_isos/storagevolumes', @@ -762,13 +772,11 @@ class RestTests(unittest.TestCase): self.assertEquals('image/png', resp.getheader('content-type')) lastMod1 = resp.getheader('last-modified') - # Take another screenshot instantly and compare the last Modified date resp = self.request('/vms/test-vm/screenshot') lastMod2 = resp.getheader('last-modified') self.assertEquals(lastMod2, lastMod1) - resp = self.request('/vms/test-vm/screenshot', '{}', 'DELETE') self.assertEquals(405, resp.status) @@ -998,7 +1006,7 @@ class RestTests(unittest.TestCase): self.assertEquals(200, resp.status) def _report_delete(self, name): - resp = request(host, port, '/debugreports/%s' % name, '{}', 'DELETE') + request(host, port, '/debugreports/%s' % name, '{}', 'DELETE') def test_create_debugreport(self): req = json.dumps({'name': 'report1'}) diff --git a/tests/utils.py b/tests/utils.py index 960e0be..008f668 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -18,7 +18,7 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # import base64 @@ -28,7 +28,6 @@ import os import socket import sys import threading -import time import unittest @@ -60,7 +59,8 @@ if sys.version_info[:2] == (2, 6): def assertGreaterEqual(self, a, b, msg=None): if not a >= b: - self.fail('%s not greater than or equal to %s' % (repr(a), repr(b))) + self.fail('%s not greater than or equal to %s' + % (repr(a), repr(b))) def assertIsInstance(self, obj, cls, msg=None): if not isinstance(obj, cls): @@ -80,6 +80,7 @@ if sys.version_info[:2] == (2, 6): unittest.TestCase.assertIn = assertIn unittest.TestCase.assertNotIn = assertNotIn + def get_free_port(name='http'): global _ports if _ports.get(name) is not None: @@ -93,7 +94,9 @@ def get_free_port(name='http'): _ports[name] = sock.getsockname()[1] return _ports[name] -def run_server(host, port, ssl_port, test_mode, model=None, environment='development'): + +def run_server(host, port, ssl_port, test_mode, + model=None, environment='development'): args = type('_', (object,), {'host': host, 'port': port, 'ssl_port': ssl_port, 'ssl_cert': '', 'ssl_key': '', @@ -109,12 +112,14 @@ def run_server(host, port, ssl_port, test_mode, model=None, environment='develop cherrypy.engine.wait(cherrypy.engine.states.STARTED) return s + def silence_server(): """ Silence server status messages on stdout """ cherrypy.config.update({"environment": "embedded"}) + def running_as_root(): return os.geteuid() == 0 @@ -130,6 +135,7 @@ def _request(conn, path, data, method, headers): conn.request(method, path, data, headers) return conn.getresponse() + def request(host, port, path, data=None, method='GET', headers=None): conn = httplib.HTTPConnection(host, port) return _request(conn, path, data, method, headers) -- 1.8.4.2

Reviewed-by: Aline Manera <alinefm@linux.vnet.ibm.com> On 12/27/2013 08:40 AM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
Touch 4 files when move RollbackContext Fix pep8 on these 4 files
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- Makefile.am | 10 +++++-- tests/test_model.py | 83 +++++++++++++++++++++++++++++++++-------------------- tests/test_rest.py | 70 ++++++++++++++++++++++++-------------------- tests/utils.py | 14 ++++++--- 4 files changed, 108 insertions(+), 69 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 0fd92c8..8a29923 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,17 +38,21 @@ EXTRA_DIST = \ # When fixing a file to conform with pep8, add it to the WL here. # So it will be checked from now on. PEP8_WHITELIST = \ + plugins/__init__.py \ + plugins/sample/__init__.py \ + plugins/sample/model.py \ src/kimchi/asynctask.py \ src/kimchi/auth.py \ src/kimchi/cachebust.py \ src/kimchi/config.py.in \ src/kimchi/disks.py \ + src/kimchi/rollbackcontext.py \ src/kimchi/root.py \ src/kimchi/server.py \ - plugins/__init__.py \ - plugins/sample/__init__.py \ - plugins/sample/model.py \ + tests/test_model.py \ tests/test_plugin.py \ + tests/test_rest.py \ + tests/utils.py \ $(NULL)
check-local: diff --git a/tests/test_model.py b/tests/test_model.py index 7ecd8c6..c03cc3f 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -19,7 +19,7 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os import platform @@ -149,12 +149,13 @@ class ModelTests(unittest.TestCase): self.assertEquals('active', poolinfo['state'])
autostart = poolinfo['autostart'] - ori_params = {'autostart': True} if autostart else {'autostart': False} + ori_params = {'autostart': + True} if autostart else {'autostart': False} for i in [True, False]: params = {'autostart': i} inst.storagepool_update(name, params) rollback.prependDefer(inst.storagepool_update, name, - ori_params) + ori_params) poolinfo = inst.storagepool_lookup(name) self.assertEquals(i, poolinfo['autostart']) inst.storagepool_update(name, ori_params) @@ -182,7 +183,8 @@ class ModelTests(unittest.TestCase): inst.storagepools_create(args) rollback.prependDefer(inst.storagepool_delete, pool)
- self.assertRaises(InvalidOperation, inst.storagevolumes_get_list, pool) + self.assertRaises(InvalidOperation, inst.storagevolumes_get_list, + pool) poolinfo = inst.storagepool_lookup(pool) self.assertEquals(0, poolinfo['nr_volumes']) # Activate the pool before adding any volume @@ -235,7 +237,8 @@ class ModelTests(unittest.TestCase): rollback.prependDefer(inst.template_delete, 'test')
params = {'storagepool': '/storagepools/test-pool'} - self.assertRaises(InvalidParameter, inst.template_update, 'test', params) + self.assertRaises(InvalidParameter, inst.template_update, + 'test', params)
args = {'name': pool, 'path': path, @@ -258,7 +261,8 @@ class ModelTests(unittest.TestCase): self.assertTrue(os.access(disk_path, os.F_OK))
def test_template_create(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) # Test non-exist path raises InvalidParameter params = {'name': 'test', 'cdrom': '/non-exsitent.iso'} @@ -270,7 +274,8 @@ class ModelTests(unittest.TestCase):
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_template_update(self): - inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('qemu:///system', + objstore_loc=self.tmp_store)
orig_params = {'name': 'test', 'memory': '1024', 'cpus': '1'} inst.templates_create(orig_params) @@ -291,7 +296,8 @@ class ModelTests(unittest.TestCase): self.assertEquals(params[key], info[key])
def test_vm_edit(self): - inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('qemu:///system', + objstore_loc=self.tmp_store)
orig_params = {'name': 'test', 'memory': '1024', 'cpus': '1'} inst.templates_create(orig_params) @@ -314,11 +320,13 @@ class ModelTests(unittest.TestCase): self.assertEquals('running', info['state'])
params = {'name': 'new-vm'} - self.assertRaises(InvalidParameter, inst.vm_update, 'kimchi-vm1', params) + self.assertRaises(InvalidParameter, inst.vm_update, + 'kimchi-vm1', params)
inst.vm_stop('kimchi-vm1') params = {'name': 'new-vm'} - self.assertRaises(OperationFailed, inst.vm_update, 'kimchi-vm1', {'name': 'kimchi-vm2'}) + self.assertRaises(OperationFailed, inst.vm_update, + 'kimchi-vm1', {'name': 'kimchi-vm2'}) inst.vm_update('kimchi-vm1', params) self.assertEquals(info['uuid'], inst.vm_lookup('new-vm')['uuid']) rollback.prependDefer(inst.vm_delete, 'new-vm') @@ -427,7 +435,8 @@ class ModelTests(unittest.TestCase): self.assertEquals(10, len(store._connections.keys()))
def test_get_interfaces(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) expected_ifaces = netinfo.all_favored_interfaces() ifaces = inst.interfaces_get_list() self.assertEquals(len(expected_ifaces), len(ifaces)) @@ -456,7 +465,8 @@ class ModelTests(unittest.TestCase): except: cb("Exception raised", False)
- inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) taskid = inst.add_task('', quick_op, 'Hello') self._wait_task(inst, taskid) self.assertEquals(1, taskid) @@ -464,17 +474,19 @@ class ModelTests(unittest.TestCase): self.assertEquals('Hello', inst.task_lookup(taskid)['message'])
taskid = inst.add_task('', long_op, - {'delay': 3, 'result': False, - 'message': 'It was not meant to be'}) + {'delay': 3, 'result': False, + 'message': 'It was not meant to be'}) self.assertEquals(2, taskid) self.assertEquals('running', inst.task_lookup(taskid)['status']) self.assertEquals('OK', inst.task_lookup(taskid)['message']) self._wait_task(inst, taskid) self.assertEquals('failed', inst.task_lookup(taskid)['status']) - self.assertEquals('It was not meant to be', inst.task_lookup(taskid)['message']) + self.assertEquals('It was not meant to be', + inst.task_lookup(taskid)['message']) taskid = inst.add_task('', abnormal_op, {}) self._wait_task(inst, taskid) - self.assertEquals('Exception raised', inst.task_lookup(taskid)['message']) + self.assertEquals('Exception raised', + inst.task_lookup(taskid)['message']) self.assertEquals('failed', inst.task_lookup(taskid)['status'])
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root') @@ -516,18 +528,20 @@ class ModelTests(unittest.TestCase): self.assertEquals(vms, sorted(vms, key=unicode.lower))
def test_use_test_host(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store)
with RollbackContext() as rollback: params = {'name': 'test', 'disks': [], - 'storagepool': '/storagepools/default-pool', - 'domain': 'test', - 'arch': 'i686'} + 'storagepool': '/storagepools/default-pool', + 'domain': 'test', + 'arch': 'i686'}
inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test')
- params = {'name': 'kimchi-vm', 'template': '/templates/test',} + params = {'name': 'kimchi-vm', + 'template': '/templates/test'} inst.vms_create(params) rollback.prependDefer(inst.vm_delete, 'kimchi-vm')
@@ -537,7 +551,8 @@ class ModelTests(unittest.TestCase):
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_debug_reports(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) namePrefix = 'unitTestReport' # sosreport always deletes unsual letters like '-' and '_' in the # generated report file name. @@ -555,9 +570,11 @@ class ModelTests(unittest.TestCase): rollback.prependDefer(inst.debugreport_delete, reportName) taskid = task['id'] self._wait_task(inst, taskid, 60) - self.assertEquals('finished', inst.task_lookup(taskid)['status'], - "It is not necessary an error. You may need to increase the " - "timeout number in _wait_task()") + self.assertEquals('finished', + inst.task_lookup(taskid)['status'], + "It is not necessary an error. " + "You may need to increase the " + "timeout number in _wait_task()") report_list = inst.debugreports_get_list() self.assertTrue(reportName in report_list) except OperationFailed, e: @@ -570,7 +587,8 @@ class ModelTests(unittest.TestCase): time.sleep(1)
def test_get_distros(self): - inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('test:///default', + objstore_loc=self.tmp_store) distros = inst._get_distros() for distro in distros.values(): self.assertIn('name', distro) @@ -580,7 +598,8 @@ class ModelTests(unittest.TestCase):
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_get_hostinfo(self): - inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('qemu:///system', + objstore_loc=self.tmp_store) info = inst.host_lookup() distro, version, codename = platform.linux_distribution() self.assertIn('cpu', info) @@ -617,15 +636,17 @@ class ModelTests(unittest.TestCase):
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_deep_scan(self): - inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) + inst = kimchi.model.Model('qemu:///system', + objstore_loc=self.tmp_store) with RollbackContext() as rollback: path = '/tmp/kimchi-images/tmpdir' if not os.path.exists(path): os.makedirs(path) - iso_gen.construct_fake_iso('/tmp/kimchi-images/tmpdir/ubuntu12.04.iso', - True, '12.04', 'ubuntu') + iso_gen.construct_fake_iso('/tmp/kimchi-images/tmpdir/' + 'ubuntu12.04.iso', True, + '12.04', 'ubuntu') iso_gen.construct_fake_iso('/tmp/kimchi-images/sles10.iso', - True, '10', 'sles') + True, '10', 'sles')
args = {'name': 'kimchi-scanning-pool', 'path': '/tmp/kimchi-images', diff --git a/tests/test_rest.py b/tests/test_rest.py index 1b7312f..e626d2f 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -18,7 +18,7 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import base64 import json @@ -32,7 +32,6 @@ from functools import partial
import kimchi.mockmodel import kimchi.server -from kimchi.asynctask import AsyncTask from kimchi.rollbackcontext import RollbackContext from utils import fake_user, get_free_port, https_request, patch_auth, request from utils import run_server @@ -134,12 +133,12 @@ class RestTests(unittest.TestCase): resp = self.request("/", headers={'Accept': 'text/html'}) self.assertTrue('<!doctype html>' in resp.read().lower())
- resp = self.request("/", - headers={'Accept': 'application/json, text/html'}) + resp = self.request("/", headers={'Accept': + 'application/json, text/html'}) self.assertValidJSON(resp.read())
- resp = self.request("/", - headers={'Accept': 'text/html, application/json'}) + resp = self.request("/", headers={'Accept': + 'text/html, application/json'}) self.assertValidJSON(resp.read())
h = {'Accept': 'text/plain'} @@ -212,7 +211,7 @@ class RestTests(unittest.TestCase): # Create a Template req = json.dumps({'name': 'test', 'disks': [{'size': 1}], 'icon': 'images/icon-debian.png', - 'cdrom': '/nonexistent.iso'}) + 'cdrom': '/nonexistent.iso'}) resp = self.request('/templates', req, 'POST') self.assertEquals(201, resp.status)
@@ -303,7 +302,7 @@ class RestTests(unittest.TestCase):
def test_template_customise_storage(self): req = json.dumps({'name': 'test', 'cdrom': '/nonexistent.iso', - 'disks': [{'size': 1}]}) + 'disks': [{'size': 1}]}) resp = self.request('/templates', req, 'POST') self.assertEquals(201, resp.status)
@@ -437,7 +436,8 @@ class RestTests(unittest.TestCase): self.assertEquals(201, resp.status)
# Verify the storage pool - storagepool = json.loads(self.request('/storagepools/test-pool').read()) + storagepool = json.loads( + self.request('/storagepools/test-pool').read()) self.assertEquals('inactive', storagepool['state']) if storagepool['type'] == 'dir': self.assertEquals(True, storagepool['autostart']) @@ -446,12 +446,14 @@ class RestTests(unittest.TestCase):
# activate the storage pool resp = self.request('/storagepools/test-pool/activate', '{}', 'POST') - storagepool = json.loads(self.request('/storagepools/test-pool').read()) + storagepool = json.loads( + self.request('/storagepools/test-pool').read()) self.assertEquals('active', storagepool['state'])
# Deactivate the storage pool resp = self.request('/storagepools/test-pool/deactivate', '{}', 'POST') - storagepool = json.loads(self.request('/storagepools/test-pool').read()) + storagepool = json.loads( + self.request('/storagepools/test-pool').read()) self.assertEquals('inactive', storagepool['state'])
# Set autostart flag of the storage pool @@ -460,7 +462,7 @@ class RestTests(unittest.TestCase): req = json.dumps(t) resp = self.request('/storagepools/test-pool', req, 'PUT') storagepool = json.loads( - self.request('/storagepools/test-pool').read()) + self.request('/storagepools/test-pool').read()) self.assertEquals(autostart, storagepool['autostart'])
# Delete the storage pool @@ -477,7 +479,8 @@ class RestTests(unittest.TestCase):
resp = self.request('/storagepools/pool-1/activate', '{}', 'POST') self.assertEquals(200, resp.status) - nr_vols = json.loads(self.request('/storagepools/pool-1').read())['nr_volumes'] + nr_vols = json.loads( + self.request('/storagepools/pool-1').read())['nr_volumes'] self.assertEquals(0, nr_vols)
# Now add a couple of storage volumes to the mock model @@ -489,10 +492,11 @@ class RestTests(unittest.TestCase): 'type': 'disk', 'format': 'raw'}) resp = self.request('/storagepools/pool-1/storagevolumes', - req, 'POST') + req, 'POST') self.assertEquals(201, resp.status)
- nr_vols = json.loads(self.request('/storagepools/pool-1').read())['nr_volumes'] + nr_vols = json.loads( + self.request('/storagepools/pool-1').read())['nr_volumes'] self.assertEquals(5, nr_vols) resp = self.request('/storagepools/pool-1/storagevolumes') storagevolumes = json.loads(resp.read()) @@ -502,7 +506,8 @@ class RestTests(unittest.TestCase): storagevolume = json.loads(resp.read()) self.assertEquals('volume-1', storagevolume['name']) self.assertEquals('raw', storagevolume['format']) - self.assertEquals('/var/lib/libvirt/images/volume-1', storagevolume['path']) + self.assertEquals('/var/lib/libvirt/images/volume-1', + storagevolume['path'])
# Now remove the StoragePool from mock model self._delete_pool('pool-1') @@ -516,11 +521,13 @@ class RestTests(unittest.TestCase): 'allocation': 512, 'type': 'disk', 'format': 'raw'}) - resp = self.request('/storagepools/pool-2/storagevolumes/', req, 'POST') + resp = self.request('/storagepools/pool-2/storagevolumes/', + req, 'POST') self.assertEquals(400, resp.status) resp = self.request('/storagepools/pool-2/activate', '{}', 'POST') self.assertEquals(200, resp.status) - resp = self.request('/storagepools/pool-2/storagevolumes/', req, 'POST') + resp = self.request('/storagepools/pool-2/storagevolumes/', + req, 'POST') self.assertEquals(201, resp.status)
# Verify the storage volume @@ -545,7 +552,7 @@ class RestTests(unittest.TestCase):
# Delete the storage volume resp = self.request('/storagepools/pool-2/storagevolumes/test-volume', - '{}', 'DELETE') + '{}', 'DELETE') self.assertEquals(204, resp.status)
# Now remove the StoragePool from mock model @@ -561,7 +568,8 @@ class RestTests(unittest.TestCase): self.assertEquals(201, resp.status)
# Verify the storage pool - storagepool = json.loads(self.request('/storagepools/%s' % name).read()) + storagepool = json.loads(self.request('/storagepools/%s' + % name).read()) self.assertEquals('inactive', storagepool['state']) return name
@@ -572,8 +580,8 @@ class RestTests(unittest.TestCase):
def test_templates(self): def verify_template(t, res): - for field in ('name', 'os_distro', - 'os_version', 'memory', 'cpus', 'storagepool'): + for field in ('name', 'os_distro', 'os_version', + 'memory', 'cpus', 'storagepool'): self.assertEquals(t[field], res[field])
resp = self.request('/templates') @@ -700,15 +708,17 @@ class RestTests(unittest.TestCase): '/storagepools/kimchi_isos/storagevolumes/').read())[0] self.assertEquals('pool-3-fedora.iso', storagevolume['name']) self.assertEquals('iso', storagevolume['format']) - self.assertEquals('/var/lib/libvirt/images/fedora.iso',storagevolume['path']) + self.assertEquals('/var/lib/libvirt/images/fedora.iso', + storagevolume['path']) self.assertEquals(1024 << 20, storagevolume['capacity']) self.assertEquals(1024 << 20, storagevolume['allocation']) self.assertEquals('17', storagevolume['os_version']) - self.assertEquals('fedora',storagevolume['os_distro']) - self.assertEquals(True,storagevolume['bootable']) + self.assertEquals('fedora', storagevolume['os_distro']) + self.assertEquals(True, storagevolume['bootable'])
# Create a template - # In real model os distro/version can be omitted as we will scan the iso + # In real model os distro/version can be omitted + # as we will scan the iso req = json.dumps({'name': 'test', 'cdrom': storagevolume['path'], 'os_distro': storagevolume['os_distro'], @@ -724,8 +734,8 @@ class RestTests(unittest.TestCase): self.assertEquals(1024, t['memory'])
# Deactivate or destroy scan pool return 405 - resp = self.request('/storagepools/kimchi_isos/storagevolumes/deactivate', - '{}', 'POST') + resp = self.request('/storagepools/kimchi_isos/storagevolumes' + '/deactivate', '{}', 'POST') self.assertEquals(405, resp.status)
resp = self.request('/storagepools/kimchi_isos/storagevolumes', @@ -762,13 +772,11 @@ class RestTests(unittest.TestCase): self.assertEquals('image/png', resp.getheader('content-type')) lastMod1 = resp.getheader('last-modified')
- # Take another screenshot instantly and compare the last Modified date resp = self.request('/vms/test-vm/screenshot') lastMod2 = resp.getheader('last-modified') self.assertEquals(lastMod2, lastMod1)
- resp = self.request('/vms/test-vm/screenshot', '{}', 'DELETE') self.assertEquals(405, resp.status)
@@ -998,7 +1006,7 @@ class RestTests(unittest.TestCase): self.assertEquals(200, resp.status)
def _report_delete(self, name): - resp = request(host, port, '/debugreports/%s' % name, '{}', 'DELETE') + request(host, port, '/debugreports/%s' % name, '{}', 'DELETE')
def test_create_debugreport(self): req = json.dumps({'name': 'report1'}) diff --git a/tests/utils.py b/tests/utils.py index 960e0be..008f668 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -18,7 +18,7 @@ # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #
import base64 @@ -28,7 +28,6 @@ import os import socket import sys import threading -import time import unittest
@@ -60,7 +59,8 @@ if sys.version_info[:2] == (2, 6):
def assertGreaterEqual(self, a, b, msg=None): if not a >= b: - self.fail('%s not greater than or equal to %s' % (repr(a), repr(b))) + self.fail('%s not greater than or equal to %s' + % (repr(a), repr(b)))
def assertIsInstance(self, obj, cls, msg=None): if not isinstance(obj, cls): @@ -80,6 +80,7 @@ if sys.version_info[:2] == (2, 6): unittest.TestCase.assertIn = assertIn unittest.TestCase.assertNotIn = assertNotIn
+ def get_free_port(name='http'): global _ports if _ports.get(name) is not None: @@ -93,7 +94,9 @@ def get_free_port(name='http'): _ports[name] = sock.getsockname()[1] return _ports[name]
-def run_server(host, port, ssl_port, test_mode, model=None, environment='development'): + +def run_server(host, port, ssl_port, test_mode, + model=None, environment='development'): args = type('_', (object,), {'host': host, 'port': port, 'ssl_port': ssl_port, 'ssl_cert': '', 'ssl_key': '', @@ -109,12 +112,14 @@ def run_server(host, port, ssl_port, test_mode, model=None, environment='develop cherrypy.engine.wait(cherrypy.engine.states.STARTED) return s
+ def silence_server(): """ Silence server status messages on stdout """ cherrypy.config.update({"environment": "embedded"})
+ def running_as_root(): return os.geteuid() == 0
@@ -130,6 +135,7 @@ def _request(conn, path, data, method, headers): conn.request(method, path, data, headers) return conn.getresponse()
+ def request(host, port, path, data=None, method='GET', headers=None): conn = httplib.HTTPConnection(host, port) return _request(conn, path, data, method, headers)

Reviewed-by: Aline Manera <alinefm@linux.vnet.ibm.com> On 12/27/2013 08:40 AM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
Then kimchi source code can make use of it Also add src/kimchi/rollbackcontext.py in dist list
Signed-off-by: Zhou Zheng Sheng <zhshzhou@linux.vnet.ibm.com> Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/Makefile.am | 59 +++++++++++++++++------------------ src/kimchi/rollbackcontext.py | 71 +++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 25 +++++++-------- tests/test_rest.py | 3 +- tests/utils.py | 45 --------------------------- 5 files changed, 116 insertions(+), 87 deletions(-) create mode 100644 src/kimchi/rollbackcontext.py
diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 47a3bd2..2f05ab7 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -21,35 +21,36 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
kimchi_PYTHON = \ - asynctask.py \ - auth.py \ - controller.py \ - disks.py \ - distroloader.py \ - exception.py \ - __init__.py \ - isoinfo.py \ - netinfo.py \ - network.py \ - networkxml.py \ - mockmodel.py \ - model.py \ - objectstore.py \ - osinfo.py \ - root.py \ - scan.py \ - screenshot.py \ - server.py \ - sslcert.py \ - template.py \ - vmtemplate.py \ - vnc.py \ - websocket.py \ - websockify.py \ - xmlutils.py \ - utils.py \ - cachebust.py \ - featuretests.py + __init__.py \ + asynctask.py \ + auth.py \ + cachebust.py \ + controller.py \ + disks.py \ + distroloader.py \ + exception.py \ + featuretests.py \ + isoinfo.py \ + mockmodel.py \ + model.py \ + netinfo.py \ + network.py \ + networkxml.py \ + objectstore.py \ + osinfo.py \ + rollbackcontext.py \ + root.py \ + scan.py \ + screenshot.py \ + server.py \ + sslcert.py \ + template.py \ + utils.py \ + vmtemplate.py \ + vnc.py \ + websocket.py \ + websockify.py \ + xmlutils.py
nodist_kimchi_PYTHON = config.py
diff --git a/src/kimchi/rollbackcontext.py b/src/kimchi/rollbackcontext.py new file mode 100644 index 0000000..2afd114 --- /dev/null +++ b/src/kimchi/rollbackcontext.py @@ -0,0 +1,71 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@linux.vnet.ibm.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import sys + + +class RollbackContext(object): + ''' + A context manager for recording and playing rollback. + The first exception will be remembered and re-raised after rollback + + Sample usage: + with RollbackContext() as rollback: + step1() + rollback.prependDefer(lambda: undo step1) + def undoStep2(arg): pass + step2() + rollback.prependDefer(undoStep2, arg) + ''' + def __init__(self, *args): + self._finally = [] + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + firstException = exc_value + + for undo, args, kwargs in self._finally: + try: + undo(*args, **kwargs) + except Exception as e: + # keep the earliest exception info + if not firstException: + firstException = e + # keep the original traceback info + traceback = sys.exc_info()[2] + + # re-raise the earliest exception + if firstException is not None: + if type(firstException) is str: + sys.stderr.write(firstException) + else: + raise firstException, None, traceback + + def defer(self, func, *args, **kwargs): + self._finally.append((func, args, kwargs)) + + def prependDefer(self, func, *args, **kwargs): + self._finally.insert(0, (func, args, kwargs)) diff --git a/tests/test_model.py b/tests/test_model.py index e19364f..7ecd8c6 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -38,6 +38,7 @@ import utils from kimchi import netinfo from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.exception import NotFoundError, OperationFailed +from kimchi.rollbackcontext import RollbackContext
class ModelTests(unittest.TestCase): @@ -72,7 +73,7 @@ class ModelTests(unittest.TestCase): def test_vm_lifecycle(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': []} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -97,7 +98,7 @@ class ModelTests(unittest.TestCase): def test_vm_storage_provisioning(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': [{'size': 1}]} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -115,7 +116,7 @@ class ModelTests(unittest.TestCase): def test_storagepool(self): inst = kimchi.model.Model('qemu:///system', self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images' name = 'test-pool' if not os.path.exists(path): @@ -168,7 +169,7 @@ class ModelTests(unittest.TestCase): def test_storagevolume(self): inst = kimchi.model.Model('qemu:///system', self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images' pool = 'test-pool' vol = 'test-volume.img' @@ -223,7 +224,7 @@ class ModelTests(unittest.TestCase): def test_template_storage_customise(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images' pool = 'test-pool' if not os.path.exists(path): @@ -295,7 +296,7 @@ class ModelTests(unittest.TestCase): orig_params = {'name': 'test', 'memory': '1024', 'cpus': '1'} inst.templates_create(orig_params)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params_1 = {'name': 'kimchi-vm1', 'template': '/templates/test'} params_2 = {'name': 'kimchi-vm2', 'template': '/templates/test'} inst.vms_create(params_1) @@ -326,7 +327,7 @@ class ModelTests(unittest.TestCase): def test_network(self): inst = kimchi.model.Model('qemu:///system', self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: name = 'test-network'
networks = inst.networks_get_list() @@ -480,7 +481,7 @@ class ModelTests(unittest.TestCase): def test_delete_running_vm(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': u'test', 'disks': []} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -501,7 +502,7 @@ class ModelTests(unittest.TestCase): def test_vm_list_sorted(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': []} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -517,7 +518,7 @@ class ModelTests(unittest.TestCase): def test_use_test_host(self): inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': [], 'storagepool': '/storagepools/default-pool', 'domain': 'test', @@ -546,7 +547,7 @@ class ModelTests(unittest.TestCase): inst.debugreport_delete(namePrefix + '*') except NotFoundError: pass - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: report_list = inst.debugreports_get_list() self.assertFalse(reportName in report_list) try: @@ -617,7 +618,7 @@ class ModelTests(unittest.TestCase): @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_deep_scan(self): inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images/tmpdir' if not os.path.exists(path): os.makedirs(path) diff --git a/tests/test_rest.py b/tests/test_rest.py index 73946c0..1b7312f 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -33,8 +33,9 @@ from functools import partial import kimchi.mockmodel import kimchi.server from kimchi.asynctask import AsyncTask +from kimchi.rollbackcontext import RollbackContext from utils import fake_user, get_free_port, https_request, patch_auth, request -from utils import RollbackContext, run_server +from utils import run_server
test_server = None diff --git a/tests/utils.py b/tests/utils.py index a7596e8..960e0be 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -140,51 +140,6 @@ def https_request(host, port, path, data=None, method='GET', headers=None): return _request(conn, path, data, method, headers)
-class RollbackContext(object): - ''' - A context manager for recording and playing rollback. - The first exception will be remembered and re-raised after rollback - - Sample usage: - with RollbackContext() as rollback: - step1() - rollback.prependDefer(lambda: undo step1) - def undoStep2(arg): pass - step2() - rollback.prependDefer(undoStep2, arg) - ''' - def __init__(self, *args): - self._finally = [] - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - firstException = exc_value - - for undo, args, kwargs in self._finally: - try: - undo(*args, **kwargs) - except Exception as e: - # keep the earliest exception info - if not firstException: - firstException = e - # keep the original traceback info - traceback = sys.exc_info()[2] - - # re-raise the earliest exception - if firstException is not None: - if type(firstException) is str: - sys.stderr.write(firstException) - else: - raise firstException, None, traceback - - def defer(self, func, *args, **kwargs): - self._finally.append((func, args, kwargs)) - - def prependDefer(self, func, *args, **kwargs): - self._finally.insert(0, (func, args, kwargs)) - def patch_auth(): """ Override the authenticate function with a simple test against an

Needs rebase On 12/27/2013 08:40 AM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
Then kimchi source code can make use of it Also add src/kimchi/rollbackcontext.py in dist list
Signed-off-by: Zhou Zheng Sheng <zhshzhou@linux.vnet.ibm.com> Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/Makefile.am | 59 +++++++++++++++++------------------ src/kimchi/rollbackcontext.py | 71 +++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 25 +++++++-------- tests/test_rest.py | 3 +- tests/utils.py | 45 --------------------------- 5 files changed, 116 insertions(+), 87 deletions(-) create mode 100644 src/kimchi/rollbackcontext.py
diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 47a3bd2..2f05ab7 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -21,35 +21,36 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
kimchi_PYTHON = \ - asynctask.py \ - auth.py \ - controller.py \ - disks.py \ - distroloader.py \ - exception.py \ - __init__.py \ - isoinfo.py \ - netinfo.py \ - network.py \ - networkxml.py \ - mockmodel.py \ - model.py \ - objectstore.py \ - osinfo.py \ - root.py \ - scan.py \ - screenshot.py \ - server.py \ - sslcert.py \ - template.py \ - vmtemplate.py \ - vnc.py \ - websocket.py \ - websockify.py \ - xmlutils.py \ - utils.py \ - cachebust.py \ - featuretests.py + __init__.py \ + asynctask.py \ + auth.py \ + cachebust.py \ + controller.py \ + disks.py \ + distroloader.py \ + exception.py \ + featuretests.py \ + isoinfo.py \ + mockmodel.py \ + model.py \ + netinfo.py \ + network.py \ + networkxml.py \ + objectstore.py \ + osinfo.py \ + rollbackcontext.py \ + root.py \ + scan.py \ + screenshot.py \ + server.py \ + sslcert.py \ + template.py \ + utils.py \ + vmtemplate.py \ + vnc.py \ + websocket.py \ + websockify.py \ + xmlutils.py
nodist_kimchi_PYTHON = config.py
diff --git a/src/kimchi/rollbackcontext.py b/src/kimchi/rollbackcontext.py new file mode 100644 index 0000000..2afd114 --- /dev/null +++ b/src/kimchi/rollbackcontext.py @@ -0,0 +1,71 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@linux.vnet.ibm.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import sys + + +class RollbackContext(object): + ''' + A context manager for recording and playing rollback. + The first exception will be remembered and re-raised after rollback + + Sample usage: + with RollbackContext() as rollback: + step1() + rollback.prependDefer(lambda: undo step1) + def undoStep2(arg): pass + step2() + rollback.prependDefer(undoStep2, arg) + ''' + def __init__(self, *args): + self._finally = [] + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + firstException = exc_value + + for undo, args, kwargs in self._finally: + try: + undo(*args, **kwargs) + except Exception as e: + # keep the earliest exception info + if not firstException: + firstException = e + # keep the original traceback info + traceback = sys.exc_info()[2] + + # re-raise the earliest exception + if firstException is not None: + if type(firstException) is str: + sys.stderr.write(firstException) + else: + raise firstException, None, traceback + + def defer(self, func, *args, **kwargs): + self._finally.append((func, args, kwargs)) + + def prependDefer(self, func, *args, **kwargs): + self._finally.insert(0, (func, args, kwargs)) diff --git a/tests/test_model.py b/tests/test_model.py index e19364f..7ecd8c6 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -38,6 +38,7 @@ import utils from kimchi import netinfo from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.exception import NotFoundError, OperationFailed +from kimchi.rollbackcontext import RollbackContext
class ModelTests(unittest.TestCase): @@ -72,7 +73,7 @@ class ModelTests(unittest.TestCase): def test_vm_lifecycle(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': []} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -97,7 +98,7 @@ class ModelTests(unittest.TestCase): def test_vm_storage_provisioning(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': [{'size': 1}]} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -115,7 +116,7 @@ class ModelTests(unittest.TestCase): def test_storagepool(self): inst = kimchi.model.Model('qemu:///system', self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images' name = 'test-pool' if not os.path.exists(path): @@ -168,7 +169,7 @@ class ModelTests(unittest.TestCase): def test_storagevolume(self): inst = kimchi.model.Model('qemu:///system', self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images' pool = 'test-pool' vol = 'test-volume.img' @@ -223,7 +224,7 @@ class ModelTests(unittest.TestCase): def test_template_storage_customise(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images' pool = 'test-pool' if not os.path.exists(path): @@ -295,7 +296,7 @@ class ModelTests(unittest.TestCase): orig_params = {'name': 'test', 'memory': '1024', 'cpus': '1'} inst.templates_create(orig_params)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params_1 = {'name': 'kimchi-vm1', 'template': '/templates/test'} params_2 = {'name': 'kimchi-vm2', 'template': '/templates/test'} inst.vms_create(params_1) @@ -326,7 +327,7 @@ class ModelTests(unittest.TestCase): def test_network(self): inst = kimchi.model.Model('qemu:///system', self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: name = 'test-network'
networks = inst.networks_get_list() @@ -480,7 +481,7 @@ class ModelTests(unittest.TestCase): def test_delete_running_vm(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': u'test', 'disks': []} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -501,7 +502,7 @@ class ModelTests(unittest.TestCase): def test_vm_list_sorted(self): inst = kimchi.model.Model(objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': []} inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') @@ -517,7 +518,7 @@ class ModelTests(unittest.TestCase): def test_use_test_host(self): inst = kimchi.model.Model('test:///default', objstore_loc=self.tmp_store)
- with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: params = {'name': 'test', 'disks': [], 'storagepool': '/storagepools/default-pool', 'domain': 'test', @@ -546,7 +547,7 @@ class ModelTests(unittest.TestCase): inst.debugreport_delete(namePrefix + '*') except NotFoundError: pass - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: report_list = inst.debugreports_get_list() self.assertFalse(reportName in report_list) try: @@ -617,7 +618,7 @@ class ModelTests(unittest.TestCase): @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_deep_scan(self): inst = kimchi.model.Model('qemu:///system', objstore_loc=self.tmp_store) - with utils.RollbackContext() as rollback: + with RollbackContext() as rollback: path = '/tmp/kimchi-images/tmpdir' if not os.path.exists(path): os.makedirs(path) diff --git a/tests/test_rest.py b/tests/test_rest.py index 73946c0..1b7312f 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -33,8 +33,9 @@ from functools import partial import kimchi.mockmodel import kimchi.server from kimchi.asynctask import AsyncTask +from kimchi.rollbackcontext import RollbackContext from utils import fake_user, get_free_port, https_request, patch_auth, request -from utils import RollbackContext, run_server +from utils import run_server
test_server = None diff --git a/tests/utils.py b/tests/utils.py index a7596e8..960e0be 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -140,51 +140,6 @@ def https_request(host, port, path, data=None, method='GET', headers=None): return _request(conn, path, data, method, headers)
-class RollbackContext(object): - ''' - A context manager for recording and playing rollback. - The first exception will be remembered and re-raised after rollback - - Sample usage: - with RollbackContext() as rollback: - step1() - rollback.prependDefer(lambda: undo step1) - def undoStep2(arg): pass - step2() - rollback.prependDefer(undoStep2, arg) - ''' - def __init__(self, *args): - self._finally = [] - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - firstException = exc_value - - for undo, args, kwargs in self._finally: - try: - undo(*args, **kwargs) - except Exception as e: - # keep the earliest exception info - if not firstException: - firstException = e - # keep the original traceback info - traceback = sys.exc_info()[2] - - # re-raise the earliest exception - if firstException is not None: - if type(firstException) is str: - sys.stderr.write(firstException) - else: - raise firstException, None, traceback - - def defer(self, func, *args, **kwargs): - self._finally.append((func, args, kwargs)) - - def prependDefer(self, func, *args, **kwargs): - self._finally.insert(0, (func, args, kwargs)) - def patch_auth(): """ Override the authenticate function with a simple test against an
participants (2)
-
Aline Manera
-
shaohef@linux.vnet.ibm.com