- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
246 lines
7.2 KiB
PHP
246 lines
7.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\Filesystem\ValueObjects\FilePath;
|
|
use App\Framework\Filesystem\TemporaryDirectory;
|
|
use App\Framework\Exception\FrameworkException;
|
|
|
|
describe('TemporaryDirectory', function () {
|
|
it('creates temporary directory with default name', function () {
|
|
$temp = TemporaryDirectory::make()->create();
|
|
|
|
expect($temp->exists())->toBeTrue();
|
|
expect($temp->getPath()->isDirectory())->toBeTrue();
|
|
|
|
// Cleanup
|
|
$temp->delete();
|
|
});
|
|
|
|
it('creates temporary directory with custom name', function () {
|
|
$temp = TemporaryDirectory::make()
|
|
->name('my-custom-temp')
|
|
->create();
|
|
|
|
$path = $temp->getPath();
|
|
|
|
expect($path->getFilename())->toBe('my-custom-temp');
|
|
expect($temp->exists())->toBeTrue();
|
|
|
|
$temp->delete();
|
|
});
|
|
|
|
it('creates temporary directory in custom location', function () {
|
|
$customLocation = FilePath::tempDir()->join('custom-temp-location');
|
|
|
|
if (!$customLocation->isDirectory()) {
|
|
mkdir($customLocation->toString(), 0755, true);
|
|
}
|
|
|
|
$temp = TemporaryDirectory::make()
|
|
->location($customLocation)
|
|
->name('nested-temp')
|
|
->create();
|
|
|
|
expect($temp->exists())->toBeTrue();
|
|
expect($temp->getPath()->toString())->toContain('custom-temp-location');
|
|
|
|
$temp->delete();
|
|
rmdir($customLocation->toString());
|
|
});
|
|
|
|
it('sanitizes directory names', function () {
|
|
$temp = TemporaryDirectory::make()
|
|
->name('my/dangerous\\name:with*symbols')
|
|
->create();
|
|
|
|
$filename = $temp->getPath()->getFilename();
|
|
|
|
expect($filename)->not->toContain('/');
|
|
expect($filename)->not->toContain('\\');
|
|
expect($filename)->not->toContain(':');
|
|
expect($filename)->not->toContain('*');
|
|
|
|
$temp->delete();
|
|
});
|
|
|
|
it('throws exception when directory exists without force', function () {
|
|
$temp = TemporaryDirectory::make()
|
|
->name('existing-dir')
|
|
->create();
|
|
|
|
expect(fn () => TemporaryDirectory::make()
|
|
->name('existing-dir')
|
|
->create()
|
|
)->toThrow(FrameworkException::class);
|
|
|
|
$temp->delete();
|
|
});
|
|
|
|
it('overwrites existing directory with force', function () {
|
|
$temp1 = TemporaryDirectory::make()
|
|
->name('overwrite-test')
|
|
->create();
|
|
|
|
// Create a file in the first directory
|
|
$testFile = $temp1->path('test.txt');
|
|
file_put_contents($testFile->toString(), 'test content');
|
|
|
|
$temp2 = TemporaryDirectory::make()
|
|
->name('overwrite-test')
|
|
->force()
|
|
->create();
|
|
|
|
// File should be gone
|
|
expect($testFile->exists())->toBeFalse();
|
|
expect($temp2->exists())->toBeTrue();
|
|
|
|
$temp2->delete();
|
|
});
|
|
|
|
it('returns FilePath for files in directory', function () {
|
|
$temp = TemporaryDirectory::make()->create();
|
|
|
|
$filePath = $temp->path('subdir/file.txt');
|
|
|
|
expect($filePath)->toBeInstanceOf(FilePath::class);
|
|
expect($filePath->toString())->toContain('subdir');
|
|
expect($filePath->toString())->toContain('file.txt');
|
|
|
|
$temp->delete();
|
|
});
|
|
|
|
it('empties directory without deleting it', function () {
|
|
$temp = TemporaryDirectory::make()->create();
|
|
|
|
// Create some files
|
|
file_put_contents($temp->path('file1.txt')->toString(), 'content1');
|
|
file_put_contents($temp->path('file2.txt')->toString(), 'content2');
|
|
mkdir($temp->path('subdir')->toString());
|
|
file_put_contents($temp->path('subdir/file3.txt')->toString(), 'content3');
|
|
|
|
$temp->empty();
|
|
|
|
// Directory should still exist
|
|
expect($temp->exists())->toBeTrue();
|
|
|
|
// But should be empty
|
|
$items = iterator_to_array(new \FilesystemIterator($temp->getPath()->toString()));
|
|
expect($items)->toHaveCount(0);
|
|
|
|
$temp->delete();
|
|
});
|
|
|
|
it('deletes directory and all contents', function () {
|
|
$temp = TemporaryDirectory::make()->create();
|
|
$path = $temp->getPath();
|
|
|
|
// Create nested structure
|
|
mkdir($temp->path('dir1')->toString());
|
|
mkdir($temp->path('dir1/dir2')->toString());
|
|
file_put_contents($temp->path('dir1/dir2/file.txt')->toString(), 'nested');
|
|
|
|
$result = $temp->delete();
|
|
|
|
expect($result)->toBeTrue();
|
|
expect($path->exists())->toBeFalse();
|
|
});
|
|
|
|
it('auto-deletes on destruct by default', function () {
|
|
$temp = TemporaryDirectory::make()->create();
|
|
$path = $temp->getPath();
|
|
|
|
expect($path->isDirectory())->toBeTrue();
|
|
|
|
// Explicitly trigger destruct and cleanup
|
|
$temp->delete();
|
|
unset($temp);
|
|
|
|
// Directory should be deleted
|
|
expect($path->exists())->toBeFalse();
|
|
});
|
|
|
|
it('does not auto-delete when disabled', function () {
|
|
$path = null;
|
|
|
|
{
|
|
$temp = TemporaryDirectory::make()
|
|
->doNotDeleteWhenDestruct()
|
|
->create();
|
|
|
|
$path = $temp->getPath();
|
|
} // $temp goes out of scope
|
|
|
|
// Directory should still exist
|
|
expect($path->isDirectory())->toBeTrue();
|
|
|
|
// Manual cleanup
|
|
rmdir($path->toString());
|
|
});
|
|
|
|
it('throws exception when accessing path before creation', function () {
|
|
$temp = TemporaryDirectory::make();
|
|
|
|
expect(fn () => $temp->path())->toThrow(FrameworkException::class);
|
|
});
|
|
|
|
it('handles special characters in filenames', function () {
|
|
$temp = TemporaryDirectory::make()
|
|
->name('test with spaces and-dashes_underscores')
|
|
->create();
|
|
|
|
$filename = $temp->getPath()->getFilename();
|
|
|
|
// Underscores are preserved, spaces become dashes
|
|
expect($filename)->toBe('test-with-spaces-and-dashes_underscores');
|
|
|
|
$temp->delete();
|
|
});
|
|
|
|
it('can chain method calls fluently', function () {
|
|
$temp = TemporaryDirectory::make()
|
|
->name('fluent-test')
|
|
->location(FilePath::tempDir())
|
|
->force()
|
|
->doNotDeleteWhenDestruct()
|
|
->create();
|
|
|
|
expect($temp)->toBeInstanceOf(TemporaryDirectory::class);
|
|
expect($temp->exists())->toBeTrue();
|
|
|
|
$temp->delete();
|
|
});
|
|
|
|
it('deletes deeply nested structures', function () {
|
|
$temp = TemporaryDirectory::make()->create();
|
|
|
|
// Create deep nesting
|
|
$deepPath = $temp->path('a/b/c/d/e/f/g');
|
|
mkdir($deepPath->toString(), 0755, true);
|
|
file_put_contents($deepPath->join('file.txt')->toString(), 'deep content');
|
|
|
|
expect($deepPath->exists())->toBeTrue();
|
|
|
|
$temp->delete();
|
|
|
|
expect($temp->getPath()->exists())->toBeFalse();
|
|
});
|
|
|
|
it('returns false when deleting non-existent directory', function () {
|
|
$temp = TemporaryDirectory::make()->name('never-created');
|
|
|
|
$result = $temp->delete();
|
|
|
|
expect($result)->toBeFalse();
|
|
});
|
|
|
|
it('empty() does nothing on non-existent directory', function () {
|
|
$temp = TemporaryDirectory::make()->name('never-created');
|
|
|
|
// Should not throw
|
|
$result = $temp->empty();
|
|
|
|
expect($result)->toBeInstanceOf(TemporaryDirectory::class);
|
|
});
|
|
});
|