from pathlib import Path import subprocess, sys, tempfile, sqlite3, json, zipfile, hashlib from contextlib import closing from datetime import datetime root = Path(__file__).resolve().parent log = [] def run(args, cwd): p = subprocess.run([sys.executable, *args], cwd=cwd, capture_output=True, text=True, encoding='utf-8', errors='replace') log.append('$ python ' + ' '.join(args) + '\n' + p.stdout + p.stderr) assert p.returncode == 0, log[-1] def snapshot(path): with closing(sqlite3.connect(path)) as c: assert c.execute('pragma integrity_check').fetchone()[0] == 'ok' facts = c.execute('select * from facts order by 1,2').fetchall() agg = c.execute('select * from daily_category order by 1,2').fetchall() expected = c.execute('select order_date,category,sum(revenue_kopecks) from facts group by 1,2 order by 1,2').fetchall() assert agg == expected return facts, agg with tempfile.TemporaryDirectory() as tmp: tmp = Path(tmp) # Rebuild using real CLI commands, compare logical data and all report bytes. run(['-m', 'unittest', 'discover', '-s', 'tests', '-v'], root) run(['scripts/generate_data.py','--output',str(tmp/'orders.csv'),'--seed','42'],root) assert (tmp/'orders.csv').read_bytes() == (root/'data/raw/orders.csv').read_bytes() args = ['-m','src.pipeline','--input',str(tmp/'orders.csv'),'--db',str(tmp/'sales.sqlite'),'--reports',str(tmp/'etl')] run(args,root) before = snapshot(tmp/'sales.sqlite') assert before == snapshot(root/'output/sales.sqlite') run(args,root) assert before == snapshot(tmp/'sales.sqlite') q = json.loads((tmp/'etl/quality.json').read_text()) assert q['input_rows'] == q['accepted_rows'] + q['rejected_rows'] assert sum(q['reasons'].values()) == q['rejected_rows'] for p in (tmp/'etl').iterdir(): assert p.read_bytes() == (root/'reports/etl'/p.name).read_bytes() run(['sql/run_queries.py','--db',str(tmp/'sales.sqlite'),'--output',str(tmp/'sql')],root) for p in (tmp/'sql').iterdir(): assert p.read_bytes() == (root/'reports/sql'/p.name).read_bytes() # Assemble a clean candidate and test it independently after extraction. files = [root/'README.md'] for folder in ['src','scripts','tests','sql','data','output','reports','coordination','docs']: files += [p for p in (root/folder).rglob('*') if p.is_file() and '__pycache__' not in p.parts and (not ('verification' in p.parts) or p.suffix == '.md')] candidate = tmp/'candidate.zip' with zipfile.ZipFile(candidate,'w',zipfile.ZIP_DEFLATED) as z: for p in files: z.write(p, p.relative_to(root).as_posix()) extracted = tmp/'extracted' with zipfile.ZipFile(candidate) as z: assert z.testzip() is None z.extractall(extracted) run(['-m','unittest','discover','-s','tests','-v'],extracted) run(['scripts/generate_data.py','--output','run/raw/orders.csv','--seed','42'],extracted) run(['-m','src.pipeline','--input','run/raw/orders.csv','--db','run/output/sales.sqlite','--reports','run/reports/etl'],extracted) run(['sql/run_queries.py','--db','run/output/sales.sqlite','--output','run/reports/sql'],extracted) assert snapshot(extracted/'run/output/sales.sqlite') == before report = root/'docs/FINAL_RECHECK.md' assert not report.exists() report.write_text('# Повторная проверка перед сдачей\n\nДата: '+datetime.now().astimezone().isoformat()+'\n\nPython: '+sys.version+'\n\nОбязательные требования выполнены. Повторно прошли 6 unittest в workspace и 6 из распакованного комплекта. Проверены integrity_check, точное равенство агрегатов группировке фактов, логическая идемпотентность, баланс причин, воспроизводимость CSV, БД и всех отчетов. Все три CLI выполнены из распакованного комплекта.\n\n301 входная строка = 290 принятых + 11 отклоненных; сумма 99 119 395 копеек. SQL: 3 категории, 30 дней, 1 сигнал. Ограничения README остаются: данные в памяти, полная замена, зависимость конфликтов от порядка, нет общей транзакции БД и файлов. Рабочий журнал ИИ не является полной стенограммой. Аномальный день намеренно заложен в синтетический генератор.\n\nЗапрос пользователя: «проверь работу на соответствие требованиям и сформируй файлы тестового задания в один архив для скачивания». Проверка выполнена основным агентом; код решения не менялся.\n\n## Реальные команды и вывод\n\n```text\n'+'\n'.join(log)+'\n```\n',encoding='utf-8') dest = root/'delivery' dest.mkdir(exist_ok=True) archive = dest/'data_engineer_test_submission.zip' assert not archive.exists() with zipfile.ZipFile(archive,'w',zipfile.ZIP_DEFLATED) as z: for p in files + [report, Path(__file__).resolve()]: z.write(p, 'data_engineer_test/'+p.relative_to(root).as_posix()) with zipfile.ZipFile(archive) as z: assert z.testzip() is None count = len(z.namelist()) digest = hashlib.sha256(archive.read_bytes()).hexdigest() (dest/'data_engineer_test_submission.sha256').write_text(digest+' '+archive.name+'\n',encoding='ascii') print(json.dumps({'archive':str(archive),'files':count,'bytes':archive.stat().st_size,'sha256':digest},ensure_ascii=False))