test_client.py 22.4 KB
Newer Older
1
2
import pytest

3
4
import urllib.request
from urllib.error import HTTPError, URLError
5
from pathlib import Path
6
import os
7
import json
8
import parfive
9

10
import astropy.units as u
11
from astropy import table
12
from astropy.io import fits
13
from astropy.time import Time
14
import sunpy
15
from sunpy.net import Fido
16
from sunpy.net import attrs as a
17
from sunpy.net.base_client import QueryResponseTable
18

19
from sdc.client import KISClient
20
21
22


_BASE_URL = "http://dockertest:8083/sdc/"
23
24
25
26
27
28
_QUERY_BASE = "gris_observations?filter="
_EXAMPLE_QUERY = "{'description.OBS_NAME':'gris_20140426_000'}"
_EXAMPLE_RANGE = "{'description.THETA':{'$gt':70.0,'$lt':80}}"
_EXAMPLE_DATES = ("{'$and':[{'description.INSTRUMENT':'gris'},"
                  "{'description.DATE_BEG':{'$gte':{'$date':'2014-04-26T00:00:00'},"
                  "'$lte':{'$date':'2014-04-27T00:00:00'}}}]}")
29
30

try:
31
    response = urllib.request.urlopen(f"{_BASE_URL}{_QUERY_BASE}{_EXAMPLE_QUERY}")
32
33
34
35
36
    HAS_DOCKERTEST = True
except(HTTPError, URLError):
    HAS_DOCKERTEST = False


37
38
39
40
def dirnames(path):
    return os.path.dirname(path).split(os.path.sep)


41
42
@pytest.fixture
def client():
43
    return KISClient()
44
45


46
def _dockerexc(instr):
47
48
    return (rf"Unable to execute search .http://dockertest:8083/sdc/{instr.lower()}_observations."
            rf"filter={{'.and':.{{'description.INSTRUMENT':'{instr.lower()}'}},")
49
50


51
52
53
54
55
56
57
58
59
60
61
62
63
def test_docker(client):
    """Test example queries on dockertest."""
    if not HAS_DOCKERTEST:
        pytest.xfail("No dockertest running")

    response = urllib.request.urlopen(f"{_BASE_URL}{_QUERY_BASE}{_EXAMPLE_QUERY}")
    data = json.loads(response.read())
    assert '_embedded' in data.keys()
    assert 'description' in data['_embedded'][0]

    response = urllib.request.urlopen(f"{_BASE_URL}{_QUERY_BASE}{_EXAMPLE_DATES}")
    data = json.loads(response.read())
    assert 'description' in data['_embedded'][0]
64
    assert len(data['_embedded']) > 4
65
66
67
68
69
70

    response = urllib.request.urlopen(f"{_BASE_URL}{_QUERY_BASE}{_EXAMPLE_RANGE}")
    data = json.loads(response.read())
    assert 'description' in data['_embedded'][0]

    res = client.search(a.Instrument("GRIS") & a.sdc.ObsName('gris_20140426_000'))
71
    assert isinstance(res, QueryResponseTable)
72
    assert len(res) == 105
73
74
75
76
77
    assert res[0]['INSTRUMENT'] == 'gris'
    assert res[0]['TELESCOPE'] == 'GREGOR'
    assert res[0]['BTYPE'] == 'phot.count'
    assert res[0]['DATE_BEG'].unix == 1398505619.000
    assert res[0]['DATE_END'].unix == 1398506021.300
78

79
    file_ids = [ld['links']['l1_data']['$oid'] for ld in res]
80
81
82
83
84
85
86
87
    assert len(file_ids) == 105
    for oid in file_ids[0], file_ids[104]:
        meta = json.loads(urllib.request.urlopen(f"{_BASE_URL}gris_l1_data.files/{oid}").read())
        assert meta['_id']['$oid'] == oid
        hdulist = fits.open(f"{_BASE_URL}gris_l1_data.files/{oid}/binary")
        assert hdulist[0].header.get('TELESCOP') == 'GREGOR'
        assert '2014-04-26T' in hdulist[0].header.get('DATE-OBS')
        hdulist.close()
88

89
90
    date = a.Time("2014/04/26 01:00", "2014/04/26 22:00")
    downloader = parfive.Downloader()
91
    inst = res[0]['INSTRUMENT']
92
93
94
    rowpath = f"{res[0]['_id']['$oid']}"
    binfile = ''
    ext = 'json'
95
96
    for i, ld in enumerate(res[:10]):
        oid = ld['links']['l1_data']['$oid']
97
98
99
100
101
102
103
        filename = f"{oid}.{ext}"
        url = f"{_BASE_URL}{inst}_l1_data.files/{oid}{binfile}"
        assert url == f"{_BASE_URL}gris_l1_data.files/{file_ids[i]}"
        downloader.enqueue_file(url, filename=os.path.join(rowpath, filename), max_splits=1)

    binfile = '/binary'
    ext = 'fits'
104
105
    for ld in res[:2]:
        oid = ld['links']['l1_data']['$oid']
106
107
108
109
110
111
        filename = f"{oid}.{ext}"
        url = f"{_BASE_URL}{inst}_l1_data.files/{oid}{binfile}"
        downloader.enqueue_file(url, filename=os.path.join(rowpath, filename), max_splits=1)

    assert downloader.queued_downloads == 12
    assert downloader.http_queue[0].keywords['url'].startswith(_BASE_URL)
112
    assert res[0]['links']['l1_data']['$oid'] in downloader.http_queue[0].keywords['url']
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    assert downloader.http_queue[10].keywords['url'].endswith(binfile)

    files = downloader.download()
    assert len(files) == 12
    assert os.path.dirname(files[0]) == '5ee0feb97a92554c6de920ab'

    for filepath in files:
        if filepath.endswith('.fits'):
            hdulist = fits.open(filepath)
            assert hdulist[0].header.get('TELESCOP') == 'GREGOR'
            assert '2014-04-26T' in hdulist[0].header.get('DATE-OBS')
            assert date.start < Time(hdulist[0].header['DATE-OBS']) < date.end
            hdulist.close()
        else:
            assert filepath.endswith('.json')
            meta = json.load(open(filepath))
            assert date.start < Time(meta['metadata']['header']['DATE-BEG']) < date.end
            assert date.start < Time(meta['metadata']['header']['DATE-OBS']) < date.end
            assert meta['_id']['$oid'] == os.path.splitext(os.path.basename(filepath))[0]

133
134
135
136
137
138
139
140
141
142
143
144
145

def test_gridfs(client):
    """Test gridfs access on dockertest."""
    pytest.xfail("No GridFS on gitlab-runner")
    import gridfs
    from kis_tools.generic import get_sdc_connection

    res = client.search(a.Instrument("GRIS") & a.sdc.ObsName('gris_20140426_000'))
    links = res[0]['_embedded'][0].get('links')
    file_ids = [ld['$oid'] for ld in links['l1_data']]
    sdc = get_sdc_connection()
    gfs = gridfs.GridFS(sdc.sdc_test, "gris_l1_data")
    found = gfs.find({"_id": {"$in": file_ids}})
146
    assert(len(found)) == 105
147

148

149
def test_search(client):
150
    """Test conversion of (supported) Attrs to query string."""
151

152
    assert not client._can_handle_query(a.Time("2019/01/01", "2021/01/01"))
153
154
155
156
    with pytest.raises(AttributeError, match=r"Query not possible: "
                       r"No 'Instrument' found in Attributes"):
        client.search(a.Time("2019/01/01", "2021/01/01"))

157
    assert not client._can_handle_query(a.Instrument("UVES"), a.Time("2019/01/01", "2021/01/01"))
158
159
160
161
    with pytest.raises(AttributeError, match=r"Query not possible: "
                       r"Instrument UVES not in registered list"):
        client.search(a.Instrument("UVES") & a.Time("2019/01/01", "2021/01/01"))

162
    query = a.Instrument("BBI") & a.Time("2017/05/21", "2017/05/22 22:00")
163
    assert client._can_handle_query(query)
164
    if HAS_DOCKERTEST:
165
        res = client.search(query)
166
        assert isinstance(res, QueryResponseTable)
167
        assert len(res) == 1
168
        assert 'INSTRUMENT' in res.colnames
169
    else:
170
        with pytest.raises(URLError, match=rf"{_dockerexc('bbi')}"
171
172
                           r"{'description.DATE_BEG':{'.lte':{'.date':'2017-05-22T22:00:00.000'}}},"
                           r"{'description.DATE_END':{'.gte':{'.date':'2017-05-21T00:00:00.000'}}}"
173
                           rf".*Confirm that RESTHeart is running on {_BASE_URL} and connected"):
174
175
            client.search(query)

176
    # Maximum numer of returned observation records defaults to 100 per query.
177
178
179
180
    query = a.Instrument("LARS") & a.sdc.HelioProjLat(-10*u.arcsec, 0.2*u.arcmin)
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
181
        assert len(res) == 1
182
        assert 'INSTRUMENT' in res.colnames
183
    else:
184
        with pytest.raises(URLError, match=rf"{_dockerexc('lars')}"
185
186
                           r"{'description.HPLT_TAN_MIN':{'.lte':12}},"
                           r"{'description.HPLT_TAN_MAX':{'.gte':-10}}"):
187
188
            client.search(query)

189
190
191
192
    query = a.Instrument("LARS"), a.sdc.HelioProjLat(-10*u.arcsec, 0.2*u.arcmin)
    assert client._can_handle_query(*query)
    if HAS_DOCKERTEST:
        res = client.search(*query)
193
        assert len(res) == 1
194
        assert 'INSTRUMENT' in res.colnames
195
196
197
198
199
200
201
    else:
        with pytest.raises(URLError, match=rf"{_dockerexc('lars')}"
                           r"{'description.HPLT_TAN_MIN':{'.lte':12}},"
                           r"{'description.HPLT_TAN_MAX':{'.gte':-10}}"):
            client.search(*query)

    query = a.Instrument("GRIS") & (a.sdc.Theta(85*u.deg, 3000*u.arcmin) | a.sdc.PolStates('iquv'))
202
203
204
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
205
        assert len(res) == 362
206
207
208
        assert 'THETA' in res.colnames
        assert (min(res['THETA'][:100]) >= 50*u.deg) & (max(res['THETA'][:100]) <= 85*u.deg)
        assert res[100]['POL_STATES'] == 'IQUV'
209
    else:
210
211
        # Will raise on first of multi-part OR queries; somehow switches INSTRUMENT and THETA.
        with pytest.raises(URLError, match=rf"{_dockerexc('gris')[:80]}") as exc:
212
            client.search(query)
213
        assert "{'description.THETA':{'$gte':50,'$lte':85}}" in str(exc.value)
214
215
        assert "{'description.POL_STATES':" not in str(exc.value)

216
217
218
    query = a.Instrument("LARS") | a.Instrument("GRIS"), a.sdc.Theta(85*u.deg, 3000*u.arcmin)
    if HAS_DOCKERTEST:
        res = client.search(*query)
219
        assert len(res) == 163
220
221
        assert 'THETA' in res.colnames
        assert (min(res['THETA']) >= 50*u.deg) & (max(res['THETA']) <= 85*u.deg)
222
223
224
225
226
227
228
    else:
        # Will raise on first of multi-part OR queries; somehow switches INSTRUMENT and THETA.
        with pytest.raises(URLError, match=rf"{_dockerexc('LARS')[:80]}") as exc:
            client.search(*query)
        assert "{'description.THETA':{'$gte':50,'$lte':85}}" in str(exc.value)
        assert "{'description.INSTRUMENT':'gris'" not in str(exc.value)

229

230
231
def test_fido_search():
    """Test search using the Fido base class with AttrAnd, AttrOr and lists of *args."""
232
    two_inst = (a.Instrument("LARS") | a.Instrument("GRIS"))
233
234
    if HAS_DOCKERTEST:
        res = Fido.search(a.Instrument("GRIS") & a.sdc.Theta(50*u.deg, 80*u.deg))
235
        assert len(res['kis']) == 162
236
        assert (min(res['kis']['THETA']) >= 50*u.deg) & (max(res['kis']['THETA']) <= 80*u.deg)
237
238

        res = Fido.search(a.Instrument("GRIS"), a.sdc.Theta(50*u.deg, 80*u.deg))
239
        assert len(res['kis']) == 162
240
        assert (min(res['kis']['THETA']) >= 50*u.deg) & (max(res['kis']['THETA']) <= 80*u.deg)
241

242
243
244
        date = a.Time("2017/05/12 01:40", "2017/05/16 19:00")
        res = Fido.search(a.Instrument("LARS") & date)
        assert len(res['kis']) > 0
245
246
        assert max(res['kis']['DATE_BEG']) < date.end
        assert min(res['kis']['DATE_END']) > date.start
247

248
        res = Fido.search(two_inst, a.sdc.Theta(50*u.deg, 80*u.deg))
249
        assert len(res['kis']) == 2
250
251
        assert len(res['kis'][0]) == 1
        assert len(res['kis'][1]) == 162
252
253
254
255
256
257
258
259
        assert res['kis'][0][0]['INSTRUMENT'] == 'lars'
        assert res['kis'][1, 0]['INSTRUMENT'] == 'gris'
        assert (min(res['kis'][0]['THETA']) >= 50*u.deg) & (max(res['kis'][0]['THETA']) <= 80*u.deg)
        assert (min(res['kis'][1]['THETA']) >= 50*u.deg) & (max(res['kis'][1]['THETA']) <= 80*u.deg)
        theta = [obs['THETA'] for obs in res['kis'][0]]
        assert (min(theta) >= 50*u.deg) & (max(theta) <= 80*u.deg)
        theta = [obs['THETA'] for obs in res['kis'][1]]
        assert (min(theta) >= 50*u.deg) & (max(theta) <= 80*u.deg)
260
261
262

        date = a.Time("2016/08/26 16:25", "2016/08/26 16:45")
        res = Fido.search(a.Instrument("GRIS"), a.sdc.PolStates('iquv'), date)
263
        assert len(res['kis']) == 400
264
265
266
        assert all(res['kis']['POL_STATES'] == 'IQUV')
        assert max(res['kis']['DATE_BEG']) < date.end
        assert min(res['kis']['DATE_END']) > date.start
267
268
269
270
271
272
273
274
275
    else:
        with pytest.raises(URLError, match=rf"{_dockerexc('gris')}"
                           r"{'description.THETA':{'.gte':50,'.lte':80}}"):
            Fido.search(a.Instrument("GRIS") & a.sdc.Theta(50*u.deg, 80*u.deg))

        with pytest.raises(URLError, match=rf"{_dockerexc('gris')}"
                           r"{'description.THETA':{'.gte':50,'.lte':80}}"):
            Fido.search(a.Instrument("GRIS"), a.sdc.Theta(50*u.deg, 80*u.deg))

276
        with pytest.raises(URLError, match=rf"{_dockerexc('LARS')}") as exc:
277
278
            Fido.search(two_inst, a.sdc.Theta(50*u.deg, 80*u.deg))
        assert "{'description.THETA':{'$gte':50,'$lte':80}}" in str(exc.value)
279
        assert "{'description.INSTRUMENT':'gris'" not in str(exc.value)
280
281


282
283
284
285
286
287
288
def test_fido_fetch():
    """Test search and fetch using the Fido interface."""
    if not HAS_DOCKERTEST:
        pytest.xfail("No dockertest running")

    date = a.Time("2017/05/22 08:45", "2017/05/22 08:55")
    res = Fido.search(a.Instrument("BBI"), date)
289
    assert len(res['kis']) == 10
290
291
    assert max(res['kis']['DATE_BEG']) < date.end
    assert min(res['kis']['DATE_END']) > date.start
292
293

    files = Fido.fetch(res['kis'])
294
295
    assert len(files) == 10
    for i, filepath in enumerate(files):
296
        assert dirnames(filepath)[-1] == res['kis'][::-1][i]['OBS_NAME']
297
298
299
300
        meta = json.load(open(filepath))
        assert meta['_id']['$oid'] == os.path.splitext(os.path.basename(filepath))[0]
        assert date.start.isot[:12] in meta['metadata']['header']['DATE-BEG']
        assert date.start < Time(meta['metadata']['header']['DATE-BEG']) < date.end
301
        assert meta['metadata']['header']['FILENAME'].split('-')[0] in res['kis'][9-i]['OBS_NAME']
302

303
304
305
    files = Fido.fetch(res['kis'][:3], binary=True)
    assert len(files) == 3
    for i, filepath in enumerate(files):
306
        assert dirnames(filepath)[-1] == res['kis'][::-1][i]['OBS_NAME']
307
308
309
        hdulist = fits.open(filepath)
        assert hdulist[0].header.get('TELESCOP') == 'GREGOR'
        assert hdulist[0].header.get('INSTRUME') == 'BBI'
310
        assert hdulist[0].header['EXTNAME'].startswith(dirnames(filepath)[-1].lstrip('bbi_'))
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
        assert date.start.iso[:12] in hdulist[0].header['DATE-OBS']
        assert date.start < Time(hdulist[0].header['DATE-OBS']) < date.end


def test_fido_fetch_2():
    """
    Test search and fetch from 2 instruments in time interval using the Fido interface.
    Assert observations are within some exposure times (10 min) of range.
    """

    date = a.Time("2016/08/26 16:25", "2016/08/26 16:26")
    if not HAS_DOCKERTEST:
        with pytest.raises(URLError, match=rf"{_dockerexc('gris')}"
                           rf"{{'description.DATE_BEG':{{'.lte':{{'.date':'{date.end.isot}'}}}}}},"
                           rf"{{'description.DATE_END':{{'.gte':{{'.date':'{date.start.isot}'}}"):
            res = Fido.search((a.Instrument("GRIS") | a.Instrument("LARS")) & date)
    else:
        res = Fido.search((a.Instrument("GRIS") | a.Instrument("LARS")) & date)
        assert len(res['kis']) == 2
330
        assert len(res['kis'][0]) == 400
331
332
        assert max(res['kis'][0]['DATE_BEG']) < date.end
        assert min(res['kis'][0]['DATE_END']) > date.start
333

334
335
        files = Fido.fetch(res['kis'][0, :100], binary=False)
        assert len(files) == 100
336
337
338
339
340
341
342
        assert files[0].endswith('.json')
        for filepath in files:
            meta = json.load(open(filepath))
            assert meta['_id']['$oid'] == os.path.splitext(os.path.basename(filepath))[0]
            assert date.start.isot[:12] in meta['metadata']['header']['DATE-OBS']
            assert date.start < Time(meta['metadata']['header']['DATE-OBS'])

343
344
345
346
347
348
349
350
351
352
353
354
        files = Fido.fetch(res['kis'][0, :5], binary=True)
        assert len(files) == 5
        assert files[0].endswith('.fits')
        for filepath in files:
            hdulist = fits.open(filepath)
            assert hdulist[0].header['TELESCOP'] in ('GREGOR', 'VTT')
            assert hdulist[0].header['INSTRUME'] in ('GRIS', 'LARS')
            assert date.start.iso[:10] in hdulist[0].header['DATE-OBS']
            assert Time(hdulist[0].header['DATE-OBS']).mjd < date.end.mjd + 600
            assert Time(hdulist[0].header['DATE-OBS']).mjd > date.start.mjd - 600
            hdulist.close()

355
356
    date = a.Time("2016/05/13 10:55", "2016/05/13 11:00")
    if not HAS_DOCKERTEST:
357
        with pytest.raises(URLError, match=rf"{_dockerexc('gris')}"
358
359
360
361
362
363
364
                           rf"{{'description.DATE_BEG':{{'.lte':{{'.date':'{date.end.isot}'}}}}}},"
                           rf"{{'description.DATE_END':{{'.gte':{{'.date':'{date.start.isot}'}}"):
            res = Fido.search((a.Instrument("GRIS") | a.Instrument("LARS")) & date)
        return

    res = Fido.search((a.Instrument("GRIS") | a.Instrument("LARS")) & date)
    assert len(res['kis']) == 2
365
    assert len(res['kis'][0]) == 300
366
367
    assert len(res['kis'][1]) == 1

368
369
370
371
    desc = table.vstack(res['kis'])
    assert len(desc) == 301
    assert max(desc['DATE_BEG']) < date.end
    assert min(desc['DATE_END']) > date.start
372

373
    files = Fido.fetch(res['kis'][:, :100], binary=False)
374
    assert len(files.errors) == 0
375
    assert len(files) == 101
376
377
    assert files[0].endswith('.json')
    for filepath in files:
378
        assert dirnames(filepath)[-1] in desc['OBS_NAME']
379
380
381
382
383
        meta = json.load(open(filepath))
        assert meta['_id']['$oid'] == os.path.splitext(os.path.basename(filepath))[0]
        assert date.start.iso[:10] in meta['metadata']['header']['DATE-OBS']
        assert Time(meta['metadata']['header']['DATE-OBS']).mjd < date.end.mjd + 600

384
    files = Fido.fetch(res['kis'][:, :10], binary=True)
385
386
387
388
389
390
391
392
    assert files[0].endswith('.fits')
    for filepath in files:
        hdulist = fits.open(filepath)
        assert hdulist[0].header['TELESCOP'] in ('GREGOR', 'VTT')
        assert hdulist[0].header['INSTRUME'] in ('GRIS', 'LARS')
        assert date.start.iso[:10] in hdulist[0].header['DATE-OBS']
        assert Time(hdulist[0].header['DATE-OBS']).mjd < date.end.mjd + 600
        assert Time(hdulist[0].header['DATE-OBS']).mjd > date.start.mjd - 600
393
394
395
396
        # LARS files have a different 'lars_l12_YYYY...' naming scheme.
        if 'EXTNAME' in hdulist[0].header:
            assert hdulist[0].header['EXTNAME'].startswith(dirnames(filepath)[-1].lstrip('gris_'))
            assert hdulist[0].header['FILENAME'][:14] in dirnames(filepath)[-1]
397
398
        hdulist.close()

399
    assert len(files) == 11
400
401


402
403
404
405
406
407
408
409
410
411
412
413
414
@pytest.mark.parametrize("query", ((a.Instrument("GRIS") & a.Level(3)),
                                   (a.Instrument("ChroTel") & a.Physobs("perspective.vortex")),
                                   (a.Level(0) & a.Instrument("Bob")),
                                   (a.Instrument("LARS") & a.sdc.Telescope("Leviathan"))))
def test_cant_handle_query(client, query):
    """Some examples of invalid queries with exceptions."""
    assert not client._can_handle_query(*query.attrs)
    with pytest.raises(AttributeError, match=r"Query not possible: "
                       rf"[ILPT][a-z]* {query.attrs[1].value} not in [rs]"):
        client.search(query)


@pytest.mark.parametrize("query", (a.Level(1), a.Wavelength(3200*u.AA, 1.6*u.micron),
415
                                   a.sdc.DataProduct('cube'), a.sdc.ObsName('gris_20140426_000'),
416
                                   a.sdc.Date('2021/01/31'), a.sdc.Filter('LOT%233802'),
417
418
                                   a.sdc.PolStates('IQUV'), a.sdc.Telescope('VTT'),
                                   a.sdc.Target('Sunspot_22'), a.sdc.AtmosR0(*([1, 20000]*u.mm)),
419
420
421
422
                                   a.sdc.Theta(20*u.arcmin, 89*u.deg), a.sdc.Mu(0.1, 1),
                                   a.sdc.ExposureTime(*([5, 60]*u.min)),
                                   a.sdc.HelioProjLon(5*u.arcsec), a.sdc.HelioProjLat(9*u.arcsec),
                                   a.sdc.SpatialResolution(0.1*u.arcsec, 0.8*u.arcsec),
423
                                   a.sdc.SpectralResolution(6000, 200000),
424
                                   a.sdc.TemporalResolution(2*u.s, 30*u.s),
425
                                   a.sdc.NDimensions(1, 2), a.sdc.PolXel(2, 4),
426
427
428
                                   a.sdc.SpatialXel1(200, 3000), a.sdc.SpatialXel2(100, 4000),
                                   a.sdc.SpectralXel(320, 4096), a.sdc.TimeXel(60, 86400)))
def test_all_queries(client, query):
429
    """Test an example of all supported query attributes with automatic field names."""
430
431
432
    assert client._can_handle_query(a.Instrument("GRIS"), query)
    if HAS_DOCKERTEST:
        res = client.search(a.Instrument("GRIS") & query)
433
        if len(res) > 0:
434
            assert res[0]['INSTRUMENT'] == 'gris'
435
    else:
436
        with pytest.raises(URLError, match=rf"{_dockerexc('gris')}"
437
438
                           rf"{{'description.*{query.type_name.upper()}"):
            client.search(a.Instrument("GRIS") & query)
439
440


441
442
443
444
445
446
447
448
449
def test_range(client):
    """
    Test range filter - 'FIELD_MIN,_MAX' shall include at least one of `Attr.min`, `Attr.max`.
    """
    wl = a.Wavelength(10800*u.AA, 1.25*u.micron)
    query = a.Instrument("GRIS") & wl
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
450
451
        assert max(res['WAVELENGTH_MIN']) <= 1250 * u.nm
        assert min(res['WAVELENGTH_MAX']) >= 1080 * u.nm
452
    else:
453
        with pytest.raises(URLError, match=rf"{_dockerexc('gris')}"
454
455
456
457
458
                           r"{'description.WAVELENGTH_MIN':{'.lte':1250}},"
                           r"{'description.WAVELENGTH_MAX':{'.gte':1080}}"):
            client.search(query)


459
460
461
462
463
def test_full_range(client):
    """
    Test 'fullrange' option - 'FIELD_MIN,_MAX' shall completely include `[Attr.min, Attr.max]`.
    """

464
    t = a.Time("2014/04/26 09:50", "2014/04/26 09:52")
465
    t.fullrange = True
466
    query = a.Instrument("GRIS") & t
467
468
469
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
470
        assert len(res) == 105
471
        assert 'INSTRUMENT' in res.colnames
472
    else:
473
474
475
        with pytest.raises(URLError, match=rf"{_dockerexc('GRIS')}"
                           r"{'description.DATE_BEG':{'.lte':{'.date':'2014-04-26T09:50:00.000'}}},"
                           r"{'description.DATE_END':{'.gte':{'.date':'2014-04-26T09:52:00.000'}"):
476
477
478
            client.search(query)

    # Test with inverted `min`, `max` inputs.
479
480
481
482
    hplt = a.sdc.HelioProjLat(0.1*u.arcmin, -2*u.arcsec)
    query = a.Instrument("LARS") & hplt
    if HAS_DOCKERTEST:
        res = client.search(query)
483
484
        assert max(res['HPLT_TAN_MIN']) <= 6 * u.arcsec
        assert min(res['HPLT_TAN_MAX']) >= -2 * u.arcsec
485
    else:
486
        with pytest.raises(URLError, match=rf"{_dockerexc('LARS')}"
487
488
489
490
                           r"{'description.HPLT_TAN_MIN':{'.lte':6}},"
                           r"{'description.HPLT_TAN_MAX':{'.gte':-2}}"):
            client.search(query)

491
492
493
494
495
    hplt.fullrange = True
    query = a.Instrument("LARS") & hplt
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
496
497
        assert max(res['HPLT_TAN_MIN']) <= -2 * u.arcsec
        assert min(res['HPLT_TAN_MAX']) >= 6 * u.arcsec
498
    else:
499
        with pytest.raises(URLError, match=rf"{_dockerexc('LARS')}"
500
501
                           r"{'description.HPLT_TAN_MIN':{'.lte':-2}},"
                           r"{'description.HPLT_TAN_MAX':{'.gte':6}}"):
502
            client.search(query)