Skip to content

Commit cfdcde3

Browse files
author
Kevin McDonald
committed
Adds more REST tests, use request.headers as query params
1 parent ed4c62e commit cfdcde3

File tree

3 files changed

+110
-25
lines changed

3 files changed

+110
-25
lines changed

SoftLayer/transports.py

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ def __call__(self, request):
120120
headers[header_name] = {'id': request.identifier}
121121

122122
if request.mask is not None:
123-
headers.update(_format_object_mask(request.mask, request.service))
123+
headers.update(_format_object_mask_xmlrpc(request.mask,
124+
request.service))
124125

125126
if request.filter is not None:
126127
headers['%sObjectFilter' % request.service] = request.filter
@@ -215,10 +216,9 @@ def __call__(self, request):
215216
'application/json')
216217
request.transport_headers.setdefault('User-Agent', self.user_agent)
217218

218-
params = {}
219-
body = {}
219+
params = request.headers.copy()
220220
if request.mask:
221-
params['objectMask'] = request.mask
221+
params['objectMask'] = _format_object_mask(request.mask)
222222

223223
if request.limit:
224224
params['limit'] = request.limit
@@ -229,26 +229,30 @@ def __call__(self, request):
229229
if request.filter:
230230
params['objectFilter'] = json.dumps(request.filter)
231231

232-
if request.args:
233-
body['parameters'] = json.dumps(request.args)
234-
235232
auth = None
236233
if request.transport_user:
237234
auth = requests.auth.HTTPBasicAuth(
238235
request.transport_user,
239236
request.transport_password,
240237
)
241238

242-
raw_body = None
243-
if body:
244-
raw_body = json.dumps(body)
245-
246239
method = REST_SPECIAL_METHODS.get(request.method)
247240
is_special_method = True
248241
if method is None:
249242
is_special_method = False
250243
method = 'GET'
251244

245+
body = {}
246+
if request.args:
247+
# NOTE(kmcdonald): force POST when there are arguments because
248+
# the request body is ignored otherwise.
249+
method = 'POST'
250+
body['parameters'] = request.args
251+
252+
raw_body = None
253+
if body:
254+
raw_body = json.dumps(body)
255+
252256
url_parts = [self.endpoint_url, request.service]
253257
if request.identifier is not None:
254258
url_parts.append(str(request.identifier))
@@ -258,14 +262,12 @@ def __call__(self, request):
258262
if request.method is not None and not is_special_method:
259263
url_parts.append(request.method)
260264

261-
for arg in request.args:
262-
url_parts.append(str(arg))
263-
264265
url = '%s.%s' % ('/'.join(url_parts), 'json')
265266

266267
LOGGER.debug("=== REQUEST ===")
267268
LOGGER.info(url)
268269
LOGGER.debug(request.transport_headers)
270+
LOGGER.debug(raw_body)
269271
try:
270272
resp = requests.request(method, url,
271273
auth=auth,
@@ -347,7 +349,7 @@ def _proxies_dict(proxy):
347349
return {'http': proxy, 'https': proxy}
348350

349351

350-
def _format_object_mask(objectmask, service):
352+
def _format_object_mask_xmlrpc(objectmask, service):
351353
"""Format new and old style object masks into proper headers.
352354
353355
:param objectmask: a string- or dict-based object mask
@@ -358,10 +360,22 @@ def _format_object_mask(objectmask, service):
358360
mheader = '%sObjectMask' % service
359361
else:
360362
mheader = 'SoftLayer_ObjectMask'
361-
362-
objectmask = objectmask.strip()
363-
if (not objectmask.startswith('mask') and
364-
not objectmask.startswith('[')):
365-
objectmask = "mask[%s]" % objectmask
363+
objectmask = _format_object_mask(objectmask)
366364

367365
return {mheader: {'mask': objectmask}}
366+
367+
368+
def _format_object_mask(objectmask):
369+
"""Format the new style object mask.
370+
371+
This wraps the user mask with mask[USER_MASK] if it does not already
372+
have one. This makes it slightly easier for users.
373+
374+
:param objectmask: a string-based object mask
375+
376+
"""
377+
objectmask = objectmask.strip()
378+
if (not objectmask.startswith('mask') and
379+
not objectmask.startswith('[')):
380+
objectmask = "mask[%s]" % objectmask
381+
return objectmask

docs/dev/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,12 @@ versions every time you push new code.
7575

7676
Using tox to running the tests in multiple environments can be very time
7777
consuming. If you wish to quickly run the tests in your own environment, you
78-
may do so using `nose <https://nose.readthedocs.org>`_. The command to do that
78+
may do so using `py.test <http://pytest.org/>`_. The command to do that
7979
is:
8080

8181
::
8282

83-
nosetests
83+
py.test tests
8484

8585

8686
Documentation

tests/transport_tests.py

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,17 +372,88 @@ def test_with_args(self, request):
372372

373373
self.assertEqual(resp, {})
374374
request.assert_called_with(
375-
'GET',
376-
'http://something.com/SoftLayer_Service/getObject/test/1.json',
375+
'POST',
376+
'http://something.com/SoftLayer_Service/getObject.json',
377377
headers=mock.ANY,
378378
auth=None,
379-
data='{"parameters": "[\\"test\\", 1]"}',
379+
data='{"parameters": ["test", 1]}',
380380
params={},
381381
verify=True,
382382
cert=None,
383383
proxies=None,
384384
timeout=None)
385385

386+
387+
@mock.patch('requests.request')
388+
def test_with_filter(self, request):
389+
request().content = '{}'
390+
391+
req = transports.Request()
392+
req.service = 'SoftLayer_Service'
393+
req.method = 'getObject'
394+
req.filter = {'TYPE': {'attribute': {'operation': '^= prefix'}}}
395+
396+
resp = self.transport(req)
397+
398+
self.assertEqual(resp, {})
399+
request.assert_called_with(
400+
'GET',
401+
'http://something.com/SoftLayer_Service/getObject.json',
402+
params={'objectFilter':
403+
'{"TYPE": {"attribute": {"operation": "^= prefix"}}}'},
404+
headers=mock.ANY,
405+
auth=None,
406+
data=None,
407+
verify=True,
408+
cert=None,
409+
proxies=None,
410+
timeout=None)
411+
412+
@mock.patch('requests.request')
413+
def test_with_mask(self, request):
414+
request().content = '{}'
415+
416+
req = transports.Request()
417+
req.service = 'SoftLayer_Service'
418+
req.method = 'getObject'
419+
req.mask = 'id,property'
420+
421+
resp = self.transport(req)
422+
423+
self.assertEqual(resp, {})
424+
request.assert_called_with(
425+
'GET',
426+
'http://something.com/SoftLayer_Service/getObject.json',
427+
params={'objectMask': 'mask[id,property]'},
428+
headers=mock.ANY,
429+
auth=None,
430+
data=None,
431+
verify=True,
432+
cert=None,
433+
proxies=None,
434+
timeout=None)
435+
436+
# Now test with mask[] prefix
437+
req = transports.Request()
438+
req.service = 'SoftLayer_Service'
439+
req.method = 'getObject'
440+
req.mask = 'mask[id,property]'
441+
442+
resp = self.transport(req)
443+
444+
self.assertEqual(resp, {})
445+
request.assert_called_with(
446+
'GET',
447+
'http://something.com/SoftLayer_Service/getObject.json',
448+
params={'objectMask': 'mask[id,property]'},
449+
headers=mock.ANY,
450+
auth=None,
451+
data=None,
452+
verify=True,
453+
cert=None,
454+
proxies=None,
455+
timeout=None)
456+
386457
@mock.patch('requests.request')
387458
def test_unknown_error(self, request):
388459
e = requests.RequestException('error')

0 commit comments

Comments
 (0)