#!/usr/bin/env python3 """격리 MySQL에서 KCP 실제 콜백과 MyISAM/InnoDB 재통보를 검증한다. 실행: python3 tests/kcp_notification_http.py 33443 localhost의 지정 포트에 root/빈 비밀번호로 접속하여 임시 DB만 만들고 삭제한다. 공통 초기화·발신 IP·SQL 실패만 대역이며 SQL 저장과 실제 콜백은 그대로 실행한다. """ import concurrent.futures import json import os from pathlib import Path import re import signal import socket import subprocess import sys import tempfile import time import urllib.parse import urllib.request ROOT = Path(__file__).resolve().parents[1] PORT = int(sys.argv[1]) DB = 'kcp43_test_' + str(time.time_ns()) checks = 0 def mysql(sql, database=True): command = ['mysql', '--no-defaults', '-h127.0.0.1', '-P' + str(PORT), '-uroot', '-N', '-B'] if database: command.append(DB) return subprocess.check_output(command, input="SET sql_mode='NO_ENGINE_SUBSTITUTION';" + sql, text=True).strip() def check(value, message): global checks if not value: raise AssertionError(message) checks += 1 mysql('CREATE DATABASE `' + DB + '`', False) server = None try: schema = (ROOT / 'install/gnuboard5shop.sql').read_text() for table in ['order', 'personalpay', 'cart', 'default', 'kcp_noti']: statement = re.search(r'CREATE TABLE(?: IF NOT EXISTS)? `g5_shop_' + table + r'` \(.*?;', schema, re.S).group() mysql(statement) with tempfile.TemporaryDirectory(prefix='kcp43-http-') as temp: directory = Path(temp) fixture = directory / 'fixture.json' bootstrap = r'''set_charset('utf8mb4'); $db->query("SET sql_mode='NO_ENGINE_SUBSTITUTION'"); $fixture = json_decode(file_get_contents(__DIR__.'/fixture.json'), true); $default = array('de_card_test' => $fixture['test'], 'de_pg_service' => 'kcp'); if (isset($fixture['ip'])) $_SERVER['REMOTE_ADDR'] = $fixture['ip']; $g5 = array('g5_shop_order_table' => 'g5_shop_order', 'g5_shop_personalpay_table' => 'g5_shop_personalpay', 'g5_shop_cart_table' => 'g5_shop_cart', 'g5_shop_default_table' => 'g5_shop_default'); $writes = 0; function sql_query($sql, $error = false) { global $db, $writes, $fixture; $write = preg_match('/^(UPDATE|INSERT) /', $sql); if ($write) $writes++; if ($write && isset($fixture['fail_before']) && $writes === $fixture['fail_before']) return false; $result = $db->query($sql); if ($write && isset($fixture['fail_after']) && $writes === $fixture['fail_after']) return false; return $result; } function sql_fetch_array($result) { return $result->fetch_assoc(); } function sql_num_rows($result) { return $result->num_rows; } function sql_escape_string($value) { global $db; return $db->real_escape_string($value); } function sql_real_escape_string($value) { return sql_escape_string($value); } function sql_error_info() { global $db; return $db->error; } '''.replace('ROOT_PATH', repr(str(ROOT))).replace('TEST_DB', repr(DB)).replace('TEST_PORT', str(PORT)) (directory / '_common.php').write_text(bootstrap) (directory / 'router.php').write_text("