summaryrefslogtreecommitdiffstats
path: root/tests/pytests/conn_flood.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-08 20:37:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-08 20:37:50 +0000
commitc1f743ab2e4a7046d5500875a47d1f62c8624603 (patch)
tree709946d52f5f3bbaeb38be9e3f1d56d11f058237 /tests/pytests/conn_flood.py
parentInitial commit. (diff)
downloadknot-resolver-upstream/5.7.1.tar.xz
knot-resolver-upstream/5.7.1.zip
Adding upstream version 5.7.1.upstream/5.7.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/pytests/conn_flood.py')
-rw-r--r--tests/pytests/conn_flood.py85
1 files changed, 85 insertions, 0 deletions
diff --git a/tests/pytests/conn_flood.py b/tests/pytests/conn_flood.py
new file mode 100644
index 0000000..88bbfa5
--- /dev/null
+++ b/tests/pytests/conn_flood.py
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+"""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 = 10000 # upper bound of how many connections to open
+MAX_ITERATIONS = 10 # number of iterations to run the test
+
+# we can't use softlimit itself 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() + 4 # less than tcp idle timeout / 2
+ while True:
+ additional_sockets = 0
+ 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)])
+ additional_sockets += 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() + 4
+ for s in sockets:
+ utils.ping_alive(s)
+
+ # break when no more than 20% additional sockets are created
+ if additional_sockets / len(sockets) < 0.2:
+ return sockets
+
+ 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:
+ make_sock = getattr(kresd, sock_func_name) # function for creating sockets
+ sockets = create_sockets(make_sock, nsockets)
+ print("\nEstablished {} connections".format(len(sockets)))
+
+ 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!")