Skip to content

Commit f6a4306

Browse files
committed
gcloud.datastore.connection: 27% -> 52% coverage.
1 parent 02dfc77 commit f6a4306

1 file changed

Lines changed: 281 additions & 0 deletions

File tree

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
import unittest2
2+
3+
class TestConnection(unittest2.TestCase):
4+
5+
def _getTargetClass(self):
6+
from gcloud.datastore.connection import Connection
7+
return Connection
8+
9+
def _makeOne(self, *args, **kw):
10+
return self._getTargetClass()(*args, **kw)
11+
12+
def test_ctor_defaults(self):
13+
conn = self._makeOne()
14+
self.assertEqual(conn.credentials, None)
15+
16+
def test_ctor_explicit(self):
17+
creds = object()
18+
conn = self._makeOne(creds)
19+
self.assertTrue(conn.credentials is creds)
20+
21+
def test_http_w_existing(self):
22+
conn = self._makeOne()
23+
conn._http = http = object()
24+
self.assertTrue(conn.http is http)
25+
26+
def test_http_wo_creds(self):
27+
from httplib2 import Http
28+
conn = self._makeOne()
29+
self.assertTrue(isinstance(conn.http, Http))
30+
31+
def test_http_w_creds(self):
32+
from httplib2 import Http
33+
authorized = object()
34+
class Creds(object):
35+
def authorize(self, http):
36+
self._called_with = http
37+
return authorized
38+
creds = Creds()
39+
conn = self._makeOne(creds)
40+
self.assertTrue(conn.http is authorized)
41+
self.assertTrue(isinstance(creds._called_with, Http))
42+
43+
def test__request_w_200(self):
44+
DATASET_ID = 'DATASET'
45+
METHOD = 'METHOD'
46+
DATA = 'DATA'
47+
conn = self._makeOne()
48+
URI = '/'.join([conn.API_BASE_URL,
49+
'datastore',
50+
conn.API_VERSION,
51+
'datasets',
52+
DATASET_ID,
53+
METHOD,
54+
])
55+
http = conn._http = Http({'status': '200'}, 'CONTENT')
56+
self.assertEqual(conn._request(DATASET_ID, METHOD, DATA), 'CONTENT')
57+
self.assertEqual(http._called_with,
58+
{'uri': URI,
59+
'method': 'POST',
60+
'headers':
61+
{'Content-Type': 'application/x-protobuf',
62+
'Content-Length': '4',
63+
},
64+
'body': DATA,
65+
})
66+
67+
def test__request_not_200(self):
68+
DATASET_ID = 'DATASET'
69+
METHOD = 'METHOD'
70+
DATA = 'DATA'
71+
conn = self._makeOne()
72+
http = conn._http = Http({'status': '400'}, 'Bad Request')
73+
with self.assertRaises(Exception) as e:
74+
conn._request(DATASET_ID, METHOD, DATA)
75+
self.assertEqual(str(e.exception),
76+
'Request failed. Error was: Bad Request')
77+
78+
def test__rpc(self):
79+
80+
class ReqPB(object):
81+
def SerializeToString(self):
82+
return 'REQPB'
83+
84+
class RspPB(object):
85+
def __init__(self, pb):
86+
self._pb = pb
87+
@classmethod
88+
def FromString(cls, pb):
89+
return cls(pb)
90+
91+
DATASET_ID = 'DATASET'
92+
METHOD = 'METHOD'
93+
conn = self._makeOne()
94+
URI = '/'.join([conn.API_BASE_URL,
95+
'datastore',
96+
conn.API_VERSION,
97+
'datasets',
98+
DATASET_ID,
99+
METHOD,
100+
])
101+
http = conn._http = Http({'status': '200'}, 'CONTENT')
102+
response = conn._rpc(DATASET_ID, METHOD, ReqPB(), RspPB)
103+
self.assertTrue(isinstance(response, RspPB))
104+
self.assertEqual(response._pb, 'CONTENT')
105+
self.assertEqual(http._called_with,
106+
{'uri': URI,
107+
'method': 'POST',
108+
'headers':
109+
{'Content-Type': 'application/x-protobuf',
110+
'Content-Length': '5',
111+
},
112+
'body': 'REQPB',
113+
})
114+
115+
def test_build_api_url_w_default_base_version(self):
116+
DATASET_ID = 'DATASET'
117+
METHOD = 'METHOD'
118+
klass = self._getTargetClass()
119+
URI = '/'.join([klass.API_BASE_URL,
120+
'datastore',
121+
klass.API_VERSION,
122+
'datasets',
123+
DATASET_ID,
124+
METHOD,
125+
])
126+
self.assertEqual(klass.build_api_url(DATASET_ID, METHOD), URI)
127+
128+
def test_build_api_url_w_explicit_base_version(self):
129+
BASE = 'http://example.com/'
130+
VER = '3.1415926'
131+
DATASET_ID = 'DATASET'
132+
METHOD = 'METHOD'
133+
klass = self._getTargetClass()
134+
URI = '/'.join([BASE,
135+
'datastore',
136+
VER,
137+
'datasets',
138+
DATASET_ID,
139+
METHOD,
140+
])
141+
self.assertEqual(klass.build_api_url(DATASET_ID, METHOD, BASE, VER),
142+
URI)
143+
144+
def test_transaction_getter_unset(self):
145+
conn = self._makeOne()
146+
self.assertTrue(conn.transaction() is None)
147+
148+
def test_transaction_setter(self):
149+
xact = object()
150+
conn = self._makeOne()
151+
self.assertTrue(conn.transaction(xact) is conn)
152+
self.assertTrue(conn.transaction() is xact)
153+
154+
def test_mutation_wo_transaction(self):
155+
from gcloud.datastore.connection import datastore_pb
156+
class Mutation(object):
157+
pass
158+
conn = self._makeOne()
159+
with _Monkey(datastore_pb, Mutation=Mutation):
160+
found = conn.mutation()
161+
self.assertTrue(isinstance(found, Mutation))
162+
163+
def test_mutation_w_transaction(self):
164+
class Mutation(object):
165+
pass
166+
class Xact(object):
167+
def mutation(self):
168+
return Mutation()
169+
conn = self._makeOne()
170+
conn.transaction(Xact())
171+
found = conn.mutation()
172+
self.assertTrue(isinstance(found, Mutation))
173+
174+
def test_dataset(self):
175+
DATASET_ID = 'DATASET'
176+
conn = self._makeOne()
177+
dataset = conn.dataset(DATASET_ID)
178+
self.assertTrue(dataset.connection() is conn)
179+
self.assertEqual(dataset.id(), DATASET_ID)
180+
181+
def test_begin_transaction_already(self):
182+
DATASET_ID = 'DATASET'
183+
conn = self._makeOne()
184+
conn.transaction(object())
185+
self.assertRaises(ValueError, conn.begin_transaction, DATASET_ID)
186+
187+
def test_begin_transaction_default_serialize(self):
188+
from gcloud.datastore.connection import datastore_pb
189+
xact = object()
190+
class RspPB(object):
191+
def __init__(self, pb):
192+
self._pb = pb
193+
self.transaction = xact
194+
@classmethod
195+
def FromString(cls, pb):
196+
return cls(pb)
197+
198+
DATASET_ID = 'DATASET'
199+
TRANSACTION = 'TRANSACTION'
200+
rsp_pb = datastore_pb.BeginTransactionResponse()
201+
rsp_pb.transaction = TRANSACTION
202+
conn = self._makeOne()
203+
URI = '/'.join([conn.API_BASE_URL,
204+
'datastore',
205+
conn.API_VERSION,
206+
'datasets',
207+
DATASET_ID,
208+
'beginTransaction',
209+
])
210+
http = conn._http = Http({'status': '200'}, rsp_pb.SerializeToString())
211+
self.assertEqual(conn.begin_transaction(DATASET_ID), TRANSACTION)
212+
self.assertEqual(http._called_with,
213+
{'uri': URI,
214+
'method': 'POST',
215+
'headers':
216+
{'Content-Type': 'application/x-protobuf',
217+
'Content-Length': '2',
218+
},
219+
'body': b'\x08\x00', # SNAPSHOT
220+
})
221+
222+
def test_begin_transaction_explicit_serialize(self):
223+
from gcloud.datastore.connection import datastore_pb
224+
xact = object()
225+
class RspPB(object):
226+
def __init__(self, pb):
227+
self._pb = pb
228+
self.transaction = xact
229+
@classmethod
230+
def FromString(cls, pb):
231+
return cls(pb)
232+
233+
DATASET_ID = 'DATASET'
234+
TRANSACTION = 'TRANSACTION'
235+
rsp_pb = datastore_pb.BeginTransactionResponse()
236+
rsp_pb.transaction = TRANSACTION
237+
conn = self._makeOne()
238+
URI = '/'.join([conn.API_BASE_URL,
239+
'datastore',
240+
conn.API_VERSION,
241+
'datasets',
242+
DATASET_ID,
243+
'beginTransaction',
244+
])
245+
http = conn._http = Http({'status': '200'}, rsp_pb.SerializeToString())
246+
self.assertEqual(conn.begin_transaction(DATASET_ID, True), TRANSACTION)
247+
self.assertEqual(http._called_with,
248+
{'uri': URI,
249+
'method': 'POST',
250+
'headers':
251+
{'Content-Type': 'application/x-protobuf',
252+
'Content-Length': '2',
253+
},
254+
'body': b'\x08\x01', # SERIALIZABLE
255+
})
256+
257+
class Http(object):
258+
259+
def __init__(self, headers, content):
260+
self._headers = headers
261+
self._content = content
262+
263+
def request(self, **kw):
264+
self._called_with = kw
265+
return self._headers, self._content
266+
267+
268+
class _Monkey(object):
269+
# context-manager for replacing module names in the scope of a test.
270+
def __init__(self, module, **kw):
271+
self.module = module
272+
self.to_restore = dict([(key, getattr(module, key)) for key in kw])
273+
for key, value in kw.items():
274+
setattr(module, key, value)
275+
276+
def __enter__(self):
277+
return self
278+
279+
def __exit__(self, exc_type, exc_val, exc_tb):
280+
for key, value in self.to_restore.items():
281+
setattr(self.module, key, value)

0 commit comments

Comments
 (0)