Files
zyt/server/tests/DifyRequestDeadlineTransportTest.php
2026-10-27 14:03:35 +08:00

46 lines
2.9 KiB
PHP

<?php
declare(strict_types=1);
namespace app\common\service {
function hrtime(bool $asNumber = false) { return $GLOBALS['deadlineTestNs']; }
}
namespace {
require dirname(__DIR__) . '/vendor/autoload.php';
use app\common\service\DifyChatService;
$deadlineTestNs = 10000000000;
$cap = new ReflectionMethod(DifyChatService::class, 'capRequestDeadline');
$checks = 0;
function deadlineExpect(bool $ok, string $message): void {
++$GLOBALS['checks'];
if (!$ok) throw new RuntimeException($message);
}
$options = ['request_deadline_ns' => $deadlineTestNs + 500000000, 'timeout_ms' => 90000];
deadlineExpect($cap->invokeArgs(null, [&$options]) && $options['timeout_ms'] === 500, 'First retry uses only remaining request budget');
$deadlineTestNs += 400000000;
deadlineExpect($cap->invokeArgs(null, [&$options]) && $options['timeout_ms'] === 100, 'Compatibility retry cannot reset elapsed budget');
$options['timeout_ms'] = 10;
deadlineExpect($cap->invokeArgs(null, [&$options]) && $options['timeout_ms'] === 10, 'Shorter attempt timeout is preserved');
$deadlineTestNs += 100000000;
$timeouts = 0;
$options['on_timeout'] = static function (string $task) use (&$timeouts): void { ++$timeouts; };
deadlineExpect(!$cap->invokeArgs(null, [&$options]) && $timeouts === 1, 'Expiration notifies timeout without fabricating a task');
$blocking = (new ReflectionMethod(DifyChatService::class, 'sendRequest'))->invoke(null,
'http://invalid.invalid/never-connect', [], 'synthetic', 90, $options);
deadlineExpect($blocking['errno'] === CURLE_OPERATION_TIMEDOUT && $blocking['http_code'] === 0, 'Expired blocking attempt performs no network call');
$deltas = 0;
$streaming = (new ReflectionMethod(DifyChatService::class, 'sendStreamRequest'))->invoke(null,
'dify', 'http://invalid.invalid/never-connect', [], 'synthetic', 90,
static function () use (&$deltas): void { ++$deltas; }, null, $options);
deadlineExpect($streaming['errno'] === CURLE_OPERATION_TIMEDOUT && $deltas === 0, 'Expired streaming attempt performs no network or delta');
$clinical = (new ReflectionMethod(DifyChatService::class, 'requiredClinicalChat'))->invoke(null,
'qwen', [], 'synthetic', 'synthetic-user', [['type' => 'image', 'url' => 'http://invalid.invalid/never-upload']],
$options, null, null, 3, 90);
deadlineExpect(($clinical['error_code'] ?? '') === 'UPSTREAM_TIMEOUT', 'Expired shared request is refused before file validation, upload, or model work');
foreach ([[], ['timeout_ms' => 1000], ['request_deadline_ns' => 0]] as $unbounded) {
$copy = $unbounded;
deadlineExpect($cap->invokeArgs(null, [&$unbounded]) && $copy === $unbounded, 'Existing stop cleanup and unbudgeted callers stay unchanged');
}
echo "Dify monotonic request budget across compatibility attempts: {$checks} checks OK\n";
}