From b702787a4d2f6bb3f5ba1d4abf92ed1b80c5ce91 Mon Sep 17 00:00:00 2001 From: Diana Clarke Date: Sun, 7 Feb 2016 03:40:36 -0500 Subject: [PATCH] Top 100 slow tests: api.openstack.compute.test_versions The version tests are slow. They account for 14 of the top 100 slow unit tests: http://paste.openstack.org/show/485806/ These tests create a bunch fake WSGI apps, each costing as much as 0.5 seconds. This patch reduces the cost of creating those fakes by using the init_only option, and stubbing out extension loading. It also reduces the number of fakes created (see ncalls). $ tox -e py27 nova.tests.unit.api.openstack.compute.test_versions Before: total runtime: 27.5037 sec ncalls tottime percall cumtime percall filename:lineno(function) 18 0.001 0.000 7.251 0.403 fakes.py:67(wsgi_app) ncalls tottime percall cumtime percall filename:lineno(function) 14 0.001 0.000 7.399 0.529 fakes.py:90(wsgi_app_v21) After: total runtime: 1.3134 sec ncalls tottime percall cumtime percall filename:lineno(function) 10 0.000 0.000 0.154 0.015 fakes.py:67(wsgi_app) ncalls tottime percall cumtime percall filename:lineno(function) 14 0.001 0.000 0.192 0.014 fakes.py:89(wsgi_app_v21) Change-Id: I2f659dd70af041ad32770e7b52a95af2b0f6ce74 --- .../api/openstack/compute/test_versions.py | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/nova/tests/unit/api/openstack/compute/test_versions.py b/nova/tests/unit/api/openstack/compute/test_versions.py index f94e4e003f..97fab478ff 100644 --- a/nova/tests/unit/api/openstack/compute/test_versions.py +++ b/nova/tests/unit/api/openstack/compute/test_versions.py @@ -16,10 +16,12 @@ import copy import uuid as stdlib_uuid +import mock from oslo_serialization import jsonutils import webob from nova.api.openstack.compute import views +from nova.api.openstack import extensions from nova import test from nova.tests.unit.api.openstack import fakes from nova.tests.unit import matchers @@ -101,9 +103,11 @@ def _get_self_href(response): class VersionsTestV20(test.NoDBTestCase): - def setUp(self): - super(VersionsTestV20, self).setUp() - self.wsgi_app = fakes.wsgi_app() + @property + def wsgi_app(self): + with mock.patch.object(extensions.ExtensionManager, 'load_extension'): + # patch load_extension because it's expensive in fakes.wsgi_app + return fakes.wsgi_app(init_only=('servers', 'images', 'versions')) def test_get_version_list(self): req = webob.Request.blank('/') @@ -444,10 +448,14 @@ class VersionsTestV21(test.NoDBTestCase): {'href': 'http://localhost/v2.1/', 'rel': 'self'}, ) + @property + def wsgi_app(self): + return fakes.wsgi_app_v21(init_only=('versions',)) + def test_get_version_list_302(self): req = webob.Request.blank('/v2.1') req.accept = "application/json" - res = req.get_response(fakes.wsgi_app_v21()) + res = req.get_response(self.wsgi_app) self.assertEqual(302, res.status_int) redirect_req = webob.Request.blank('/v2.1/') self.assertEqual(redirect_req.url, res.location) @@ -455,7 +463,7 @@ class VersionsTestV21(test.NoDBTestCase): def test_get_version_21_detail(self): req = webob.Request.blank('/v2.1/') req.accept = "application/json" - res = req.get_response(fakes.wsgi_app_v21()) + res = req.get_response(self.wsgi_app) self.assertEqual(200, res.status_int) self.assertEqual("application/json", res.content_type) version = jsonutils.loads(res.body) @@ -465,7 +473,7 @@ class VersionsTestV21(test.NoDBTestCase): def test_get_version_21_versions_v21_detail(self): req = webob.Request.blank('/v2.1/fake/versions/v2.1') req.accept = "application/json" - res = req.get_response(fakes.wsgi_app_v21()) + res = req.get_response(self.wsgi_app) self.assertEqual(200, res.status_int) self.assertEqual("application/json", res.content_type) version = jsonutils.loads(res.body) @@ -475,7 +483,7 @@ class VersionsTestV21(test.NoDBTestCase): def test_get_version_21_versions_v20_detail(self): req = webob.Request.blank('/v2.1/fake/versions/v2.0') req.accept = "application/json" - res = req.get_response(fakes.wsgi_app_v21()) + res = req.get_response(self.wsgi_app) self.assertEqual(200, res.status_int) self.assertEqual("application/json", res.content_type) version = jsonutils.loads(res.body) @@ -485,13 +493,13 @@ class VersionsTestV21(test.NoDBTestCase): def test_get_version_21_versions_invalid(self): req = webob.Request.blank('/v2.1/versions/1234/foo') req.accept = "application/json" - res = req.get_response(fakes.wsgi_app_v21()) + res = req.get_response(self.wsgi_app) self.assertEqual(404, res.status_int) def test_get_version_21_detail_content_type(self): req = webob.Request.blank('/') req.accept = "application/json;version=2.1" - res = req.get_response(fakes.wsgi_app_v21()) + res = req.get_response(self.wsgi_app) self.assertEqual(200, res.status_int) self.assertEqual("application/json", res.content_type) version = jsonutils.loads(res.body) @@ -504,10 +512,16 @@ class VersionBehindSslTestCase(test.NoDBTestCase): super(VersionBehindSslTestCase, self).setUp() self.flags(secure_proxy_ssl_header='HTTP_X_FORWARDED_PROTO') + @property + def wsgi_app(self): + with mock.patch.object(extensions.ExtensionManager, 'load_extension'): + # patch load_extension because it's expensive in fakes.wsgi_app + return fakes.wsgi_app(init_only=('versions',)) + def test_versions_without_headers(self): req = wsgi.Request.blank('/') req.accept = "application/json" - res = req.get_response(fakes.wsgi_app()) + res = req.get_response(self.wsgi_app) self.assertEqual(200, res.status_int) href = _get_self_href(res) self.assertTrue(href.startswith('http://')) @@ -516,7 +530,7 @@ class VersionBehindSslTestCase(test.NoDBTestCase): req = wsgi.Request.blank('/') req.accept = "application/json" req.headers['X-Forwarded-Proto'] = 'https' - res = req.get_response(fakes.wsgi_app()) + res = req.get_response(self.wsgi_app) self.assertEqual(200, res.status_int) href = _get_self_href(res) self.assertTrue(href.startswith('https://')) @@ -524,6 +538,6 @@ class VersionBehindSslTestCase(test.NoDBTestCase): class VersionsTestV21WithV2CompatibleWrapper(VersionsTestV20): - def setUp(self): - super(VersionsTestV21WithV2CompatibleWrapper, self).setUp() - self.wsgi_app = fakes.wsgi_app_v21(v2_compatible=True) + @property + def wsgi_app(self): + return fakes.wsgi_app_v21(v2_compatible=True, init_only=('versions',))