Move request_and_transport to the Client

This patch moves the `_get_transport` and `request_and_transport` method
to the client. Both method are useful for other resources like Message,
for example.

This patch also moves the is_functional logic to the BaseTest class and
splits unittests from functional tests.

Partially-Implements: python-marconiclient-v1
Change-Id: Iaf56c234291b355c98817feee5644a5dd07c0b7f
This commit is contained in:
Flavio Percoco 2013-12-09 23:16:18 +01:00
parent d215aaaa55
commit b153951e57
9 changed files with 79 additions and 69 deletions

View File

@ -17,6 +17,7 @@ import uuid
from marconiclient.queues.v1 import queues from marconiclient.queues.v1 import queues
from marconiclient import transport from marconiclient import transport
from marconiclient.transport import request
class Client(object): class Client(object):
@ -44,6 +45,34 @@ class Client(object):
self.client_uuid = self.conf.get('client_uuid', self.client_uuid = self.conf.get('client_uuid',
uuid.uuid4().hex) uuid.uuid4().hex)
def _get_transport(self, request):
"""Gets a transport and caches its instance
This method gets a transport instance based on
the request's endpoint and caches that for later
use. The transport instance is invalidated whenever
a session expires.
:param request: The request to use to load the
transport instance.
:type request: `transport.request.Request`
"""
trans = transport.get_transport_for(request,
options=self.conf)
return (trans or self.transport)
def _request_and_transport(self):
api = 'queues.v' + str(self.api_version)
req = request.prepare_request(self.auth_opts,
endpoint=self.api_url,
api=api)
req.headers['Client-ID'] = self.client_uuid
trans = self._get_transport(req)
return req, trans
def transport(self): def transport(self):
"""Gets a transport based the api url and version.""" """Gets a transport based the api url and version."""
return transport.get_transport_for(self.url, return transport.get_transport_for(self.url,

View File

@ -14,8 +14,6 @@
# limitations under the License. # limitations under the License.
from marconiclient.queues.v1 import core from marconiclient.queues.v1 import core
from marconiclient import transport
from marconiclient.transport import request
class Queue(object): class Queue(object):
@ -30,37 +28,9 @@ class Queue(object):
if auto_create: if auto_create:
self.ensure_exists() self.ensure_exists()
def _get_transport(self, request):
"""Gets a transport and caches its instance
This method gets a transport instance based on
the request's endpoint and caches that for later
use. The transport instance is invalidated whenever
a session expires.
:param request: The request to use to load the
transport instance.
:type request: `transport.request.Request`
"""
trans = transport.get_transport_for(request,
options=self.client.conf)
return (trans or self.client.transport)
def _request_and_transport(self):
api = 'queues.v' + str(self.client.api_version)
req = request.prepare_request(self.client.auth_opts,
endpoint=self.client.api_url,
api=api)
req.headers['Client-ID'] = self.client.client_uuid
trans = self._get_transport(req)
return req, trans
def exists(self): def exists(self):
"""Checks if the queue exists.""" """Checks if the queue exists."""
req, trans = self._request_and_transport() req, trans = self.client._request_and_transport()
return core.queue_exists(trans, req, self._id) return core.queue_exists(trans, req, self._id)
def ensure_exists(self): def ensure_exists(self):
@ -70,7 +40,7 @@ class Queue(object):
the queue could've been deleted the queue could've been deleted
right after it was called. right after it was called.
""" """
req, trans = self._request_and_transport() req, trans = self.client._request_and_transport()
core.queue_create(trans, req, self._id) core.queue_create(trans, req, self._id)
def metadata(self, new_meta=None, force_reload=False): def metadata(self, new_meta=None, force_reload=False):
@ -88,7 +58,7 @@ class Queue(object):
:returns: The queue metadata. :returns: The queue metadata.
""" """
req, trans = self._request_and_transport() req, trans = self.client._request_and_transport()
if new_meta: if new_meta:
core.queue_set_metadata(trans, req, self._id, new_meta) core.queue_set_metadata(trans, req, self._id, new_meta)
@ -102,7 +72,7 @@ class Queue(object):
return self._metadata return self._metadata
def delete(self): def delete(self):
req, trans = self._request_and_transport() req, trans = self.client._request_and_transport()
core.queue_delete(trans, req, self._id) core.queue_delete(trans, req, self._id)
# Messages API # Messages API
@ -119,7 +89,7 @@ class Queue(object):
if not isinstance(messages, list): if not isinstance(messages, list):
messages = [messages] messages = [messages]
req, trans = self._request_and_transport() req, trans = self.client._request_and_transport()
# TODO(flaper87): Return a list of messages # TODO(flaper87): Return a list of messages
return core.message_post(trans, req, return core.message_post(trans, req,
@ -134,7 +104,7 @@ class Queue(object):
:returns: A message :returns: A message
:rtype: `dict` :rtype: `dict`
""" """
req, trans = self._request_and_transport() req, trans = self.client._request_and_transport()
return core.message_get(trans, req, self._id, return core.message_get(trans, req, self._id,
message_id) message_id)
@ -158,7 +128,7 @@ class Queue(object):
:returns: List of messages :returns: List of messages
:rtype: `list` :rtype: `list`
""" """
req, trans = self._request_and_transport() req, trans = self.client._request_and_transport()
# TODO(flaper87): Return a MessageIterator. # TODO(flaper87): Return a MessageIterator.
# This iterator should handle limits, pagination # This iterator should handle limits, pagination

View File

@ -13,12 +13,19 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os
import fixtures import fixtures
import testtools import testtools
_RUN_FUNCTIONAL = os.environ.get('MARCONICLIENT_TEST_FUNCTIONAL', False)
class TestBase(testtools.TestCase): class TestBase(testtools.TestCase):
transport_cls = None
is_functional = False
def setUp(self): def setUp(self):
super(TestBase, self).setUp() super(TestBase, self).setUp()
@ -30,6 +37,9 @@ class TestBase(testtools.TestCase):
stderr = self.useFixture(fixtures.StringStream('stderr')).stream stderr = self.useFixture(fixtures.StringStream('stderr')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
if not _RUN_FUNCTIONAL and self.is_functional:
self.skipTest('Functional tests disabled')
def config(self, group=None, **kw): def config(self, group=None, **kw):
"""Override some configuration values. """Override some configuration values.

View File

@ -13,23 +13,16 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os
import json import json
import mock import mock
import testtools
from marconiclient.queues.v1 import client from marconiclient.queues.v1 import client
from marconiclient.tests import base from marconiclient.tests import base
from marconiclient.transport import response from marconiclient.transport import response
_RUN_FUNCTIONAL = os.environ.get('MARCONICLIENT_TEST_FUNCTIONAL', False)
class QueuesV1QueueTestBase(base.TestBase): class QueuesV1QueueTestBase(base.TestBase):
transport_cls = None
# NOTE(flaper87): These class attributes # NOTE(flaper87): These class attributes
# are intended for functional tests only # are intended for functional tests only
# and will be replaced with something # and will be replaced with something
@ -45,13 +38,16 @@ class QueuesV1QueueTestBase(base.TestBase):
self.client = client.Client(self.url, self.version, self.client = client.Client(self.url, self.version,
self.conf) self.conf)
mocked_transport = mock.Mock(return_value=self.transport)
self.client._get_transport = mocked_transport
# NOTE(flaper87): Nasty monkeypatch, lets use # NOTE(flaper87): Nasty monkeypatch, lets use
# the dummy transport here. # the dummy transport here.
#setattr(self.client, 'transport', self.transport) #setattr(self.client, 'transport', self.transport)
self.queue = self.client.queue(1, auto_create=False) self.queue = self.client.queue(1, auto_create=False)
self.queue._get_transport = mock.Mock(return_value=self.transport)
self.is_functional = _RUN_FUNCTIONAL
class QueuesV1QueueUnitTest(QueuesV1QueueTestBase):
def test_queue_metadata(self): def test_queue_metadata(self):
test_metadata = {'type': 'Bank Accounts'} test_metadata = {'type': 'Bank Accounts'}
@ -199,17 +195,13 @@ class QueuesV1QueueTestBase(base.TestBase):
# doesn't crash. # doesn't crash.
class QueuesV1QueueFuncMixin(object): class QueuesV1QueueFunctionalTest(QueuesV1QueueTestBase):
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_queue_create_functional(self): def test_queue_create_functional(self):
queue = self.client.queue("nonono") queue = self.client.queue("nonono")
queue._get_transport = mock.Mock(return_value=self.transport) queue._get_transport = mock.Mock(return_value=self.transport)
self.assertTrue(queue.exists()) self.assertTrue(queue.exists())
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_queue_delete_functional(self): def test_queue_delete_functional(self):
queue = self.client.queue("nonono") queue = self.client.queue("nonono")
queue._get_transport = mock.Mock(return_value=self.transport) queue._get_transport = mock.Mock(return_value=self.transport)
@ -217,15 +209,11 @@ class QueuesV1QueueFuncMixin(object):
queue.delete() queue.delete()
self.assertFalse(queue.exists()) self.assertFalse(queue.exists())
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_queue_exists_functional(self): def test_queue_exists_functional(self):
queue = self.client.queue("404", auto_create=False) queue = self.client.queue("404", auto_create=False)
queue._get_transport = mock.Mock(return_value=self.transport) queue._get_transport = mock.Mock(return_value=self.transport)
self.assertFalse(queue.exists()) self.assertFalse(queue.exists())
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_queue_metadata_functional(self): def test_queue_metadata_functional(self):
test_metadata = {'type': 'Bank Accounts'} test_metadata = {'type': 'Bank Accounts'}
queue = self.client.queue("meta-test") queue = self.client.queue("meta-test")
@ -236,8 +224,6 @@ class QueuesV1QueueFuncMixin(object):
metadata = queue.metadata() metadata = queue.metadata()
self.assertEqual(metadata, test_metadata) self.assertEqual(metadata, test_metadata)
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_queue_metadata_reload_functional(self): def test_queue_metadata_reload_functional(self):
test_metadata = {'type': 'Bank Accounts'} test_metadata = {'type': 'Bank Accounts'}
queue = self.client.queue("meta-test") queue = self.client.queue("meta-test")
@ -249,8 +235,6 @@ class QueuesV1QueueFuncMixin(object):
metadata = queue.metadata(force_reload=True) metadata = queue.metadata(force_reload=True)
self.assertEqual(metadata, test_metadata) self.assertEqual(metadata, test_metadata)
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_message_post_functional(self): def test_message_post_functional(self):
messages = [ messages = [
{'ttl': 60, 'body': 'Post It!'}, {'ttl': 60, 'body': 'Post It!'},
@ -264,8 +248,6 @@ class QueuesV1QueueFuncMixin(object):
self.assertIn('resources', result) self.assertIn('resources', result)
self.assertEqual(len(result['resources']), 3) self.assertEqual(len(result['resources']), 3)
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_message_list_functional(self): def test_message_list_functional(self):
queue = self.client.queue("test_queue") queue = self.client.queue("test_queue")
queue._get_transport = mock.Mock(return_value=self.transport) queue._get_transport = mock.Mock(return_value=self.transport)
@ -277,8 +259,6 @@ class QueuesV1QueueFuncMixin(object):
self.assertTrue(isinstance(messages, list)) self.assertTrue(isinstance(messages, list))
self.assertGreaterEqual(len(messages), 0) self.assertGreaterEqual(len(messages), 0)
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_message_list_echo_functional(self): def test_message_list_echo_functional(self):
queue = self.client.queue("test_queue") queue = self.client.queue("test_queue")
queue._get_transport = mock.Mock(return_value=self.transport) queue._get_transport = mock.Mock(return_value=self.transport)
@ -293,8 +273,6 @@ class QueuesV1QueueFuncMixin(object):
self.assertTrue(isinstance(messages, list)) self.assertTrue(isinstance(messages, list))
self.assertGreaterEqual(len(messages), 3) self.assertGreaterEqual(len(messages), 3)
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_message_get_functional(self): def test_message_get_functional(self):
queue = self.client.queue("test_queue") queue = self.client.queue("test_queue")
queue._get_transport = mock.Mock(return_value=self.transport) queue._get_transport = mock.Mock(return_value=self.transport)
@ -311,8 +289,6 @@ class QueuesV1QueueFuncMixin(object):
self.assertTrue(isinstance(message, dict)) self.assertTrue(isinstance(message, dict))
self.assertEqual(message['href'], res[0]) self.assertEqual(message['href'], res[0])
@testtools.skipUnless(_RUN_FUNCTIONAL,
'Functional tests disabled')
def test_message_get_many_functional(self): def test_message_get_many_functional(self):
queue = self.client.queue("test_queue") queue = self.client.queue("test_queue")
queue._get_transport = mock.Mock(return_value=self.transport) queue._get_transport = mock.Mock(return_value=self.transport)

View File

View File

View File

View File

@ -0,0 +1,26 @@
# Copyright (c) 2013 Red Hat, Inc.
#
# 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 marconiclient.tests.queues import queues
from marconiclient.transport import http
class QueuesV1QueueHttpFunctionalTest(queues.QueuesV1QueueFunctionalTest):
is_functional = True
transport_cls = http.HttpTransport
url = 'http://127.0.0.1:8888/v1'
version = 1

View File

@ -24,8 +24,7 @@ class QueuesV1QueueDummyTransportTest(queues.QueuesV1QueueTestBase):
transport_cls = dummy.DummyTransport transport_cls = dummy.DummyTransport
class QueuesV1QueueHttpTransportTest(queues.QueuesV1QueueTestBase, class QueuesV1QueueHttpUnitTest(queues.QueuesV1QueueUnitTest):
queues.QueuesV1QueueFuncMixin):
transport_cls = http.HttpTransport transport_cls = http.HttpTransport
url = 'http://127.0.0.1:8888/v1' url = 'http://127.0.0.1:8888/v1'