ui = $this->getMockBuilder(CronUIInterface::class)->disableOriginalConstructor()->getMock(); $this->logger = $this->getMockBuilder(LoggerInterface::class)->disableOriginalConstructor()->getMock(); $this->connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); $this->fileRepository = $this->getMockBuilder(FileRepository::class)->disableOriginalConstructor()->getMock(); $this->storage = $this->getMockBuilder(LocalStorage::class)->disableOriginalConstructor()->getMock(); } private function getFilesGarbageCollectorMockFor(string $methodName): TestableFilesGarbageCollector|MockObject { $filesGarbageCollector = $this->getMockBuilder(TestableFilesGarbageCollector::class) ->setConstructorArgs([$this->connection, $this->fileRepository, $this->storage]) ->setMethodsExcept([$methodName, 'setUI', 'setLoggerInterface']) ->getMock(); $filesGarbageCollector->setUI($this->ui); $filesGarbageCollector->setLoggerInterface($this->logger); return $filesGarbageCollector; } /** * @see FilesGarbageCollector::preview() */ public function testPreview(): void { $filesGarbageCollector = $this->getFilesGarbageCollectorMockFor('preview'); $file1 = $this->getMockBuilder(File::class)->getMock(); $file1->method('getSlug')->willReturn('file1.txt'); $file1->method('getStatus')->willReturn(FileStatusEnum::DELETION_REQUESTED); $file2 = $this->getMockBuilder(File::class)->getMock(); $file2->method('getSlug')->willReturn('file2.txt'); $file2->method('getStatus')->willReturn(FileStatusEnum::DELETION_REQUESTED); $files = [$file1, $file2]; $filesGarbageCollector->expects(self::once()) ->method('listFilesToDelete') ->willReturn($files); $this->storage->expects(self::exactly(2)) ->method('exists') ->willReturnMap([ [$file1, true], [$file2, false] ]); $this->ui->expects(self::exactly(4)) ->method('print') ->withConsecutive( ['2 files to be removed'], ['> Printing the first and last 50 :'], [' * file1.txt (Status: DELETION_REQUESTED - Exists: Yes)'], [' * file2.txt (Status: DELETION_REQUESTED - Exists: No)'] ); $filesGarbageCollector->preview(); } /** * @see FilesGarbageCollector::execute() */ public function testExecute(): void { $filesGarbageCollector = $this->getFilesGarbageCollectorMockFor('execute'); $file1 = $this->getMockBuilder(File::class)->getMock(); $file2 = $this->getMockBuilder(File::class)->getMock(); $files = [$file1, $file2]; $filesGarbageCollector->expects(self::once()) ->method('listFilesToDelete') ->willReturn($files); $filesGarbageCollector->expects(self::once()) ->method('deleteFiles') ->with($files); $this->logger->expects(self::once()) ->method('info') ->with('2 files to be removed'); $filesGarbageCollector->execute(); } /** * @see FilesGarbageCollector::listFilesToDelete() */ public function testListFilesToDelete(): void { $filesGarbageCollector = $this->getFilesGarbageCollectorMockFor('listFilesToDelete'); $queryBuilder = $this->getMockBuilder(QueryBuilder::class) ->disableOriginalConstructor() ->getMock(); $query = $this->getMockBuilder(Query::class) ->disableOriginalConstructor() ->getMock(); $file1 = $this->getMockBuilder(File::class)->getMock(); $file2 = $this->getMockBuilder(File::class)->getMock(); $expectedResult = [$file1, $file2]; $this->fileRepository->expects(self::once()) ->method('createQueryBuilder') ->with('f') ->willReturn($queryBuilder); $queryBuilder->expects(self::once()) ->method('select') ->willReturnSelf(); $filesGarbageCollector->expects(self::once()) ->method('getQueryConditions') ->with($queryBuilder); $queryBuilder->expects(self::once()) ->method('getQuery') ->willReturn($query); $query->expects(self::once()) ->method('getResult') ->willReturn($expectedResult); $this->ui->expects(self::once()) ->method('print') ->with('List files with host ap2i and status DELETION_REQUESTED'); $result = $filesGarbageCollector->listFilesToDelete(); $this->assertEquals($expectedResult, $result); } /** * @see FilesGarbageCollector::deleteFiles() */ public function testDeleteFiles(): void { $filesGarbageCollector = $this->getFilesGarbageCollectorMockFor('deleteFiles'); $file1 = $this->getMockBuilder(File::class)->getMock(); $file1->method('getId')->willReturn(1); $file2 = $this->getMockBuilder(File::class)->getMock(); $file2->method('getId')->willReturn(2); $files = [$file1, $file2]; $queryBuilder = $this->getMockBuilder(QueryBuilder::class) ->disableOriginalConstructor() ->getMock(); $query = $this->getMockBuilder(Query::class) ->disableOriginalConstructor() ->getMock(); $this->fileRepository->expects(self::once()) ->method('createQueryBuilder') ->with('f') ->willReturn($queryBuilder); $this->storage->expects(self::exactly(2)) ->method('exists') ->willReturnMap([ [$file1, true], [$file2, false] ]); $this->storage->expects(self::once()) ->method('hardDelete') ->with($file1); $queryBuilder->expects(self::exactly(2)) ->method('delete') ->willReturnSelf(); $queryBuilder->expects(self::exactly(2)) ->method('where') ->with('f.id = :id') ->willReturnSelf(); $queryBuilder->expects(self::exactly(2)) ->method('setParameter') ->withConsecutive( ['id', 1], ['id', 2] ) ->willReturnSelf(); $queryBuilder->expects(self::exactly(2)) ->method('getQuery') ->willReturn($query); $query->expects(self::exactly(2)) ->method('execute'); $this->logger->expects(self::exactly(3)) ->method('info') ->withConsecutive( ['2 files to be removed'], ['Deleting files...'], ['2 files deleted'] ); $this->ui->expects(self::exactly(3)) ->method('progress'); $filesGarbageCollector->deleteFiles($files); } /** * @see FilesGarbageCollector::deleteFiles() */ public function testDeleteFilesWithNonBlockingErrors(): void { $filesGarbageCollector = $this->getFilesGarbageCollectorMockFor('deleteFiles'); $file1 = $this->getMockBuilder(File::class)->getMock(); $file1->method('getId')->willReturn(1); $file2 = $this->getMockBuilder(File::class)->getMock(); $file2->method('getId')->willReturn(2); $files = [$file1, $file2]; $queryBuilder = $this->getMockBuilder(QueryBuilder::class) ->disableOriginalConstructor() ->getMock(); $this->fileRepository->expects(self::once()) ->method('createQueryBuilder') ->with('f') ->willReturn($queryBuilder); $this->storage->expects(self::exactly(2)) ->method('exists') ->willReturnMap([ [$file1, true], [$file2, true] ]); $this->storage->expects(self::exactly(2)) ->method('hardDelete') ->willReturnOnConsecutiveCalls( $this->throwException(new \RuntimeException('Storage error')), $this->throwException(new \InvalidArgumentException('Invalid file')) ); $this->logger->expects(self::exactly(3)) ->method('info') ->withConsecutive( ['2 files to be removed'], ['Deleting files...'], ['0 files deleted'] ); $this->logger->expects(self::exactly(2)) ->method('error') ->withConsecutive( ['ERROR : Storage error'], ['ERROR : Invalid file'] ); $this->ui->expects(self::exactly(3)) ->method('progress'); $filesGarbageCollector->deleteFiles($files); } /** * @see FilesGarbageCollector::deleteFiles() */ public function testDeleteFilesWithBlockingError(): void { $filesGarbageCollector = $this->getFilesGarbageCollectorMockFor('deleteFiles'); $file = $this->getMockBuilder(File::class)->getMock(); $file->method('getId')->willReturn(1); $files = [$file]; $queryBuilder = $this->getMockBuilder(QueryBuilder::class) ->disableOriginalConstructor() ->getMock(); $this->fileRepository->expects(self::once()) ->method('createQueryBuilder') ->with('f') ->willReturn($queryBuilder); $this->storage->expects(self::once()) ->method('exists') ->with($file) ->willReturn(true); $this->storage->expects(self::once()) ->method('hardDelete') ->with($file) ->willThrowException(new \Exception('Critical storage error')); $this->logger->expects(self::exactly(2)) ->method('info') ->withConsecutive( ['1 files to be removed'], ['Deleting files...'] ); $this->ui->expects(self::exactly(2)) ->method('progress'); $this->expectException(\Exception::class); $this->expectExceptionMessage('Critical storage error'); $filesGarbageCollector->deleteFiles($files); } /** * @see FilesGarbageCollector::getQueryConditions() */ public function testGetQueryConditions(): void { $filesGarbageCollector = $this->getFilesGarbageCollectorMockFor('getQueryConditions'); $queryBuilder = $this->getMockBuilder(QueryBuilder::class) ->disableOriginalConstructor() ->getMock(); $expr = $this->getMockBuilder(Expr::class) ->disableOriginalConstructor() ->getMock(); $queryBuilder->expects(self::atLeastOnce()) ->method('expr') ->willReturn($expr); $hostComparison = $this->getMockBuilder(Expr\Comparison::class) ->disableOriginalConstructor() ->getMock(); $statusComparison = $this->getMockBuilder(Expr\Comparison::class) ->disableOriginalConstructor() ->getMock(); $expr->expects(self::exactly(2)) ->method('eq') ->willReturnMap([ ['f.host', ':host', $hostComparison], ['f.status', ':status', $statusComparison] ]); $queryBuilder->expects(self::exactly(2)) ->method('andWhere') ->withConsecutive( [$hostComparison], [$statusComparison] ) ->willReturnSelf(); $queryBuilder->expects(self::exactly(2)) ->method('setParameter') ->withConsecutive( ['host', FileHostEnum::AP2I], ['status', FileStatusEnum::DELETION_REQUESTED] ) ->willReturnSelf(); $filesGarbageCollector->getQueryConditions($queryBuilder); } }