Skip to content
This repository has been archived by the owner on Oct 11, 2022. It is now read-only.

Commit

Permalink
Merge 67f5903 into 50d5b14
Browse files Browse the repository at this point in the history
  • Loading branch information
Rudi committed Feb 9, 2015
2 parents 50d5b14 + 67f5903 commit daf0b9f
Show file tree
Hide file tree
Showing 5 changed files with 471 additions and 10 deletions.
17 changes: 14 additions & 3 deletions .travis.yml
Expand Up @@ -2,17 +2,28 @@ language: python
python:
- "2.6"
- "2.7"
services:
- riak
before_install:
# we need the protobuf-compiler so we can install Riak client libraries
# We need Riak 1.4, so we add Basho's repo and install from there.
# Additionally, we remove existing Riak data and replace the config with ours.
- sudo service riak stop
- "curl http://apt.basho.com/gpg/basho.apt.key | sudo apt-key add -"
- sudo bash -c "echo deb http://apt.basho.com $(lsb_release -sc) main > /etc/apt/sources.list.d/basho.list"
- sudo apt-get -qq update
- sudo apt-get install -qq -y --force-yes riak=1.4.12-1
- sudo rm -rf /var/lib/riak/*
- sudo cp utils/app.config /etc/riak/app.config
- sudo service riak start
# We need the protobuf-compiler so we can install Riak client libraries.
- sudo apt-get install -qq protobuf-compiler
install:
- "pip install -r requirements.txt --use-wheel"
- "pip install coveralls --use-wheel"
- "pip install -e ."
# We need to install the verified fake as well so we can test it.
- "pip install -e ./verified-fake"
# To see what version of Riak we're running and check that it's happy.
- riak version
- riak-admin member-status
script:
- coverage run --source=go_contacts `which trial` go_contacts
after_success:
Expand Down
28 changes: 26 additions & 2 deletions go_contacts/backends/contacts.py
Expand Up @@ -9,6 +9,7 @@

from go.vumitools.contact import (
ContactStore, ContactNotFoundError, Contact)
from go.vumitools.contact.models import normalize_addr

from go_api.collections import ICollection
from go_api.collections.errors import (
Expand Down Expand Up @@ -91,6 +92,28 @@ def all_keys(self):
"""
raise NotImplementedError()

@inlineCallbacks
def _get_contacts_by_query(self, query):
try:
[field, value] = query.split('=')
except ValueError:
raise CollectionUsageError(
"Query must be of the form 'field=value'")
if field not in Contact.ADDRESS_FIELDS:
raise CollectionUsageError(
"Query field must be one of: %s" %
sorted(Contact.ADDRESS_FIELDS))

value = normalize_addr(field, value)
try:
contact = yield self.contact_store.contact_for_addr_field(
field, value, create=False)
except ContactNotFoundError:
raise CollectionObjectNotFound(
'Contact with %s %s' % (field, value))

returnValue([contact_to_dict(contact)])

def stream(self, query):
"""
Return a :class:`PausingDeferredQueue` of the objects in the
Expand Down Expand Up @@ -137,7 +160,7 @@ def page(self, cursor, max_results, query):
to ``None`` if no limit was specified.
:param unicode query:
Search term requested through the API. Defaults to ``None`` if no
search term was requested.
search term was requested. Query must be of the form `field=value`.
:return:
(cursor, data). ``cursor`` is an opaque string that refers to the
Expand All @@ -146,7 +169,8 @@ def page(self, cursor, max_results, query):
:rtype: tuple
"""
if query is not None:
raise CollectionUsageError("query parameter not supported")
contacts = yield self._get_contacts_by_query(query)
returnValue((None, contacts))

max_results = max_results or float('inf')
max_results = min(max_results, self.max_contacts_per_page)
Expand Down
56 changes: 52 additions & 4 deletions go_contacts/tests/server_contacts_test_mixin.py
Expand Up @@ -407,13 +407,61 @@ def test_page_bad_cursor(self):
u"Riak error, possible invalid cursor: u'bad-id'")

@inlineCallbacks
def test_page_query(self):
def test_page_invalid_query_format(self):
"""
If a query parameter is supplied, a CollectionUsageError should be
thrown, as querys are not yet supported.
If an invalid query format is supplied, a CollectionUsageError should
be thrown.
"""
api = self.mk_api()
code, data = yield self.request(api, 'GET', '/contacts/?query=foo')
self.assertEqual(code, 400)
self.assertEqual(data.get(u'status_code'), 400)
self.assertEqual(data.get(u'reason'), u'query parameter not supported')
self.assertEqual(
data.get(u'reason'), u"Query must be of the form 'field=value'")

@inlineCallbacks
def test_page_invalid_query_parameter(self):
"""
If an invalid query parameter is supplied, a CollectionUsageError
should be thrown.
"""
api = self.mk_api()
code, data = yield self.request(
api, 'GET', '/contacts/?query="foo=bar"')
self.assertEqual(code, 400)
self.assertEqual(data.get(u'status_code'), 400)
self.assertEqual(
data.get(u'reason'),
u"Query field must be one of: ['bbm_pin', 'facebook_id', "
"'gtalk_id', 'msisdn', 'mxit_id', 'twitter_handle', 'wechat_id']")

@inlineCallbacks
def test_page_with_query(self):
"""
If a valid query is supplied, the contact should be returned
"""
api = self.mk_api()
contact = yield self.create_contact(api, name=u'Bob', msisdn=u'+12345')
yield self.create_contact(api, name=u'Sue', msisdn=u'+54321')

code, data = yield self.request(
api, 'GET', '/contacts/?query=msisdn=%2B12345')
self.assertEqual(code, 200)
self.assertEqual(data.get(u'cursor'), None)
self.assertEqual(data.get('data'), [contact])

@inlineCallbacks
def test_page_with_query_no_contact_found(self):
"""
If no contact exists that fulfills the query, a ContactNotFoundError
should be thrown.
"""
api = self.mk_api()

code, data = yield self.request(
api, 'GET', '/contacts/?query=msisdn=bar')
self.assertEqual(code, 400)
self.assertEqual(data.get(u'status_code'), 400)
self.assertEqual(
data.get('reason'),
u"Object u'Contact with msisdn +bar' not found.")

0 comments on commit daf0b9f

Please sign in to comment.