123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- from django.core.exceptions import PermissionDenied
- from django.http import Http404
- from django.test import TestCase
- from misago.core.apipatch import ApiPatch, InvalidAction
- class MockRequest(object):
- def __init__(self, data=None):
- self.data = data
- class MockObject(object):
- def __init__(self, pk):
- self.id = pk
- self.pk = pk
- class ApiPatchTests(TestCase):
- def test_add(self):
- """add method adds function to patch object"""
- patch = ApiPatch()
- def mock_function():
- pass
- patch.add('test-add', mock_function)
- self.assertEqual(len(patch._actions), 1)
- self.assertEqual(patch._actions[0]['op'], 'add')
- self.assertEqual(patch._actions[0]['path'], 'test-add')
- self.assertEqual(patch._actions[0]['handler'], mock_function)
- def test_remove(self):
- """remove method adds function to patch object"""
- patch = ApiPatch()
- def mock_function():
- pass
- patch.remove('test-remove', mock_function)
- self.assertEqual(len(patch._actions), 1)
- self.assertEqual(patch._actions[0]['op'], 'remove')
- self.assertEqual(patch._actions[0]['path'], 'test-remove')
- self.assertEqual(patch._actions[0]['handler'], mock_function)
- def test_replace(self):
- """replace method adds function to patch object"""
- patch = ApiPatch()
- def mock_function():
- pass
- patch.replace('test-replace', mock_function)
- self.assertEqual(len(patch._actions), 1)
- self.assertEqual(patch._actions[0]['op'], 'replace')
- self.assertEqual(patch._actions[0]['path'], 'test-replace')
- self.assertEqual(patch._actions[0]['handler'], mock_function)
- def test_validate_action(self):
- """validate_action method validates action dict"""
- patch = ApiPatch()
- VALID_ACTIONS = [
- {
- 'op': 'add',
- 'path': 'test',
- 'value': 42
- },
- {
- 'op': 'remove',
- 'path': 'other-test',
- 'value': 'Lorem'
- },
- {
- 'op': 'replace',
- 'path': 'false-test',
- 'value': None
- },
- ]
- for action in VALID_ACTIONS:
- patch.validate_action(action)
- # undefined op
- UNSUPPORTED_ACTIONS = ({}, {'op': ''}, {'no': 'op'}, )
- for action in UNSUPPORTED_ACTIONS:
- try:
- patch.validate_action(action)
- except InvalidAction as e:
- self.assertEqual(e.args[0], "undefined op")
- # unsupported op
- try:
- patch.validate_action({'op': 'nope'})
- except InvalidAction as e:
- self.assertEqual(e.args[0], '"nope" op is unsupported')
- # op lacking patch
- try:
- patch.validate_action({'op': 'add'})
- except InvalidAction as e:
- self.assertEqual(e.args[0], '"add" op has to specify path')
- # op lacking value
- try:
- patch.validate_action({
- 'op': 'add',
- 'path': 'yolo',
- })
- except InvalidAction as e:
- self.assertEqual(e.args[0], '"add" op has to specify value')
- # empty value is allowed
- try:
- patch.validate_action({
- 'op': 'add',
- 'path': 'yolo',
- 'value': '',
- })
- except InvalidAction as e:
- self.assertEqual(e.args[0], '"add" op has to specify value')
- def test_dispatch_action(self):
- """dispatch_action calls specified actions"""
- patch = ApiPatch()
- mock_target = MockObject(13)
- def action_a(request, target, value):
- self.assertEqual(request, 'request')
- self.assertEqual(target, mock_target)
- return {'a': value * 2, 'b': 111}
- patch.replace('abc', action_a)
- def action_b(request, target, value):
- self.assertEqual(request, 'request')
- self.assertEqual(target, mock_target)
- return {'b': value * 10}
- patch.replace('abc', action_b)
- def action_fail(request, target, value):
- self.fail("unrequired action was called")
- patch.add('c', action_fail)
- patch.remove('c', action_fail)
- patch.replace('c', action_fail)
- patch_dict = {'id': 123}
- patch.dispatch_action(
- patch_dict, 'request', mock_target, {
- 'op': 'replace',
- 'path': 'abc',
- 'value': 5,
- }
- )
- self.assertEqual(len(patch_dict), 3)
- self.assertEqual(patch_dict['id'], 123)
- self.assertEqual(patch_dict['a'], 10)
- self.assertEqual(patch_dict['b'], 50)
- def test_dispatch(self):
- """dispatch calls actions and returns response"""
- patch = ApiPatch()
- def action_error(request, target, value):
- if value == '404':
- raise Http404()
- if value == 'perm':
- raise PermissionDenied("yo ain't doing that!")
- patch.replace('error', action_error)
- def action_mutate(request, target, value):
- return {'value': value * 2}
- patch.replace('mutate', action_mutate)
- # dispatch requires list as an argument
- response = patch.dispatch(MockRequest({}), {})
- self.assertEqual(response.status_code, 400)
- self.assertEqual(response.data['detail'], "PATCH request should be list of operations")
- # valid dispatch
- response = patch.dispatch(
- MockRequest([
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 2,
- },
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 6,
- },
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 7,
- },
- ]), MockObject(13)
- )
- self.assertEqual(response.status_code, 200)
- self.assertEqual(len(response.data['detail']), 3)
- self.assertEqual(response.data['detail'][0], 'ok')
- self.assertEqual(response.data['detail'][1], 'ok')
- self.assertEqual(response.data['detail'][2], 'ok')
- self.assertEqual(response.data['id'], 13)
- self.assertEqual(response.data['value'], 14)
- # invalid action in dispatch
- response = patch.dispatch(
- MockRequest([
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 2,
- },
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 6,
- },
- {
- 'op': 'replace',
- },
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 7,
- },
- ]), MockObject(13)
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(len(response.data['detail']), 3)
- self.assertEqual(response.data['detail'][0], 'ok')
- self.assertEqual(response.data['detail'][1], 'ok')
- self.assertEqual(response.data['detail'][2], '"replace" op has to specify path')
- self.assertEqual(response.data['id'], 13)
- self.assertEqual(response.data['value'], 12)
- # action in dispatch raised 404
- response = patch.dispatch(
- MockRequest([
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 2,
- },
- {
- 'op': 'replace',
- 'path': 'error',
- 'value': '404',
- },
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 6,
- },
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 7,
- },
- ]), MockObject(13)
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(len(response.data['detail']), 2)
- self.assertEqual(response.data['detail'][0], 'ok')
- self.assertEqual(response.data['detail'][1], "NOT FOUND")
- self.assertEqual(response.data['id'], 13)
- self.assertEqual(response.data['value'], 4)
- # action in dispatch raised perm denied
- response = patch.dispatch(
- MockRequest([
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 2,
- },
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 6,
- },
- {
- 'op': 'replace',
- 'path': 'mutate',
- 'value': 9,
- },
- {
- 'op': 'replace',
- 'path': 'error',
- 'value': 'perm',
- },
- ]), MockObject(13)
- )
- self.assertEqual(response.status_code, 400)
- self.assertEqual(len(response.data['detail']), 4)
- self.assertEqual(response.data['detail'][0], 'ok')
- self.assertEqual(response.data['detail'][1], 'ok')
- self.assertEqual(response.data['detail'][2], 'ok')
- self.assertEqual(response.data['detail'][3], "yo ain't doing that!")
- self.assertEqual(response.data['id'], 13)
- self.assertEqual(response.data['value'], 18)
|