Skip to content

Commit bce6c58

Browse files
icingptitSeb
authored andcommitted
pytest: improvements
- set CURL_CI for pytest runs in CI environments - exclude timing sensitive tests from CI runs - for failed results, list only the log and stat of the failed transfer - fix type in http.c comment Closes curl#11812
1 parent 027e226 commit bce6c58

File tree

9 files changed

+47
-15
lines changed

9 files changed

+47
-15
lines changed

.github/workflows/linux.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ jobs:
404404
# run for `tests` directory, so pytest does not pick up any other
405405
# packages we might have built here
406406
run:
407-
pytest -v tests
407+
pytest tests
408408
name: 'run pytest'
409409
env:
410410
TFLAGS: "${{ matrix.build.tflags }}"
411+
CURL_CI: github

.github/workflows/ngtcp2-linux.yml

+4-2
Original file line numberDiff line numberDiff line change
@@ -263,15 +263,17 @@ jobs:
263263
env:
264264
TFLAGS: "${{ matrix.build.tflags }}"
265265

266-
- run: pytest -v
266+
- run: pytest tests
267267
name: 'run pytest'
268268
env:
269269
TFLAGS: "${{ matrix.build.tflags }}"
270+
CURL_CI: github
270271

271-
- run: pytest
272+
- run: pytest tests
272273
name: 'run pytest with slowed network'
273274
env:
274275
# 33% of sends are EAGAINed
275276
CURL_DBG_SOCK_WBLOCK: 33
276277
# only 80% of data > 10 bytes is send
277278
CURL_DBG_SOCK_WPARTIAL: 80
279+
CURL_CI: github

.github/workflows/quiche-linux.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ jobs:
202202
env:
203203
TFLAGS: "${{ matrix.build.tflags }}"
204204

205-
- run: pytest -v tests/http
205+
- run: pytest tests
206206
name: 'run pytest'
207207
env:
208208
TFLAGS: "${{ matrix.build.tflags }}"
209+
CURL_CI: github

lib/http.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2707,7 +2707,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
27072707

27082708
if(!data->req.upload_chunky) {
27092709
/* We're not sending it 'chunked', append it to the request
2710-
already now to reduce the number if send() calls */
2710+
already now to reduce the number of send() calls */
27112711
result = Curl_dyn_addn(r, data->set.postfields,
27122712
(size_t)http->postsize);
27132713
included_body = http->postsize;

tests/http/test_02_download.py

+3
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ def test_02_09_1MB_parallel(self, env: Env,
201201
r.check_response(count=count, http_status=200)
202202

203203
@pytest.mark.skipif(condition=Env().slow_network, reason="not suitable for slow network tests")
204+
@pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
204205
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
205206
def test_02_10_10MB_serial(self, env: Env,
206207
httpd, nghttpx, repeat, proto):
@@ -213,6 +214,7 @@ def test_02_10_10MB_serial(self, env: Env,
213214
r.check_response(count=count, http_status=200)
214215

215216
@pytest.mark.skipif(condition=Env().slow_network, reason="not suitable for slow network tests")
217+
@pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
216218
@pytest.mark.parametrize("proto", ['h2', 'h3'])
217219
def test_02_11_10MB_parallel(self, env: Env,
218220
httpd, nghttpx, repeat, proto):
@@ -255,6 +257,7 @@ def test_02_13_head_serial_h2c(self, env: Env,
255257
r.check_response(count=count, http_status=200)
256258

257259
@pytest.mark.skipif(condition=Env().slow_network, reason="not suitable for slow network tests")
260+
@pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
258261
def test_02_20_h2_small_frames(self, env: Env, httpd, repeat):
259262
# Test case to reproduce content corruption as observed in
260263
# https://github.com/curl/curl/issues/10525

tests/http/test_04_stuttered.py

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737

3838
@pytest.mark.skipif(condition=Env().slow_network, reason="not suitable for slow network tests")
39+
@pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
3940
class TestStuttered:
4041

4142
@pytest.fixture(autouse=True, scope='class')

tests/http/test_08_caddy.py

+3
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ def test_08_03_download_1mb_parallel(self, env: Env, caddy: Caddy,
111111

112112
# download 5MB files sequentially
113113
@pytest.mark.skipif(condition=Env().slow_network, reason="not suitable for slow network tests")
114+
@pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
114115
@pytest.mark.parametrize("proto", ['h2', 'h3'])
115116
def test_08_04a_download_10mb_sequential(self, env: Env, caddy: Caddy,
116117
repeat, proto):
@@ -126,6 +127,7 @@ def test_08_04a_download_10mb_sequential(self, env: Env, caddy: Caddy,
126127

127128
# download 10MB files sequentially
128129
@pytest.mark.skipif(condition=Env().slow_network, reason="not suitable for slow network tests")
130+
@pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
129131
@pytest.mark.parametrize("proto", ['h2', 'h3'])
130132
def test_08_04b_download_10mb_sequential(self, env: Env, caddy: Caddy,
131133
repeat, proto):
@@ -142,6 +144,7 @@ def test_08_04b_download_10mb_sequential(self, env: Env, caddy: Caddy,
142144
# download 10MB files parallel
143145
@pytest.mark.skipif(condition=Env().slow_network, reason="not suitable for slow network tests")
144146
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
147+
@pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
145148
def test_08_05_download_1mb_parallel(self, env: Env, caddy: Caddy,
146149
repeat, proto):
147150
if proto == 'h3' and not env.have_h3_curl():

tests/http/testenv/curl.py

+27-10
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#
2525
###########################################################################
2626
#
27-
import pytest
2827
import json
2928
import logging
3029
import os
@@ -199,15 +198,15 @@ def check_response(self, http_status: Optional[int] = 200,
199198
if self.with_stats:
200199
for idx, x in enumerate(self.stats):
201200
assert 'http_code' in x, \
202-
f'response #{idx} reports no http_code\n{self.dump_logs()}'
201+
f'response #{idx} reports no http_code\n{self.dump_stat(x)}'
203202
assert x['http_code'] == http_status, \
204203
f'response #{idx} http_code: expected {http_status}, '\
205-
f'got {x["http_code"]}\n{self.dump_logs()}'
204+
f'got {x["http_code"]}\n{self.dump_stat(x)}'
206205
else:
207206
for idx, x in enumerate(self.responses):
208207
assert x['status'] == http_status, \
209208
f'response #{idx} status: expected {http_status},'\
210-
f'got {x["status"]}\n{self.dump_logs()}'
209+
f'got {x["status"]}\n{self.dump_stat(x)}'
211210
if protocol is not None:
212211
if self.with_stats:
213212
http_version = None
@@ -221,7 +220,7 @@ def check_response(self, http_status: Optional[int] = 200,
221220
for idx, x in enumerate(self.stats):
222221
assert x['http_version'] == http_version, \
223222
f'response #{idx} protocol: expected http/{http_version},' \
224-
f'got version {x["http_version"]}\n{self.dump_logs()}'
223+
f'got version {x["http_version"]}\n{self.dump_stat(x)}'
225224
else:
226225
for idx, x in enumerate(self.responses):
227226
assert x['protocol'] == protocol, \
@@ -241,26 +240,44 @@ def check_stats(self, count: int, http_status: Optional[int] = None,
241240
if http_status is not None:
242241
for idx, x in enumerate(self.stats):
243242
assert 'http_code' in x, \
244-
f'status #{idx} reports no http_code\n{self.dump_logs()}'
243+
f'status #{idx} reports no http_code\n{self.dump_stat(x)}'
245244
assert x['http_code'] == http_status, \
246245
f'status #{idx} http_code: expected {http_status}, '\
247-
f'got {x["http_code"]}\n{self.dump_logs()}'
246+
f'got {x["http_code"]}\n{self.dump_stat(x)}'
248247
if exitcode is not None:
249248
for idx, x in enumerate(self.stats):
250249
if 'exitcode' in x:
251250
assert x['exitcode'] == 0, \
252251
f'status #{idx} exitcode: expected {exitcode}, '\
253-
f'got {x["exitcode"]}\n{self.dump_logs()}'
252+
f'got {x["exitcode"]}\n{self.dump_stat(x)}'
254253

255254
def dump_logs(self):
256-
lines = []
257-
lines.append('>>--stdout ----------------------------------------------\n')
255+
lines = ['>>--stdout ----------------------------------------------\n']
258256
lines.extend(self._stdout)
259257
lines.append('>>--stderr ----------------------------------------------\n')
260258
lines.extend(self._stderr)
261259
lines.append('<<-------------------------------------------------------\n')
262260
return ''.join(lines)
263261

262+
def dump_stat(self, x):
263+
lines = [
264+
'json stat from curl:',
265+
json.JSONEncoder(indent=2).encode(x),
266+
]
267+
if 'xfer_id' in x:
268+
xfer_id = x['xfer_id']
269+
lines.append(f'>>--xfer {xfer_id} trace:\n')
270+
lines.extend(self.xfer_trace_for(xfer_id))
271+
else:
272+
lines.append('>>--full trace-------------------------------------------\n')
273+
lines.extend(self._stderr)
274+
lines.append('<<-------------------------------------------------------\n')
275+
return ''.join(lines)
276+
277+
def xfer_trace_for(self, xfer_id) -> List[str]:
278+
pat = re.compile(f'^[^[]* \\[{xfer_id}-.*$')
279+
return [line for line in self._stderr if pat.match(line)]
280+
264281

265282
class CurlClient:
266283

tests/http/testenv/env.py

+4
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,10 @@ def slow_network(self) -> bool:
444444
return "CURL_DBG_SOCK_WBLOCK" in os.environ or \
445445
"CURL_DBG_SOCK_WPARTIAL" in os.environ
446446

447+
@property
448+
def ci_run(self) -> bool:
449+
return "CURL_CI" in os.environ
450+
447451
def authority_for(self, domain: str, alpn_proto: Optional[str] = None):
448452
if alpn_proto is None or \
449453
alpn_proto in ['h2', 'http/1.1', 'http/1.0', 'http/0.9']:

0 commit comments

Comments
 (0)