429 lines
11 KiB
PHP
429 lines
11 KiB
PHP
<?php
|
|
|
|
namespace Unit;
|
|
|
|
|
|
use Flow\File;
|
|
use Flow\Config;
|
|
use Flow\FileLockException;
|
|
use Flow\FileOpenException;
|
|
use Flow\Request;
|
|
use \org\bovigo\vfs\vfsStreamWrapper;
|
|
use \org\bovigo\vfs\vfsStreamDirectory;
|
|
use \org\bovigo\vfs\vfsStream;
|
|
|
|
/**
|
|
* File unit tests
|
|
*
|
|
* @coversDefaultClass \Flow\File
|
|
*
|
|
* @package Unit
|
|
*/
|
|
class FileTest extends FlowUnitCase
|
|
{
|
|
/**
|
|
* Config
|
|
*
|
|
* @var Config
|
|
*/
|
|
protected $config;
|
|
|
|
/**
|
|
* Virtual file system
|
|
*
|
|
* @var vfsStreamDirectory
|
|
*/
|
|
protected $vfs;
|
|
|
|
protected function setUp()
|
|
{
|
|
parent::setUp();
|
|
|
|
// Setup virtual file system
|
|
vfsStreamWrapper::register();
|
|
$this->vfs = new vfsStreamDirectory('chunks');
|
|
vfsStreamWrapper::setRoot($this->vfs);
|
|
|
|
// Setup Config
|
|
$this->config = new Config();
|
|
$this->config->setTempDir($this->vfs->url());
|
|
}
|
|
|
|
/**
|
|
* @covers ::__construct
|
|
* @covers ::getIdentifier
|
|
*/
|
|
public function testFile_construct_withRequest()
|
|
{
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
|
|
$expIdentifier = sha1($this->requestArr['flowIdentifier']);
|
|
$this->assertSame($expIdentifier, $file->getIdentifier());
|
|
}
|
|
|
|
/**
|
|
* @covers ::__construct
|
|
* @covers ::getIdentifier
|
|
*/
|
|
public function testFile_construct_noRequest()
|
|
{
|
|
$_REQUEST = $this->requestArr;
|
|
|
|
$file = new File($this->config);
|
|
|
|
$expIdentifier = sha1($this->requestArr['flowIdentifier']);
|
|
$this->assertSame($expIdentifier, $file->getIdentifier());
|
|
}
|
|
|
|
/**
|
|
* @covers ::getChunkPath
|
|
*/
|
|
public function testFile_construct_getChunkPath()
|
|
{
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
|
|
$expPath = $this->vfs->url() . DIRECTORY_SEPARATOR . sha1($this->requestArr['flowIdentifier']) . '_1';
|
|
$this->assertSame($expPath, $file->getChunkPath(1));
|
|
}
|
|
|
|
/**
|
|
* @covers ::checkChunk
|
|
*/
|
|
public function testFile_construct_checkChunk()
|
|
{
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
|
|
$this->assertFalse($file->checkChunk());
|
|
|
|
$chunkName = sha1($request->getIdentifier()) . '_' . $request->getCurrentChunkNumber();
|
|
$firstChunk = vfsStream::newFile($chunkName);
|
|
$this->vfs->addChild($firstChunk);
|
|
|
|
$this->assertTrue($file->checkChunk());
|
|
}
|
|
|
|
/**
|
|
* @covers ::validateChunk
|
|
*/
|
|
public function testFile_validateChunk()
|
|
{
|
|
// No $_FILES
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
|
|
$this->assertFalse($file->validateChunk());
|
|
|
|
// No 'file' key $_FILES
|
|
$fileInfo = new \ArrayObject();
|
|
$request = new Request($this->requestArr, $fileInfo);
|
|
$file = new File($this->config, $request);
|
|
|
|
$this->assertFalse($file->validateChunk());
|
|
|
|
// Upload OK
|
|
$fileInfo->exchangeArray(array(
|
|
'size' => 10,
|
|
'error' => UPLOAD_ERR_OK,
|
|
'tmp_name' => ''
|
|
));
|
|
$this->assertTrue($file->validateChunk());
|
|
|
|
// Chunk size doesn't match
|
|
$fileInfo->exchangeArray(array(
|
|
'size' => 9,
|
|
'error' => UPLOAD_ERR_OK,
|
|
'tmp_name' => ''
|
|
));
|
|
$this->assertFalse($file->validateChunk());
|
|
|
|
// Upload error
|
|
$fileInfo->exchangeArray(array(
|
|
'size' => 10,
|
|
'error' => UPLOAD_ERR_EXTENSION,
|
|
'tmp_name' => ''
|
|
));
|
|
$this->assertFalse($file->validateChunk());
|
|
}
|
|
|
|
/**
|
|
* @covers ::validateFile
|
|
*/
|
|
public function testFile_validateFile()
|
|
{
|
|
$this->requestArr['flowTotalSize'] = 10;
|
|
$this->requestArr['flowTotalChunks'] = 3;
|
|
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
$chunkPrefix = sha1($request->getIdentifier()) . '_';
|
|
|
|
// No chunks uploaded yet
|
|
$this->assertFalse($file->validateFile());
|
|
|
|
// First chunk
|
|
$firstChunk = vfsStream::newFile($chunkPrefix . '1');
|
|
$firstChunk->setContent('123');
|
|
$this->vfs->addChild($firstChunk);
|
|
|
|
// Uploaded not yet complete
|
|
$this->assertFalse($file->validateFile());
|
|
|
|
// Second chunk
|
|
$secondChunk = vfsStream::newFile($chunkPrefix . '2');
|
|
$secondChunk->setContent('456');
|
|
$this->vfs->addChild($secondChunk);
|
|
|
|
// Uploaded not yet complete
|
|
$this->assertFalse($file->validateFile());
|
|
|
|
// Third chunk
|
|
$lastChunk = vfsStream::newFile($chunkPrefix . '3');
|
|
$lastChunk->setContent('7890');
|
|
$this->vfs->addChild($lastChunk);
|
|
|
|
// All chunks uploaded
|
|
$this->assertTrue($file->validateFile());
|
|
|
|
//// Test false values
|
|
|
|
// File size doesn't match
|
|
$lastChunk->setContent('789');
|
|
$this->assertFalse($file->validateFile());
|
|
|
|
// Correct file size and expect true
|
|
$this->requestArr['flowTotalSize'] = 9;
|
|
$this->assertTrue($file->validateFile());
|
|
}
|
|
|
|
/**
|
|
* @covers ::deleteChunks
|
|
*/
|
|
public function testFile_deleteChunks()
|
|
{
|
|
//// Setup test
|
|
|
|
$this->requestArr['flowTotalChunks'] = 4;
|
|
|
|
$fileInfo = new \ArrayObject();
|
|
$request = new Request($this->requestArr, $fileInfo);
|
|
$file = new File($this->config, $request);
|
|
$chunkPrefix = sha1($request->getIdentifier()) . '_';
|
|
|
|
$firstChunk = vfsStream::newFile($chunkPrefix . 1);
|
|
$this->vfs->addChild($firstChunk);
|
|
|
|
$secondChunk = vfsStream::newFile($chunkPrefix . 3);
|
|
$this->vfs->addChild($secondChunk);
|
|
|
|
$thirdChunk = vfsStream::newFile('other');
|
|
$this->vfs->addChild($thirdChunk);
|
|
|
|
//// Actual test
|
|
|
|
$this->assertTrue(file_exists($firstChunk->url()));
|
|
$this->assertTrue(file_exists($secondChunk->url()));
|
|
$this->assertTrue(file_exists($thirdChunk->url()));
|
|
|
|
$file->deleteChunks();
|
|
$this->assertFalse(file_exists($firstChunk->url()));
|
|
$this->assertFalse(file_exists($secondChunk->url()));
|
|
$this->assertTrue(file_exists($thirdChunk->url()));
|
|
}
|
|
|
|
/**
|
|
* @covers ::saveChunk
|
|
*/
|
|
public function testFile_saveChunk()
|
|
{
|
|
//// Setup test
|
|
|
|
// Setup temporary file
|
|
$tmpDir = new vfsStreamDirectory('tmp');
|
|
$tmpFile = vfsStream::newFile('tmpFile');
|
|
$tmpFile->setContent('1234567890');
|
|
$tmpDir->addChild($tmpFile);
|
|
$this->vfs->addChild($tmpDir);
|
|
$this->filesArr['file']['tmp_name'] = $tmpFile->url();
|
|
|
|
// Mock File to use rename instead of move_uploaded_file
|
|
$request = new Request($this->requestArr, $this->filesArr['file']);
|
|
$file = $this->getMock('Flow\File', array('_move_uploaded_file'), array($this->config, $request));
|
|
$file->expects($this->once())
|
|
->method('_move_uploaded_file')
|
|
->will($this->returnCallback(function ($filename, $destination) {
|
|
return rename($filename, $destination);
|
|
}));
|
|
|
|
// Expected destination file
|
|
$expDstFile = $this->vfs->url() . DIRECTORY_SEPARATOR . sha1($request->getIdentifier()) . '_1';
|
|
|
|
//// Accrual test
|
|
|
|
$this->assertFalse(file_exists($expDstFile));
|
|
$this->assertTrue(file_exists($tmpFile->url()));
|
|
|
|
/** @noinspection PhpUndefinedMethodInspection */
|
|
$this->assertTrue($file->saveChunk());
|
|
|
|
$this->assertTrue(file_exists($expDstFile));
|
|
//$this->assertFalse(file_exists($tmpFile->url()));
|
|
|
|
$this->assertSame('1234567890', file_get_contents($expDstFile));
|
|
}
|
|
|
|
/**
|
|
* @covers ::save
|
|
*/
|
|
public function testFile_save()
|
|
{
|
|
//// Setup test
|
|
|
|
$this->requestArr['flowTotalChunks'] = 3;
|
|
$this->requestArr['flowTotalSize'] = 10;
|
|
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
|
|
$chunkPrefix = sha1($request->getIdentifier()) . '_';
|
|
|
|
$chunk = vfsStream::newFile($chunkPrefix . '1', 0777);
|
|
$chunk->setContent('0123');
|
|
$this->vfs->addChild($chunk);
|
|
|
|
$chunk = vfsStream::newFile($chunkPrefix . '2', 0777);
|
|
$chunk->setContent('456');
|
|
$this->vfs->addChild($chunk);
|
|
|
|
$chunk = vfsStream::newFile($chunkPrefix . '3', 0777);
|
|
$chunk->setContent('789');
|
|
$this->vfs->addChild($chunk);
|
|
|
|
$filePath = $this->vfs->url() . DIRECTORY_SEPARATOR . 'file';
|
|
|
|
//// Actual test
|
|
|
|
$this->assertTrue($file->save($filePath));
|
|
$this->assertTrue(file_exists($filePath));
|
|
$this->assertEquals($request->getTotalSize(), filesize($filePath));
|
|
}
|
|
|
|
/**
|
|
* @covers ::save
|
|
*/
|
|
public function testFile_save_lock()
|
|
{
|
|
//// Setup test
|
|
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
|
|
$dstFile = $this->vfs->url() . DIRECTORY_SEPARATOR . 'file';
|
|
|
|
// Lock file
|
|
$fh = fopen($dstFile, 'wb');
|
|
$this->assertTrue(flock($fh, LOCK_EX));
|
|
|
|
//// Actual test
|
|
|
|
try {
|
|
// practically on a normal file system exception would not be thrown, this happens
|
|
// because vfsStreamWrapper does not support locking with block
|
|
$file->save($dstFile);
|
|
$this->fail();
|
|
} catch (FileLockException $e) {
|
|
$this->assertEquals('failed to lock file: ' . $dstFile, $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @covers ::save
|
|
*/
|
|
public function testFile_save_FileOpenException()
|
|
{
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
|
|
try {
|
|
@$file->save('not/existing/path');
|
|
$this->fail();
|
|
} catch (FileOpenException $e) {
|
|
$this->assertEquals('failed to open destination file: not/existing/path', $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @covers ::save
|
|
*/
|
|
public function testFile_save_chunk_FileOpenException()
|
|
{
|
|
//// Setup test
|
|
|
|
$this->requestArr['flowTotalChunks'] = 3;
|
|
$this->requestArr['flowTotalSize'] = 10;
|
|
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
|
|
$chunkPrefix = sha1($request->getIdentifier()) . '_';
|
|
|
|
$chunk = vfsStream::newFile($chunkPrefix . '1', 0777);
|
|
$chunk->setContent('0123');
|
|
$this->vfs->addChild($chunk);
|
|
|
|
$chunk = vfsStream::newFile($chunkPrefix . '2', 0777);
|
|
$chunk->setContent('456');
|
|
$this->vfs->addChild($chunk);
|
|
|
|
$missingChunk = $this->vfs->url() . DIRECTORY_SEPARATOR . $chunkPrefix . '3';
|
|
$filePath = $this->vfs->url() . DIRECTORY_SEPARATOR . 'file';
|
|
|
|
//// Actual test
|
|
|
|
try {
|
|
@$file->save($filePath);
|
|
} catch (FileOpenException $e) {
|
|
$this->assertEquals('failed to open chunk: ' . $missingChunk, $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @covers ::save
|
|
*/
|
|
public function testFile_save_preProcess()
|
|
{
|
|
//// Setup test
|
|
|
|
$this->requestArr['flowTotalChunks'] = 1;
|
|
$this->requestArr['flowTotalSize'] = 10;
|
|
$processCalled = false;
|
|
|
|
$process = function($chunk) use (&$processCalled)
|
|
{
|
|
$processCalled = true;
|
|
};
|
|
|
|
$this->config->setPreprocessCallback($process);
|
|
|
|
$request = new Request($this->requestArr);
|
|
$file = new File($this->config, $request);
|
|
|
|
$chunkPrefix = sha1($request->getIdentifier()) . '_';
|
|
|
|
$chunk = vfsStream::newFile($chunkPrefix . '1', 0777);
|
|
$chunk->setContent('1234567890');
|
|
$this->vfs->addChild($chunk);
|
|
|
|
$filePath = $this->vfs->url() . DIRECTORY_SEPARATOR . 'file';
|
|
|
|
//// Actual test
|
|
|
|
$this->assertTrue($file->save($filePath));
|
|
$this->assertTrue(file_exists($filePath));
|
|
$this->assertEquals($request->getTotalSize(), filesize($filePath));
|
|
$this->assertTrue($processCalled);
|
|
}
|
|
}
|