Implement message controller.

This patchset contributes a message controller for Marconi client. It
implements simple property querying for messages, as well as the
ability to reload these properties as needed (polling?) and delete a
message. It also uses the assumed structure of the HTTPclient that
will form the basis of the connection from the common libraries.

six is used to boost py3k compat.

This also introduces a directory structure for supporting multiple
transports. Instead of having a 'controller' dir, now we have a
'transports/http' and 'transports/zmq'.

Author: Alejandro Cabrera
Implements: blueprint messages-management
Change-Id: I9d4e7c28939cdb68b74690e5c56e69d58ac1559a
This commit is contained in:
Alejandro Cabrera 2013-07-15 17:36:44 -04:00 committed by Flavio Percoco
parent 793b0313f2
commit bf5844a074
18 changed files with 364 additions and 19 deletions

View File

@ -1,19 +0,0 @@
# 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.
import pbr.version
__version__ = pbr.version.VersionInfo("python-marconiclient").version_string()

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,26 @@
# Copyright (c) 2013 Rackspace, 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.
"""Easy creation of mock Marconi message replies."""
def message(href='/v1/queues/dgq/messages/w78sdwsqdsib',
ttl=0, age=0, body=None):
body = body or {}
return {
'href': href,
'ttl': ttl,
'age': age,
'body': body
}

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,76 @@
# Copyright (c) 2013 Rackspace, 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.
"""Implements a message controller that understands Marconi messages."""
def _args_from_dict(msg):
return {
'href': msg['href'],
'ttl': msg['ttl'],
'age': msg['age'],
'body': msg['body']
}
def from_dict(msg, connection=None):
"""from_dict(dict, Connection) => Message
:param msg: A dictionary created by decoding a Marconi message JSON reply
:param connection: A connection to a Marconi server.
:raises: KeyError If msg is missing fields
:raises: TypeError if msg is not a dict.
"""
return Message(
connection=connection,
**_args_from_dict(msg)
)
class Message(object):
"""A handler for Marconi server Message resources.
Attributes are only downloaded once - at creation time.
"""
def __init__(self, href, ttl, age, body, connection):
self.href = href
self.ttl = ttl
self.age = age
self.body = body
self._connection = connection
self._deleted = False
def __repr__(self):
return '<Message ttl:%s>' % (self.ttl,)
def _assert_not_deleted(self):
assert not self._deleted, 'Already deleted'
def reload(self):
"""Queries the server and updates all local attributes
with new values.
"""
self._assert_not_deleted()
msg = self._connection.get(self.href).json()
self.href = msg['href']
self.ttl = msg['ttl']
self.age = msg['age']
self.body = msg['body']
def delete(self):
"""Deletes this resource from the server, but leaves the local
object intact.
"""
self._assert_not_deleted()
self._connection.delete(self.href)
self._deleted = True

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

18
marconiclient/version.py Normal file
View File

@ -0,0 +1,18 @@
# 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.
import pbr.version
version_info = pbr.version.VersionInfo('marconi')

View File

@ -1,2 +1,6 @@
d2to1>=0.2.10,<0.3
pbr>=0.5.16,<0.6
six>=1.3.0
-f http://tarballs.openstack.org/oslo.config/oslo.config-1.2.0a3.tar.gz#egg=oslo.config-1.2.0a3
oslo.config>=1.2.0a3

14
tests/unit/__init__.py Normal file
View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.

View File

@ -0,0 +1,72 @@
# Copyright (c) 2013 Rackspace, 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.
import unittest
import mock
from marconiclient.tests.mock import message as mock_message
from marconiclient.transport.http import message
HREF = '/v1/queue/dgq/messages/my_msg_is_chocolate'
AGE = 100
TTL = 120
class TestSimpleMessage(unittest.TestCase):
def setUp(self):
msg_body = {
'href': HREF,
'ttl': TTL,
'age': AGE,
'body': {'name': 'chocolate'}
}
self.conn = mock.MagicMock()
self.msg = message.from_dict(msg_body, connection=self.conn)
def _attr_check(self, xhref, xttl, xage, xbody):
self.assertEqual(self.msg.href, xhref)
self.assertEqual(self.msg.ttl, xttl)
self.assertEqual(self.msg.age, xage)
self.assertEqual(self.msg.body, xbody)
def test_attributes_match_expected(self):
self._attr_check(xhref=HREF, xttl=TTL, xage=AGE,
xbody={'name': 'chocolate'})
def test_repr_matches_expected(self):
self.assertEqual(repr(self.msg),
'<Message ttl:%s>' % (self.msg.ttl,))
def test_delete_works(self):
self.msg.delete()
def test_reload_works(self):
msg = mock_message.message(
href=HREF, ttl=TTL - 1, age=AGE + 1,
body={'name': 'vanilla'})
self.conn.get.return_value = mock.MagicMock()
self.conn.get.return_value.json.return_value = msg
self.msg.reload()
self._attr_check(xhref=HREF, xttl=TTL - 1, xage=AGE + 1,
xbody={'name': 'vanilla'})
def test_reload_after_delete_throws(self):
self.msg.delete()
self.assertRaises(AssertionError, self.msg.reload)
def test_delete_after_delete_throws(self):
self.msg.delete()
self.assertRaises(AssertionError, self.msg.delete)

View File

@ -0,0 +1,14 @@
# Copyright (c) 2013 Rackspace, 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.