api: return err_desc & reason in case of error (#24025)

This commit is contained in:
Lauréline Guérin 2019-10-31 09:42:22 +01:00
parent 191f24c865
commit 3bf36a1617
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
4 changed files with 190 additions and 49 deletions

26
chrono/api/utils.py Normal file
View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# chrono - agendas system
# Copyright (C) 2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from rest_framework.response import Response as DRFResponse
class Response(DRFResponse):
def __init__(self, data=None, *args, **kwargs):
# add reason for compatibility (https://dev.entrouvert.org/issues/24025)
if data is not None and 'err_class' in data:
data['reason'] = data['err_class']
super(Response, self).__init__(data=data, *args, **kwargs)

View File

@ -24,11 +24,14 @@ from django.shortcuts import get_object_or_404
from django.utils.dateparse import parse_date
from django.utils.encoding import force_text
from django.utils.timezone import now, make_aware, localtime
from django.utils.translation import gettext_noop
from django.utils.translation import ugettext_lazy as _
from rest_framework import permissions, serializers, status
from rest_framework.response import Response
from rest_framework.views import APIView
from chrono.api.utils import Response
from ..agendas.models import (Agenda, Event, Booking, MeetingType,
TimePeriod, Desk)
from ..interval import Intervals
@ -352,7 +355,8 @@ class Fillslots(APIView):
if not serializer.is_valid():
return Response({
'err': 1,
'reason': 'invalid payload',
'err_class': 'invalid payload',
'err_desc': _('invalid payload'),
'errors': serializer.errors
}, status=status.HTTP_400_BAD_REQUEST)
payload = serializer.validated_data
@ -362,7 +366,8 @@ class Fillslots(APIView):
if not slots:
return Response({
'err': 1,
'reason': 'slots list cannot be empty',
'err_class': 'slots list cannot be empty',
'err_desc': _('slots list cannot be empty'),
}, status=status.HTTP_400_BAD_REQUEST)
if 'count' in payload:
@ -374,7 +379,8 @@ class Fillslots(APIView):
except ValueError:
return Response({
'err': 1,
'reason': 'invalid value for count (%s)' % request.query_params['count'],
'err_class': 'invalid value for count (%s)' % request.query_params['count'],
'err_desc': _('invalid value for count (%s)') % request.query_params['count'],
}, status=status.HTTP_400_BAD_REQUEST)
else:
places_count = 1
@ -382,7 +388,8 @@ class Fillslots(APIView):
if places_count <= 0:
return Response({
'err': 1,
'reason': 'count cannot be less than or equal to zero'
'err_class': 'count cannot be less than or equal to zero',
'err_desc': _('count cannot be less than or equal to zero'),
}, status=status.HTTP_400_BAD_REQUEST)
to_cancel_booking = None
@ -393,7 +400,8 @@ class Fillslots(APIView):
except (ValueError, TypeError):
return Response({
'err': 1,
'reason': 'cancel_booking_id is not an integer'
'err_class': 'cancel_booking_id is not an integer',
'err_desc': _('cancel_booking_id is not an integer'),
}, status=status.HTTP_400_BAD_REQUEST)
if cancel_booking_id is not None:
@ -401,16 +409,20 @@ class Fillslots(APIView):
try:
to_cancel_booking = Booking.objects.get(pk=cancel_booking_id)
if to_cancel_booking.cancellation_datetime:
cancel_error = 'cancel booking: booking already cancelled'
cancel_error = gettext_noop('cancel booking: booking already cancelled')
else:
to_cancel_places_count = to_cancel_booking.secondary_booking_set.count() + 1
if places_count != to_cancel_places_count:
cancel_error = 'cancel booking: count is different'
cancel_error = gettext_noop('cancel booking: count is different')
except Booking.DoesNotExist:
cancel_error = 'cancel booking: booking does no exist'
cancel_error = gettext_noop('cancel booking: booking does no exist')
if cancel_error:
return Response({'err': 1, 'reason': cancel_error})
return Response({
'err': 1,
'err_class': cancel_error,
'err_desc': _(cancel_error),
})
extra_data = {}
for k, v in request.data.items():
@ -430,12 +442,14 @@ class Fillslots(APIView):
except ValueError:
return Response({
'err': 1,
'reason': 'invalid slot: %s' % slot,
'err_class': 'invalid slot: %s' % slot,
'err_desc': _('invalid slot: %s') % slot,
}, status=status.HTTP_400_BAD_REQUEST)
if meeting_type_id_ != meeting_type_id:
return Response({
'err': 1,
'reason': 'all slots must have the same meeting type id (%s)' % meeting_type_id
'err_class': 'all slots must have the same meeting type id (%s)' % meeting_type_id,
'err_desc': _('all slots must have the same meeting type id (%s)') % meeting_type_id,
}, status=status.HTTP_400_BAD_REQUEST)
datetimes.add(make_aware(datetime.datetime.strptime(datetime_str, '%Y-%m-%d-%H%M')))
@ -452,7 +466,11 @@ class Fillslots(APIView):
available_desk = Desk.objects.get(id=available_desk_id)
break
else:
return Response({'err': 1, 'reason': 'no more desk available'})
return Response({
'err': 1,
'err_class': 'no more desk available',
'err_desc': _('no more desk available'),
})
# all datetimes are free, book them in order
datetimes = list(datetimes)
@ -482,10 +500,18 @@ class Fillslots(APIView):
# in the waiting list.
in_waiting_list = True
if (event.waiting_list + places_count) > event.waiting_list_places:
return Response({'err': 1, 'reason': 'sold out'})
return Response({
'err': 1,
'err_class': 'sold out',
'err_desc': _('sold out'),
})
else:
if (event.booked_places + places_count) > event.places:
return Response({'err': 1, 'reason': 'sold out'})
return Response({
'err': 1,
'err_class': 'sold out',
'err_desc': _('sold out')
})
with transaction.atomic():
if to_cancel_booking:
@ -578,7 +604,11 @@ class CancelBooking(APIView):
def post(self, request, booking_pk=None, format=None):
booking = get_object_or_404(Booking, id=booking_pk)
if booking.cancellation_datetime:
response = {'err': 1, 'reason': 'already cancelled'}
response = {
'err': 1,
'err_class': 'already cancelled',
'err_desc': _('already cancelled'),
}
return Response(response)
booking.cancel()
response = {'err': 0, 'booking_id': booking.id}
@ -599,10 +629,18 @@ class AcceptBooking(APIView):
def post(self, request, booking_pk=None, format=None):
booking = get_object_or_404(Booking, id=booking_pk)
if booking.cancellation_datetime:
response = {'err': 1, 'reason': 'booking is cancelled'}
response = {
'err': 1,
'err_class': 'booking is cancelled',
'err_desc': _('booking is cancelled'),
}
return Response(response)
if not booking.in_waiting_list:
response = {'err': 2, 'reason': 'booking is not in waiting list'}
response = {
'err': 2,
'err_class': 'booking is not in waiting list',
'err_desc': _('booking is not in waiting list'),
}
return Response(response)
booking.accept()
response = {'err': 0, 'booking_id': booking.id}

View File

@ -316,12 +316,16 @@ def test_datetimes_api_meetings_agenda_short_time_periods(app, meetings_agenda,
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post(fillslot_url)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'no more desk available'
assert resp.json['reason'] == 'no more desk available' # legacy
assert resp.json['err_class'] == 'no more desk available'
assert resp.json['err_desc'] == 'no more desk available'
# booking the two slots fails too
fillslots_url = '/api/agenda/%s/fillslots/' % meeting_type.agenda.slug
resp = app.post(fillslots_url, params={'slots': two_slots})
assert resp.json['err'] == 1
assert resp.json['reason'] == 'no more desk available'
assert resp.json['reason'] == 'no more desk available' # legacy
assert resp.json['err_class'] == 'no more desk available'
assert resp.json['err_desc'] == 'no more desk available'
def test_booking_api(app, some_data, user):
agenda = Agenda.objects.filter(label=u'Foo bar')[0]
@ -377,7 +381,9 @@ def test_booking_api(app, some_data, user):
resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
params={'user_name': {'foo': 'bar'}}, status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'invalid payload'
assert resp.json['reason'] == 'invalid payload' # legacy
assert resp.json['err_class'] == 'invalid payload'
assert resp.json['err_desc'] == 'invalid payload'
assert len(resp.json['errors']) == 1
assert 'user_name' in resp.json['errors']
@ -541,21 +547,29 @@ def test_booking_api_fillslots(app, some_data, user):
params={'slots': events_ids,
'user_name': {'foo': 'bar'}}, status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'invalid payload'
assert resp.json['reason'] == 'invalid payload' # legacy
assert resp.json['err_class'] == 'invalid payload'
assert resp.json['err_desc'] == 'invalid payload'
assert len(resp.json['errors']) == 1
assert 'user_name' in resp.json['errors']
# empty or missing slots
resp = app.post_json('/api/agenda/%s/fillslots/' % agenda.id, params={'slots': []}, status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'slots list cannot be empty'
assert resp.json['reason'] == 'slots list cannot be empty' # legacy
assert resp.json['err_class'] == 'slots list cannot be empty'
assert resp.json['err_desc'] == 'slots list cannot be empty'
resp = app.post_json('/api/agenda/%s/fillslots/' % agenda.id, status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'slots list cannot be empty'
assert resp.json['reason'] == 'slots list cannot be empty' # legacy
assert resp.json['err_class'] == 'slots list cannot be empty'
assert resp.json['err_desc'] == 'slots list cannot be empty'
# invalid slots format
resp = app.post_json('/api/agenda/%s/fillslots/' % agenda.id, params={'slots': 'foobar'}, status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'invalid payload'
assert resp.json['reason'] == 'invalid payload' # legacy
assert resp.json['err_class'] == 'invalid payload'
assert resp.json['err_desc'] == 'invalid payload'
assert len(resp.json['errors']) == 1
assert 'slots' in resp.json['errors']
@ -592,7 +606,9 @@ def test_booking_api_meeting(app, meetings_agenda, user):
# try booking the same timeslot
resp2 = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_id))
assert resp2.json['err'] == 1
assert resp2.json['reason'] == 'no more desk available'
assert resp2.json['reason'] == 'no more desk available' # legacy
assert resp2.json['err_class'] == 'no more desk available'
assert resp2.json['err_desc'] == 'no more desk available'
# try booking another timeslot
event_id = resp.json['data'][3]['id']
@ -622,13 +638,17 @@ def test_booking_api_meeting_fillslots(app, meetings_agenda, user):
# try booking the same timeslots
resp2 = app.post('/api/agenda/%s/fillslots/' % agenda_id, params={'slots': slots})
assert resp2.json['err'] == 1
assert resp2.json['reason'] == 'no more desk available'
assert resp2.json['reason'] == 'no more desk available' # legacy
assert resp2.json['err_class'] == 'no more desk available'
assert resp2.json['err_desc'] == 'no more desk available'
# try booking partially free timeslots (one free, one busy)
nonfree_slots = [resp.json['data'][0]['id'], resp.json['data'][2]['id']]
resp2 = app.post('/api/agenda/%s/fillslots/' % agenda_id, params={'slots': nonfree_slots})
assert resp2.json['err'] == 1
assert resp2.json['reason'] == 'no more desk available'
assert resp2.json['reason'] == 'no more desk available' # legacy
assert resp2.json['err_class'] == 'no more desk available'
assert resp2.json['err_desc'] == 'no more desk available'
# booking other free timeslots
free_slots = [resp.json['data'][3]['id'], resp.json['data'][2]['id']]
@ -650,7 +670,9 @@ def test_booking_api_meeting_fillslots(app, meetings_agenda, user):
params={'slots': impossible_slots},
status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'all slots must have the same meeting type id (1)'
assert resp.json['reason'] == 'all slots must have the same meeting type id (1)' # legacy
assert resp.json['err_class'] == 'all slots must have the same meeting type id (1)'
assert resp.json['err_desc'] == 'all slots must have the same meeting type id (1)'
def test_booking_api_meeting_across_daylight_saving_time(app, meetings_agenda, user):
meetings_agenda.maximal_booking_delay = 365
@ -765,7 +787,9 @@ def test_booking_api_with_cancel_booking(app, some_data, user):
params={'cancel_booking_id': first_booking.pk}
)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'cancel booking: booking already cancelled'
assert resp.json['reason'] == 'cancel booking: booking already cancelled' # legacy
assert resp.json['err_class'] == 'cancel booking: booking already cancelled'
assert resp.json['err_desc'] == 'cancel booking: booking already cancelled'
assert Booking.objects.count() == 2
# Cancelling a non existent booking returns an error
@ -774,7 +798,9 @@ def test_booking_api_with_cancel_booking(app, some_data, user):
params={'cancel_booking_id': '-1'}
)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'cancel booking: booking does no exist'
assert resp.json['reason'] == 'cancel booking: booking does no exist' # legacy
assert resp.json['err_class'] == 'cancel booking: booking does no exist'
assert resp.json['err_desc'] == 'cancel booking: booking does no exist'
assert Booking.objects.count() == 2
# Cancelling booking with different count than new booking
@ -791,7 +817,9 @@ def test_booking_api_with_cancel_booking(app, some_data, user):
params={'cancel_booking_id': booking_id, 'count': 1}
)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'cancel booking: count is different'
assert resp.json['reason'] == 'cancel booking: count is different' # legacy
assert resp.json['err_class'] == 'cancel booking: count is different'
assert resp.json['err_desc'] == 'cancel booking: count is different'
assert Booking.objects.count() == 4
# cancel_booking_id must be an integer
@ -890,7 +918,9 @@ def test_soldout(app, some_data, user):
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id), status=200)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'sold out'
assert resp.json['reason'] == 'sold out' # legacy
assert resp.json['err_class'] == 'sold out'
assert resp.json['err_desc'] == 'sold out'
def test_status(app, some_data, user):
agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
@ -989,7 +1019,9 @@ def test_waiting_list_booking(app, some_data, user):
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id), status=200)
assert resp.json['err'] == 1
assert resp.json['reason'] == 'sold out'
assert resp.json['reason'] == 'sold out' # legacy
assert resp.json['err_class'] == 'sold out'
assert resp.json['err_desc'] == 'sold out'
def test_accept_booking(app, some_data, user):
agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
@ -1034,17 +1066,23 @@ def test_multiple_booking_api(app, some_data, user):
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post('/api/agenda/%s/fillslot/%s/?count=NaN' % (agenda.slug, event.id), status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == "invalid value for count (NaN)"
assert resp.json['reason'] == "invalid value for count (NaN)" # legacy
assert resp.json['err_class'] == "invalid value for count (NaN)"
assert resp.json['err_desc'] == "invalid value for count (NaN)"
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post('/api/agenda/%s/fillslot/%s/?count=0' % (agenda.slug, event.id), status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == "count cannot be less than or equal to zero"
assert resp.json['reason'] == "count cannot be less than or equal to zero" # legacy
assert resp.json['err_class'] == "count cannot be less than or equal to zero"
assert resp.json['err_desc'] == "count cannot be less than or equal to zero"
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post('/api/agenda/%s/fillslot/%s/?count=-3' % (agenda.slug, event.id), status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == "count cannot be less than or equal to zero"
assert resp.json['reason'] == "count cannot be less than or equal to zero" # legacy
assert resp.json['err_class'] == "count cannot be less than or equal to zero"
assert resp.json['err_desc'] == "count cannot be less than or equal to zero"
resp = app.post('/api/agenda/%s/fillslot/%s/?count=3' % (agenda.slug, event.id))
Booking.objects.get(id=resp.json['booking_id'])
@ -1071,7 +1109,9 @@ def test_multiple_booking_api(app, some_data, user):
# check waiting list overflow
resp = app.post('/api/agenda/%s/fillslot/%s/?count=5' % (agenda.slug, event.id))
assert resp.json['err'] == 1
assert resp.json['reason'] == 'sold out'
assert resp.json['reason'] == 'sold out' # legacy
assert resp.json['err_class'] == 'sold out'
assert resp.json['err_desc'] == 'sold out'
assert Event.objects.get(id=event.id).booked_places == 2
assert Event.objects.get(id=event.id).waiting_list == 5
@ -1088,7 +1128,9 @@ def test_multiple_booking_api(app, some_data, user):
resp = app.post('/api/agenda/%s/fillslot/%s/?count=5' % (agenda.slug, event.id))
assert resp.json['err'] == 1
assert resp.json['reason'] == 'sold out'
assert resp.json['reason'] == 'sold out' # legacy
assert resp.json['err_class'] == 'sold out'
assert resp.json['err_desc'] == 'sold out'
resp = app.post('/api/agenda/%s/fillslot/%s/?count=3' % (agenda.slug, event.id))
assert resp.json['err'] == 0
@ -1097,7 +1139,9 @@ def test_multiple_booking_api(app, some_data, user):
resp = app.post('/api/agenda/%s/fillslot/%s/?count=3' % (agenda.slug, event.id))
assert resp.json['err'] == 1
assert resp.json['reason'] == 'sold out'
assert resp.json['reason'] == 'sold out' # legacy
assert resp.json['err_class'] == 'sold out'
assert resp.json['err_desc'] == 'sold out'
resp = app.post('/api/agenda/%s/fillslot/%s/?count=2' % (agenda.slug, event.id))
assert resp.json['err'] == 0
@ -1115,12 +1159,16 @@ def test_multiple_booking_api_fillslots(app, some_data, user):
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.post('/api/agenda/%s/fillslots/?count=NaN' % agenda.slug, params={'slots': slots}, status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == "invalid value for count (NaN)"
assert resp.json['reason'] == "invalid value for count (NaN)" # legacy
assert resp.json['err_class'] == "invalid value for count (NaN)"
assert resp.json['err_desc'] == "invalid value for count (NaN)"
resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
params={'slots': slots, 'count': 'NaN'}, status=400)
assert resp.json['err'] == 1
assert resp.json['reason'] == "invalid payload"
assert resp.json['reason'] == "invalid payload" # legacy
assert resp.json['err_class'] == "invalid payload"
assert resp.json['err_desc'] == "invalid payload"
assert 'count' in resp.json['errors']
# get 3 places on 2 slots
@ -1164,7 +1212,9 @@ def test_multiple_booking_api_fillslots(app, some_data, user):
resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
params={'slots': slots, 'count': 5})
assert resp.json['err'] == 1
assert resp.json['reason'] == 'sold out'
assert resp.json['reason'] == 'sold out' # legacy
assert resp.json['err_class'] == 'sold out'
assert resp.json['err_desc'] == 'sold out'
for event in events:
assert Event.objects.get(id=event.id).booked_places == 2
assert Event.objects.get(id=event.id).waiting_list == 5
@ -1185,7 +1235,9 @@ def test_multiple_booking_api_fillslots(app, some_data, user):
resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
params={'slots': slots, 'count': 5})
assert resp.json['err'] == 1
assert resp.json['reason'] == 'sold out'
assert resp.json['reason'] == 'sold out' # legacy
assert resp.json['err_class'] == 'sold out'
assert resp.json['err_desc'] == 'sold out'
resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
params={'slots': slots, 'count': 3})
@ -1197,7 +1249,9 @@ def test_multiple_booking_api_fillslots(app, some_data, user):
resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
params={'slots': slots, 'count': 3})
assert resp.json['err'] == 1
assert resp.json['reason'] == 'sold out'
assert resp.json['reason'] == 'sold out' # legacy
assert resp.json['err_class'] == 'sold out'
assert resp.json['err_desc'] == 'sold out'
resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
params={'slots': slots, 'count': '2'})
@ -1308,7 +1362,9 @@ def test_agenda_meeting_api_multiple_desk(app, meetings_agenda, user):
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_id))
assert Booking.objects.count() == 2
assert resp.json['err'] == 1
assert resp.json['reason'] == 'no more desk available'
assert resp.json['reason'] == 'no more desk available' # legacy
assert resp.json['err_class'] == 'no more desk available'
assert resp.json['err_desc'] == 'no more desk available'
# cancel first booking and retry
resp = app.post(cancel_url)
@ -1345,7 +1401,9 @@ def test_agenda_meeting_api_multiple_desk(app, meetings_agenda, user):
# try booking the same timeslot again and fail
resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_id))
assert resp.json['err'] == 1
assert resp.json['reason'] == 'no more desk available'
assert resp.json['reason'] == 'no more desk available' # legacy
assert resp.json['err_class'] == 'no more desk available'
assert resp.json['err_desc'] == 'no more desk available'
# fill the agenda and make sure big O is O(1)
for idx, event_data in enumerate(resp2.json['data'][2:10]):
@ -1397,7 +1455,9 @@ def test_agenda_meeting_api_fillslots_multiple_desks(app, meetings_agenda, user)
# try booking again: no desk available
resp = app.post(fillslots_url, params={'slots': slots})
assert resp.json['err'] == 1
assert resp.json['reason'] == 'no more desk available'
assert resp.json['reason'] == 'no more desk available' # legacy
assert resp.json['err_class'] == 'no more desk available'
assert resp.json['err_desc'] == 'no more desk available'
assert get_free_places() == start_free_places - len(slots)
# cancel desk 1 booking
@ -1416,7 +1476,9 @@ def test_agenda_meeting_api_fillslots_multiple_desks(app, meetings_agenda, user)
# try booking the 3 slots again: no desk available, one slot is not fully available
resp = app.post(fillslots_url, params={'slots': slots})
assert resp.json['err'] == 1
assert resp.json['reason'] == 'no more desk available'
assert resp.json['reason'] == 'no more desk available' # legacy
assert resp.json['err_class'] == 'no more desk available'
assert resp.json['err_desc'] == 'no more desk available'
# cancel last signel slot booking, desk1 will be free
resp = app.post(cancel_url)

15
tests/test_api_utils.py Normal file
View File

@ -0,0 +1,15 @@
import pytest
from chrono.api.utils import Response
@pytest.mark.parametrize('data, expected', [
(None, None),
({}, {}),
({'reason': 'foo'}, {'reason': 'foo'}),
({'err_class': 'foo'}, {'err_class': 'foo', 'reason': 'foo'}),
({'bar': 'foo'}, {'bar': 'foo'}),
])
def test_response_data(data, expected):
resp = Response(data=data)
assert resp.data == expected