Projet

Général

Profil

0001-data_source-handle-err-in-JSON-outputs-41195.patch

Thomas Noël, 31 mars 2020 17:11

Télécharger (7,34 ko)

Voir les différences:

Subject: [PATCH] data_source: handle err in JSON outputs (#41195)

 tests/test_datasource.py | 66 ++++++++++++++++++++++++++++++++++++++++
 tests/utilities.py       |  1 +
 wcs/data_sources.py      | 24 ++++++++++++---
 3 files changed, 86 insertions(+), 5 deletions(-)
tests/test_datasource.py
296 296
    assert 'Error loading JSON data source' in caplog.records[-1].message
297 297
    assert 'error' in caplog.records[-1].message
298 298

  
299
    datasource = {'type': 'json', 'value': 'http://remote.example.net/json-list-err1'}
300
    assert data_sources.get_items(datasource) == []
301
    assert 'Error reading JSON data source output (err 1)' in caplog.records[-1].message
302

  
299 303

  
300 304
def test_json_datasource_bad_url_scheme(caplog):
301 305
    datasource = {'type': 'json', 'value': ''}
......
496 500
        assert urlopen.call_count == 3
497 501

  
498 502

  
503
def test_named_datasource_id_parameter(requests_pub):
504
    NamedDataSource.wipe()
505
    datasource = NamedDataSource(name='foobar')
506
    datasource.data_source = {'type': 'json', 'value': 'http://whatever/'}
507
    datasource.id_parameter = 'id'
508
    datasource.store()
509

  
510
    with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
511
        value = [{'id': '1', 'text': 'foo'}]
512
        urlopen.side_effect = lambda *args: StringIO(json.dumps({'data': value}))
513
        assert datasource.get_structured_value('1') == value[0]
514
        assert urlopen.call_count == 1
515
        assert urlopen.call_args[0][0] == 'http://whatever/?id=1'
516

  
517
        # try again, get from request.datasources_cache
518
        assert datasource.get_structured_value('1') == value[0]
519
        assert urlopen.call_count == 1  # no new call
520

  
521
    get_request().datasources_cache = {}
522
    with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
523
        value = [{'id': '1', 'text': 'bar'}, {'id': '2', 'text': 'foo'}]
524
        urlopen.side_effect = lambda *args: StringIO(json.dumps({'data': value}))
525
        assert datasource.get_structured_value('1') == value[0]
526
        assert urlopen.call_count == 1
527
        assert urlopen.call_args[0][0] == 'http://whatever/?id=1'
528

  
529
    get_request().datasources_cache = {}
530
    with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
531
        value = [{'id': '1', 'text': 'foo'}]
532
        urlopen.side_effect = lambda *args: StringIO(json.dumps({'data': value, 'err': 0}))
533
        assert datasource.get_structured_value('1') == value[0]
534
        assert urlopen.call_count == 1
535
        assert urlopen.call_args[0][0] == 'http://whatever/?id=1'
536

  
537
    get_request().datasources_cache = {}
538
    with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
539
        value = [{'id': '1', 'text': 'foo'}]
540
        urlopen.side_effect = lambda *args: StringIO(json.dumps({'data': value, 'err': 1}))
541
        assert datasource.get_structured_value('1') is None
542
        assert urlopen.call_count == 1
543
        assert urlopen.call_args[0][0] == 'http://whatever/?id=1'
544

  
545
        # no cache for errors
546
        assert datasource.get_structured_value('1') is None
547
        assert urlopen.call_count == 2  # called
548

  
549
    get_request().datasources_cache = {}
550
    with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
551
        value = {'id': '1', 'text': 'foo'}  # not a list
552
        urlopen.side_effect = lambda *args: StringIO(json.dumps({'data': value}))
553
        assert datasource.get_structured_value('1') is None
554
        assert urlopen.call_count == 1
555
        assert urlopen.call_args[0][0] == 'http://whatever/?id=1'
556

  
557
    get_request().datasources_cache = {}
558
    with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
559
        urlopen.side_effect = lambda *args: StringIO('not json')
560
        assert datasource.get_structured_value('1') is None
561
        assert urlopen.call_count == 1
562
        assert urlopen.call_args[0][0] == 'http://whatever/?id=1'
563

  
564

  
499 565
def test_named_datasource_in_formdef():
500 566
    from wcs.formdef import FormDef
501 567
    datasource = NamedDataSource(name='foobar')
tests/utilities.py
329 329
            'http://remote.example.net/json-list': (200, '{"data": [{"id": "a", "text": "b"}]}', None),
330 330
            'http://remote.example.net/json-err0': (200, '{"data": "foo", "err": 0}', None),
331 331
            'http://remote.example.net/json-err1': (200, '{"data": "", "err": 1}', None),
332
            'http://remote.example.net/json-list-err1': (200, '{"data": [{"id": "a", "text": "b"}], "err": 1}', None),
332 333
            'http://remote.example.net/json-errstr': (200, '{"data": "", "err": "bug"}', None),
333 334
            'http://remote.example.net/json-errheader0': (200, '{"foo": "bar"}',
334 335
                                              {'x-error-code': '0'}),
wcs/data_sources.py
201 201
            entries = misc.json_loads(misc.urlopen(url).read())
202 202
            if type(entries) is not dict:
203 203
                raise ValueError('not a json dict')
204
            if entries.get('err') not in (None, 0, "0"):
205
                raise ValueError('err %s' % entries['err'])
204 206
            if type(entries.get('data')) is not list:
205 207
                raise ValueError('not a json dict with a data list attribute')
206 208
            items = []
......
374 376

  
375 377
        unsigned_url = url
376 378
        url = sign_url_auto_orig(url)
377
        resp = misc.urlopen(url).read()
379
        try:
380
            resp = misc.urlopen(url).read()
381
            resp = misc.json_loads(resp)
382
            if type(resp) is not dict:
383
                raise ValueError('not a json dict')
384
            if resp.get('err') not in (None, 0, "0"):
385
                raise ValueError('err %s' % resp['err'])
386
            if type(resp.get('data')) is not list:
387
                raise ValueError('not a json dict with a data list attribute')
388
            resp = resp['data'][0]
389
        except misc.ConnectionError as e:
390
            get_logger().warn('Error loading JSON data source (%s)' % str(e))
391
            return None
392
        except (ValueError, TypeError) as e:
393
            get_logger().warn('Error reading JSON data source output (%s)' % str(e))
394
            return None
378 395
        if hasattr(request, 'datasources_cache'):
379 396
            request.datasources_cache[unsigned_url] = resp
380 397
        return resp
......
388 405
    def get_structured_value(self, option_id):
389 406
        value = None
390 407
        if self.type == 'json' and self.id_parameter:
391
            resp = self.load_json(self.id_parameter, option_id)
392
            response = misc.json_loads(resp)
393
            if response['data']:
394
                value = response['data'][0]
408
            value = self.load_json(self.id_parameter, option_id)
395 409
        else:
396 410
            structured_items = get_structured_items(self.data_source, mode='lazy')
397 411
            for item in structured_items:
398
-