tests.test_exceptions   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 270
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 13
eloc 181
dl 0
loc 270
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
B EnsemblRest.test_MaximumPOSTSize() 0 70 1
A EnsemblRest.test_getMsg() 0 11 2
A EnsemblRest.tearDown() 0 3 1
A EnsemblRest.test_SomethingBad() 0 26 1
A EnsemblRest.test_RestUnavailable() 0 15 1
A EnsemblRest.test_RequestTimeout() 0 20 1
A EnsemblRest.setUp() 0 3 1
A EnsemblRest.test_rateLimit() 0 41 2
A EnsemblRest.test_BadRequest() 0 9 1
A EnsemblRest.test_BadUrl() 0 35 2
1
import time
2
import unittest
3
4
import pytest
5
6
import pyensemblrest
7
from pyensemblrest.ensemblrest import FakeResponse
8
from pyensemblrest.exceptions import (
9
    EnsemblRestError,
10
    EnsemblRestRateLimitError,
11
    EnsemblRestServiceUnavailable,
12
)
13
14
15
class EnsemblRest(unittest.TestCase):
16
    """A class to test EnsemblRest methods"""
17
18
    def setUp(self) -> None:
19
        """Create a EnsemblRest object"""
20
        self.EnsEMBL = pyensemblrest.EnsemblRest()
21
22
    def tearDown(self) -> None:
23
        """Sleep a while before doing next request"""
24
        time.sleep(0.2)
25
26
    @pytest.mark.live
27
    def test_BadRequest(self) -> None:
28
        """Do an ensembl bad request"""
29
30
        self.assertRaisesRegex(
31
            EnsemblRestError,
32
            "EnsEMBL REST API returned a 400 (Bad Request)*",
33
            self.EnsEMBL.getArchiveById,
34
            id="meow",
35
        )
36
37
    @pytest.mark.live
38
    def test_BadUrl(self) -> None:
39
        """Do a Not found request"""
40
41
        # record old uri value
42
        old_uri = self.EnsEMBL.getArchiveById.__globals__["ensembl_api_table"][
43
            "getArchiveById"
44
        ]["url"]
45
46
        # set a new uri. This change a global value
47
        self.EnsEMBL.getArchiveById.__globals__["ensembl_api_table"]["getArchiveById"][
48
            "url"
49
        ] = "/archive/meow/{{id}}"
50
51
        # do a request
52
        try:
53
            self.assertRaisesRegex(
54
                EnsemblRestError,
55
                "EnsEMBL REST API returned a 404 (Not Found)*",
56
                self.EnsEMBL.getArchiveById,
57
                id="ENSG00000157764",
58
            )
59
60
        except AssertionError as e:
61
            # fix the global value
62
            self.EnsEMBL.getArchiveById.__globals__["ensembl_api_table"][
63
                "getArchiveById"
64
            ]["url"] = old_uri
65
            # then raise exception
66
            raise Exception(e)
67
68
        # fix the global value
69
        self.EnsEMBL.getArchiveById.__globals__["ensembl_api_table"]["getArchiveById"][
70
            "url"
71
        ] = old_uri
72
73
    @pytest.mark.live
74
    def test_getMsg(self) -> None:
75
        """Do a bad request and get message"""
76
77
        msg = None
78
        try:
79
            self.EnsEMBL.getArchiveById(id="miao")
80
        except EnsemblRestError as e:
81
            msg = e.msg
82
83
        self.assertRegex(msg, "EnsEMBL REST API returned a 400 (Bad Request)*")
84
85
    @pytest.mark.live
86
    def test_rateLimit(self) -> None:
87
        """Simulating a rate limiting environment"""
88
89
        # get a request
90
        self.EnsEMBL.getArchiveById(id="ENSG00000157764")
91
92
        # retrieve last_reponse
93
        response = self.EnsEMBL.last_response
94
95
        # get headers
96
        headers = response.headers
97
98
        # simulating a rate limiting
99
        # https://github.com/Ensembl/ensembl-rest/wiki/Rate-Limits#a-maxed-out-rate-limit-response
100
        headers["Retry-After"] = "40.0"
101
        headers["X-RateLimit-Limit"] = "55000"
102
        headers["X-RateLimit-Reset"] = "40"
103
        headers["X-RateLimit-Period"] = "3600"
104
        headers["X-RateLimit-Remaining"] = "0"
105
106
        # set a different status code
107
        response.status_code = 429
108
109
        # now parse request. headers is a reference to response.headers
110
        self.assertRaisesRegex(
111
            EnsemblRestRateLimitError,
112
            "EnsEMBL REST API returned a 429 (Too Many Requests)*",
113
            self.EnsEMBL.parseResponse,
114
            response,
115
        )
116
117
        # try to read exception message
118
        msg = None
119
        try:
120
            self.EnsEMBL.parseResponse(response)
121
122
        except EnsemblRestError as e:
123
            msg = e.msg
124
125
        self.assertRegex(msg, "EnsEMBL REST API returned a 429 (Too Many Requests)*")
126
127
    @pytest.mark.live
128
    def test_RestUnavailable(self) -> None:
129
        """Querying a not available REST server"""
130
131
        # get an ensembl rest service (supposing that we have no local REST service)
132
        EnsEMBL = pyensemblrest.EnsemblRest(base_url="http://localhost:3000")
133
134
        # get a request (GET)
135
        self.assertRaises(
136
            EnsemblRestServiceUnavailable, EnsEMBL.getArchiveById, id="ENSG00000157764"
137
        )
138
        self.assertRaises(
139
            EnsemblRestServiceUnavailable,
140
            EnsEMBL.getArchiveByMultipleIds,
141
            id=["ENSG00000157764", "ENSG00000248378"],
142
        )
143
144
    @pytest.mark.live
145
    def test_SomethingBad(self) -> None:
146
        """raise exception when n of attempts exceeds"""
147
148
        # get a request
149
        self.EnsEMBL.getArchiveById(id="ENSG00000157764")
150
151
        # retrieve last_reponse
152
        response = self.EnsEMBL.last_response
153
154
        # raise last_attempt number
155
        self.EnsEMBL.last_attempt = self.EnsEMBL.max_attempts
156
157
        # instantiate a fake response
158
        fakeResponse = FakeResponse(
159
            headers=response.headers,
160
            status_code=400,
161
            text="""{"error":"something bad has happened"}""",
162
        )
163
164
        # verify exception
165
        self.assertRaisesRegex(
166
            EnsemblRestError,
167
            "Max number of retries attempts reached.*",
168
            self.EnsEMBL.parseResponse,
169
            fakeResponse,
170
        )
171
172
    @pytest.mark.live
173
    def test_RequestTimeout(self) -> None:
174
        """Deal with connections timeout"""
175
176
        # Ovverride max_attempts
177
        self.EnsEMBL.max_attempts = 1
178
        self.EnsEMBL.timeout = 1
179
180
        # verify exception
181
        self.assertRaisesRegex(
182
            EnsemblRestError,
183
            "Max number of retries attempts reached.* timeout",
184
            self.EnsEMBL.searchGA4GHFeatures,
185
            parentId="ENST00000408937.7",
186
            featureSetId="",
187
            featureTypes=["cds"],
188
            end=220023,
189
            referenceName="X",
190
            start=197859,
191
            pageSize=1,
192
        )
193
194
    @pytest.mark.live
195
    def test_MaximumPOSTSize(self) -> None:
196
        """Deal with maximum post size errors"""
197
198
        # verify exception
199
        self.assertRaisesRegex(
200
            EnsemblRestError,
201
            "POST message too large.*",
202
            self.EnsEMBL.getSequenceByMultipleIds,
203
            ids=[
204
                "ENSG00000157764",
205
                "ENSG00000248378",
206
                "ENSG00000157764",
207
                "ENSG00000248378",
208
                "ENSG00000157764",
209
                "ENSG00000248378",
210
                "ENSG00000157764",
211
                "ENSG00000248378",
212
                "ENSG00000157764",
213
                "ENSG00000248378",
214
                "ENSG00000157764",
215
                "ENSG00000248378",
216
                "ENSG00000157764",
217
                "ENSG00000248378",
218
                "ENSG00000157764",
219
                "ENSG00000248378",
220
                "ENSG00000157764",
221
                "ENSG00000248378",
222
                "ENSG00000157764",
223
                "ENSG00000248378",
224
                "ENSG00000157764",
225
                "ENSG00000248378",
226
                "ENSG00000157764",
227
                "ENSG00000248378",
228
                "ENSG00000157764",
229
                "ENSG00000248378",
230
                "ENSG00000157764",
231
                "ENSG00000248378",
232
                "ENSG00000157764",
233
                "ENSG00000248378",
234
                "ENSG00000157764",
235
                "ENSG00000248378",
236
                "ENSG00000157764",
237
                "ENSG00000248378",
238
                "ENSG00000157764",
239
                "ENSG00000248378",
240
                "ENSG00000157764",
241
                "ENSG00000248378",
242
                "ENSG00000157764",
243
                "ENSG00000248378",
244
                "ENSG00000157764",
245
                "ENSG00000248378",
246
                "ENSG00000157764",
247
                "ENSG00000248378",
248
                "ENSG00000157764",
249
                "ENSG00000248378",
250
                "ENSG00000157764",
251
                "ENSG00000248378",
252
                "ENSG00000157764",
253
                "ENSG00000248378",
254
                "ENSG00000157764",
255
                "ENSG00000248378",
256
                "ENSG00000157764",
257
                "ENSG00000248378",
258
                "ENSG00000157764",
259
                "ENSG00000248378",
260
                "ENSG00000157764",
261
                "ENSG00000248378",
262
                "ENSG00000157764",
263
                "ENSG00000248378",
264
            ],
265
        )
266
267
268
if __name__ == "__main__":
269
    unittest.main()
270