Projet

Général

Profil

0001-clicrdv-improve-API-error-handling-39273.patch

Valentin Deniaud, 28 janvier 2020 18:20

Télécharger (7,16 ko)

Voir les différences:

Subject: [PATCH] clicrdv: improve API error handling (#39273)

 passerelle/apps/clicrdv/models.py | 67 ++++++++++++++++---------------
 tests/test_clicrdv.py             | 24 ++++++++---
 2 files changed, 52 insertions(+), 39 deletions(-)
passerelle/apps/clicrdv/models.py
57 57
        else:
58 58
           url = url + '?apikey=%s&format=json' % self.apikey
59 59
        basic_auth = requests.auth.HTTPBasicAuth(self.username, self.password)
60
        return self.requests.request(method, url, auth=basic_auth, **kwargs)
60
        response = self.requests.request(method, url, auth=basic_auth, **kwargs)
61
        try:
62
            response.raise_for_status()
63
        except requests.exceptions.HTTPError as e:
64
            try:
65
                error = response.json()
66
            except ValueError:
67
                error = 'invalid json, got %s' % response.text
68
            return {
69
                'success': False,
70
                'error': '%s : %s' % (e, error),
71
            }
72
        return response.json()
61 73

  
62 74
    @endpoint(name='interventionsets')
63 75
    def get_interventionsets(self, request, **kwargs):
64 76
        response = self.request('interventionsets')
65
        records = response.json().get('records')
77
        if 'error' in response:
78
            return response
79
        records = response.get('records', [])
66 80
        records.sort(lambda x,y: cmp(x['sort'], y['sort']))
67 81
        ret = []
68 82
        for record in records:
......
74 88
    def get_interventions(self, request, set, **kwargs):
75 89
        ret = []
76 90
        response = self.request('interventions?interventionset_id=%s' % set)
77
        records = response.json().get('records')
91
        if 'error' in response:
92
            return response
93
        records = response.get('records', [])
78 94
        records.sort(lambda x,y: cmp(x['sort'], y['sort']))
79 95
        for record in records:
80 96
            if record.get('publicname'):
......
93 109
            request_uri = request_uri + '&start=%s' % urlquote(date_start)
94 110
        if date_end:
95 111
            request_uri = request_uri + '&end=%s' % urlquote(date_end)
96
        for timeslot in self.request(request_uri).json().get('availabletimeslots'):
112
        response = self.request(request_uri)
113
        if 'error' in response:
114
            return response
115
        for timeslot in response.get('availabletimeslots', []):
97 116
            timeslots.append(timeslot.get('start'))
98 117
        timeslots.sort()
99 118
        return timeslots
......
135 154
        return times
136 155

  
137 156
    def cancel(self, appointment_id, **kwargs):
138
        try:
139
            r = self.request('appointments/%s' % appointment_id, method='delete')
140
            r.raise_for_status()
141
        except requests.exceptions.HTTPError as e:
142
            # clicrdv will return a "Bad Request" (HTTP 400) response
143
            # when it's not possible to remove an appointment
144
            # (for example because it's too late)
145
            response = json.loads(str(e))
146
            return {'success': False, 'error': response}
157
        response = self.request('appointments/%s' % appointment_id, method='delete')
158
        if 'error' in response:
159
            return response
147 160
        return {'success': True}
148 161

  
149 162

  
......
185 198
        for fieldname in (fields.keys() + extra.keys() + data.keys()):
186 199
            if fieldname.startswith('clicrdv_fiche_'):
187 200
                appointment['appointment']['fiche'][fieldname[14:]] = get_data(fieldname) or ''
188
        try:
189
            r = self.request('appointments', 'post', json=appointment)
190
            r.raise_for_status()
191
        except requests.exceptions.HTTPError as e:
192
            try:
193
                error = json.loads(str(e))[0].get('error')
194
            except:
195
                error = 'Unknown error (Passerelle)'
196
            return {
197
                'success': False,
198
                'error': error,
199
            }
200
        else:
201
            success = True
202
            response = r.json()
203
            appointment_id = response.get('records')[0].get('id')
204
            return {
205
                'success': True,
206
                'appointment_id': appointment_id,
207
            }
201
        response = self.request('appointments', 'post', json=appointment)
202
        if 'error' in response:
203
            return response
204
        appointment_id = response.get('records')[0].get('id')
205
        return {
206
            'success': True,
207
            'appointment_id': appointment_id,
208
        }
tests/test_clicrdv.py
164 164
    assert mocked_request.call_count == 1
165 165
    assert resp['data']['success']
166 166

  
167
@mock.patch('passerelle.utils.Request.request',
168
            side_effect=HTTPError('{"msg": "cancel failed"}'))
167
@mock.patch('passerelle.utils.Request.request')
169 168
def test_failed_cancel_appointment(mocked_request, app, connector):
169
    def raise_for_status():
170
        raise HTTPError("400 Client Error: Bad Request for url: xxx")
171

  
172
    response = mock.Mock()
173
    response.json.return_value = [{"msg": "cancel failed"}]
174
    response.raise_for_status = raise_for_status
175
    mocked_request.return_value = response
170 176
    obj_type = ContentType.objects.get_for_model(ClicRdv)
171 177
    apiuser = ApiUser.objects.create(username='apiuser', keytype='API',
172 178
                                key='apiuser')
......
177 183
    assert mocked_request.call_count == 1
178 184
    assert resp.get('err') == 0
179 185
    assert resp['data']
180
    assert resp['data']['error'] == {'msg': 'cancel failed'}
186
    assert 'cancel failed' in resp['data']['error']
181 187

  
182 188

  
183
@mock.patch('passerelle.utils.Request.request',
184
            side_effect=HTTPError('[{"error": "creation failed"}]'))
189
@mock.patch('passerelle.utils.Request.request')
185 190
def test_failed_appointment_creation(mocked_request, app, connector):
191
    def raise_for_status():
192
        raise HTTPError("400 Client Error: Bad Request for url: xxx")
193

  
194
    response = mock.Mock()
195
    response.json.return_value = [{"msg": "creation failed"}]
196
    response.raise_for_status = raise_for_status
197
    mocked_request.return_value = response
186 198
    obj_type = ContentType.objects.get_for_model(ClicRdv)
187 199
    apiuser = ApiUser.objects.create(username='apiuser', keytype='API',
188 200
                                key='apiuser')
......
196 208
    resp = app.post_json('/clicrdv/test/interventions/63258/create?apikey=apiuser', params=data).json
197 209
    assert resp['data']
198 210
    assert not resp['data']['success']
199
    assert resp['data']['error'] == 'creation failed'
211
    assert 'creation failed' in resp['data']['error']
200
-