test_client.py 11 KB
Newer Older
1
2
import pytest

3
4
import urllib.request
from urllib.error import HTTPError, URLError
5
import json
6

7
import astropy.units as u
8
from sunpy.net import attrs as a
9
from sunpy.net.base_client import QueryResponseTable
10

11
from sdc.client import KISClient
12
13
14


_BASE_URL = "http://dockertest:8083/sdc/"
15
16
17
18
19
20
_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'}}}]}")
21
22

try:
23
    response = urllib.request.urlopen(f"{_BASE_URL}{_QUERY_BASE}{_EXAMPLE_QUERY}")
24
25
26
27
28
29
30
    HAS_DOCKERTEST = True
except(HTTPError, URLError):
    HAS_DOCKERTEST = False


@pytest.fixture
def client():
31
    return KISClient()
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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]

    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'))
53
    assert isinstance(res, QueryResponseTable)
54
55
56
57
58
59
60
    assert len(res) == 1
    description = res[0]['_embedded'][0].get('description')
    assert description['INSTRUMENT'] == 'gris'
    assert description['TELESCOPE'] == 'GREGOR'
    assert description['BTYPE'] == 'phot.count'


61
def test_search(client):
62
    """Test conversion of (supported) Attrs to query string."""
63

64
    assert not client._can_handle_query(a.Time("2019/01/01", "2021/01/01"))
65
66
67
68
    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"))

69
    assert not client._can_handle_query(a.Instrument("UVES"), a.Time("2019/01/01", "2021/01/01"))
70
71
72
73
    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"))

74
    query = a.Instrument("BBI") & a.Time("2019/01/01", "2021/01/01")
75
    # TODO: Verify returned observation records.
76
    assert client._can_handle_query(query)
77
    if HAS_DOCKERTEST:
78
        res = client.search(query)
79
80
        assert isinstance(res, QueryResponseTable)
        if len(res[0].get('_embedded')) > 0:
81
            assert 'description' in res[0]['_embedded'][0]
82
83
    else:
        with pytest.raises(URLError, match=r"Unable to execute search "
84
85
                           r".http://dockertest:8083/sdc/bbi_observations.filter="
                           r"{'.and':.{'description.INSTRUMENT':'bbi'},"
86
87
                           r"{'description.DATE_BEG':{'.lte':{'.date':'2021-01-01T00:00:00.000'}}},"
                           r"{'description.DATE_END':{'.gte':{'.date':'2019-01-01T00:00:00.000'}}}"
88
                           rf".*Confirm that RESTHeart is running on {_BASE_URL} and connected"):
89
90
91
92
93
94
            client.search(query)

    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)
95
        if len(res[0].get('_embedded')) > 0:
96
            assert 'description' in res[0]['_embedded'][0]
97
98
99
100
    else:
        with pytest.raises(URLError, match=r"Unable to execute search "
                           r".http://dockertest:8083/sdc/lars_observations.filter="
                           r"{'.and':.{'description.INSTRUMENT':'lars'},"
101
102
                           r"{'description.HPLT_TAN_MIN':{'.lte':12}},"
                           r"{'description.HPLT_TAN_MAX':{'.gte':-10}}"):
103
104
            client.search(query)

105
    query = a.Instrument("GRIS") & (a.sdc.Theta(85*u.deg, 600*u.arcmin) | a.sdc.PolStates('iq'))
106
107
108
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
109
110
        assert len(res) == 2
        if len(res[0].get('_embedded')) > 0:
111
            assert 'description' in res[0]['_embedded'][0]
112
    else:
Derek Homeier's avatar
Derek Homeier committed
113
        with pytest.raises(URLError, match=r"Unable to execute search ") as exc:
114
115
            client.search(query)
        # Will raise on first of multi-part OR queries.
116
117
        assert "http://dockertest:8083/sdc/gris_observations?filter=" in str(exc.value)
        assert "{'description.THETA':{'$gte':10,'$lte':85}}" in str(exc.value)
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
        assert "{'description.POL_STATES':" not in str(exc.value)


@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),
134
135
136
137
                                   a.sdc.DataProduct('cube'), a.sdc.ObsName('gris_20140426_000'),
                                   a.sdc.Date('2021/01/31'), a.sdc.Filter('G'),
                                   a.sdc.PolStates('IQUV'), a.sdc.Telescope('VTT'),
                                   a.sdc.Target('Sunspot_22'), a.sdc.AtmosR0(*([1, 20000]*u.mm)),
138
139
140
141
                                   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),
142
                                   a.sdc.SpectralResolution(6000, 200000),
143
                                   a.sdc.TemporalResolution(2*u.s, 30*u.s),
144
                                   a.sdc.NDimensions(1, 2), a.sdc.PolXel(2, 4),
145
146
147
                                   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):
148
    """Test an example of all supported query attributes with automatic field names."""
149
150
151
    assert client._can_handle_query(a.Instrument("GRIS"), query)
    if HAS_DOCKERTEST:
        res = client.search(a.Instrument("GRIS") & query)
152
        if len(res[0].get('_embedded')) > 0:
153
            assert 'description' in res[0]['_embedded'][0]
154
155
156
157
158
159
    else:
        with pytest.raises(URLError, match=r"Unable to execute search "
                           r".http://dockertest:8083/sdc/gris_observations.filter="
                           r"{'.and':.{'description.INSTRUMENT':'gris'},"
                           rf"{{'description.*{query.type_name.upper()}"):
            client.search(a.Instrument("GRIS") & query)
160
161


162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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)
        wave_min = [obs['description']['WAVELENGTH_MIN'] for obs in res[0]['_embedded']]
        wave_max = [obs['description']['WAVELENGTH_MAX'] for obs in res[0]['_embedded']]
        assert max(wave_min) <= 1250
        assert min(wave_max) >= 1080
    else:
        with pytest.raises(URLError, match=r"Unable to execute search "
                           r".http://dockertest:8083/sdc/gris_observations.filter="
                           r"{'.and':.{'description.INSTRUMENT':'gris'},"
                           r"{'description.WAVELENGTH_MIN':{'.lte':1250}},"
                           r"{'description.WAVELENGTH_MAX':{'.gte':1080}}"):
            client.search(query)


184
185
186
187
188
189
190
191
192
193
194
def test_full_range(client):
    """
    Test 'fullrange' option - 'FIELD_MIN,_MAX' shall completely include `[Attr.min, Attr.max]`.
    """

    t = a.Time("2019/01/01", "2019/01/09")
    t.fullrange = True
    query = a.Instrument("BBI") & t
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
195
        if len(res[0].get('_embedded')) > 0:
196
            assert 'description' in res[0]['_embedded'][0]
197
198
199
200
    else:
        with pytest.raises(URLError, match=r"Unable to execute search "
                           r".http://dockertest:8083/sdc/bbi_observations.filter="
                           r"{'.and':.{'description.INSTRUMENT':'bbi'},"
201
202
                           r"{'description.DATE_BEG':{'.lte':{'.date':'2019-01-01T00:00:00.000'}}},"
                           r"{'description.DATE_END':{'.gte':{'.date':'2019-01-09T00:00:00.000'}"):
203
204
205
            client.search(query)

    # Test with inverted `min`, `max` inputs.
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    hplt = a.sdc.HelioProjLat(0.1*u.arcmin, -2*u.arcsec)
    query = a.Instrument("LARS") & hplt
    if HAS_DOCKERTEST:
        res = client.search(query)
        hplt_tan_min = [obs['description']['HPLT_TAN_MIN'] for obs in res[0]['_embedded']]
        hplt_tan_max = [obs['description']['HPLT_TAN_MAX'] for obs in res[0]['_embedded']]
        assert max(hplt_tan_min) <= 6
        assert min(hplt_tan_max) >= -2
    else:
        with pytest.raises(URLError, match=r"Unable to execute search "
                           r".http://dockertest:8083/sdc/lars_observations.filter="
                           r"{'.and':.{'description.INSTRUMENT':'lars'},"
                           r"{'description.HPLT_TAN_MIN':{'.lte':6}},"
                           r"{'description.HPLT_TAN_MAX':{'.gte':-2}}"):
            client.search(query)

222
223
224
225
226
    hplt.fullrange = True
    query = a.Instrument("LARS") & hplt
    assert client._can_handle_query(query)
    if HAS_DOCKERTEST:
        res = client.search(query)
227
228
229
230
        hplt_tan_min = [obs['description']['HPLT_TAN_MIN'] for obs in res[0]['_embedded']]
        hplt_tan_max = [obs['description']['HPLT_TAN_MAX'] for obs in res[0]['_embedded']]
        assert max(hplt_tan_min) <= -2
        assert min(hplt_tan_max) >= 6
231
232
233
234
    else:
        with pytest.raises(URLError, match=r"Unable to execute search "
                           r".http://dockertest:8083/sdc/lars_observations.filter="
                           r"{'.and':.{'description.INSTRUMENT':'lars'},"
235
236
                           r"{'description.HPLT_TAN_MIN':{'.lte':-2}},"
                           r"{'description.HPLT_TAN_MAX':{'.gte':6}}"):
237
            client.search(query)