Commit 4d91c0a0 authored by Petr Špaček's avatar Petr Špaček

Merge branch 'ci-transport-tests' into 'master'

transport tests

See merge request !707
parents e494bd26 dc6ad4a9
Pipeline #42915 passed with stages
in 21 minutes and 52 seconds
......@@ -61,6 +61,7 @@ _obj
/tests/test_zonecut
/tests/dnstap/src/dnstap-test/vendor/github.com/
/tests/dnstap/src/github.com/
.pytest_cache
kresd.amalg.c
libkres.amalg.c
/doc/kresd.8
......
......@@ -16,7 +16,7 @@ stages:
- build
- test
- coverage
- respdiff
- extended
- deploy
build:linux:amd64:
......@@ -268,8 +268,58 @@ test:linux:amd64:valgrind:
- linux
- amd64
pytests:lint:
stage: test
dependencies: []
except:
- master
script:
- ./ci/pytests/lint.sh
tags:
- docker
- linux
- amd64
pytests:run:
stage: test
dependencies:
- build:linux:amd64
except:
- master
script:
- pushd tests/pytests/rehandshake
- make all
- popd
- PATH="$PREFIX/sbin:$PATH" ./ci/pytests/run.sh &> pytests.log.txt
after_script:
- tail -1 pytests.log.txt
- echo "See pytests.html or pytests.log.txt for full report."
artifacts:
when: always
expire_in: 1 week
paths:
- pytest*
tags:
- docker
- linux
- amd64
pytests:extended:
stage: extended
dependencies:
- build:linux:amd64
except:
- master
script:
- PATH="$PREFIX/sbin:$PATH" ./ci/pytests/run-extended.sh
tags:
- docker
- linux
- amd64
.respdiff: &respdiff
stage: respdiff
stage: extended
dependencies: []
only: # trigger job only in repos under our control
- branches@knot/knot-resolver
......@@ -370,7 +420,7 @@ respdiff:iter:udp:linux:amd64:
.resperf: &resperf
stage: respdiff
stage: extended
dependencies: []
only: # trigger job only in repos under our control
- branches@knot/knot-resolver
......
......@@ -25,6 +25,8 @@ RUN pip3 install --upgrade pip
RUN pip3 install pylint
RUN pip3 install pep8
RUN pip3 install pytest-xdist
# tests/pytest dependencies
RUN pip3 install dnspython jinja2 pytest pytest-html pytest-xdist
# C dependencies for python-augeas
RUN apt-get install -y -qqq libaugeas-dev libffi-dev
......
#!/bin/bash
python3 -m flake8 --max-line-length=100 tests/pytests
FLAKE8=$?
ci/pytests/pylint-run.sh
PYLINT=$?
if [ $PYLINT -ne 0 ]; then
exit 1
fi
if [ $FLAKE8 -ne 0 ]; then
exit 1
fi
exit 0
#!/usr/bin/env bash
set -e
# Find Python modules and standalone Python scripts
FILES=$(find ./tests/pytests \
-type d -exec test -e '{}/__init__.py' \; -print -prune -o \
-name '*.py' -print)
python3 -m pylint -j 0 --rcfile ./tests/pytests/pylintrc ${FILES}
#!/bin/bash
# Execute extended, long-running test suite
python3 -m pytest -ra --capture=no tests/pytests/conn_flood.py
#!/bin/bash
python3 -m pytest --html pytests.html --self-contained-html -dn 24 tests/pytests
Python client tests for kresd
=============================
The tests run `/usr/bin/env kresd` (can be modified with `$PATH`) with custom config
and execute client-side testing, such as TCP / TLS connection management.
Requirements
------------
- pip3 install -r requirements.txt
Executing tests
---------------
Tests can be executed with the pytest framework.
.. code-block:: bash
$ pytest-3 # sequential, all tests (with exception of few special tests)
$ pytest-3 test_conn_mgmt.py::test_ignore_garbage # specific test only
$ pytest-3 --html pytests.html --self-contained-html # html report
It's highly recommended to run these tests in parallel, since lot of them
wait for kresd timeout. This can be done with `python-xdist`:
.. code-block:: bash
$ pytest-3 -n 24 # parallel with 24 jobs
Each test spawns an independent kresd instance, so test failures shouldn't affect
each other.
Some tests are omitted from automatic test collection by default, due to their
resource contraints. These typicially have to be executed separately by providing
the path to test file directly.
.. code-block:: bash
$ pytest-3 conn_flood.py
Note: some tests may fail without an internet connection.
Developer notes
---------------
Typically, each test requires a setup of kresd, and a connected socket to run tests on.
The framework provides a few useful pytest fixtures to simplify this process:
- `kresd_sock` provides a connected socket to a test-specific, running kresd instance.
It expands to 4 values (tests) - IPv4 TCP, IPv6 TCP, IPv4 TLS, IPv6 TLS sockets
- `make_kresd_sock` is similar to `kresd_sock`, except it's a factory function that
produces a new connected socket (of the same type) on each call
- `kresd`, `kresd_tt` are all Kresd instances, already running
and initialized with config (with no / valid TLS certificates)
# !/bin/bash
if [ ! -d ./demoCA ]; then
mkdir ./demoCA
fi
if [ ! -d ./demoCA/newcerts ]; then
mkdir ./demoCA/newcerts
fi
touch ./demoCA/index.txt
touch ./demoCA/index.txt.attr
if [ ! -f ./demoCA/serial ]; then
echo 01 > ./demoCA/serial
fi
openssl genrsa -out tt-expired.key.pem 2048
openssl req -config tt.conf -new -key tt-expired.key.pem -out tt-expired.csr.pem
openssl ca -config tt.conf -selfsign -keyfile tt-expired.key.pem -out tt-expired.cert.pem -in tt-expired.csr.pem -startdate 19700101000000Z -enddate 19700101000000Z
# !/bin/sh
openssl req -config tt.conf -new -x509 -newkey rsa:2048 -nodes -keyout tt.key.pem -sha256 -out tt.cert.pem -days 20000
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=CZ, ST=PRAGUE, CN=transport-test-server.com
Validity
Not Before: Jan 1 00:00:00 1970 GMT
Not After : Jan 1 00:00:00 1970 GMT
Subject: C=CZ, ST=PRAGUE, CN=transport-test-server.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:bf:6b:1a:11:47:01:ac:eb:5c:2d:cf:ce:6a:a4:
00:ce:2f:d1:25:03:5f:06:38:02:92:24:18:92:2a:
69:19:b2:2b:a3:4f:f7:79:de:35:c3:f5:72:37:83:
44:93:f9:76:fc:89:29:32:9c:0d:4b:95:7d:d1:5d:
40:e9:ba:49:50:7d:c6:0a:c8:1e:e7:90:1e:37:7c:
0b:23:a3:e3:bc:c9:53:81:de:d6:5f:cb:b2:3d:36:
ac:59:b0:33:91:8f:0c:5f:10:20:70:bf:a3:22:b3:
98:ac:d4:7a:ea:67:b8:b1:8c:cf:e5:fe:8f:a0:a5:
02:ad:6d:ce:f1:62:ab:dc:5d:96:9c:4f:95:47:d5:
82:b7:b3:e3:87:4c:8d:38:85:2a:24:9d:7f:c7:a4:
0e:bd:8a:2d:6b:d2:d4:e8:78:62:1b:aa:25:5f:5a:
64:e5:76:23:ae:11:03:9a:5c:ed:a2:ba:51:ec:b1:
f3:ae:ba:5c:eb:dd:49:63:ca:c7:af:0c:16:1d:94:
95:3a:ce:2c:8f:e2:94:7f:1f:a1:76:e2:9f:d1:41:
31:f0:68:e5:ae:df:d0:75:a0:34:f5:25:93:85:b3:
25:50:42:6c:00:c0:fe:3b:e0:fb:00:de:75:33:86:
6a:21:35:14:9d:7f:4a:af:f7:15:f2:d7:bb:2f:de:
df:ab
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
B3:42:0A:9A:00:19:CB:CB:24:A0:02:45:1E:8A:B0:54:CB:9F:55:FE
X509v3 Authority Key Identifier:
keyid:B3:42:0A:9A:00:19:CB:CB:24:A0:02:45:1E:8A:B0:54:CB:9F:55:FE
Signature Algorithm: sha256WithRSAEncryption
32:9a:05:e3:6f:ae:ee:b1:a2:12:0a:9f:0a:e7:78:26:df:90:
fb:84:60:ae:13:fc:ff:fd:42:84:23:14:c3:2e:e2:a9:df:4b:
5c:2f:5b:0e:3d:f9:5a:56:50:13:bc:89:1a:08:70:dd:6c:6c:
e8:ae:cf:22:39:92:f2:3b:40:03:8f:4e:bc:54:88:6b:fd:8c:
b6:eb:30:90:21:db:fc:4e:5c:7e:12:75:e2:52:76:df:19:0f:
30:49:1e:15:bc:ba:6a:e6:f7:af:93:ad:e4:36:da:47:47:a6:
88:b0:ae:46:1e:91:e1:d6:b1:5e:a4:f0:68:02:81:57:86:5d:
17:d1:6c:7e:7a:9f:5e:0d:fc:10:e7:7a:1a:b5:f9:4b:1d:78:
a4:9a:9d:d7:c2:64:c3:52:28:7f:a1:b7:25:d7:13:3f:09:7f:
f2:fd:dd:c6:91:eb:9b:51:80:e2:36:cb:9f:5b:4e:47:eb:77:
d3:cc:8b:18:b5:0b:97:a2:53:8e:fb:9b:94:7d:57:21:32:c6:
f3:67:93:a4:9b:eb:46:b7:cd:08:43:99:dd:c1:c3:51:b9:19:
ef:92:77:1c:84:67:80:67:95:ba:00:75:3d:7b:8b:ff:24:30:
f1:fa:6d:da:31:9d:cf:06:da:5d:04:07:14:45:8c:6b:e7:21:
31:ec:7b:23
-----BEGIN CERTIFICATE-----
MIIDfjCCAmagAwIBAgIBATANBgkqhkiG9w0BAQsFADBCMQswCQYDVQQGEwJDWjEP
MA0GA1UECAwGUFJBR1VFMSIwIAYDVQQDDBl0cmFuc3BvcnQtdGVzdC1zZXJ2ZXIu
Y29tMCIYDzE5NzAwMTAxMDAwMDAwWhgPMTk3MDAxMDEwMDAwMDBaMEIxCzAJBgNV
BAYTAkNaMQ8wDQYDVQQIDAZQUkFHVUUxIjAgBgNVBAMMGXRyYW5zcG9ydC10ZXN0
LXNlcnZlci5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/axoR
RwGs61wtz85qpADOL9ElA18GOAKSJBiSKmkZsiujT/d53jXD9XI3g0ST+Xb8iSky
nA1LlX3RXUDpuklQfcYKyB7nkB43fAsjo+O8yVOB3tZfy7I9NqxZsDORjwxfECBw
v6Mis5is1HrqZ7ixjM/l/o+gpQKtbc7xYqvcXZacT5VH1YK3s+OHTI04hSoknX/H
pA69ii1r0tToeGIbqiVfWmTldiOuEQOaXO2iulHssfOuulzr3UljysevDBYdlJU6
ziyP4pR/H6F24p/RQTHwaOWu39B1oDT1JZOFsyVQQmwAwP474PsA3nUzhmohNRSd
f0qv9xXy17sv3t+rAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8W
HU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBSzQgqaABnL
yySgAkUeirBUy59V/jAfBgNVHSMEGDAWgBSzQgqaABnLyySgAkUeirBUy59V/jAN
BgkqhkiG9w0BAQsFAAOCAQEAMpoF42+u7rGiEgqfCud4Jt+Q+4RgrhP8//1ChCMU
wy7iqd9LXC9bDj35WlZQE7yJGghw3Wxs6K7PIjmS8jtAA49OvFSIa/2MtuswkCHb
/E5cfhJ14lJ23xkPMEkeFby6aub3r5Ot5DbaR0emiLCuRh6R4daxXqTwaAKBV4Zd
F9FsfnqfXg38EOd6GrX5Sx14pJqd18Jkw1Iof6G3JdcTPwl/8v3dxpHrm1GA4jbL
n1tOR+t308yLGLULl6JTjvublH1XITLG82eTpJvrRrfNCEOZ3cHDUbkZ75J3HIRn
gGeVugB1PXuL/yQw8fpt2jGdzwbaXQQHFEWMa+chMex7Iw==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAv2saEUcBrOtcLc/OaqQAzi/RJQNfBjgCkiQYkippGbIro0/3
ed41w/VyN4NEk/l2/IkpMpwNS5V90V1A6bpJUH3GCsge55AeN3wLI6PjvMlTgd7W
X8uyPTasWbAzkY8MXxAgcL+jIrOYrNR66me4sYzP5f6PoKUCrW3O8WKr3F2WnE+V
R9WCt7Pjh0yNOIUqJJ1/x6QOvYota9LU6HhiG6olX1pk5XYjrhEDmlztorpR7LHz
rrpc691JY8rHrwwWHZSVOs4sj+KUfx+hduKf0UEx8Gjlrt/QdaA09SWThbMlUEJs
AMD+O+D7AN51M4ZqITUUnX9Kr/cV8te7L97fqwIDAQABAoIBAEA4ytIpJKLDhHXK
VtLom2ySFnV4oBUSDarCeYvwtrpsUL/GQJ2etCM+4kdFv2h2NjmcOzpDqSJG0aPA
ydqhKZ/b0uojIltGuxyafZJDllDsqxvTi9EwImjvQvwEZgjcGaZ7Xqb1ZOJrpzm1
QFgM3KaVO9tKgR3Avxk40kmidU7FctFi5IELwnH/RR1OHvJbxOE4+i0LlDx0QzhX
QHtnvHLqLLdqsFk8KvuVuVj1FwqJ6cSL0JrAdt7dnGmXBo4PDqT8Hj0AjM+CcNrV
1D6Li9xr4y55EZUK2qU/FVDC3LqlYQy5mBfasJAXPQG4RgSVFxJ929HC7gi8vMCO
UMeLniECgYEA6gBoRwzQ5pJUXfZGW41lJt08utfycGZm7VrA81r0x0F+DcuZ2t6J
kB9Wnp/MNpB4DJLbl7oM2OlFOO3cw0n3VaFpNMPHVHzNbyi1hp94AIIeDz/sxfUI
Lx7ynAQSPPQzDRfVJesT8waBdweA71TBOlrFQ2Cp7O4Qf+p0akQSv3cCgYEA0Wnd
1Gbierv2m6Jnblg+brTMQwbRsOAM2n0V4Gd2kRaLSYd23ebshvx8xTWipRlrb5vP
UEh+LkfuscqaJDCrikasht9z5FJtfIzHKgTrLSoR3MJRjrnuLJWTQUwSqzd0UNN6
HigV6p+CqesNnELErak53IMfmkHAhTSkII8R9m0CgYBRY+DhTaDfgegcYouoTm7v
bKYx6uillciZKCbSvkFDiREaJUYXba31ViEfvT8ff3JyFSaSCKFtVP3BxmIx/ukr
fKAGPU54oYwm7Mbu00q/CoMAFOD7HbZCBYanI3dggiO7mx2FOdXPguTHDPIYzKcE
8AuK2vVftpJAm8DwMUtAEwKBgH/eRc5ZGDdbKGS10LQm+9A7Y3IV6to2pIKQ2FfS
tSo4espmBeXPCGQQLdt5OZvYHqril77s1OdLkutKy74HXecr6lLchHZJAoOHrmDw
6e0FAC0tFgGxdEYS+vxnCAs17DciOjHJxkAiL/WzCfd9KXzklOkZw6U8OuLbVtBu
q8gtAoGAbl03XZm+SHrO7XjHK/Fe5YD13cOirg48htvjbpqEDZNQr3l0eVnEj074
IopDa/wUFlaaqPZ/DVFctqSocyskWIP4u9HfmsNBHjK5zQlge7B1fNVao++YKund
qnVnXjWQuF2aL8k2geFxdSKmHTF4/N1qEyeyR+tMaFpGfMZOuM8=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDkTCCAnmgAwIBAgIJAP/KybHquuyUMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV
BAYTAkNaMQ8wDQYDVQQIDAZQUkFHVUUxIjAgBgNVBAMMGXRyYW5zcG9ydC10ZXN0
LXNlcnZlci5jb20wIBcNMTgwNzE4MTAwODIzWhgPMjA3MzA0MjAxMDA4MjNaMEIx
CzAJBgNVBAYTAkNaMQ8wDQYDVQQIDAZQUkFHVUUxIjAgBgNVBAMMGXRyYW5zcG9y
dC10ZXN0LXNlcnZlci5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQDRAQDAX6+lFKurvm7fgQqm8WyYzT/wxfPJjsVQGe87OlH1KFzVfzYzgEt0RMlM
eZgipREBZB2zK+WFM5RBHWYAwlI5PKt7EAGn8q1Zm4z+M9Uom3/Hy3bZ9q+AJwjk
odpHYuFyWJqHIQBqaQ3SFyJwdZ/GsuzEUfWuIl74oyyMAeykTKFGdaVuIlLC3fKm
8UCnfk99i/LEXUwRcmOV0uaG7deN5ITDDCFdb615yVjLkMhGY/jHK7uuxATOopEk
4vThQ1aQjSkHwluaqFUW6Zl4QF8WOAufoWQPFZ8XxmUYEIG/sMvLv6dol7ltjEbC
bfyzlS+9Qbnq6MfhTZF/4jAPAgMBAAGjgYcwgYQwHQYDVR0OBBYEFBNiUgCiKw4b
CFNKaEkqhkNSer7wMB8GA1UdIwQYMBaAFBNiUgCiKw4bCFNKaEkqhkNSer7wMA8G
A1UdEwEB/wQFMAMBAf8wJAYDVR0RBB0wG4IZdHJhbnNwb3J0LXRlc3Qtc2VydmVy
LmNvbTALBgNVHQ8EBAMCAaYwDQYJKoZIhvcNAQELBQADggEBACz1ZQ8XkGobhTcA
hkSTSw0ko6qwVuJJD5ue3SUcWLATsskohTJmN6bde3IMDRyQvLJAlMdG2p1qMbtA
OTbnQJTT7oDLaW8w2D+eO5oWTJvxLpl6TxbIfJN/8ITB1ltOCxTU9cVNbd2eh8sj
l3R4etg9djYRrqtNxCQZOYSwvhHw2MefnwjGVuJEu6JYOn3IE8Jqsh/LI59C87nE
MetZrXlzC6kSAFfRYgQET9RhBobMU9yFR8zGVHDFoxqNQs2lYKPz/3rFPetL2rjT
cFwzxkxDdwn+RNisBc1LMfIg7pvSMFR6sAnpjeRHN0Uoem1jj2qtzjbFENDuyQ4/
HSi4UcE=
-----END CERTIFICATE-----
This diff is collapsed.
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDRAQDAX6+lFKur
vm7fgQqm8WyYzT/wxfPJjsVQGe87OlH1KFzVfzYzgEt0RMlMeZgipREBZB2zK+WF
M5RBHWYAwlI5PKt7EAGn8q1Zm4z+M9Uom3/Hy3bZ9q+AJwjkodpHYuFyWJqHIQBq
aQ3SFyJwdZ/GsuzEUfWuIl74oyyMAeykTKFGdaVuIlLC3fKm8UCnfk99i/LEXUwR
cmOV0uaG7deN5ITDDCFdb615yVjLkMhGY/jHK7uuxATOopEk4vThQ1aQjSkHwlua
qFUW6Zl4QF8WOAufoWQPFZ8XxmUYEIG/sMvLv6dol7ltjEbCbfyzlS+9Qbnq6Mfh
TZF/4jAPAgMBAAECggEBALSs10d18FMW0WjAUPxpgxnaLnTRSesMVLjy8ONT6Bkd
S2hRIh91vxc6WwABzrqLita4N0EqmPoggmNpuUmo7lrNoWLVbbAOoD/da7nA3FuL
10MpWYcP/ohh1klEdU2gFSAM/LNqoPsbrk5OzqHFWgI5zItqdX8pEucb01nBRWsp
VMY2vzVuFB2jweZQ5+LCpfSMcRIzlxQa9CG4Peu6YW1Z4b3aUcS63/829JN/ZOGd
uoRqR+gP71yNIt6i7wA5cot5FRmzlFEGhb1XzBOB1FFHOiknOZzbBtDsGUUmVtfA
6mXcTumhdHbC0bXnHei/s2s9X0EeyQFYPkoS4NUQ2dECgYEA/7lhgn89K8rpUPnS
eccTpKVPWp8luQei98Hi/F94kwP32l7Zl7Bmu2nltUoB1GBRXoXY6KzTphmT6ioA
8joLCKIii5/nOdZAdHbIN2tkXS56h524q5I2jKogjfRrpCaAJE8x99f8L9uTBfZb
/7BBQDHai1/S6LcpIRf/4g1/xBsCgYEA0Tq4V5hR9mGDUFir1FDGhA3ijDkIE/sO
3QGTU7W90BL27te98FuQtWOPqfd1fi26WypNpNQUZb3V4x5tmDcpWscfj6I10432
4zECPlDgaevucJjj245U7WjUhdAvlRy6K8H/8MgRBAjw9h8dwIGIx9gmOqKdA+/h
ve3xyjKQex0CgYAz0XzQ1LewiA1/OyBLTOvOETFjS5x5QfLkAYXdXfswzz0KIu40
rqoij/LcKYL1Zg8W+Ehb3amFnuk6KgjHDLvvo+scH+ra7W9iKi+oCzrrJt/tWyhw
m9Ax8Mdn/H9TY/nTYbjeYAXaLMQ+EQ3TYgPW3kNKusAiJ/tNmW9gfxvEwQKBgGSJ
Rbj5fTDZjGKYKQDdS3Z6wYhFg0culObHcgaARtPruPHtgtwy82blj0vJl5Bo4qoZ
urNgIOj+ff8jSOAiaWGwWs8Gz7x289IZY42UCTF8Z9d878g5LT/i5nPiJGsPIboS
/yuwxtRcg4SQURiGZbY5e60jJDWXF67O3icdguVVAoGARXLufXvZ/9Xf1DmFFxjq
PJMCa1sfofqjB4KqYbt17vFtTsddCiyqsbpx36oY6nIdm9yUiGo10YaSEJtDEGLS
L3TPZ4s8M8dcjOfj8Kk75pKbJ7NY4qA64dtbxcZbrFp3/mGZkDing94y+Zc/aFqa
xQsA/yhmYV9r+FHDL54Cn6I=
-----END PRIVATE KEY-----
import socket
import pytest
from kresd import init_portdir, make_kresd
@pytest.fixture
def kresd(tmpdir):
with make_kresd(tmpdir) as kresd:
yield kresd
@pytest.fixture
def kresd_tt(tmpdir):
with make_kresd(tmpdir, 'tt') as kresd:
yield kresd
@pytest.fixture(params=[
'ip_tcp_socket',
'ip6_tcp_socket',
'ip_tls_socket',
'ip6_tls_socket',
])
def make_kresd_sock(request, kresd):
"""Factory function to create sockets of the same kind."""
sock_func = getattr(kresd, request.param)
def _make_kresd_sock():
return sock_func()
return _make_kresd_sock
@pytest.fixture
def kresd_sock(make_kresd_sock):
return make_kresd_sock()
@pytest.fixture(params=[
socket.AF_INET,
socket.AF_INET6,
])
def sock_family(request):
return request.param
@pytest.fixture(params=[
True,
False
])
def single_buffer(request): # whether to send all data in a single buffer
return request.param
@pytest.fixture(params=[
True,
False
])
def query_before(request): # whether to send an initial query
return request.param
@pytest.mark.optionalhook
def pytest_metadata(metadata): # filter potentially sensitive data from GitLab CI
keys_to_delete = []
for key in metadata.keys():
key_lower = key.lower()
if 'password' in key_lower or 'token' in key_lower or \
key_lower.startswith('ci') or key_lower.startswith('gitlab'):
keys_to_delete.append(key)
for key in keys_to_delete:
del metadata[key]
def pytest_sessionstart(session): # pylint: disable=unused-argument
init_portdir()
"""Test opening as many connections as possible.
Due to resource-intensity of this test, it's filename doesn't contain
"test" on purpose, so it doesn't automatically get picked up by pytest
(to allow easy parallel testing).
To execute this test, pass the filename of this file to pytest directly.
Also, make sure not to use parallel execution (-n).
"""
import resource
import time
import pytest
from kresd import Kresd
import utils
MAX_SOCKETS = 15000 # upper bound of how many connections to open
MAX_ITERATIONS = 20 # number of iterations to run the test
# we can't use softlimit ifself since kresd already has open sockets,
# so use lesser value
RESERVED_NOFILE = 40 # 40 is empirical value
@pytest.mark.parametrize('sock_func_name', [
'ip_tcp_socket',
'ip6_tcp_socket',
'ip_tls_socket',
'ip6_tls_socket',
])
def test_conn_flood(tmpdir, sock_func_name):
def create_sockets(make_sock, nsockets):
sockets = []
next_ping = time.time() + 5 # less than tcp idle timeout
while True:
while time.time() < next_ping:
nsock_to_init = min(100, nsockets - len(sockets))
if not nsock_to_init:
return sockets
sockets.extend([make_sock() for _ in range(nsock_to_init)])
# large number of connections can take a lot of time to open
# send some valid data to avoid TCP idle timeout for already open sockets
next_ping = time.time() + 5
for s in sockets:
utils.ping_alive(s)
max_num_of_open_files = resource.getrlimit(resource.RLIMIT_NOFILE)[0] - RESERVED_NOFILE
nsockets = min(max_num_of_open_files, MAX_SOCKETS)
# create kresd instance with verbose=False
ip = '127.0.0.1'
ip6 = '::1'
with Kresd(tmpdir, ip=ip, ip6=ip6, verbose=False) as kresd:
print("\nEstablishing {} connections".format(nsockets))
make_sock = getattr(kresd, sock_func_name) # function for creating sockets
sockets = create_sockets(make_sock, nsockets)
print("Start sending data")
for i in range(MAX_ITERATIONS):
for s in sockets:
utils.ping_alive(s)
print("Iteration {} done...".format(i))
print("Close connections")
for s in sockets:
s.close()
# check in kresd is alive
print("Check upstream is still alive")
sock = make_sock()
utils.ping_alive(sock)
print("OK!")
This diff is collapsed.
[MESSAGES CONTROL]
disable=
missing-docstring,
too-many-arguments,
too-many-instance-attributes,
fixme,
unused-import, # checked by flake8
line-too-long, # checked by flake8
invalid-name,
broad-except,
bad-continuation,
global-statement,
no-else-return,
redefined-outer-name, # commonly used with pytest fixtures
[SIMILARITIES]
min-similarity-lines=6
ignore-comments=yes
ignore-docstrings=yes
ignore-imports=no
[DESIGN]
max-parents=10
max-locals=20
[TYPECHECK]
ignored-modules=ssl
CC=gcc
CFLAGS_TLS=-DDEBUG -ggdb3 -O0 -lgnutls -luv
CFLAGS_TCP=-DDEBUG -ggdb3 -O0 -luv
all: tcproxy tlsproxy
tlsproxy: tls-proxy.o tlsproxy.o
$(CC) tls-proxy.o tlsproxy.o -o tlsproxy $(CFLAGS_TLS)
tls-proxy.o: tls-proxy.c tls-proxy.h array.h
$(CC) -c -o $@ $< $(CFLAGS_TLS)
tlsproxy.o: tlsproxy.c tls-proxy.h
$(CC) -c -o $@ $< $(CFLAGS_TLS)
tcproxy: tcp-proxy.o tcproxy.o
$(CC) tcp-proxy.o tcproxy.o -o tcproxy $(CFLAGS_TCP)
tcp-proxy.o: tcp-proxy.c tcp-proxy.h array.h
$(CC) -c -o $@ $< $(CFLAGS_TCP)
tcproxy.o: tcproxy.c tcp-proxy.h
$(CC) -c -o $@ $< $(CFLAGS_TCP)
clean:
rm -f tcp-proxy.o tcproxy.o tcproxy tls-proxy.o tlsproxy.o tlsproxy
.PHONY: all clean
../../../lib/generic/array.h
\ No newline at end of file
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <uv.h>
#include "array.h"
struct buf {
char buf[16 * 1024];
size_t size;
};
enum peer_state {
STATE_NOT_CONNECTED,
STATE_LISTENING,
STATE_CONNECTED,
STATE_CONNECT_IN_PROGRESS,
STATE_CLOSING_IN_PROGRESS
};
struct proxy_ctx {
uv_loop_t *loop;
uv_tcp_t server;
uv_tcp_t client;
uv_tcp_t upstream;
struct sockaddr_storage server_addr;
struct sockaddr_storage upstream_addr;
int server_state;
int client_state;
int upstream_state;
array_t(struct buf *) buffer_pool;
array_t(struct buf *) upstream_pending;
};
static void read_from_upstream_cb(uv_stream_t *upstream, ssize_t nread, const uv_buf_t *buf);
static void read_from_client_cb(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf);
static struct buf *borrow_io_buffer(struct proxy_ctx *proxy)
{
struct buf *buf = NULL;
if (proxy->buffer_pool.len > 0) {
buf = array_tail(proxy->buffer_pool);
array_pop(proxy->buffer_pool);
} else {
buf = calloc(1, sizeof (struct buf));
}
return buf;
}
static void release_io_buffer(struct proxy_ctx *proxy, struct buf *buf)
{
if (!buf) {
return;
}
if (proxy->buffer_pool.len < 1000) {
buf->size = 0;
array_push(proxy->buffer_pool, buf);
} else {
free(buf);
}
}
static void push_to_upstream_pending(struct proxy_ctx *proxy, const char *buf, size_t size)
{
while (size > 0) {
struct buf *b = borrow_io_buffer(proxy);
b->size = size <= sizeof(b->buf) ? size : sizeof(b->buf);
memcpy(b->buf, buf, b->size);
array_push(proxy->upstream_pending, b);
size -= b->size;
}
}
static struct buf *get_first_upstream_pending(struct proxy_ctx *proxy)
{
struct buf *buf = NULL;
if (proxy->upstream_pending.len > 0) {
buf = proxy->upstream_pending.at[0];
}
return buf;
}
static void remove_first_upstream_pending(struct proxy_ctx *proxy)
{
for (int i = 1; i < proxy->upstream_pending.len; ++i) {
proxy->upstream_pending.at[i - 1] = proxy->upstream_pending.at[i];
}
if (proxy->upstream_pending.len > 0) {
proxy->upstream_pending.len -= 1;
}
}
static void clear_upstream_pending(struct proxy_ctx *proxy)
{
for (int i = 1; i < proxy->upstream_pending.len; ++i) {
struct buf *b = proxy->upstream_pending.at[i];
release_io_buffer(proxy, b);
}
proxy->upstream_pending.len = 0;
}
static void clear_buffer_pool(struct proxy_ctx *proxy)
{
for (int i = 1; i < proxy->buffer_pool.len; ++i) {
struct buf *b = proxy->buffer_pool.at[i];
free(b);
}
proxy->buffer_pool.len = 0;
}
static void alloc_uv_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}
static void on_client_close(uv_handle_t *handle)
{
struct proxy_ctx *proxy = (struct proxy_ctx *)handle->loop->data;
proxy->client_state = STATE_NOT_CONNECTED;
}
static void on_upstream_close(uv_handle_t *handle)
{
struct proxy_ctx *proxy = (struct proxy_ctx *)handle->loop->data