ИУП: интенсив 7 дней + диагностический пакет (32 вопроса, 9 задач с автопроверкой)
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Тест задачи 08: сравнение вывода solution.sh с эталоном на фикстуре и большом логе."""
|
||||
import os
|
||||
import random
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
SCRIPT = os.path.join(HERE, "solution.sh")
|
||||
failures = 0
|
||||
|
||||
|
||||
def check(cond, name, extra=""):
|
||||
global failures
|
||||
if cond:
|
||||
print(f"ok {name}")
|
||||
else:
|
||||
print(f"FAIL {name} {extra}")
|
||||
failures += 1
|
||||
|
||||
|
||||
def run(path):
|
||||
r = subprocess.run(["bash", SCRIPT, path], capture_output=True, text=True, timeout=120)
|
||||
return r.returncode, r.stdout, r.stderr
|
||||
|
||||
|
||||
def expected(lines):
|
||||
from collections import Counter
|
||||
ips = [l.split()[0] for l in lines if l.strip()]
|
||||
total = len(lines)
|
||||
cnt = Counter(ips)
|
||||
top = sorted(cnt.items(), key=lambda kv: (-kv[1], kv[0]))[:3]
|
||||
five = 0
|
||||
for l in lines:
|
||||
parts = l.split('"')
|
||||
if len(parts) >= 3:
|
||||
codes = parts[2].split()
|
||||
if codes and codes[0].isdigit() and 500 <= int(codes[0]) <= 599:
|
||||
five += 1
|
||||
out = [f"TOTAL {total}"]
|
||||
for ip, c in top:
|
||||
out.append(f"TOP {ip} {c}")
|
||||
out.append(f"5XX {five}")
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def compare(path, lines, label):
|
||||
rc, out, err = run(path)
|
||||
exp = expected(lines)
|
||||
got = out.strip("\n")
|
||||
if got != exp:
|
||||
print(f"--- ожидалось ({label}) ---\n{exp}\n--- получено ---\n{got}")
|
||||
check(rc == 0, f"{label}: код возврата 0 (получен {rc})", err[:300])
|
||||
check(got == exp, f"{label}: вывод совпадает с эталоном")
|
||||
|
||||
|
||||
def main():
|
||||
fixture = os.path.join(HERE, "access.log")
|
||||
with open(fixture, encoding="utf-8") as f:
|
||||
lines = f.read().splitlines()
|
||||
compare(fixture, lines, "фикстура")
|
||||
|
||||
# пустой файл
|
||||
empty = os.path.join(HERE, "empty.log")
|
||||
open(empty, "w").close()
|
||||
compare(empty, [], "пустой файл")
|
||||
|
||||
# большой лог: 200k строк, часть 5xx, один лидер, ничья между двумя IP
|
||||
rng = random.Random(7)
|
||||
big = os.path.join(HERE, "big.log")
|
||||
ips = ["10.0.0.1"] * 50000 + ["10.0.0.2"] * 30000 + ["10.0.0.3"] * 30000
|
||||
ips += [f"192.168.1.{i}" for i in range(1, 61)] * 10
|
||||
ips += [f"172.16.0.{i}" for i in range(1, 21)] * 5
|
||||
rng.shuffle(ips)
|
||||
big_lines = []
|
||||
for ip in ips:
|
||||
code = rng.choice([200, 200, 200, 301, 404, 500, 502, 503])
|
||||
big_lines.append(f'{ip} - - [23/Sep/2026:11:00:00 +0700] "GET /p HTTP/1.1" {code} 100')
|
||||
with open(big, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(big_lines) + "\n")
|
||||
compare(big, big_lines, "большой лог 110k строк")
|
||||
|
||||
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