diff --git a/heatclient/tests/test_events.py b/heatclient/tests/test_events.py new file mode 100644 index 00000000..02094369 --- /dev/null +++ b/heatclient/tests/test_events.py @@ -0,0 +1,114 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 IBM Corp. +# +# 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 heatclient.v1.events import Event +from heatclient.v1.events import EventManager + +from mock import MagicMock +import mox +import testtools + + +class EventManagerTest(testtools.TestCase): + + def setUp(self): + super(EventManagerTest, self).setUp() + self.m = mox.Mox() + self.addCleanup(self.m.UnsetStubs) + self.addCleanup(self.m.ResetAll) + + def test_list_event(self): + stack_id = 'teststack', + resource_name = 'testresource' + manager = EventManager(None) + self.m.StubOutWithMock(manager, '_resolve_stack_id') + manager._resolve_stack_id(stack_id).AndReturn('teststack/abcd1234') + self.m.ReplayAll() + manager._list = MagicMock() + manager.list(stack_id, resource_name) + # Make sure url is correct. + manager._list.assert_called_once_with('/stacks/teststack%2Fabcd1234/' + 'resources/testresource/events', + "events") + + def test_list_event_with_unicode_resource_name(self): + stack_id = 'teststack', + resource_name = u'\u5de5\u4f5c' + manager = EventManager(None) + self.m.StubOutWithMock(manager, '_resolve_stack_id') + manager._resolve_stack_id(stack_id).AndReturn('teststack/abcd1234') + self.m.ReplayAll() + manager._list = MagicMock() + manager.list(stack_id, resource_name) + # Make sure url is correct. + manager._list.assert_called_once_with('/stacks/teststack%2Fabcd1234/' + 'resources/%E5%B7%A5%E4%BD%9C/' + 'events', "events") + + def test_list_event_with_none_resource_name(self): + stack_id = 'teststack', + manager = EventManager(None) + manager._list = MagicMock() + manager.list(stack_id) + # Make sure url is correct. + manager._list.assert_called_once_with('/stacks/teststack/' + 'events', "events") + + def test_get_event(self): + fields = {'stack_id': 'teststack', + 'resource_name': 'testresource', + 'event_id': '1'} + + class FakeAPI(object): + """Fake API and ensure request url is correct.""" + + def json_request(self, *args, **kwargs): + expect = ('GET', + '/stacks/teststack%2Fabcd1234/resources' + '/testresource/events/1') + assert args == expect + return {}, {'event': []} + + manager = EventManager(FakeAPI()) + Event.__init__ = MagicMock() + Event.__init__.return_value = None + self.m.StubOutWithMock(manager, '_resolve_stack_id') + manager._resolve_stack_id('teststack').AndReturn('teststack/abcd1234') + self.m.ReplayAll() + manager.get(**fields) + + def test_get_event_with_unicode_resource_name(self): + fields = {'stack_id': 'teststack', + 'resource_name': u'\u5de5\u4f5c', + 'event_id': '1'} + + class FakeAPI(object): + """Fake API and ensure request url is correct.""" + + def json_request(self, *args, **kwargs): + expect = ('GET', + '/stacks/teststack%2Fabcd1234/resources' + '/%E5%B7%A5%E4%BD%9C/events/1') + assert args == expect + return {}, {'event': []} + + manager = EventManager(FakeAPI()) + Event.__init__ = MagicMock() + Event.__init__.return_value = None + self.m.StubOutWithMock(manager, '_resolve_stack_id') + manager._resolve_stack_id('teststack').AndReturn('teststack/abcd1234') + self.m.ReplayAll() + manager.get(**fields) diff --git a/heatclient/tests/test_resources.py b/heatclient/tests/test_resources.py new file mode 100644 index 00000000..a15dc40b --- /dev/null +++ b/heatclient/tests/test_resources.py @@ -0,0 +1,75 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 IBM Corp. +# +# 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 heatclient.v1.resources import Resource +from heatclient.v1.resources import ResourceManager + +from mock import MagicMock +import mox +import testtools + + +class ResourceManagerTest(testtools.TestCase): + + def setUp(self): + super(ResourceManagerTest, self).setUp() + self.m = mox.Mox() + self.addCleanup(self.m.UnsetStubs) + self.addCleanup(self.m.ResetAll) + + def test_get_event(self): + fields = {'stack_id': 'teststack', + 'resource_name': 'testresource'} + + class FakeAPI(object): + """Fake API and ensure request url is correct.""" + + def json_request(self, *args, **kwargs): + expect = ('GET', + '/stacks/teststack%2Fabcd1234/resources' + '/testresource') + assert args == expect + return {}, {'resource': []} + + manager = ResourceManager(FakeAPI()) + Resource.__init__ = MagicMock() + Resource.__init__.return_value = None + self.m.StubOutWithMock(manager, '_resolve_stack_id') + manager._resolve_stack_id('teststack').AndReturn('teststack/abcd1234') + self.m.ReplayAll() + manager.get(**fields) + + def test_get_event_with_unicode_resource_name(self): + fields = {'stack_id': 'teststack', + 'resource_name': u'\u5de5\u4f5c'} + + class FakeAPI(object): + """Fake API and ensure request url is correct.""" + + def json_request(self, *args, **kwargs): + expect = ('GET', + '/stacks/teststack%2Fabcd1234/resources' + '/%E5%B7%A5%E4%BD%9C') + assert args == expect + return {}, {'resource': []} + + manager = ResourceManager(FakeAPI()) + Resource.__init__ = MagicMock() + Resource.__init__.return_value = None + self.m.StubOutWithMock(manager, '_resolve_stack_id') + manager._resolve_stack_id('teststack').AndReturn('teststack/abcd1234') + self.m.ReplayAll() + manager.get(**fields) diff --git a/heatclient/v1/events.py b/heatclient/v1/events.py index 3db2f94b..28aaa185 100644 --- a/heatclient/v1/events.py +++ b/heatclient/v1/events.py @@ -14,6 +14,8 @@ # under the License. from heatclient.common import base +from heatclient.openstack.common.py3kcompat import urlutils +from heatclient.openstack.common import strutils from heatclient.v1 import stacks DEFAULT_PAGE_SIZE = 20 @@ -46,7 +48,10 @@ class EventManager(stacks.StackChildManager): url = '/stacks/%s/events' % stack_id else: stack_id = self._resolve_stack_id(stack_id) - url = '/stacks/%s/resources/%s/events' % (stack_id, resource_name) + # Use urlutils for python2/python3 compatibility + url = '/stacks/%s/resources/%s/events' % ( + urlutils.quote(stack_id, ''), + urlutils.quote(strutils.safe_encode(resource_name), '')) return self._list(url, "events") def get(self, stack_id, resource_name, event_id): @@ -57,8 +62,10 @@ class EventManager(stacks.StackChildManager): :param event_id: ID of event to get the details for """ stack_id = self._resolve_stack_id(stack_id) - url_str = '/stacks/%s/resources/%s/events/%s' % (stack_id, - resource_name, - event_id) + # Use urlutils for python2/python3 compatibility + url_str = '/stacks/%s/resources/%s/events/%s' % ( + urlutils.quote(stack_id, ''), + urlutils.quote(strutils.safe_encode(resource_name), ''), + urlutils.quote(event_id, '')) resp, body = self.api.json_request('GET', url_str) return Event(self, body['event']) diff --git a/heatclient/v1/resources.py b/heatclient/v1/resources.py index 476163d2..cd2df29c 100644 --- a/heatclient/v1/resources.py +++ b/heatclient/v1/resources.py @@ -14,6 +14,8 @@ # under the License. from heatclient.common import base +from heatclient.openstack.common.py3kcompat import urlutils +from heatclient.openstack.common import strutils from heatclient.v1 import stacks DEFAULT_PAGE_SIZE = 20 @@ -50,10 +52,11 @@ class ResourceManager(stacks.StackChildManager): :param resource_name: ID of resource to get the details for """ stack_id = self._resolve_stack_id(stack_id) - resp, body = self.api.json_request('GET', - '/stacks/%s/resources/%s' % - (stack_id, resource_name)) - + # Use urlutils for python2/python3 compatibility + url_str = '/stacks/%s/resources/%s' % ( + urlutils.quote(stack_id, ''), + urlutils.quote(strutils.safe_encode(resource_name), '')) + resp, body = self.api.json_request('GET', url_str) return Resource(self, body['resource']) def metadata(self, stack_id, resource_name): @@ -63,13 +66,16 @@ class ResourceManager(stacks.StackChildManager): :param resource_name: ID of resource to get metadata for """ stack_id = self._resolve_stack_id(stack_id) - resp, body = self.api.json_request('GET', - '/stacks/%s/resources/%s/metadata' % - (stack_id, resource_name)) + # Use urlutils for python2/python3 compatibility + url_str = '/stacks/%s/resources/%s/metadata' % ( + urlutils.quote(stack_id, ''), + urlutils.quote(strutils.safe_encode(resource_name), '')) + resp, body = self.api.json_request('GET', url_str) return body['metadata'] def generate_template(self, resource_name): - resp, body = self.api.json_request('GET', - '/resource_types/%s/template' % - resource_name) + # Use urlutils for python2/python3 compatibility + url_str = '/resource_types/%s/template' % ( + urlutils.quote(strutils.safe_encode(resource_name), '')) + resp, body = self.api.json_request('GET', url_str) return body