Merge lp:~terrycojones/txfluiddb/add-slash-values-support-821418 into lp:~terrycojones/txfluiddb/add-exists-tests-for-namespaces-and-tags

Proposed by Terry Jones
Status: Needs review
Proposed branch: lp:~terrycojones/txfluiddb/add-slash-values-support-821418
Merge into: lp:~terrycojones/txfluiddb/add-exists-tests-for-namespaces-and-tags
Diff against target: 339 lines (+294/-3)
3 files modified
setup.py (+1/-1)
txfluiddb/client.py (+73/-0)
txfluiddb/test/test_client.py (+220/-2)
To merge this branch: bzr merge lp:~terrycojones/txfluiddb/add-slash-values-support-821418
Reviewer Review Type Date Requested Status
Terry Jones Pending
Review via email: mp+70650@code.launchpad.net

Description of the change

A simple approach to letting txFluidDB call the /values endpoint in Fluidinfo.

To post a comment you must log in.

Unmerged revisions

18. By Terry Jones

Bumped version number.

17. By Terry Jones

Added simple support for GET, PUT, DELETE on /values.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'setup.py'
2--- setup.py 2011-07-31 21:38:07 +0000
3+++ setup.py 2011-08-06 13:24:39 +0000
4@@ -5,7 +5,7 @@
5
6 setup(
7 name = 'txfluiddb',
8- version = '0.1.1',
9+ version = '0.1.2',
10 packages = ['txfluiddb'],
11 author = 'Tristan Seligmann',
12 )
13
14=== modified file 'txfluiddb/client.py'
15--- txfluiddb/client.py 2011-07-31 21:29:38 +0000
16+++ txfluiddb/client.py 2011-08-06 13:24:39 +0000
17@@ -436,6 +436,79 @@
18 collectionName = u'tag-values'
19
20
21+class Values(object):
22+ """
23+ Provides for operations on sets of tag values using the Fluidinfo
24+ /values endpoint.
25+ """
26+
27+
28+ def get(self, endpoint, query, tags):
29+ """
30+ Get the tag values matching a query.
31+
32+ @type endpoint: L{Endpoint}
33+ @param endpoint: The endpoint to operate through.
34+
35+ @type query: C{unicode}
36+ @param query: The query specifiying which Fluidinfo
37+ objects to operate on.
38+
39+ @type tags: C{list} of C{unicode}
40+ @param tags: The tags whose values are wanted.
41+
42+ @rtype: C{Deferred}
43+ """
44+ url = '%svalues?%s' % (
45+ endpoint.getRootURL(),
46+ urlencode({
47+ 'query' : query.encode('utf-8'),
48+ 'tag' : [tag.encode('utf-8') for tag in tags],
49+ }, doseq=True))
50+ return endpoint.submit(url=url, method='GET')
51+
52+
53+ def put(self, endpoint, payload):
54+ """
55+ Delete tag values matching queries.
56+
57+ @type endpoint: L{Endpoint}
58+ @param endpoint: The endpoint to operate through.
59+
60+ @type payload: C{dict}
61+ @param payload: A dictionary to be converted to JSON
62+ for the request payload to the /values endpoint.
63+
64+ @rtype: C{Deferred}
65+ """
66+ return endpoint.submit(url='%svalues' % endpoint.getRootURL(),
67+ method='PUT')
68+
69+
70+ def delete(self, endpoint, query, tags):
71+ """
72+ Delete the tag values matching a query.
73+
74+ @type endpoint: L{Endpoint}
75+ @param endpoint: The endpoint to operate through.
76+
77+ @type query: C{unicode}
78+ @param query: The query specifiying which Fluidinfo
79+ objects to operate on.
80+
81+ @type tags: C{list} of C{unicode}
82+ @param tags: The tags whose values should be deleted.
83+
84+ @rtype: C{Deferred}
85+ """
86+ url = '%svalues?%s' % (
87+ endpoint.getRootURL(),
88+ urlencode({
89+ 'query' : query.encode('utf-8'),
90+ 'tag' : [tag.encode('utf-8') for tag in tags],
91+ }, doseq=True))
92+ return endpoint.submit(url=url, method='DELETE')
93+
94
95 class BasicCreds(object):
96 """
97
98=== modified file 'txfluiddb/test/test_client.py'
99--- txfluiddb/test/test_client.py 2011-07-31 21:29:38 +0000
100+++ txfluiddb/test/test_client.py 2011-08-06 13:24:39 +0000
101@@ -1,11 +1,13 @@
102 from twisted.trial.unittest import TestCase
103 from twisted.internet.defer import succeed, fail
104
105+from urllib import splitquery
106+
107 import simplejson as json
108
109 from txfluiddb.errors import InvalidName
110-from txfluiddb.client import (
111- Namespace, Tag, Endpoint, _HasPath, Object, Blob, BasicCreds, loads)
112+from txfluiddb.client import (Namespace, Tag, Values, Endpoint, _HasPath,
113+ Object, Blob, BasicCreds, loads)
114 from txfluiddb.http import HTTPError
115
116
117@@ -623,6 +625,222 @@
118 return d
119
120
121+class ValuesTests(TestCase):
122+ """
123+ Tests for the /values URI endpoint on Fluidinfo.
124+ """
125+ def setUp(self):
126+ self.endpoint = MockEndpoint('http://fluiddb.url/')
127+ self.values = Values()
128+
129+
130+ def testGetMethodAndURI(self):
131+ """
132+ Check that the requested URI for GET starts with the /values
133+ endpoint and that the request method is correct.
134+ """
135+ self.endpoint.response = None
136+ d = self.values.get(self.endpoint, u'fake query', [u'fake tag'])
137+ self.assertEqual(self.endpoint.method, 'GET')
138+ self.assertTrue(
139+ self.endpoint.url.startswith('http://fluiddb.url/values'))
140+ return d
141+
142+
143+ def testGetTagCountAndContent(self):
144+ """
145+ Check that the requested URI has the expected number of tag=
146+ arguments and that the expected values are all present.
147+ """
148+ self.endpoint.response = None
149+ d = self.values.get(
150+ self.endpoint,
151+ query=u'has fun/eating',
152+ tags=[u'hey/you', u'who/me', u'yes/you'])
153+ self.assertEqual(3, self.endpoint.url.count('tag='))
154+ self.assertTrue(1, self.endpoint.url.count('tag=hey%2Fyou'))
155+ self.assertTrue(1, self.endpoint.url.count('tag=who%2Fme'))
156+ self.assertTrue(1, self.endpoint.url.count('tag=yes%2Fyou'))
157+ return d
158+
159+
160+ def testGetQueryCount(self):
161+ """
162+ Check that the requested URI has one query= argument, with the
163+ expected value.
164+ """
165+ self.endpoint.response = None
166+ d = self.values.get(
167+ self.endpoint,
168+ query=u'has fun/eating',
169+ tags=[u'hey/you'])
170+ self.assertEqual(1, self.endpoint.url.count('query='))
171+ self.assertTrue(1, self.endpoint.url.count('query=has+fun%2Feating'))
172+ return d
173+
174+
175+ def testGetTagURIEncoding(self):
176+ """
177+ Check that the requested tag name is properly UTF-8 and %-encoded
178+ in the request URI.
179+ """
180+ self.endpoint.response = None
181+ d = self.values.get(
182+ self.endpoint,
183+ query=u'has fun/eating',
184+ tags=[u'hey/y \xF2 u'])
185+ _, query = splitquery(self.endpoint.url)
186+ args = query.split('&')
187+ # Find the argument that starts with tag=
188+ if args[0].startswith('tag='):
189+ arg = args[0]
190+ else:
191+ arg = args[1]
192+ value = arg.split('=')[1]
193+ # The argument value should have its '/' %-encoded, the spaces
194+ # converted to '+', and the %-encoded UTF-8 of the unicode
195+ # \xF2 char.
196+ self.assertEqual('hey%2Fy+%C3%B2+u', value)
197+ return d
198+
199+
200+ def testGetQueryURIEncoding(self):
201+ """
202+ Check that the requested query is properly UTF-8 and %-encoded in
203+ the request URI.
204+ """
205+ response = {}
206+ self.endpoint.response = json.dumps(response)
207+ d = self.values.get(
208+ self.endpoint,
209+ query=u'joe/blow = "embedded/slash with \xF1"',
210+ tags=[u'hey/you'])
211+ _, query = splitquery(self.endpoint.url)
212+ args = query.split('&')
213+ # Find the argument that starts with query=
214+ if args[0].startswith('query='):
215+ arg = args[0]
216+ else:
217+ arg = args[1]
218+ value = arg.split('=')[1]
219+ # The argument value should have the '/', '=' and '"' %-encoded,
220+ # the spaces converted to '+', and the %-encoded UTF-8 of the
221+ # unicode \xF1 char.
222+ self.assertEqual('joe%2Fblow+%3D+%22embedded%2Fslash+with+%C3%B1%22',
223+ value)
224+ return d
225+
226+
227+ def testPutMethodAndURI(self):
228+ """
229+ Check that the requested URI for PUT has just the /values endpoint
230+ (the details of the PUT request are sent in the payload) and that
231+ the request method is correct.
232+ """
233+ self.endpoint.response = None
234+ d = self.values.put(self.endpoint, None)
235+ self.assertEqual(self.endpoint.method, 'PUT')
236+ self.assertEqual(self.endpoint.url, 'http://fluiddb.url/values')
237+ return d
238+
239+
240+ def testDeleteMethodAndURI(self):
241+ """
242+ Check that the requested URI for DELETE starts with the /values
243+ endpoint and that the request method is correct.
244+ """
245+ self.endpoint.response = None
246+ d = self.values.delete(self.endpoint, u'fake query', [u'fake tag'])
247+ self.assertEqual(self.endpoint.method, 'DELETE')
248+ self.assertTrue(
249+ self.endpoint.url.startswith('http://fluiddb.url/values'))
250+ return d
251+
252+
253+ def testDeleteTagCountAndContent(self):
254+ """
255+ Check that the requested URI has the expected number of tag=
256+ arguments and that the expected values are all present.
257+ """
258+ self.endpoint.response = None
259+ d = self.values.delete(
260+ self.endpoint,
261+ query=u'has fun/eating',
262+ tags=[u'hey/you', u'who/me', u'yes/you'])
263+ self.assertEqual(3, self.endpoint.url.count('tag='))
264+ self.assertTrue(1, self.endpoint.url.count('tag=hey%2Fyou'))
265+ self.assertTrue(1, self.endpoint.url.count('tag=who%2Fme'))
266+ self.assertTrue(1, self.endpoint.url.count('tag=yes%2Fyou'))
267+ return d
268+
269+
270+ def testDeleteQueryCount(self):
271+ """
272+ Check that the requested URI has one query= argument, with the
273+ expected value.
274+ """
275+ self.endpoint.response = None
276+ d = self.values.delete(
277+ self.endpoint,
278+ query=u'has fun/eating',
279+ tags=[u'hey/you'])
280+ self.assertEqual(1, self.endpoint.url.count('query='))
281+ self.assertTrue(1, self.endpoint.url.count('query=has+fun%2Feating'))
282+ return d
283+
284+
285+ def testDeleteTagURIEncoding(self):
286+ """
287+ Check that the requested tag name is properly UTF-8 and %-encoded
288+ in the request URI.
289+ """
290+ self.endpoint.response = None
291+ d = self.values.delete(
292+ self.endpoint,
293+ query=u'has fun/eating',
294+ tags=[u'hey/y \xF2 u'])
295+ _, query = splitquery(self.endpoint.url)
296+ args = query.split('&')
297+ # Find the argument that starts with tag=
298+ if args[0].startswith('tag='):
299+ arg = args[0]
300+ else:
301+ arg = args[1]
302+ value = arg.split('=')[1]
303+ # The argument value should have its '/' %-encoded, the spaces
304+ # converted to '+', and the %-encoded UTF-8 of the unicode
305+ # \xF2 char.
306+ self.assertEqual('hey%2Fy+%C3%B2+u', value)
307+ return d
308+
309+
310+ def testDeleteQueryURIEncoding(self):
311+ """
312+ Check that the requested query is properly UTF-8 and %-encoded in
313+ the request URI.
314+ """
315+ response = {}
316+ self.endpoint.response = json.dumps(response)
317+ d = self.values.delete(
318+ self.endpoint,
319+ query=u'joe/blow = "embedded/slash with \xF1"',
320+ tags=[u'hey/you'])
321+ _, query = splitquery(self.endpoint.url)
322+ args = query.split('&')
323+ # Find the argument that starts with query=
324+ if args[0].startswith('query='):
325+ arg = args[0]
326+ else:
327+ arg = args[1]
328+ value = arg.split('=')[1]
329+ # The argument value should have the '/', '=' and '"' %-encoded,
330+ # the spaces converted to '+', and the %-encoded UTF-8 of the
331+ # unicode \xF1 char.
332+ self.assertEqual('joe%2Fblow+%3D+%22embedded%2Fslash+with+%C3%B1%22',
333+ value)
334+ return d
335+
336+
337
338 class MockEndpoint(Endpoint):
339 """

Subscribers

People subscribed via source and target branches

to all changes: