test_client.py 23.7 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']['$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
    for i, ld in enumerate(res[:10]):
96
        oid = ld['links']['$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
    for ld in res[:2]:
105
        oid = ld['links']['$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']['$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
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
@pytest.mark.parametrize("level", ((0, 4), (1, 400), (2, 0)))
def test_level_data(level):
    """Test search and fetch of l{level[0]}_data."""
    obsname = 'gris_20150510_009'
    query = (a.Instrument("GRIS"), a.sdc.ObsName(obsname), a.Level(level[0]))

    if not HAS_DOCKERTEST:
        with pytest.raises(URLError, match=rf"{_dockerexc('gris')}"
                           rf"{{'description.OBS_NAME':'{obsname}'}},"
                           rf"{{'description.CALIB_LEVEL':{level[0]}"):
            res = Fido.search(*query)
        return

    res = Fido.search(*query)
    assert len(res['kis']) == level[1]

    files = Fido.fetch(res['kis'][:10])
    assert len(files) == min(level[1], 10)
    for filepath in files:
        assert dirnames(filepath)[-1] == res['kis'][0]['OBS_NAME']
        meta = json.load(open(filepath))
        assert meta['_id']['$oid'] == os.path.splitext(os.path.basename(filepath))[0]
        assert meta['metadata']['header']['CAMERA'] == 'IR1024'
        assert meta['metadata']['header']['FILENAME'].split('-')[0] in res['kis'][0]['OBS_NAME']

    files = Fido.fetch(res['kis'][:1], binary=True)
    assert len(files) == 1
    assert dirnames(files[0])[-1] == res['kis'][0]['OBS_NAME']
    hdulist = fits.open(files[0])
    assert hdulist[0].header.get('TELESCOP') == 'GREGOR'
    assert hdulist[0].header.get('CAMERA') == 'IR1024'
    hdulist.close()


436
437
438
439
440
441
442
443
444
445
446
447
448
@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),
449
                                   a.sdc.DataProduct('cube'), a.sdc.ObsName('gris_20140426_000'),
450
                                   a.sdc.Date('2021/01/31'), a.sdc.Filter('LOT%233802'),
451
452
                                   a.sdc.PolStates('IQUV'), a.sdc.Telescope('VTT'),
                                   a.sdc.Target('Sunspot_22'), a.sdc.AtmosR0(*([1, 20000]*u.mm)),
453
454
455
456
                                   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),
457
                                   a.sdc.SpectralResolution(6000, 200000),
458
                                   a.sdc.TemporalResolution(2*u.s, 30*u.s),
459
                                   a.sdc.NDimensions(1, 2), a.sdc.PolXel(2, 4),
460
461
462
                                   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):
463
    """Test an example of all supported query attributes with automatic field names."""
464
465
466
    assert client._can_handle_query(a.Instrument("GRIS"), query)
    if HAS_DOCKERTEST:
        res = client.search(a.Instrument("GRIS") & query)
467
        if len(res) > 0:
468
            assert res[0]['INSTRUMENT'] == 'gris'
469
    else:
470
        with pytest.raises(URLError, match=rf"{_dockerexc('gris')}"
471
472
                           rf"{{'description.*{query.type_name.upper()}"):
            client.search(a.Instrument("GRIS") & query)
473
474


475
476
477
478
479
480
481
482
483
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)
484
485
        assert max(res['WAVELENGTH_MIN']) <= 1250 * u.nm
        assert min(res['WAVELENGTH_MAX']) >= 1080 * u.nm
486
    else:
487
        with pytest.raises(URLError, match=rf"{_dockerexc('gris')}"
488
489
490
491
492
                           r"{'description.WAVELENGTH_MIN':{'.lte':1250}},"
                           r"{'description.WAVELENGTH_MAX':{'.gte':1080}}"):
            client.search(query)


493
494
495
496
497
def test_full_range(client):
    """
    Test 'fullrange' option - 'FIELD_MIN,_MAX' shall completely include `[Attr.min, Attr.max]`.
    """

498
    t = a.Time("2014/04/26 09:50", "2014/04/26 09:52")
499
    t.fullrange = True
500
    query = a.Instrument("GRIS") & t
501
502
503
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
504
        assert len(res) == 105
505
        assert 'INSTRUMENT' in res.colnames
506
    else:
507
508
509
        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'}"):
510
511
512
            client.search(query)

    # Test with inverted `min`, `max` inputs.
513
514
515
516
    hplt = a.sdc.HelioProjLat(0.1*u.arcmin, -2*u.arcsec)
    query = a.Instrument("LARS") & hplt
    if HAS_DOCKERTEST:
        res = client.search(query)
517
518
        assert max(res['HPLT_TAN_MIN']) <= 6 * u.arcsec
        assert min(res['HPLT_TAN_MAX']) >= -2 * u.arcsec
519
    else:
520
        with pytest.raises(URLError, match=rf"{_dockerexc('LARS')}"
521
522
523
524
                           r"{'description.HPLT_TAN_MIN':{'.lte':6}},"
                           r"{'description.HPLT_TAN_MAX':{'.gte':-2}}"):
            client.search(query)

525
526
527
528
529
    hplt.fullrange = True
    query = a.Instrument("LARS") & hplt
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
530
531
        assert max(res['HPLT_TAN_MIN']) <= -2 * u.arcsec
        assert min(res['HPLT_TAN_MAX']) >= 6 * u.arcsec
532
    else:
533
        with pytest.raises(URLError, match=rf"{_dockerexc('LARS')}"
534
535
                           r"{'description.HPLT_TAN_MIN':{'.lte':-2}},"
                           r"{'description.HPLT_TAN_MAX':{'.gte':6}}"):
536
            client.search(query)