更新bug
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
final class LocalAudioUploadContractExpect
|
||||
{
|
||||
public static function contains(string $haystack, string $needle, string $message): void
|
||||
{
|
||||
if (!str_contains($haystack, $needle)) {
|
||||
throw new RuntimeException($message . ': missing ' . $needle);
|
||||
}
|
||||
}
|
||||
|
||||
public static function isTrue(bool $condition, string $message): void
|
||||
{
|
||||
if (!$condition) {
|
||||
throw new RuntimeException($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$root = dirname(__DIR__);
|
||||
$controllerPath = $root . '/app/adminapi/controller/tcm/DiagnosisController.php';
|
||||
$logicPath = $root . '/app/adminapi/logic/tcm/DiagnosisLogic.php';
|
||||
$migrationPath = $root . '/database/migrations/2026_08_19_add_local_call_audio_fields.sql';
|
||||
|
||||
$controller = (string)file_get_contents($controllerPath);
|
||||
$logic = (string)file_get_contents($logicPath);
|
||||
$migration = (string)file_get_contents($migrationPath);
|
||||
|
||||
LocalAudioUploadContractExpect::contains(
|
||||
$controller,
|
||||
'public function uploadCallRecording()',
|
||||
'The ThinkPHP controller must expose the desktop upload action'
|
||||
);
|
||||
LocalAudioUploadContractExpect::contains(
|
||||
$controller,
|
||||
'DiagnosisLogic::uploadCallRecording($params)',
|
||||
'The controller must delegate multipart uploads to the diagnosis logic'
|
||||
);
|
||||
|
||||
foreach (
|
||||
[
|
||||
"'webm'",
|
||||
"'ogg'",
|
||||
"'media_kind' => \$isLocalAudio ? 'local_audio' : 'video'",
|
||||
'attachLocalCallAudio($attachmentParams)',
|
||||
"'local_audio_urls'",
|
||||
"'local_audio_status' => 2",
|
||||
"'local_audio_urls_list'",
|
||||
"'local_audio_status_text'",
|
||||
"'uploads/audio/'",
|
||||
'FileEnum::FILE_TYPE',
|
||||
] as $needle
|
||||
) {
|
||||
LocalAudioUploadContractExpect::contains(
|
||||
$logic,
|
||||
$needle,
|
||||
'Local audio upload and DTO contract must remain complete'
|
||||
);
|
||||
}
|
||||
|
||||
foreach (
|
||||
[
|
||||
"'uploads/video/'",
|
||||
'FileEnum::VIDEO_TYPE',
|
||||
'attachLocalCallRecording($attachmentParams)',
|
||||
"'recording_status' => \$isLocalAudio ? 0 : 2",
|
||||
] as $needle
|
||||
) {
|
||||
LocalAudioUploadContractExpect::contains(
|
||||
$logic,
|
||||
$needle,
|
||||
'Manual video uploads must remain separate from local audio'
|
||||
);
|
||||
}
|
||||
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
str_contains($logic, '!$isAmbiguousWebm && $hasAudioMime'),
|
||||
'Known non-WebM video extensions must not be misclassified when an old client sends audio/webm'
|
||||
);
|
||||
|
||||
foreach (['zyt_tcm_call_record', 'local_audio_urls', 'local_audio_status'] as $needle) {
|
||||
LocalAudioUploadContractExpect::contains(
|
||||
$migration,
|
||||
$needle,
|
||||
'The database migration must include every local audio field'
|
||||
);
|
||||
}
|
||||
|
||||
// Exercise the real internal-file path used after all recording chunks are
|
||||
// merged. A source-code assertion alone did not catch the missing realPath key
|
||||
// (or the missing File object required by the local storage engine).
|
||||
$sourceBase = tempnam(sys_get_temp_dir(), 'zyt-audio-source-');
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
is_string($sourceBase),
|
||||
'A temporary local-audio source file must be creatable'
|
||||
);
|
||||
$sourcePath = $sourceBase . '.webm';
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
rename($sourceBase, $sourcePath),
|
||||
'The temporary local-audio source must keep its WebM extension'
|
||||
);
|
||||
$payload = "\x1A\x45\xDF\xA3local-audio-regression";
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
file_put_contents($sourcePath, $payload) === strlen($payload),
|
||||
'The local-audio fixture must be written completely'
|
||||
);
|
||||
$targetDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR
|
||||
. 'zyt-local-audio-target-' . bin2hex(random_bytes(6));
|
||||
|
||||
try {
|
||||
$localStorage = new \app\common\service\storage\engine\Local();
|
||||
$localStorage->setUploadFileByReal($sourcePath);
|
||||
$fileInfo = $localStorage->getFileInfo();
|
||||
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
isset($fileInfo['realPath']) && $fileInfo['realPath'] === realpath($sourcePath),
|
||||
'Internal storage metadata must include the merged recording realPath'
|
||||
);
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
($fileInfo['tmp_name'] ?? '') === realpath($sourcePath),
|
||||
'Internal storage metadata must preserve a compatible temporary path'
|
||||
);
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
str_ends_with($localStorage->getFileName(), '.webm'),
|
||||
'The generated storage name must preserve the recording extension'
|
||||
);
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
$localStorage->upload($targetDir),
|
||||
'The local storage driver must accept a merged internal recording'
|
||||
);
|
||||
|
||||
$storedPath = $targetDir . DIRECTORY_SEPARATOR . $localStorage->getFileName();
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
is_file($storedPath) && file_get_contents($storedPath) === $payload,
|
||||
'The internally uploaded local recording must remain byte-identical'
|
||||
);
|
||||
} finally {
|
||||
if (isset($storedPath) && is_file($storedPath)) {
|
||||
unlink($storedPath);
|
||||
}
|
||||
if (is_file($sourcePath)) {
|
||||
unlink($sourcePath);
|
||||
}
|
||||
if (is_dir($targetDir)) {
|
||||
rmdir($targetDir);
|
||||
}
|
||||
}
|
||||
|
||||
$missingPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR
|
||||
. 'zyt-missing-local-audio-' . bin2hex(random_bytes(8)) . '.webm';
|
||||
$missingRejected = false;
|
||||
try {
|
||||
$localStorage = new \app\common\service\storage\engine\Local();
|
||||
$localStorage->setUploadFileByReal($missingPath);
|
||||
} catch (Throwable $exception) {
|
||||
$missingRejected = !str_contains($exception->getMessage(), 'realPath')
|
||||
&& str_contains($exception->getMessage(), 'does not exist');
|
||||
}
|
||||
LocalAudioUploadContractExpect::isTrue(
|
||||
$missingRejected,
|
||||
'A missing merged recording must fail clearly before storage-name generation'
|
||||
);
|
||||
|
||||
echo "Local audio upload contract: OK\n";
|
||||
Reference in New Issue
Block a user