From 8b58c7296ae394772dab82fbb76469722798cc29 Mon Sep 17 00:00:00 2001 From: Cerberus Date: Wed, 25 Aug 2010 16:37:22 -0500 Subject: Moved API tests into a sub-folder of the tests/ and added a stubbed-out test declarations to mirror existing API tickets --- nova/api/test.py | 61 ------------------- nova/tests/api/__init__.py | 0 nova/tests/api/rackspace/__init__.py | 0 nova/tests/api/rackspace/flavors.py | 34 +++++++++++ nova/tests/api/rackspace/images.py | 42 +++++++++++++ nova/tests/api/rackspace/servers.py | 55 +++++++++++++++++ nova/tests/api/rackspace/sharedipgroups.py | 40 +++++++++++++ nova/tests/api/test.py | 59 ++++++++++++++++++ nova/tests/api/test_helper.py | 7 +++ nova/tests/api/wsgi_test.py | 96 ++++++++++++++++++++++++++++++ nova/wsgi_test.py | 96 ------------------------------ 11 files changed, 333 insertions(+), 157 deletions(-) delete mode 100644 nova/api/test.py create mode 100644 nova/tests/api/__init__.py create mode 100644 nova/tests/api/rackspace/__init__.py create mode 100644 nova/tests/api/rackspace/flavors.py create mode 100644 nova/tests/api/rackspace/images.py create mode 100644 nova/tests/api/rackspace/servers.py create mode 100644 nova/tests/api/rackspace/sharedipgroups.py create mode 100644 nova/tests/api/test.py create mode 100644 nova/tests/api/test_helper.py create mode 100644 nova/tests/api/wsgi_test.py delete mode 100644 nova/wsgi_test.py diff --git a/nova/api/test.py b/nova/api/test.py deleted file mode 100644 index 51b114b8e..000000000 --- a/nova/api/test.py +++ /dev/null @@ -1,61 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 OpenStack LLC. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Test for the root WSGI middleware for all API controllers. -""" - -import unittest - -import stubout -import webob -import webob.dec - -from nova import api - - -class Test(unittest.TestCase): - - def setUp(self): # pylint: disable-msg=C0103 - self.stubs = stubout.StubOutForTesting() - - def tearDown(self): # pylint: disable-msg=C0103 - self.stubs.UnsetAll() - - def test_rackspace(self): - self.stubs.Set(api.rackspace, 'API', APIStub) - result = webob.Request.blank('/v1.0/cloud').get_response(api.API()) - self.assertEqual(result.body, "/cloud") - - def test_ec2(self): - self.stubs.Set(api.ec2, 'API', APIStub) - result = webob.Request.blank('/ec2/cloud').get_response(api.API()) - self.assertEqual(result.body, "/cloud") - - def test_not_found(self): - self.stubs.Set(api.ec2, 'API', APIStub) - self.stubs.Set(api.rackspace, 'API', APIStub) - result = webob.Request.blank('/test/cloud').get_response(api.API()) - self.assertNotEqual(result.body, "/cloud") - - -class APIStub(object): - """Class to verify request and mark it was called.""" - - @webob.dec.wsgify - def __call__(self, req): - return req.path_info diff --git a/nova/tests/api/__init__.py b/nova/tests/api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nova/tests/api/rackspace/__init__.py b/nova/tests/api/rackspace/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/nova/tests/api/rackspace/flavors.py b/nova/tests/api/rackspace/flavors.py new file mode 100644 index 000000000..fb8ba94a5 --- /dev/null +++ b/nova/tests/api/rackspace/flavors.py @@ -0,0 +1,34 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +from nova.api.rackspace import flavors +from nova.tests.api.test_helper import * + +class FlavorsTest(unittest.TestCase): + def setUp(self): + self.stubs = stubout.StubOutForTesting() + + def tearDown(self): + self.stubs.UnsetAll() + + def test_get_flavor_list(self): + pass + + def test_get_flavor_by_id(self): + pass diff --git a/nova/tests/api/rackspace/images.py b/nova/tests/api/rackspace/images.py new file mode 100644 index 000000000..0e3a87051 --- /dev/null +++ b/nova/tests/api/rackspace/images.py @@ -0,0 +1,42 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +from nova.api.rackspace import images +from nova.tests.api.test_helper import * + +class ImagesTest(unittest.TestCase): + def setUp(self): + self.stubs = stubout.StubOutForTesting() + + def tearDown(self): + self.stubs.UnsetAll() + + def test_get_image_list(self): + pass + + def test_get_backup_schedule(self): + pass + + def test_delete_image(self): + pass + + def test_create_image(self): + pass + + diff --git a/nova/tests/api/rackspace/servers.py b/nova/tests/api/rackspace/servers.py new file mode 100644 index 000000000..980e69b84 --- /dev/null +++ b/nova/tests/api/rackspace/servers.py @@ -0,0 +1,55 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +from nova.api.rackspace import servers +from nova.tests.api.test_helper import * + +class ServersTest(unittest.TestCase): + def setUp(self): + self.stubs = stubout.StubOutForTesting() + + def tearDown(self): + self.stubs.UnsetAll() + + def test_get_server_list(self): + pass + + def test_create_instance(self): + pass + + def test_get_server_by_id(self): + pass + + def test_get_server_details(self): + pass + + def test_get_server_ips(self): + pass + + def test_server_reboot(self): + pass + + def test_server_rebuild(self): + pass + + def test_server_resize(self): + pass + + def test_delete_server_instance(self): + pass diff --git a/nova/tests/api/rackspace/sharedipgroups.py b/nova/tests/api/rackspace/sharedipgroups.py new file mode 100644 index 000000000..b4b281db7 --- /dev/null +++ b/nova/tests/api/rackspace/sharedipgroups.py @@ -0,0 +1,40 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +from nova.api.rackspace import sharedipgroups +from nova.tests.api.test_helper import * + +class SharedIpGroupsTest(unittest.TestCase): + def setUp(self): + self.stubs = stubout.StubOutForTesting() + + def tearDown(self): + self.stubs.UnsetAll() + + def test_get_shared_ip_groups(self): + pass + + def test_create_shared_ip_group(self): + pass + + def test_delete_shared_ip_group(self): + pass + + + diff --git a/nova/tests/api/test.py b/nova/tests/api/test.py new file mode 100644 index 000000000..59c4adc3d --- /dev/null +++ b/nova/tests/api/test.py @@ -0,0 +1,59 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Test for the root WSGI middleware for all API controllers. +""" + +import unittest + +import stubout +import webob +import webob.dec + +from nova import api +from nova.tests.api.test_helper import * + +class Test(unittest.TestCase): + + def setUp(self): # pylint: disable-msg=C0103 + self.stubs = stubout.StubOutForTesting() + + def tearDown(self): # pylint: disable-msg=C0103 + self.stubs.UnsetAll() + + def test_rackspace(self): + self.stubs.Set(api.rackspace, 'API', APIStub) + result = webob.Request.blank('/v1.0/cloud').get_response(api.API()) + self.assertEqual(result.body, "/cloud") + + def test_ec2(self): + self.stubs.Set(api.ec2, 'API', APIStub) + result = webob.Request.blank('/ec2/cloud').get_response(api.API()) + self.assertEqual(result.body, "/cloud") + + def test_not_found(self): + self.stubs.Set(api.ec2, 'API', APIStub) + self.stubs.Set(api.rackspace, 'API', APIStub) + result = webob.Request.blank('/test/cloud').get_response(api.API()) + self.assertNotEqual(result.body, "/cloud") + + def test_query_api_version(self): + pass + +if __name__ == '__main__': + unittest.main() diff --git a/nova/tests/api/test_helper.py b/nova/tests/api/test_helper.py new file mode 100644 index 000000000..8151a4af6 --- /dev/null +++ b/nova/tests/api/test_helper.py @@ -0,0 +1,7 @@ +import webob.dec + +class APIStub(object): + """Class to verify request and mark it was called.""" + @webob.dec.wsgify + def __call__(self, req): + return req.path_info diff --git a/nova/tests/api/wsgi_test.py b/nova/tests/api/wsgi_test.py new file mode 100644 index 000000000..786dc1bce --- /dev/null +++ b/nova/tests/api/wsgi_test.py @@ -0,0 +1,96 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Test WSGI basics and provide some helper functions for other WSGI tests. +""" + +import unittest + +import routes +import webob + +from nova import wsgi + + +class Test(unittest.TestCase): + + def test_debug(self): + + class Application(wsgi.Application): + """Dummy application to test debug.""" + + def __call__(self, environ, start_response): + start_response("200", [("X-Test", "checking")]) + return ['Test result'] + + application = wsgi.Debug(Application()) + result = webob.Request.blank('/').get_response(application) + self.assertEqual(result.body, "Test result") + + def test_router(self): + + class Application(wsgi.Application): + """Test application to call from router.""" + + def __call__(self, environ, start_response): + start_response("200", []) + return ['Router result'] + + class Router(wsgi.Router): + """Test router.""" + + def __init__(self): + mapper = routes.Mapper() + mapper.connect("/test", controller=Application()) + super(Router, self).__init__(mapper) + + result = webob.Request.blank('/test').get_response(Router()) + self.assertEqual(result.body, "Router result") + result = webob.Request.blank('/bad').get_response(Router()) + self.assertNotEqual(result.body, "Router result") + + def test_controller(self): + + class Controller(wsgi.Controller): + """Test controller to call from router.""" + test = self + + def show(self, req, id): # pylint: disable-msg=W0622,C0103 + """Default action called for requests with an ID.""" + self.test.assertEqual(req.path_info, '/tests/123') + self.test.assertEqual(id, '123') + return id + + class Router(wsgi.Router): + """Test router.""" + + def __init__(self): + mapper = routes.Mapper() + mapper.resource("test", "tests", controller=Controller()) + super(Router, self).__init__(mapper) + + result = webob.Request.blank('/tests/123').get_response(Router()) + self.assertEqual(result.body, "123") + result = webob.Request.blank('/test/123').get_response(Router()) + self.assertNotEqual(result.body, "123") + + def test_serializer(self): + # TODO(eday): Placeholder for serializer testing. + pass diff --git a/nova/wsgi_test.py b/nova/wsgi_test.py deleted file mode 100644 index 786dc1bce..000000000 --- a/nova/wsgi_test.py +++ /dev/null @@ -1,96 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# Copyright 2010 OpenStack LLC. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Test WSGI basics and provide some helper functions for other WSGI tests. -""" - -import unittest - -import routes -import webob - -from nova import wsgi - - -class Test(unittest.TestCase): - - def test_debug(self): - - class Application(wsgi.Application): - """Dummy application to test debug.""" - - def __call__(self, environ, start_response): - start_response("200", [("X-Test", "checking")]) - return ['Test result'] - - application = wsgi.Debug(Application()) - result = webob.Request.blank('/').get_response(application) - self.assertEqual(result.body, "Test result") - - def test_router(self): - - class Application(wsgi.Application): - """Test application to call from router.""" - - def __call__(self, environ, start_response): - start_response("200", []) - return ['Router result'] - - class Router(wsgi.Router): - """Test router.""" - - def __init__(self): - mapper = routes.Mapper() - mapper.connect("/test", controller=Application()) - super(Router, self).__init__(mapper) - - result = webob.Request.blank('/test').get_response(Router()) - self.assertEqual(result.body, "Router result") - result = webob.Request.blank('/bad').get_response(Router()) - self.assertNotEqual(result.body, "Router result") - - def test_controller(self): - - class Controller(wsgi.Controller): - """Test controller to call from router.""" - test = self - - def show(self, req, id): # pylint: disable-msg=W0622,C0103 - """Default action called for requests with an ID.""" - self.test.assertEqual(req.path_info, '/tests/123') - self.test.assertEqual(id, '123') - return id - - class Router(wsgi.Router): - """Test router.""" - - def __init__(self): - mapper = routes.Mapper() - mapper.resource("test", "tests", controller=Controller()) - super(Router, self).__init__(mapper) - - result = webob.Request.blank('/tests/123').get_response(Router()) - self.assertEqual(result.body, "123") - result = webob.Request.blank('/test/123').get_response(Router()) - self.assertNotEqual(result.body, "123") - - def test_serializer(self): - # TODO(eday): Placeholder for serializer testing. - pass -- cgit From 0d20ee4894f5f8566b00f7a28fabc630ca3195aa Mon Sep 17 00:00:00 2001 From: Cerberus Date: Thu, 26 Aug 2010 13:38:29 -0500 Subject: Renamed test.py and moved a test as per merge proposal feedback --- nova/tests/api/__init__.py | 59 +++++++++++++++++++++++++++++++++++++ nova/tests/api/rackspace/servers.py | 3 ++ nova/tests/api/test.py | 59 ------------------------------------- 3 files changed, 62 insertions(+), 59 deletions(-) delete mode 100644 nova/tests/api/test.py diff --git a/nova/tests/api/__init__.py b/nova/tests/api/__init__.py index e69de29bb..59c4adc3d 100644 --- a/nova/tests/api/__init__.py +++ b/nova/tests/api/__init__.py @@ -0,0 +1,59 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Test for the root WSGI middleware for all API controllers. +""" + +import unittest + +import stubout +import webob +import webob.dec + +from nova import api +from nova.tests.api.test_helper import * + +class Test(unittest.TestCase): + + def setUp(self): # pylint: disable-msg=C0103 + self.stubs = stubout.StubOutForTesting() + + def tearDown(self): # pylint: disable-msg=C0103 + self.stubs.UnsetAll() + + def test_rackspace(self): + self.stubs.Set(api.rackspace, 'API', APIStub) + result = webob.Request.blank('/v1.0/cloud').get_response(api.API()) + self.assertEqual(result.body, "/cloud") + + def test_ec2(self): + self.stubs.Set(api.ec2, 'API', APIStub) + result = webob.Request.blank('/ec2/cloud').get_response(api.API()) + self.assertEqual(result.body, "/cloud") + + def test_not_found(self): + self.stubs.Set(api.ec2, 'API', APIStub) + self.stubs.Set(api.rackspace, 'API', APIStub) + result = webob.Request.blank('/test/cloud').get_response(api.API()) + self.assertNotEqual(result.body, "/cloud") + + def test_query_api_version(self): + pass + +if __name__ == '__main__': + unittest.main() diff --git a/nova/tests/api/rackspace/servers.py b/nova/tests/api/rackspace/servers.py index 980e69b84..6d628e78a 100644 --- a/nova/tests/api/rackspace/servers.py +++ b/nova/tests/api/rackspace/servers.py @@ -36,6 +36,9 @@ class ServersTest(unittest.TestCase): def test_get_server_by_id(self): pass + def test_get_backup_schedule(self): + pass + def test_get_server_details(self): pass diff --git a/nova/tests/api/test.py b/nova/tests/api/test.py deleted file mode 100644 index 59c4adc3d..000000000 --- a/nova/tests/api/test.py +++ /dev/null @@ -1,59 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 OpenStack LLC. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Test for the root WSGI middleware for all API controllers. -""" - -import unittest - -import stubout -import webob -import webob.dec - -from nova import api -from nova.tests.api.test_helper import * - -class Test(unittest.TestCase): - - def setUp(self): # pylint: disable-msg=C0103 - self.stubs = stubout.StubOutForTesting() - - def tearDown(self): # pylint: disable-msg=C0103 - self.stubs.UnsetAll() - - def test_rackspace(self): - self.stubs.Set(api.rackspace, 'API', APIStub) - result = webob.Request.blank('/v1.0/cloud').get_response(api.API()) - self.assertEqual(result.body, "/cloud") - - def test_ec2(self): - self.stubs.Set(api.ec2, 'API', APIStub) - result = webob.Request.blank('/ec2/cloud').get_response(api.API()) - self.assertEqual(result.body, "/cloud") - - def test_not_found(self): - self.stubs.Set(api.ec2, 'API', APIStub) - self.stubs.Set(api.rackspace, 'API', APIStub) - result = webob.Request.blank('/test/cloud').get_response(api.API()) - self.assertNotEqual(result.body, "/cloud") - - def test_query_api_version(self): - pass - -if __name__ == '__main__': - unittest.main() -- cgit From 58e1886113e6408d502d095d382a250d33fa0195 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Fri, 27 Aug 2010 20:17:30 +0200 Subject: Create console.log ahead of time. This ensures that the user running nova-compute maintains read privileges. --- nova/virt/libvirt_conn.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 524646ee5..ee8efde7f 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -23,7 +23,7 @@ A connection to a hypervisor (e.g. KVM) through libvirt. import json import logging -import os.path +import os import shutil from twisted.internet import defer @@ -218,6 +218,8 @@ class LibvirtConnection(object): f.write(libvirt_xml) f.close() + os.close(os.open(basepath('console.log'), os.O_CREAT | os.O_WRONLY, 0660)) + user = manager.AuthManager().get_user(data['user_id']) project = manager.AuthManager().get_project(data['project_id']) if not os.path.exists(basepath('disk')): -- cgit From c6100bb1b16722807a583eae2312c4d6653e5643 Mon Sep 17 00:00:00 2001 From: Cerberus Date: Mon, 30 Aug 2010 14:04:47 -0500 Subject: Removed get_backup_schedules from the image test --- nova/tests/api/rackspace/images.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/nova/tests/api/rackspace/images.py b/nova/tests/api/rackspace/images.py index 0e3a87051..560d8c898 100644 --- a/nova/tests/api/rackspace/images.py +++ b/nova/tests/api/rackspace/images.py @@ -30,9 +30,6 @@ class ImagesTest(unittest.TestCase): def test_get_image_list(self): pass - def test_get_backup_schedule(self): - pass - def test_delete_image(self): pass -- cgit From 921d9d01d731f2fda05c73775606f87b3be9aba6 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 31 Aug 2010 21:17:48 +0200 Subject: Better log formatter for Nova. It's just like gnuchangelog, but logs the author rather than the committer. --- bzrplugins/novalog/__init__.py | 59 ++++++++++++++++++++++++++++++++++++++++++ setup.py | 6 +++-- 2 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 bzrplugins/novalog/__init__.py diff --git a/bzrplugins/novalog/__init__.py b/bzrplugins/novalog/__init__.py new file mode 100644 index 000000000..e16b2e00f --- /dev/null +++ b/bzrplugins/novalog/__init__.py @@ -0,0 +1,59 @@ +# Copyright 2010 OpenStack LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Log format for Nova's changelog.""" + +import bzrlib.log +from bzrlib.osutils import format_date + +# +# This is mostly stolen from bzrlib.log.GnuChangelogLogFormatter +# The difference is that it logs the author rather than the committer +# which for Nova always is Tarmac. +# +class NovaLogFormat(bzrlib.log.GnuChangelogLogFormatter): + preferred_levels = 1 + def log_revision(self, revision): + """Log a revision, either merged or not.""" + to_file = self.to_file + + date_str = format_date(revision.rev.timestamp, + revision.rev.timezone or 0, + self.show_timezone, + date_fmt='%Y-%m-%d', + show_offset=False) + + authors = revision.rev.get_apparent_authors() + to_file.write('%s %s\n\n' % (date_str, ", ".join(authors))) + + if revision.delta is not None and revision.delta.has_changed(): + for c in revision.delta.added + revision.delta.removed + revision.delta.modified: + path, = c[:1] + to_file.write('\t* %s:\n' % (path,)) + for c in revision.delta.renamed: + oldpath,newpath = c[:2] + # For renamed files, show both the old and the new path + to_file.write('\t* %s:\n\t* %s:\n' % (oldpath,newpath)) + to_file.write('\n') + + if not revision.rev.message: + to_file.write('\tNo commit message\n') + else: + message = revision.rev.message.rstrip('\r\n') + for l in message.split('\n'): + to_file.write('\t%s\n' % (l.lstrip(),)) + to_file.write('\n') + +bzrlib.log.register_formatter('novalog', NovaLogFormat) + diff --git a/setup.py b/setup.py index 0fd286f7d..ca23efd7b 100644 --- a/setup.py +++ b/setup.py @@ -29,8 +29,10 @@ class local_sdist(sdist): def run(self): if os.path.isdir('.bzr'): # We're in a bzr branch - log_cmd = subprocess.Popen(["bzr", "log", "--gnu"], - stdout=subprocess.PIPE) + env = os.environ.copy() + env['BZR_PLUGIN_PATH'] = os.path.abspath('./bzrplugins') + log_cmd = subprocess.Popen(["bzr", "log", "--novalog"], + stdout=subprocess.PIPE, env=env) changelog = log_cmd.communicate()[0] with open("ChangeLog", "w") as changelog_file: changelog_file.write(changelog) -- cgit From 7595f752137d13449b4cde5680e722582a36c1de Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Wed, 1 Sep 2010 16:27:46 -0400 Subject: Abstractified generalization mechanism --- nova/wsgi.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/nova/wsgi.py b/nova/wsgi.py index bec0a7b1c..543ecb71e 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -241,6 +241,9 @@ class Serializer(object): """ self.environ = environ self.metadata = metadata or {} + self._methods = { + 'application/json', self._to_json, + 'application/xml', self._to_xml} def to_content_type(self, data): """ @@ -250,20 +253,20 @@ class Serializer(object): """ mimetype = 'application/xml' # TODO(gundlach): determine mimetype from request - - if mimetype == 'application/json': - import json - return json.dumps(data) - elif mimetype == 'application/xml': - metadata = self.metadata.get('application/xml', {}) - # We expect data to contain a single key which is the XML root. - root_key = data.keys()[0] - from xml.dom import minidom - doc = minidom.Document() - node = self._to_xml_node(doc, metadata, root_key, data[root_key]) - return node.toprettyxml(indent=' ') - else: - return repr(data) + return self._methods.get(mimetype, repr)(data) + + def _to_json(self, data): + import json + return json.dumps(data) + + def _to_xml(self, data): + metadata = self.metadata.get('application/xml', {}) + # We expect data to contain a single key which is the XML root. + root_key = data.keys()[0] + from xml.dom import minidom + doc = minidom.Document() + node = self._to_xml_node(doc, metadata, root_key, data[root_key]) + return node.toprettyxml(indent=' ') def _to_xml_node(self, doc, metadata, nodename, data): """Recursive method to convert data members to XML nodes.""" -- cgit From 89d8fb48628b6ff72a6baff1dca8772d0a7587f8 Mon Sep 17 00:00:00 2001 From: Michael Gundlach Date: Wed, 1 Sep 2010 17:53:39 -0400 Subject: Nurrr --- nova/wsgi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/wsgi.py b/nova/wsgi.py index 543ecb71e..8a4e2a9f4 100644 --- a/nova/wsgi.py +++ b/nova/wsgi.py @@ -242,8 +242,8 @@ class Serializer(object): self.environ = environ self.metadata = metadata or {} self._methods = { - 'application/json', self._to_json, - 'application/xml', self._to_xml} + 'application/json': self._to_json, + 'application/xml': self._to_xml} def to_content_type(self, data): """ -- cgit From 450eac9e6cc76d6a1f03f9da67b40d814e5712c1 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 2 Sep 2010 14:43:02 -0700 Subject: removed dangling files --- nova/datastore.old.py | 261 -------------------------------------- nova/tests/model_unittest.py | 292 ------------------------------------------- run_tests.py | 1 - 3 files changed, 554 deletions(-) delete mode 100644 nova/datastore.old.py delete mode 100644 nova/tests/model_unittest.py diff --git a/nova/datastore.old.py b/nova/datastore.old.py deleted file mode 100644 index 751c5eeeb..000000000 --- a/nova/datastore.old.py +++ /dev/null @@ -1,261 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Datastore: - -MAKE Sure that ReDIS is running, and your flags are set properly, -before trying to run this. -""" - -import logging - -from nova import exception -from nova import flags -from nova import utils - - -FLAGS = flags.FLAGS -flags.DEFINE_string('redis_host', '127.0.0.1', - 'Host that redis is running on.') -flags.DEFINE_integer('redis_port', 6379, - 'Port that redis is running on.') -flags.DEFINE_integer('redis_db', 0, 'Multiple DB keeps tests away') - - -class Redis(object): - def __init__(self): - if hasattr(self.__class__, '_instance'): - raise Exception('Attempted to instantiate singleton') - - @classmethod - def instance(cls): - if not hasattr(cls, '_instance'): - inst = redis.Redis(host=FLAGS.redis_host, - port=FLAGS.redis_port, - db=FLAGS.redis_db) - cls._instance = inst - return cls._instance - - -class ConnectionError(exception.Error): - pass - - -def absorb_connection_error(fn): - def _wrapper(*args, **kwargs): - try: - return fn(*args, **kwargs) - except redis.exceptions.ConnectionError, ce: - raise ConnectionError(str(ce)) - return _wrapper - - -class BasicModel(object): - """ - All Redis-backed data derives from this class. - - You MUST specify an identifier() property that returns a unique string - per instance. - - You MUST have an initializer that takes a single argument that is a value - returned by identifier() to load a new class with. - - You may want to specify a dictionary for default_state(). - - You may also specify override_type at the class left to use a key other - than __class__.__name__. - - You override save and destroy calls to automatically build and destroy - associations. - """ - - override_type = None - - @absorb_connection_error - def __init__(self): - state = Redis.instance().hgetall(self.__redis_key) - if state: - self.initial_state = state - self.state = dict(self.initial_state) - else: - self.initial_state = {} - self.state = self.default_state() - - - def default_state(self): - """You probably want to define this in your subclass""" - return {} - - @classmethod - def _redis_name(cls): - return cls.override_type or cls.__name__.lower() - - @classmethod - def lookup(cls, identifier): - rv = cls(identifier) - if rv.is_new_record(): - return None - else: - return rv - - @classmethod - @absorb_connection_error - def all(cls): - """yields all objects in the store""" - redis_set = cls._redis_set_name(cls.__name__) - for identifier in Redis.instance().smembers(redis_set): - yield cls(identifier) - - @classmethod - def associated_to(cls, foreign_type, foreign_id): - for identifier in cls.associated_keys(foreign_type, foreign_id): - yield cls(identifier) - - @classmethod - @absorb_connection_error - def associated_keys(cls, foreign_type, foreign_id): - redis_set = cls._redis_association_name(foreign_type, foreign_id) - return Redis.instance().smembers(redis_set) or [] - - @classmethod - def _redis_set_name(cls, kls_name): - # stupidly pluralize (for compatiblity with previous codebase) - return kls_name.lower() + "s" - - @classmethod - def _redis_association_name(cls, foreign_type, foreign_id): - return cls._redis_set_name("%s:%s:%s" % - (foreign_type, foreign_id, cls._redis_name())) - - @property - def identifier(self): - """You DEFINITELY want to define this in your subclass""" - raise NotImplementedError("Your subclass should define identifier") - - @property - def __redis_key(self): - return '%s:%s' % (self._redis_name(), self.identifier) - - def __repr__(self): - return "<%s:%s>" % (self.__class__.__name__, self.identifier) - - def keys(self): - return self.state.keys() - - def copy(self): - copyDict = {} - for item in self.keys(): - copyDict[item] = self[item] - return copyDict - - def get(self, item, default): - return self.state.get(item, default) - - def update(self, update_dict): - return self.state.update(update_dict) - - def setdefault(self, item, default): - return self.state.setdefault(item, default) - - def __contains__(self, item): - return item in self.state - - def __getitem__(self, item): - return self.state[item] - - def __setitem__(self, item, val): - self.state[item] = val - return self.state[item] - - def __delitem__(self, item): - """We don't support this""" - raise Exception("Silly monkey, models NEED all their properties.") - - def is_new_record(self): - return self.initial_state == {} - - @absorb_connection_error - def add_to_index(self): - """Each insance of Foo has its id tracked int the set named Foos""" - set_name = self.__class__._redis_set_name(self.__class__.__name__) - Redis.instance().sadd(set_name, self.identifier) - - @absorb_connection_error - def remove_from_index(self): - """Remove id of this instance from the set tracking ids of this type""" - set_name = self.__class__._redis_set_name(self.__class__.__name__) - Redis.instance().srem(set_name, self.identifier) - - @absorb_connection_error - def associate_with(self, foreign_type, foreign_id): - """Add this class id into the set foreign_type:foreign_id:this_types""" - # note the extra 's' on the end is for plurality - # to match the old data without requiring a migration of any sort - self.add_associated_model_to_its_set(foreign_type, foreign_id) - redis_set = self.__class__._redis_association_name(foreign_type, - foreign_id) - Redis.instance().sadd(redis_set, self.identifier) - - @absorb_connection_error - def unassociate_with(self, foreign_type, foreign_id): - """Delete from foreign_type:foreign_id:this_types set""" - redis_set = self.__class__._redis_association_name(foreign_type, - foreign_id) - Redis.instance().srem(redis_set, self.identifier) - - def add_associated_model_to_its_set(self, model_type, model_id): - """ - When associating an X to a Y, save Y for newer timestamp, etc, and to - make sure to save it if Y is a new record. - If the model_type isn't found as a usable class, ignore it, this can - happen when associating to things stored in LDAP (user, project, ...). - """ - table = globals() - klsname = model_type.capitalize() - if table.has_key(klsname): - model_class = table[klsname] - model_inst = model_class(model_id) - model_inst.save() - - @absorb_connection_error - def save(self): - """ - update the directory with the state from this model - also add it to the index of items of the same type - then set the initial_state = state so new changes are tracked - """ - # TODO(ja): implement hmset in redis-py and use it - # instead of multiple calls to hset - if self.is_new_record(): - self["create_time"] = utils.isotime() - for key, val in self.state.iteritems(): - Redis.instance().hset(self.__redis_key, key, val) - self.add_to_index() - self.initial_state = dict(self.state) - return True - - @absorb_connection_error - def destroy(self): - """deletes all related records from datastore.""" - logging.info("Destroying datamodel for %s %s", - self.__class__.__name__, self.identifier) - Redis.instance().delete(self.__redis_key) - self.remove_from_index() - return True - diff --git a/nova/tests/model_unittest.py b/nova/tests/model_unittest.py deleted file mode 100644 index 130516c66..000000000 --- a/nova/tests/model_unittest.py +++ /dev/null @@ -1,292 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from datetime import datetime, timedelta -import logging -import time - -from nova import flags -from nova import test -from nova import utils -from nova.compute import model - - -FLAGS = flags.FLAGS - - -class ModelTestCase(test.TrialTestCase): - def setUp(self): - super(ModelTestCase, self).setUp() - self.flags(connection_type='fake', - fake_storage=True) - - def tearDown(self): - model.Instance('i-test').destroy() - model.Host('testhost').destroy() - model.Daemon('testhost', 'nova-testdaemon').destroy() - - def create_instance(self): - inst = model.Instance('i-test') - inst['reservation_id'] = 'r-test' - inst['launch_time'] = '10' - inst['user_id'] = 'fake' - inst['project_id'] = 'fake' - inst['instance_type'] = 'm1.tiny' - inst['mac_address'] = utils.generate_mac() - inst['ami_launch_index'] = 0 - inst['private_dns_name'] = '10.0.0.1' - inst.save() - return inst - - def create_host(self): - host = model.Host('testhost') - host.save() - return host - - def create_daemon(self): - daemon = model.Daemon('testhost', 'nova-testdaemon') - daemon.save() - return daemon - - def create_session_token(self): - session_token = model.SessionToken('tk12341234') - session_token['user'] = 'testuser' - session_token.save() - return session_token - - def test_create_instance(self): - """store with create_instace, then test that a load finds it""" - instance = self.create_instance() - old = model.Instance(instance.identifier) - self.assertFalse(old.is_new_record()) - - def test_delete_instance(self): - """create, then destroy, then make sure loads a new record""" - instance = self.create_instance() - instance.destroy() - newinst = model.Instance('i-test') - self.assertTrue(newinst.is_new_record()) - - def test_instance_added_to_set(self): - """create, then check that it is listed in global set""" - instance = self.create_instance() - found = False - for x in model.InstanceDirectory().all: - if x.identifier == 'i-test': - found = True - self.assert_(found) - - def test_instance_associates_project(self): - """create, then check that it is listed for the project""" - instance = self.create_instance() - found = False - for x in model.InstanceDirectory().by_project(instance.project): - if x.identifier == 'i-test': - found = True - self.assert_(found) - - def test_instance_associates_ip(self): - """create, then check that it is listed for the ip""" - instance = self.create_instance() - found = False - x = model.InstanceDirectory().by_ip(instance['private_dns_name']) - self.assertEqual(x.identifier, 'i-test') - - def test_instance_associates_node(self): - """create, then check that it is listed for the host""" - instance = self.create_instance() - found = False - for x in model.InstanceDirectory().by_node(FLAGS.host): - if x.identifier == 'i-test': - found = True - self.assertFalse(found) - instance['host'] = 'test_node' - instance.save() - for x in model.InstanceDirectory().by_node('test_node'): - if x.identifier == 'i-test': - found = True - self.assert_(found) - - - def test_host_class_finds_hosts(self): - host = self.create_host() - self.assertEqual('testhost', model.Host.lookup('testhost').identifier) - - def test_host_class_doesnt_find_missing_hosts(self): - rv = model.Host.lookup('woahnelly') - self.assertEqual(None, rv) - - def test_create_host(self): - """store with create_host, then test that a load finds it""" - host = self.create_host() - old = model.Host(host.identifier) - self.assertFalse(old.is_new_record()) - - def test_delete_host(self): - """create, then destroy, then make sure loads a new record""" - instance = self.create_host() - instance.destroy() - newinst = model.Host('testhost') - self.assertTrue(newinst.is_new_record()) - - def test_host_added_to_set(self): - """create, then check that it is included in list""" - instance = self.create_host() - found = False - for x in model.Host.all(): - if x.identifier == 'testhost': - found = True - self.assert_(found) - - def test_create_daemon_two_args(self): - """create a daemon with two arguments""" - d = self.create_daemon() - d = model.Daemon('testhost', 'nova-testdaemon') - self.assertFalse(d.is_new_record()) - - def test_create_daemon_single_arg(self): - """Create a daemon using the combined host:bin format""" - d = model.Daemon("testhost:nova-testdaemon") - d.save() - d = model.Daemon('testhost:nova-testdaemon') - self.assertFalse(d.is_new_record()) - - def test_equality_of_daemon_single_and_double_args(self): - """Create a daemon using the combined host:bin arg, find with 2""" - d = model.Daemon("testhost:nova-testdaemon") - d.save() - d = model.Daemon('testhost', 'nova-testdaemon') - self.assertFalse(d.is_new_record()) - - def test_equality_daemon_of_double_and_single_args(self): - """Create a daemon using the combined host:bin arg, find with 2""" - d = self.create_daemon() - d = model.Daemon('testhost:nova-testdaemon') - self.assertFalse(d.is_new_record()) - - def test_delete_daemon(self): - """create, then destroy, then make sure loads a new record""" - instance = self.create_daemon() - instance.destroy() - newinst = model.Daemon('testhost', 'nova-testdaemon') - self.assertTrue(newinst.is_new_record()) - - def test_daemon_heartbeat(self): - """Create a daemon, sleep, heartbeat, check for update""" - d = self.create_daemon() - ts = d['updated_at'] - time.sleep(2) - d.heartbeat() - d2 = model.Daemon('testhost', 'nova-testdaemon') - ts2 = d2['updated_at'] - self.assert_(ts2 > ts) - - def test_daemon_added_to_set(self): - """create, then check that it is included in list""" - instance = self.create_daemon() - found = False - for x in model.Daemon.all(): - if x.identifier == 'testhost:nova-testdaemon': - found = True - self.assert_(found) - - def test_daemon_associates_host(self): - """create, then check that it is listed for the host""" - instance = self.create_daemon() - found = False - for x in model.Daemon.by_host('testhost'): - if x.identifier == 'testhost:nova-testdaemon': - found = True - self.assertTrue(found) - - def test_create_session_token(self): - """create""" - d = self.create_session_token() - d = model.SessionToken(d.token) - self.assertFalse(d.is_new_record()) - - def test_delete_session_token(self): - """create, then destroy, then make sure loads a new record""" - instance = self.create_session_token() - instance.destroy() - newinst = model.SessionToken(instance.token) - self.assertTrue(newinst.is_new_record()) - - def test_session_token_added_to_set(self): - """create, then check that it is included in list""" - instance = self.create_session_token() - found = False - for x in model.SessionToken.all(): - if x.identifier == instance.token: - found = True - self.assert_(found) - - def test_session_token_associates_user(self): - """create, then check that it is listed for the user""" - instance = self.create_session_token() - found = False - for x in model.SessionToken.associated_to('user', 'testuser'): - if x.identifier == instance.identifier: - found = True - self.assertTrue(found) - - def test_session_token_generation(self): - instance = model.SessionToken.generate('username', 'TokenType') - self.assertFalse(instance.is_new_record()) - - def test_find_generated_session_token(self): - instance = model.SessionToken.generate('username', 'TokenType') - found = model.SessionToken.lookup(instance.identifier) - self.assert_(found) - - def test_update_session_token_expiry(self): - instance = model.SessionToken('tk12341234') - oldtime = datetime.utcnow() - instance['expiry'] = oldtime.strftime(utils.TIME_FORMAT) - instance.update_expiry() - expiry = utils.parse_isotime(instance['expiry']) - self.assert_(expiry > datetime.utcnow()) - - def test_session_token_lookup_when_expired(self): - instance = model.SessionToken.generate("testuser") - instance['expiry'] = datetime.utcnow().strftime(utils.TIME_FORMAT) - instance.save() - inst = model.SessionToken.lookup(instance.identifier) - self.assertFalse(inst) - - def test_session_token_lookup_when_not_expired(self): - instance = model.SessionToken.generate("testuser") - inst = model.SessionToken.lookup(instance.identifier) - self.assert_(inst) - - def test_session_token_is_expired_when_expired(self): - instance = model.SessionToken.generate("testuser") - instance['expiry'] = datetime.utcnow().strftime(utils.TIME_FORMAT) - self.assert_(instance.is_expired()) - - def test_session_token_is_expired_when_not_expired(self): - instance = model.SessionToken.generate("testuser") - self.assertFalse(instance.is_expired()) - - def test_session_token_ttl(self): - instance = model.SessionToken.generate("testuser") - now = datetime.utcnow() - delta = timedelta(hours=1) - instance['expiry'] = (now + delta).strftime(utils.TIME_FORMAT) - # give 5 seconds of fuzziness - self.assert_(abs(instance.ttl() - FLAGS.auth_token_ttl) < 5) diff --git a/run_tests.py b/run_tests.py index c47cbe2ec..d5dc5f934 100644 --- a/run_tests.py +++ b/run_tests.py @@ -55,7 +55,6 @@ from nova.tests.api_unittest import * from nova.tests.cloud_unittest import * from nova.tests.compute_unittest import * from nova.tests.flags_unittest import * -#from nova.tests.model_unittest import * from nova.tests.network_unittest import * from nova.tests.objectstore_unittest import * from nova.tests.process_unittest import * -- cgit From bcc0004e0ebd1345dc3580e1cb01f7ca1222ef51 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 2 Sep 2010 14:57:45 -0700 Subject: fix service unit tests --- nova/service.py | 11 +++++------ nova/tests/service_unittest.py | 26 +++++++++++++++++++++----- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/nova/service.py b/nova/service.py index fc188be34..d7471f4c6 100644 --- a/nova/service.py +++ b/nova/service.py @@ -85,9 +85,6 @@ class Service(object, service.Service): manager, defaults to FLAGS._manager report_interval, defaults to FLAGS.report_interval """ - if not report_interval: - report_interval = FLAGS.report_interval - if not host: host = FLAGS.host if not binary: @@ -96,16 +93,18 @@ class Service(object, service.Service): topic = binary.rpartition("nova-")[2] if not manager: manager = FLAGS.get('%s_manager' % topic, None) + if not report_interval: + report_interval = FLAGS.report_interval logging.warn("Starting %s node", topic) - service_obj = cls(FLAGS.host, binary, topic, manager) + service_obj = cls(host, binary, topic, manager) conn = rpc.Connection.instance() consumer_all = rpc.AdapterConsumer( connection=conn, - topic='%s' % topic, + topic=topic, proxy=service_obj) consumer_node = rpc.AdapterConsumer( connection=conn, - topic='%s.%s' % (topic, FLAGS.host), + topic='%s.%s' % (topic, host), proxy=service_obj) pulse = task.LoopingCall(service_obj.report_state) diff --git a/nova/tests/service_unittest.py b/nova/tests/service_unittest.py index 274e74b5b..590d760b9 100644 --- a/nova/tests/service_unittest.py +++ b/nova/tests/service_unittest.py @@ -47,34 +47,50 @@ class ServiceTestCase(test.BaseTestCase): self.mox.StubOutWithMock(service, 'db') def test_create(self): + host='foo' + binary='nova-fake' + topic='fake' self.mox.StubOutWithMock(rpc, 'AdapterConsumer', use_mock_anything=True) self.mox.StubOutWithMock( service.task, 'LoopingCall', use_mock_anything=True) rpc.AdapterConsumer(connection=mox.IgnoreArg(), - topic='fake', + topic=topic, proxy=mox.IsA(service.Service)).AndReturn( rpc.AdapterConsumer) rpc.AdapterConsumer(connection=mox.IgnoreArg(), - topic='fake.%s' % FLAGS.host, + topic='%s.%s' % (topic, host), proxy=mox.IsA(service.Service)).AndReturn( rpc.AdapterConsumer) # Stub out looping call a bit needlessly since we don't have an easy # way to cancel it (yet) when the tests finishes - service.task.LoopingCall( - mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg()).AndReturn( + service.task.LoopingCall(mox.IgnoreArg()).AndReturn( service.task.LoopingCall) service.task.LoopingCall.start(interval=mox.IgnoreArg(), now=mox.IgnoreArg()) rpc.AdapterConsumer.attach_to_twisted() rpc.AdapterConsumer.attach_to_twisted() + service_create = {'host': host, + 'binary': binary, + 'topic': topic, + 'report_count': 0} + service_ref = {'host': host, + 'binary': binary, + 'report_count': 0, + 'id': 1} + + service.db.service_get_by_args(None, + host, + binary).AndRaise(exception.NotFound()) + service.db.service_create(None, + service_create).AndReturn(service_ref['id']) self.mox.ReplayAll() - app = service.Service.create(bin_name='nova-fake') + app = service.Service.create(host=host, binary=binary) self.assert_(app) # We're testing sort of weird behavior in how report_state decides -- cgit