#!/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()