mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
180 lines
6.5 KiB
PHP
180 lines
6.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Services\Nzb\NzbService;
|
|
use ReflectionClass;
|
|
use Tests\TestCase;
|
|
|
|
final class NzbServicePathResolutionTest extends TestCase
|
|
{
|
|
public function test_select_preferred_base_path_prefers_existing_runtime_storage_path_for_foreign_storage_root(): void
|
|
{
|
|
$tempDir = sys_get_temp_dir().'/nzb-service-'.uniqid('', true);
|
|
$configuredPath = $tempDir.'/foreign-app/storage/nzb/';
|
|
$runtimePath = $tempDir.'/runtime-app/storage/nzb/';
|
|
mkdir($runtimePath, 0777, true);
|
|
|
|
try {
|
|
$service = $this->makeServiceWithoutConstructor();
|
|
$preferredPath = \Closure::bind(
|
|
fn (array $paths): string => $this->selectPreferredNzbBasePath($paths),
|
|
$service,
|
|
NzbService::class
|
|
)([$configuredPath, $runtimePath]);
|
|
|
|
$this->assertSame($runtimePath, $preferredPath);
|
|
} finally {
|
|
$this->deleteDirectory($tempDir);
|
|
}
|
|
}
|
|
|
|
public function test_nzb_path_returns_existing_file_from_alternate_candidate_base_paths(): void
|
|
{
|
|
$tempDir = sys_get_temp_dir().'/nzb-path-'.uniqid('', true);
|
|
$guid = '4aabfe07-daff-4d28-9d1d-d2a4ab7b6511';
|
|
$configuredPath = $tempDir.'/foreign-app/storage/nzb/';
|
|
$runtimePath = $tempDir.'/runtime-app/storage/nzb/';
|
|
$expectedFile = $runtimePath.'4/a/a/b/'.$guid.'.nzb.gz';
|
|
mkdir(dirname($expectedFile), 0777, true);
|
|
file_put_contents($expectedFile, 'test');
|
|
|
|
try {
|
|
$service = $this->makeServiceWithoutConstructor();
|
|
\Closure::bind(
|
|
function (int $splitLevel, string $primaryPath, array $paths): void {
|
|
$this->nzbSplitLevel = $splitLevel;
|
|
$this->siteNzbPath = $primaryPath;
|
|
$this->siteNzbPaths = $paths;
|
|
},
|
|
$service,
|
|
NzbService::class
|
|
)(4, $configuredPath, [$configuredPath, $runtimePath]);
|
|
|
|
$this->assertSame($expectedFile, $service->nzbPath($guid));
|
|
} finally {
|
|
$this->deleteDirectory($tempDir);
|
|
}
|
|
}
|
|
|
|
public function test_nzb_path_honors_split_level_one_when_searching_candidate_paths(): void
|
|
{
|
|
$tempDir = sys_get_temp_dir().'/nzb-path-split-one-'.uniqid('', true);
|
|
$guid = '4aabfe07-daff-4d28-9d1d-d2a4ab7b6511';
|
|
$configuredPath = $tempDir.'/foreign-app/storage/nzb/';
|
|
$runtimePath = $tempDir.'/runtime-app/storage/nzb/';
|
|
$expectedFile = $runtimePath.'4/'.$guid.'.nzb.gz';
|
|
mkdir(dirname($expectedFile), 0777, true);
|
|
file_put_contents($expectedFile, 'test');
|
|
|
|
try {
|
|
$service = $this->makeServiceWithoutConstructor();
|
|
\Closure::bind(
|
|
function (int $splitLevel, string $primaryPath, array $paths): void {
|
|
$this->nzbSplitLevel = $splitLevel;
|
|
$this->siteNzbPath = $primaryPath;
|
|
$this->siteNzbPaths = $paths;
|
|
},
|
|
$service,
|
|
NzbService::class
|
|
)(1, $configuredPath, [$configuredPath, $runtimePath]);
|
|
|
|
$this->assertSame($expectedFile, $service->nzbPath($guid));
|
|
} finally {
|
|
$this->deleteDirectory($tempDir);
|
|
}
|
|
}
|
|
|
|
public function test_nzb_path_works_with_existing_resources_nzb_base_path(): void
|
|
{
|
|
$tempDir = sys_get_temp_dir().'/nzb-path-resources-'.uniqid('', true);
|
|
$guid = '4aabfe07-daff-4d28-9d1d-d2a4ab7b6511';
|
|
$configuredPath = $tempDir.'/resources/nzb/';
|
|
$storagePath = $tempDir.'/storage/nzb/';
|
|
$expectedFile = $configuredPath.'4/'.$guid.'.nzb.gz';
|
|
$configuredLinkTarget = rtrim($configuredPath, '/');
|
|
$storageLinkPath = rtrim($storagePath, '/');
|
|
|
|
mkdir(dirname($expectedFile), 0777, true);
|
|
mkdir(dirname($storageLinkPath), 0777, true);
|
|
symlink($configuredLinkTarget, $storageLinkPath);
|
|
file_put_contents($expectedFile, 'test');
|
|
|
|
try {
|
|
$service = $this->makeServiceWithoutConstructor();
|
|
\Closure::bind(
|
|
function (int $splitLevel, string $primaryPath, array $paths): void {
|
|
$this->nzbSplitLevel = $splitLevel;
|
|
$this->siteNzbPath = $primaryPath;
|
|
$this->siteNzbPaths = $paths;
|
|
},
|
|
$service,
|
|
NzbService::class
|
|
)(1, $configuredPath, [$configuredPath, $storagePath]);
|
|
|
|
$this->assertSame($expectedFile, $service->nzbPath($guid));
|
|
} finally {
|
|
$this->deleteDirectory($tempDir);
|
|
}
|
|
}
|
|
|
|
public function test_build_nzb_path_creates_group_writable_setgid_directories_despite_umask(): void
|
|
{
|
|
$tempDir = sys_get_temp_dir().'/nzb-path-permissions-'.uniqid('', true);
|
|
$basePath = $tempDir.'/';
|
|
$previousUmask = umask(0022);
|
|
|
|
try {
|
|
$service = $this->makeServiceWithoutConstructor();
|
|
\Closure::bind(
|
|
function (string $path): void {
|
|
$this->siteNzbPath = $path;
|
|
},
|
|
$service,
|
|
NzbService::class
|
|
)($basePath);
|
|
|
|
$path = $service->buildNzbPath('4aabfe07-daff-4d28-9d1d-d2a4ab7b6511', 4, true);
|
|
|
|
$this->assertSame($basePath.'4/a/a/b/', $path);
|
|
foreach ([rtrim($basePath, '/'), $basePath.'4', $basePath.'4/a', $basePath.'4/a/a', $basePath.'4/a/a/b'] as $directory) {
|
|
$this->assertSame(02775, fileperms($directory) & 07777);
|
|
}
|
|
} finally {
|
|
umask($previousUmask);
|
|
$this->deleteDirectory($tempDir);
|
|
}
|
|
}
|
|
|
|
private function makeServiceWithoutConstructor(): NzbService
|
|
{
|
|
return (new ReflectionClass(NzbService::class))->newInstanceWithoutConstructor();
|
|
}
|
|
|
|
private function deleteDirectory(string $path): void
|
|
{
|
|
if (! is_dir($path)) {
|
|
return;
|
|
}
|
|
|
|
$iterator = new \RecursiveIteratorIterator(
|
|
new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS),
|
|
\RecursiveIteratorIterator::CHILD_FIRST
|
|
);
|
|
|
|
foreach ($iterator as $item) {
|
|
if ($item->isLink()) {
|
|
unlink($item->getPathname());
|
|
} elseif ($item->isDir()) {
|
|
rmdir($item->getPathname());
|
|
} else {
|
|
unlink($item->getPathname());
|
|
}
|
|
}
|
|
|
|
rmdir($path);
|
|
}
|
|
}
|