Projet

Général

Profil

0001-api-return-err_desc-reason-in-case-of-error-24025.patch

Lauréline Guérin, 31 octobre 2019 16:58

Télécharger (27,8 ko)

Voir les différences:

Subject: [PATCH] api: return err_desc & reason in case of error (#24025)

 chrono/api/utils.py     |  26 +++++++++
 chrono/api/views.py     |  74 ++++++++++++++++++------
 tests/test_api.py       | 124 ++++++++++++++++++++++++++++++----------
 tests/test_api_utils.py |  15 +++++
 4 files changed, 190 insertions(+), 49 deletions(-)
 create mode 100644 chrono/api/utils.py
 create mode 100644 tests/test_api_utils.py
chrono/api/utils.py
1
# -*- coding: utf-8 -*-
2
# chrono - agendas system
3
# Copyright (C) 2019  Entr'ouvert
4
#
5
# This program is free software: you can redistribute it and/or modify it
6
# under the terms of the GNU Affero General Public License as published
7
# by the Free Software Foundation, either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU Affero General Public License for more details.
14
#
15
# You should have received a copy of the GNU Affero General Public License
16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17

  
18
from rest_framework.response import Response as DRFResponse
19

  
20

  
21
class Response(DRFResponse):
22
    def __init__(self, data=None, *args, **kwargs):
23
        # add reason for compatibility (https://dev.entrouvert.org/issues/24025)
24
        if data is not None and 'err_class' in data:
25
            data['reason'] = data['err_class']
26
        super(Response, self).__init__(data=data, *args, **kwargs)
chrono/api/views.py
24 24
from django.utils.dateparse import parse_date
25 25
from django.utils.encoding import force_text
26 26
from django.utils.timezone import now, make_aware, localtime
27
from django.utils.translation import gettext_noop
28
from django.utils.translation import ugettext_lazy as _
27 29

  
28 30
from rest_framework import permissions, serializers, status
29
from rest_framework.response import Response
31

  
30 32
from rest_framework.views import APIView
31 33

  
34
from chrono.api.utils import Response
32 35
from ..agendas.models import (Agenda, Event, Booking, MeetingType,
33 36
                              TimePeriod, Desk)
34 37
from ..interval import Intervals
......
351 354
        if not serializer.is_valid():
352 355
            return Response({
353 356
                'err': 1,
354
                'reason': 'invalid payload',
357
                'err_class': 'invalid payload',
358
                'err_desc': _('invalid payload'),
355 359
                'errors': serializer.errors
356 360
            }, status=status.HTTP_400_BAD_REQUEST)
357 361
        payload = serializer.validated_data
......
361 365
        if not slots:
362 366
            return Response({
363 367
                'err': 1,
364
                'reason': 'slots list cannot be empty',
368
                'err_class': 'slots list cannot be empty',
369
                'err_desc': _('slots list cannot be empty'),
365 370
            }, status=status.HTTP_400_BAD_REQUEST)
366 371

  
367 372
        if 'count' in payload:
......
373 378
            except ValueError:
374 379
                return Response({
375 380
                    'err': 1,
376
                    'reason': 'invalid value for count (%s)' % request.query_params['count'],
381
                    'err_class': 'invalid value for count (%s)' % request.query_params['count'],
382
                    'err_desc': _('invalid value for count (%s)') % request.query_params['count'],
377 383
                }, status=status.HTTP_400_BAD_REQUEST)
378 384
        else:
379 385
            places_count = 1
......
381 387
        if places_count <= 0:
382 388
            return Response({
383 389
                'err': 1,
384
                'reason': 'count cannot be less than or equal to zero'
390
                'err_class': 'count cannot be less than or equal to zero',
391
                'err_desc': _('count cannot be less than or equal to zero'),
385 392
            }, status=status.HTTP_400_BAD_REQUEST)
386 393

  
387 394
        to_cancel_booking = None
......
392 399
            except (ValueError, TypeError):
393 400
                return Response({
394 401
                    'err': 1,
395
                    'reason': 'cancel_booking_id is not an integer'
402
                    'err_class': 'cancel_booking_id is not an integer',
403
                    'err_desc': _('cancel_booking_id is not an integer'),
396 404
                }, status=status.HTTP_400_BAD_REQUEST)
397 405

  
398 406
        if cancel_booking_id is not None:
......
400 408
            try:
401 409
                to_cancel_booking = Booking.objects.get(pk=cancel_booking_id)
402 410
                if to_cancel_booking.cancellation_datetime:
403
                    cancel_error = 'cancel booking: booking already cancelled'
411
                    cancel_error = gettext_noop('cancel booking: booking already cancelled')
404 412
                else:
405 413
                    to_cancel_places_count = to_cancel_booking.secondary_booking_set.count() + 1
406 414
                    if places_count != to_cancel_places_count:
407
                        cancel_error = 'cancel booking: count is different'
415
                        cancel_error = gettext_noop('cancel booking: count is different')
408 416
            except Booking.DoesNotExist:
409
                cancel_error = 'cancel booking: booking does no exist'
417
                cancel_error = gettext_noop('cancel booking: booking does no exist')
410 418

  
411 419
            if cancel_error:
412
                return Response({'err': 1, 'reason': cancel_error})
420
                return Response({
421
                    'err': 1,
422
                    'err_class': cancel_error,
423
                    'err_desc': _(cancel_error),
424
                })
413 425

  
414 426
        extra_data = {}
415 427
        for k, v in request.data.items():
......
429 441
                except ValueError:
430 442
                    return Response({
431 443
                        'err': 1,
432
                        'reason': 'invalid slot: %s' % slot,
444
                        'err_class': 'invalid slot: %s' % slot,
445
                        'err_desc': _('invalid slot: %s') % slot,
433 446
                    }, status=status.HTTP_400_BAD_REQUEST)
434 447
                if meeting_type_id_ != meeting_type_id:
435 448
                    return Response({
436 449
                        'err': 1,
437
                        'reason': 'all slots must have the same meeting type id (%s)' % meeting_type_id
450
                        'err_class': 'all slots must have the same meeting type id (%s)' % meeting_type_id,
451
                        'err_desc': _('all slots must have the same meeting type id (%s)') % meeting_type_id,
438 452
                    }, status=status.HTTP_400_BAD_REQUEST)
439 453
                datetimes.add(make_aware(datetime.datetime.strptime(datetime_str, '%Y-%m-%d-%H%M')))
440 454

  
......
451 465
                    available_desk = Desk.objects.get(id=available_desk_id)
452 466
                    break
453 467
            else:
454
                return Response({'err': 1, 'reason': 'no more desk available'})
468
                return Response({
469
                    'err': 1,
470
                    'err_class': 'no more desk available',
471
                    'err_desc': _('no more desk available'),
472
                })
455 473

  
456 474
            # all datetimes are free, book them in order
457 475
            datetimes = list(datetimes)
......
478 496
                    # in the waiting list.
479 497
                    in_waiting_list = True
480 498
                    if (event.waiting_list + places_count) > event.waiting_list_places:
481
                        return Response({'err': 1, 'reason': 'sold out'})
499
                        return Response({
500
                            'err': 1,
501
                            'err_class': 'sold out',
502
                            'err_desc': _('sold out'),
503
                        })
482 504
            else:
483 505
                if (event.booked_places + places_count) > event.places:
484
                    return Response({'err': 1, 'reason': 'sold out'})
506
                    return Response({
507
                        'err': 1,
508
                        'err_class': 'sold out',
509
                        'err_desc': _('sold out')
510
                    })
485 511

  
486 512
        with transaction.atomic():
487 513
            if to_cancel_booking:
......
574 600
    def post(self, request, booking_pk=None, format=None):
575 601
        booking = get_object_or_404(Booking, id=booking_pk)
576 602
        if booking.cancellation_datetime:
577
            response = {'err': 1, 'reason': 'already cancelled'}
603
            response = {
604
                'err': 1,
605
                'err_class': 'already cancelled',
606
                'err_desc': _('already cancelled'),
607
            }
578 608
            return Response(response)
579 609
        booking.cancel()
580 610
        response = {'err': 0, 'booking_id': booking.id}
......
595 625
    def post(self, request, booking_pk=None, format=None):
596 626
        booking = get_object_or_404(Booking, id=booking_pk)
597 627
        if booking.cancellation_datetime:
598
            response = {'err': 1, 'reason': 'booking is cancelled'}
628
            response = {
629
                'err': 1,
630
                'err_class': 'booking is cancelled',
631
                'err_desc': _('booking is cancelled'),
632
            }
599 633
            return Response(response)
600 634
        if not booking.in_waiting_list:
601
            response = {'err': 2, 'reason': 'booking is not in waiting list'}
635
            response = {
636
                'err': 2,
637
                'err_class': 'booking is not in waiting list',
638
                'err_desc': _('booking is not in waiting list'),
639
            }
602 640
            return Response(response)
603 641
        booking.accept()
604 642
        response = {'err': 0, 'booking_id': booking.id}
tests/test_api.py
316 316
    app.authorization = ('Basic', ('john.doe', 'password'))
317 317
    resp = app.post(fillslot_url)
318 318
    assert resp.json['err'] == 1
319
    assert resp.json['reason'] == 'no more desk available'
319
    assert resp.json['reason'] == 'no more desk available'  # legacy
320
    assert resp.json['err_class'] == 'no more desk available'
321
    assert resp.json['err_desc'] == 'no more desk available'
320 322
    # booking the two slots fails too
321 323
    fillslots_url = '/api/agenda/%s/fillslots/' % meeting_type.agenda.slug
322 324
    resp = app.post(fillslots_url, params={'slots': two_slots})
323 325
    assert resp.json['err'] == 1
324
    assert resp.json['reason'] == 'no more desk available'
326
    assert resp.json['reason'] == 'no more desk available'  # legacy
327
    assert resp.json['err_class'] == 'no more desk available'
328
    assert resp.json['err_desc'] == 'no more desk available'
325 329

  
326 330
def test_booking_api(app, some_data, user):
327 331
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
......
376 380
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
377 381
            params={'user_name': {'foo': 'bar'}}, status=400)
378 382
    assert resp.json['err'] == 1
379
    assert resp.json['reason'] == 'invalid payload'
383
    assert resp.json['reason'] == 'invalid payload'  # legacy
384
    assert resp.json['err_class'] == 'invalid payload'
385
    assert resp.json['err_desc'] == 'invalid payload'
380 386
    assert len(resp.json['errors']) == 1
381 387
    assert 'user_name' in resp.json['errors']
382 388

  
......
538 544
            params={'slots': events_ids,
539 545
                    'user_name': {'foo': 'bar'}}, status=400)
540 546
    assert resp.json['err'] == 1
541
    assert resp.json['reason'] == 'invalid payload'
547
    assert resp.json['reason'] == 'invalid payload'  # legacy
548
    assert resp.json['err_class'] == 'invalid payload'
549
    assert resp.json['err_desc'] == 'invalid payload'
542 550
    assert len(resp.json['errors']) == 1
543 551
    assert 'user_name' in resp.json['errors']
544 552

  
545 553
    # empty or missing slots
546 554
    resp = app.post_json('/api/agenda/%s/fillslots/' % agenda.id, params={'slots': []}, status=400)
547 555
    assert resp.json['err'] == 1
548
    assert resp.json['reason'] == 'slots list cannot be empty'
556
    assert resp.json['reason'] == 'slots list cannot be empty'  # legacy
557
    assert resp.json['err_class'] == 'slots list cannot be empty'
558
    assert resp.json['err_desc'] == 'slots list cannot be empty'
549 559
    resp = app.post_json('/api/agenda/%s/fillslots/' % agenda.id, status=400)
550 560
    assert resp.json['err'] == 1
551
    assert resp.json['reason'] == 'slots list cannot be empty'
561
    assert resp.json['reason'] == 'slots list cannot be empty'  # legacy
562
    assert resp.json['err_class'] == 'slots list cannot be empty'
563
    assert resp.json['err_desc'] == 'slots list cannot be empty'
552 564
    # invalid slots format
553 565
    resp = app.post_json('/api/agenda/%s/fillslots/' % agenda.id, params={'slots': 'foobar'}, status=400)
554 566
    assert resp.json['err'] == 1
555
    assert resp.json['reason'] == 'invalid payload'
567
    assert resp.json['reason'] == 'invalid payload'  # legacy
568
    assert resp.json['err_class'] == 'invalid payload'
569
    assert resp.json['err_desc'] == 'invalid payload'
556 570
    assert len(resp.json['errors']) == 1
557 571
    assert 'slots' in resp.json['errors']
558 572

  
......
589 603
    # try booking the same timeslot
590 604
    resp2 = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_id))
591 605
    assert resp2.json['err'] == 1
592
    assert resp2.json['reason'] == 'no more desk available'
606
    assert resp2.json['reason'] == 'no more desk available'  # legacy
607
    assert resp2.json['err_class'] == 'no more desk available'
608
    assert resp2.json['err_desc'] == 'no more desk available'
593 609

  
594 610
    # try booking another timeslot
595 611
    event_id = resp.json['data'][3]['id']
......
619 635
    # try booking the same timeslots
620 636
    resp2 = app.post('/api/agenda/%s/fillslots/' % agenda_id, params={'slots': slots})
621 637
    assert resp2.json['err'] == 1
622
    assert resp2.json['reason'] == 'no more desk available'
638
    assert resp2.json['reason'] == 'no more desk available'  # legacy
639
    assert resp2.json['err_class'] == 'no more desk available'
640
    assert resp2.json['err_desc'] == 'no more desk available'
623 641

  
624 642
    # try booking partially free timeslots (one free, one busy)
625 643
    nonfree_slots = [resp.json['data'][0]['id'], resp.json['data'][2]['id']]
626 644
    resp2 = app.post('/api/agenda/%s/fillslots/' % agenda_id, params={'slots': nonfree_slots})
627 645
    assert resp2.json['err'] == 1
628
    assert resp2.json['reason'] == 'no more desk available'
646
    assert resp2.json['reason'] == 'no more desk available'  # legacy
647
    assert resp2.json['err_class'] == 'no more desk available'
648
    assert resp2.json['err_desc'] == 'no more desk available'
629 649

  
630 650
    # booking other free timeslots
631 651
    free_slots = [resp.json['data'][3]['id'], resp.json['data'][2]['id']]
......
647 667
                    params={'slots': impossible_slots},
648 668
                    status=400)
649 669
    assert resp.json['err'] == 1
650
    assert resp.json['reason'] == 'all slots must have the same meeting type id (1)'
670
    assert resp.json['reason'] == 'all slots must have the same meeting type id (1)'  # legacy
671
    assert resp.json['err_class'] == 'all slots must have the same meeting type id (1)'
672
    assert resp.json['err_desc'] == 'all slots must have the same meeting type id (1)'
651 673

  
652 674
def test_booking_api_meeting_across_daylight_saving_time(app, meetings_agenda, user):
653 675
    meetings_agenda.maximal_booking_delay = 365
......
762 784
        params={'cancel_booking_id': first_booking.pk}
763 785
    )
764 786
    assert resp.json['err'] == 1
765
    assert resp.json['reason'] == 'cancel booking: booking already cancelled'
787
    assert resp.json['reason'] == 'cancel booking: booking already cancelled'  # legacy
788
    assert resp.json['err_class'] == 'cancel booking: booking already cancelled'
789
    assert resp.json['err_desc'] == 'cancel booking: booking already cancelled'
766 790
    assert Booking.objects.count() == 2
767 791

  
768 792
    # Cancelling a non existent booking returns an error
......
771 795
        params={'cancel_booking_id': '-1'}
772 796
    )
773 797
    assert resp.json['err'] == 1
774
    assert resp.json['reason'] == 'cancel booking: booking does no exist'
798
    assert resp.json['reason'] == 'cancel booking: booking does no exist'  # legacy
799
    assert resp.json['err_class'] == 'cancel booking: booking does no exist'
800
    assert resp.json['err_desc'] == 'cancel booking: booking does no exist'
775 801
    assert Booking.objects.count() == 2
776 802

  
777 803
    # Cancelling booking with different count than new booking
......
788 814
        params={'cancel_booking_id': booking_id, 'count': 1}
789 815
    )
790 816
    assert resp.json['err'] == 1
791
    assert resp.json['reason'] == 'cancel booking: count is different'
817
    assert resp.json['reason'] == 'cancel booking: count is different'  # legacy
818
    assert resp.json['err_class'] == 'cancel booking: count is different'
819
    assert resp.json['err_desc'] == 'cancel booking: count is different'
792 820
    assert Booking.objects.count() == 4
793 821

  
794 822
    # cancel_booking_id must be an integer
......
887 915
    app.authorization = ('Basic', ('john.doe', 'password'))
888 916
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id), status=200)
889 917
    assert resp.json['err'] == 1
890
    assert resp.json['reason'] == 'sold out'
918
    assert resp.json['reason'] == 'sold out'  # legacy
919
    assert resp.json['err_class'] == 'sold out'
920
    assert resp.json['err_desc'] == 'sold out'
891 921

  
892 922
def test_status(app, some_data, user):
893 923
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
......
980 1010
    app.authorization = ('Basic', ('john.doe', 'password'))
981 1011
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id), status=200)
982 1012
    assert resp.json['err'] == 1
983
    assert resp.json['reason'] == 'sold out'
1013
    assert resp.json['reason'] == 'sold out'  # legacy
1014
    assert resp.json['err_class'] == 'sold out'
1015
    assert resp.json['err_desc'] == 'sold out'
984 1016

  
985 1017
def test_accept_booking(app, some_data, user):
986 1018
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
......
1025 1057
    app.authorization = ('Basic', ('john.doe', 'password'))
1026 1058
    resp = app.post('/api/agenda/%s/fillslot/%s/?count=NaN' % (agenda.slug, event.id), status=400)
1027 1059
    assert resp.json['err'] == 1
1028
    assert resp.json['reason'] == "invalid value for count (NaN)"
1060
    assert resp.json['reason'] == "invalid value for count (NaN)"  # legacy
1061
    assert resp.json['err_class'] == "invalid value for count (NaN)"
1062
    assert resp.json['err_desc'] == "invalid value for count (NaN)"
1029 1063

  
1030 1064
    app.authorization = ('Basic', ('john.doe', 'password'))
1031 1065
    resp = app.post('/api/agenda/%s/fillslot/%s/?count=0' % (agenda.slug, event.id), status=400)
1032 1066
    assert resp.json['err'] == 1
1033
    assert resp.json['reason'] == "count cannot be less than or equal to zero"
1067
    assert resp.json['reason'] == "count cannot be less than or equal to zero"  # legacy
1068
    assert resp.json['err_class'] == "count cannot be less than or equal to zero"
1069
    assert resp.json['err_desc'] == "count cannot be less than or equal to zero"
1034 1070

  
1035 1071
    app.authorization = ('Basic', ('john.doe', 'password'))
1036 1072
    resp = app.post('/api/agenda/%s/fillslot/%s/?count=-3' % (agenda.slug, event.id), status=400)
1037 1073
    assert resp.json['err'] == 1
1038
    assert resp.json['reason'] == "count cannot be less than or equal to zero"
1074
    assert resp.json['reason'] == "count cannot be less than or equal to zero"  # legacy
1075
    assert resp.json['err_class'] == "count cannot be less than or equal to zero"
1076
    assert resp.json['err_desc'] == "count cannot be less than or equal to zero"
1039 1077

  
1040 1078
    resp = app.post('/api/agenda/%s/fillslot/%s/?count=3' % (agenda.slug, event.id))
1041 1079
    Booking.objects.get(id=resp.json['booking_id'])
......
1062 1100
    # check waiting list overflow
1063 1101
    resp = app.post('/api/agenda/%s/fillslot/%s/?count=5' % (agenda.slug, event.id))
1064 1102
    assert resp.json['err'] == 1
1065
    assert resp.json['reason'] == 'sold out'
1103
    assert resp.json['reason'] == 'sold out'  # legacy
1104
    assert resp.json['err_class'] == 'sold out'
1105
    assert resp.json['err_desc'] == 'sold out'
1066 1106
    assert Event.objects.get(id=event.id).booked_places == 2
1067 1107
    assert Event.objects.get(id=event.id).waiting_list == 5
1068 1108

  
......
1079 1119

  
1080 1120
    resp = app.post('/api/agenda/%s/fillslot/%s/?count=5' % (agenda.slug, event.id))
1081 1121
    assert resp.json['err'] == 1
1082
    assert resp.json['reason'] == 'sold out'
1122
    assert resp.json['reason'] == 'sold out'  # legacy
1123
    assert resp.json['err_class'] == 'sold out'
1124
    assert resp.json['err_desc'] == 'sold out'
1083 1125

  
1084 1126
    resp = app.post('/api/agenda/%s/fillslot/%s/?count=3' % (agenda.slug, event.id))
1085 1127
    assert resp.json['err'] == 0
......
1088 1130

  
1089 1131
    resp = app.post('/api/agenda/%s/fillslot/%s/?count=3' % (agenda.slug, event.id))
1090 1132
    assert resp.json['err'] == 1
1091
    assert resp.json['reason'] == 'sold out'
1133
    assert resp.json['reason'] == 'sold out'  # legacy
1134
    assert resp.json['err_class'] == 'sold out'
1135
    assert resp.json['err_desc'] == 'sold out'
1092 1136

  
1093 1137
    resp = app.post('/api/agenda/%s/fillslot/%s/?count=2' % (agenda.slug, event.id))
1094 1138
    assert resp.json['err'] == 0
......
1106 1150
    app.authorization = ('Basic', ('john.doe', 'password'))
1107 1151
    resp = app.post('/api/agenda/%s/fillslots/?count=NaN' % agenda.slug, params={'slots': slots}, status=400)
1108 1152
    assert resp.json['err'] == 1
1109
    assert resp.json['reason'] == "invalid value for count (NaN)"
1153
    assert resp.json['reason'] == "invalid value for count (NaN)"  # legacy
1154
    assert resp.json['err_class'] == "invalid value for count (NaN)"
1155
    assert resp.json['err_desc'] == "invalid value for count (NaN)"
1110 1156

  
1111 1157
    resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
1112 1158
                    params={'slots': slots, 'count': 'NaN'}, status=400)
1113 1159
    assert resp.json['err'] == 1
1114
    assert resp.json['reason'] == "invalid payload"
1160
    assert resp.json['reason'] == "invalid payload"  # legacy
1161
    assert resp.json['err_class'] == "invalid payload"
1162
    assert resp.json['err_desc'] == "invalid payload"
1115 1163
    assert 'count' in resp.json['errors']
1116 1164

  
1117 1165
    # get 3 places on 2 slots
......
1155 1203
    resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
1156 1204
                    params={'slots': slots, 'count': 5})
1157 1205
    assert resp.json['err'] == 1
1158
    assert resp.json['reason'] == 'sold out'
1206
    assert resp.json['reason'] == 'sold out'  # legacy
1207
    assert resp.json['err_class'] == 'sold out'
1208
    assert resp.json['err_desc'] == 'sold out'
1159 1209
    for event in events:
1160 1210
        assert Event.objects.get(id=event.id).booked_places == 2
1161 1211
        assert Event.objects.get(id=event.id).waiting_list == 5
......
1176 1226
    resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
1177 1227
                    params={'slots': slots, 'count': 5})
1178 1228
    assert resp.json['err'] == 1
1179
    assert resp.json['reason'] == 'sold out'
1229
    assert resp.json['reason'] == 'sold out'  # legacy
1230
    assert resp.json['err_class'] == 'sold out'
1231
    assert resp.json['err_desc'] == 'sold out'
1180 1232

  
1181 1233
    resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
1182 1234
                    params={'slots': slots, 'count': 3})
......
1188 1240
    resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
1189 1241
                    params={'slots': slots, 'count': 3})
1190 1242
    assert resp.json['err'] == 1
1191
    assert resp.json['reason'] == 'sold out'
1243
    assert resp.json['reason'] == 'sold out'  # legacy
1244
    assert resp.json['err_class'] == 'sold out'
1245
    assert resp.json['err_desc'] == 'sold out'
1192 1246

  
1193 1247
    resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug,
1194 1248
                    params={'slots': slots, 'count': '2'})
......
1299 1353
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_id))
1300 1354
    assert Booking.objects.count() == 2
1301 1355
    assert resp.json['err'] == 1
1302
    assert resp.json['reason'] == 'no more desk available'
1356
    assert resp.json['reason'] == 'no more desk available'  # legacy
1357
    assert resp.json['err_class'] == 'no more desk available'
1358
    assert resp.json['err_desc'] == 'no more desk available'
1303 1359

  
1304 1360
    # cancel first booking and retry
1305 1361
    resp = app.post(cancel_url)
......
1336 1392
    # try booking the same timeslot again and fail
1337 1393
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_id))
1338 1394
    assert resp.json['err'] == 1
1339
    assert resp.json['reason'] == 'no more desk available'
1395
    assert resp.json['reason'] == 'no more desk available'  # legacy
1396
    assert resp.json['err_class'] == 'no more desk available'
1397
    assert resp.json['err_desc'] == 'no more desk available'
1340 1398

  
1341 1399
    # fill the agenda and make sure big O is O(1)
1342 1400
    for idx, event_data in enumerate(resp2.json['data'][2:10]):
......
1387 1445
    # try booking again: no desk available
1388 1446
    resp = app.post(fillslots_url, params={'slots': slots})
1389 1447
    assert resp.json['err'] == 1
1390
    assert resp.json['reason'] == 'no more desk available'
1448
    assert resp.json['reason'] == 'no more desk available'  # legacy
1449
    assert resp.json['err_class'] == 'no more desk available'
1450
    assert resp.json['err_desc'] == 'no more desk available'
1391 1451
    assert get_free_places() == start_free_places - len(slots)
1392 1452

  
1393 1453
    # cancel desk 1 booking
......
1406 1466
    # try booking the 3 slots again: no desk available, one slot is not fully available
1407 1467
    resp = app.post(fillslots_url, params={'slots': slots})
1408 1468
    assert resp.json['err'] == 1
1409
    assert resp.json['reason'] == 'no more desk available'
1469
    assert resp.json['reason'] == 'no more desk available'  # legacy
1470
    assert resp.json['err_class'] == 'no more desk available'
1471
    assert resp.json['err_desc'] == 'no more desk available'
1410 1472

  
1411 1473
    # cancel last signel slot booking, desk1 will be free
1412 1474
    resp = app.post(cancel_url)
tests/test_api_utils.py
1
import pytest
2

  
3
from chrono.api.utils import Response
4

  
5

  
6
@pytest.mark.parametrize('data, expected', [
7
    (None, None),
8
    ({}, {}),
9
    ({'reason': 'foo'}, {'reason': 'foo'}),
10
    ({'err_class': 'foo'}, {'err_class': 'foo', 'reason': 'foo'}),
11
    ({'bar': 'foo'}, {'bar': 'foo'}),
12
])
13
def test_response_data(data, expected):
14
    resp = Response(data=data)
15
    assert resp.data == expected
0
-