ИУП: интенсив 7 дней + диагностический пакет (32 вопроса, 9 задач с автопроверкой)
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Тест задачи 07: поднимает сервер, проверяет эхо на нескольких соединениях и SIGTERM."""
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
BIN = os.path.join(HERE, "solution")
|
||||
failures = 0
|
||||
|
||||
|
||||
def check(cond, name):
|
||||
global failures
|
||||
if cond:
|
||||
print(f"ok {name}")
|
||||
else:
|
||||
print(f"FAIL {name}")
|
||||
failures += 1
|
||||
|
||||
|
||||
def free_port():
|
||||
s = socket.socket()
|
||||
s.bind(("127.0.0.1", 0))
|
||||
p = s.getsockname()[1]
|
||||
s.close()
|
||||
return p
|
||||
|
||||
|
||||
def main():
|
||||
port = free_port()
|
||||
proc = subprocess.Popen([BIN, str(port)], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
up = False
|
||||
for _ in range(100): # до 5 секунд на старт
|
||||
if proc.poll() is not None:
|
||||
break
|
||||
try:
|
||||
s = socket.create_connection(("127.0.0.1", port), timeout=0.3)
|
||||
s.close()
|
||||
up = True
|
||||
break
|
||||
except OSError:
|
||||
time.sleep(0.05)
|
||||
check(up, "сервер принял соединение и слушает порт")
|
||||
|
||||
if up:
|
||||
# три одновременных соединения, большие и разорванные сообщения
|
||||
socks = []
|
||||
for i in range(3):
|
||||
s = socket.create_connection(("127.0.0.1", port), timeout=2)
|
||||
s.settimeout(5)
|
||||
socks.append(s)
|
||||
payloads = [b"hello\n", b"x" * 70000, b"chunk-" + bytes(range(32, 127))]
|
||||
for s, p in zip(socks, payloads):
|
||||
s.sendall(p)
|
||||
ok = True
|
||||
for i, (s, p) in enumerate(zip(socks, payloads)):
|
||||
got = b""
|
||||
while len(got) < len(p):
|
||||
chunk = s.recv(65536)
|
||||
if not chunk:
|
||||
break
|
||||
got += chunk
|
||||
if got != p:
|
||||
ok = False
|
||||
print(f" соединение {i}: получено {len(got)} из {len(p)} байт")
|
||||
check(ok, "эхо на трёх одновременных соединениях (включая 70 КБ)")
|
||||
|
||||
# эхо в двух шагах по одному соединению
|
||||
s = socks[0]
|
||||
s.sendall(b"part1")
|
||||
first = s.recv(5)
|
||||
s.sendall(b"part2")
|
||||
second = b""
|
||||
while len(second) < 5:
|
||||
chunk = s.recv(5 - len(second))
|
||||
if not chunk:
|
||||
break
|
||||
second += chunk
|
||||
check(first == b"part1" and second == b"part2", "эхо по частям (несколько циклов read/write)")
|
||||
|
||||
# клиент закрывается — сервер не падает
|
||||
for s in socks:
|
||||
s.close()
|
||||
time.sleep(0.3)
|
||||
check(proc.poll() is None, "сервер жив после закрытия всех клиентов")
|
||||
|
||||
# новое соединение после закрытия старых
|
||||
try:
|
||||
s = socket.create_connection(("127.0.0.1", port), timeout=2)
|
||||
s.settimeout(3)
|
||||
s.sendall(b"again")
|
||||
check(s.recv(5) == b"again", "новое соединение после отключения старых")
|
||||
s.close()
|
||||
except OSError as e:
|
||||
check(False, f"новое соединение после отключения старых ({e})")
|
||||
|
||||
proc.send_signal(signal.SIGTERM)
|
||||
try:
|
||||
rc = proc.wait(timeout=5)
|
||||
check(rc == 0, f"аккуратное завершение по SIGTERM (exit={rc})")
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
check(False, "аккуратное завершение по SIGTERM (не завершился за 5 с)")
|
||||
|
||||
if failures:
|
||||
err = proc.stderr.read().decode(errors="replace")[:2000]
|
||||
if err:
|
||||
print("--- stderr сервера ---")
|
||||
print(err)
|
||||
print(f"\n{'FAILURES: %d' % failures if failures else 'ALL PASS'}")
|
||||
sys.exit(1 if failures else 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user