diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 89cfd7c..4fcdd1b 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,4 +1,3 @@ tools: external_code_coverage: - timeout: 300 - runs: 6 + timeout: 1200 diff --git a/.travis.yml b/.travis.yml index 21dd9cb..a2a68c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,31 @@ language: php -php: - - 5.5 - - 5.6 - - 7.0 - - hhvm - -env: - - STORAGE=array - - STORAGE=doctrine +matrix: + fast_finish: true + include: + - php: 5.6 + env: + - STORAGE=doctrine + - CODE_COVERAGE=true + - php: 5.6 + env: + - STORAGE=array + - php: 7.0 + env: + - STORAGE=doctrine + - php: 7.0 + env: + - STORAGE=array + - php: hhvm + env: + - STORAGE=doctrine + - php: hhvm + env: + - STORAGE=array install: - composer self-update - composer update - - wget https://scrutinizer-ci.com/ocular.phar before_script: - STORAGE=doctrine tests/app/console doctrine:database:create @@ -23,4 +35,10 @@ script: - phpunit -c phpunit.xml.dist --coverage-clover=coverage.clover after_script: - - php ocular.phar code-coverage:upload --access-token="230ec5e01daf5bb3e46ea304fb20348b52d80de73463ec08ee9c96fcd1349e35" --format=php-clover coverage.clover + - if [[ $CODE_COVERAGE == 'true' ]]; then wget https://scrutinizer-ci.com/ocular.phar ; fi + - if [[ $CODE_COVERAGE == 'true' ]]; then php ocular.phar code-coverage:upload --access-token="230ec5e01daf5bb3e46ea304fb20348b52d80de73463ec08ee9c96fcd1349e35" --format=php-clover coverage.clover ; fi + +cache: + directories: + - "$HOME/.composer/cache" + - vendor diff --git a/composer.json b/composer.json index 932f04c..32424f4 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": "~5.5 || ~7.0", + "php": "~5.6 || ~7.0", "php-task/php-task": "dev-master", "symfony/http-kernel": "^2.6", "symfony/dependency-injection": "^2.6", @@ -22,13 +22,19 @@ "phpunit/phpunit": "^4.8", "symfony/framework-bundle": "^2.6", "symfony/finder": "^2.6", - "doctrine/doctrine-bundle": "^1.5" + "doctrine/doctrine-bundle": "^1.5", + "doctrine/data-fixtures": "^1.2" }, "autoload": { "psr-4": { "Task\\TaskBundle\\": "src" } }, + "autoload-dev": { + "psr-4": { + "Task\\TaskBundle\\Tests\\": "tests" + } + }, "extra": { "branch-alias": { "dev-master": "1.0-dev" diff --git a/src/Command/DebugTasksCommand.php b/src/Command/DebugTasksCommand.php index f3f22f6..5dfbe52 100644 --- a/src/Command/DebugTasksCommand.php +++ b/src/Command/DebugTasksCommand.php @@ -16,7 +16,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Task\Execution\TaskExecutionRepositoryInterface; +use Task\Storage\TaskExecutionRepositoryInterface; /** * Run pending tasks. @@ -26,17 +26,17 @@ class DebugTasksCommand extends Command /** * @var TaskExecutionRepositoryInterface */ - private $storage; + private $taskExecutionRepository; /** * @param string $name - * @param TaskExecutionRepositoryInterface $storage + * @param TaskExecutionRepositoryInterface $taskExecutionRepository */ - public function __construct($name, TaskExecutionRepositoryInterface $storage) + public function __construct($name, TaskExecutionRepositoryInterface $taskExecutionRepository) { parent::__construct($name); - $this->storage = $storage; + $this->taskExecutionRepository = $taskExecutionRepository; } /** @@ -45,7 +45,8 @@ public function __construct($name, TaskExecutionRepositoryInterface $storage) protected function configure() { $this->setDescription('Debug tasks') - ->addOption('limit', 'l', InputOption::VALUE_REQUIRED, '', null); + ->addOption('page', 'p', InputOption::VALUE_REQUIRED, '', 1) + ->addOption('page-size', null, InputOption::VALUE_REQUIRED, '', null); } /** @@ -53,9 +54,10 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $limit = $input->getOption('limit'); + $page = $input->getOption('page'); + $pageSize = $input->getOption('page-size'); - $executions = $this->storage->findAll($limit); + $executions = $this->taskExecutionRepository->findAll($page, $pageSize); $table = new Table($output); $table->setHeaders(['uuid', 'status', 'handler', 'schedule time', 'end time', 'duration']); diff --git a/src/Command/RunCommand.php b/src/Command/RunCommand.php index f7a3c68..f496513 100644 --- a/src/Command/RunCommand.php +++ b/src/Command/RunCommand.php @@ -15,7 +15,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Task\Runner\TaskRunnerInterface; -use Task\Scheduler\SchedulerInterface; +use Task\Scheduler\TaskSchedulerInterface; /** * Run pending tasks. @@ -28,16 +28,16 @@ class RunCommand extends Command private $runner; /** - * @var SchedulerInterface + * @var TaskSchedulerInterface */ private $scheduler; /** * @param string $name * @param TaskRunnerInterface $runner - * @param SchedulerInterface $scheduler + * @param TaskSchedulerInterface $scheduler */ - public function __construct($name, TaskRunnerInterface $runner, SchedulerInterface $scheduler) + public function __construct($name, TaskRunnerInterface $runner, TaskSchedulerInterface $scheduler) { parent::__construct($name); diff --git a/src/Command/ScheduleTaskCommand.php b/src/Command/ScheduleTaskCommand.php index 6a104b7..063ecda 100644 --- a/src/Command/ScheduleTaskCommand.php +++ b/src/Command/ScheduleTaskCommand.php @@ -16,7 +16,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Task\Scheduler\SchedulerInterface; +use Task\Scheduler\TaskSchedulerInterface; /** * Schedule task. @@ -24,15 +24,15 @@ class ScheduleTaskCommand extends Command { /** - * @var SchedulerInterface + * @var TaskSchedulerInterface */ private $scheduler; /** * @param string $name - * @param SchedulerInterface $runner + * @param TaskSchedulerInterface $runner */ - public function __construct($name, SchedulerInterface $runner) + public function __construct($name, TaskSchedulerInterface $runner) { parent::__construct($name); @@ -46,9 +46,10 @@ protected function configure() { $this ->setDescription('Run pending tasks') - ->addArgument('handler', InputArgument::REQUIRED) + ->addArgument('handlerClass', InputArgument::REQUIRED) ->addArgument('workload', InputArgument::OPTIONAL) ->addOption('cron-expression', 'c', InputOption::VALUE_REQUIRED) + ->addOption('execution-date', null, InputOption::VALUE_REQUIRED) ->addOption('end-date', null, InputOption::VALUE_REQUIRED); } @@ -57,16 +58,17 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $handler = $input->getArgument('handler'); + $handlerClass = $input->getArgument('handlerClass'); $workload = $input->getArgument('workload'); $cronExpression = $input->getOption('cron-expression'); + $executionDateString = $input->getOption('execution-date'); $endDateString = $input->getOption('end-date'); if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $output->writeln(sprintf('Schedule task "%s" with workload "%s"', $handler, $workload)); + $output->writeln(sprintf('Schedule task "%s" with workload "%s"', $handlerClass, $workload)); } - $taskBuilder = $this->scheduler->createTask($input->getArgument('handler'), $input->getArgument('workload')); + $taskBuilder = $this->scheduler->createTask($handlerClass, $workload); if ($cronExpression !== null) { $endDate = null; @@ -77,6 +79,10 @@ protected function execute(InputInterface $input, OutputInterface $output) $taskBuilder->cron($cronExpression, new \DateTime(), $endDate); } + if ($executionDateString !== null) { + $taskBuilder->executeAt(new \DateTime($executionDateString)); + } + $this->scheduler->addTask($taskBuilder->getTask()); } } diff --git a/src/DoctrineStorage/TaskExecutionRepository.php b/src/DoctrineStorage/TaskExecutionRepository.php deleted file mode 100644 index 2ad759b..0000000 --- a/src/DoctrineStorage/TaskExecutionRepository.php +++ /dev/null @@ -1,94 +0,0 @@ -objectManager = $objectManager; - $this->taskExecutionRepository = $taskExecutionRepository; - } - - /** - * {@inheritdoc} - */ - public function store(TaskExecutionInterface $execution) - { - $this->objectManager->persist($execution); - - // FIXME move this flush to somewhere else (: - $this->objectManager->flush(); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function save(TaskExecutionInterface $execution) - { - $this->objectManager->persist($execution); - - // FIXME move this flush to somewhere else (: - $this->objectManager->flush(); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function findByStartTime(TaskInterface $task, \DateTime $scheduleTime) - { - return $this->taskExecutionRepository->findByScheduledTime($task, $scheduleTime); - } - - /** - * {@inheritdoc} - */ - public function findAll($limit = null) - { - return $this->taskExecutionRepository->findBy([], ['scheduleTime' => 'ASC'], $limit); - } - - /** - * {@inheritdoc} - */ - public function findScheduled() - { - return $this->taskExecutionRepository->findScheduled(new \DateTime()); - } -} diff --git a/src/DoctrineStorage/TaskRepository.php b/src/DoctrineStorage/TaskRepository.php deleted file mode 100644 index 7e55b9c..0000000 --- a/src/DoctrineStorage/TaskRepository.php +++ /dev/null @@ -1,83 +0,0 @@ -objectManager = $objectManager; - $this->taskRepository = $taskRepository; - } - - /** - * {@inheritdoc} - */ - public function store(TaskInterface $task) - { - $this->objectManager->persist($task); - - // FIXME move this flush to somewhere else (: - $this->objectManager->flush(); - } - - /** - * {@inheritdoc} - */ - public function findAll($limit = null) - { - return $this->taskRepository->findBy([], null, $limit); - } - - /** - * {@inheritdoc} - */ - public function findEndBeforeNow() - { - return $this->taskRepository->findEndBefore(new \DateTime()); - } - - /** - * {@inheritdoc} - */ - public function clear() - { - foreach ($this->taskRepository->findAll() as $task) { - $this->objectManager->remove($task); - } - - // FIXME move this flush to somewhere else (: - $this->objectManager->flush(); - } -} diff --git a/src/Entity/TaskExecutionRepository.php b/src/Entity/TaskExecutionRepository.php index 8e39c74..ae79d34 100644 --- a/src/Entity/TaskExecutionRepository.php +++ b/src/Entity/TaskExecutionRepository.php @@ -14,23 +14,64 @@ use Doctrine\ORM\EntityRepository; use Doctrine\ORM\NoResultException; use Task\Execution\TaskExecutionInterface; +use Task\Storage\TaskExecutionRepositoryInterface; use Task\TaskInterface; use Task\TaskStatus; /** * Repository for task-execution. */ -class TaskExecutionRepository extends EntityRepository +class TaskExecutionRepository extends EntityRepository implements TaskExecutionRepositoryInterface { /** - * Returns task-execution by task and scheduled-time. - * - * @param TaskInterface $task - * @param \DateTime $scheduleTime - * - * @return TaskExecutionInterface + * {@inheritdoc} */ - public function findByScheduledTime(TaskInterface $task, \DateTime $scheduleTime) + public function create(TaskInterface $task, \DateTime $scheduleTime) + { + return new TaskExecution($task, $task->getHandlerClass(), $scheduleTime, $task->getWorkload()); + } + + /** + * {@inheritdoc} + */ + public function persist(TaskExecutionInterface $execution) + { + $this->_em->persist($execution); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function flush() + { + $this->_em->flush(); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function findAll($page = 1, $pageSize = null) + { + $query = $this->createQueryBuilder('e') + ->innerJoin('e.task', 't') + ->getQuery(); + + if ($pageSize) { + $query->setMaxResults($pageSize); + $query->setFirstResult(($page - 1) * $pageSize); + } + + return $query->getResult(); + } + + /** + * {@inheritdoc} + */ + public function findByStartTime(TaskInterface $task, \DateTime $scheduleTime) { try { return $this->createQueryBuilder('e') @@ -47,11 +88,7 @@ public function findByScheduledTime(TaskInterface $task, \DateTime $scheduleTime } /** - * Returns scheduled task-execution. - * - * @param \DateTime|null $dateTime - * - * @return TaskExecutionInterface[] + * {@inheritdoc} */ public function findScheduled(\DateTime $dateTime = null) { diff --git a/src/Entity/TaskRepository.php b/src/Entity/TaskRepository.php index 7f670d1..8feacaf 100644 --- a/src/Entity/TaskRepository.php +++ b/src/Entity/TaskRepository.php @@ -12,13 +12,66 @@ namespace Task\TaskBundle\Entity; use Doctrine\ORM\EntityRepository; +use Task\Storage\TaskRepositoryInterface; use Task\TaskInterface; /** * Repository for task. */ -class TaskRepository extends EntityRepository +class TaskRepository extends EntityRepository implements TaskRepositoryInterface { + /** + * {@inheritdoc} + */ + public function create($handlerClass, $workload = null) + { + return new Task($handlerClass, $workload); + } + + /** + * {@inheritdoc} + */ + public function persist(TaskInterface $task) + { + $this->_em->persist($task); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function flush() + { + $this->_em->flush(); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function findAll($page = 1, $pageSize = null) + { + $query = $this->createQueryBuilder('t') + ->getQuery(); + + if ($pageSize) { + $query->setMaxResults($pageSize); + $query->setFirstResult(($page - 1) * $pageSize); + } + + return $query->getResult(); + } + + /** + * {@inheritdoc} + */ + public function findEndBeforeNow() + { + return $this->findEndBefore(new \DateTime()); + } + /** * Returns task where last-execution is before given date-time. * @@ -29,7 +82,7 @@ class TaskRepository extends EntityRepository public function findEndBefore(\DateTime $dateTime) { return $this->createQueryBuilder('t') - ->where('t.lastExecution IS NULL OR t.lastExecution >= :dateTime') + ->where('t.lastExecution IS NULL OR t.lastExecution > :dateTime') ->setParameter('dateTime', $dateTime) ->getQuery() ->getResult(); diff --git a/src/Factory.php b/src/Factory.php deleted file mode 100644 index e4af578..0000000 --- a/src/Factory.php +++ /dev/null @@ -1,38 +0,0 @@ -getHandlerClass(), $scheduleTime, $task->getWorkload()); - } -} diff --git a/src/Handler/TaskHandlerFactory.php b/src/Handler/TaskHandlerFactory.php index 9cd1040..d49061f 100644 --- a/src/Handler/TaskHandlerFactory.php +++ b/src/Handler/TaskHandlerFactory.php @@ -11,8 +11,8 @@ namespace Task\TaskBundle\Handler; -use Symfony\Component\CssSelector\Parser\Handler\HandlerInterface; use Task\Handler\TaskHandlerFactoryInterface; +use Task\Handler\TaskHandlerInterface; use Task\Handler\TaskHandlerNotExistsException; /** @@ -21,7 +21,7 @@ class TaskHandlerFactory implements TaskHandlerFactoryInterface { /** - * @var HandlerInterface[] + * @var TaskHandlerInterface[] */ private $handler = []; diff --git a/src/Resources/config/command.xml b/src/Resources/config/command.xml index dd863c4..69c6e13 100644 --- a/src/Resources/config/command.xml +++ b/src/Resources/config/command.xml @@ -11,7 +11,7 @@ - + task:run:handler diff --git a/src/Resources/config/scheduler.xml b/src/Resources/config/scheduler.xml index 34540a1..9ccad0f 100644 --- a/src/Resources/config/scheduler.xml +++ b/src/Resources/config/scheduler.xml @@ -3,10 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + - - + + diff --git a/src/Resources/config/storage/doctrine.xml b/src/Resources/config/storage/doctrine.xml index bf46469..fb22e29 100644 --- a/src/Resources/config/storage/doctrine.xml +++ b/src/Resources/config/storage/doctrine.xml @@ -8,20 +8,13 @@ TaskBundle:Task + - - - - TaskBundle:TaskExecution - - - - - + diff --git a/src/TaskBundle.php b/src/TaskBundle.php index a32c821..36805a5 100644 --- a/src/TaskBundle.php +++ b/src/TaskBundle.php @@ -8,8 +8,6 @@ /** * Integrates php-task into symfony. - * - * @author @wachterjohannes */ class TaskBundle extends Bundle { diff --git a/tests/Functional/BaseCommandTestCase.php b/tests/Functional/BaseCommandTestCase.php new file mode 100644 index 0000000..3d7b7e7 --- /dev/null +++ b/tests/Functional/BaseCommandTestCase.php @@ -0,0 +1,175 @@ +taskRunner = self::$kernel->getContainer()->get('task.runner'); + $this->taskScheduler = self::$kernel->getContainer()->get('task.scheduler'); + $this->taskRepository = self::$kernel->getContainer()->get('task.storage.task'); + $this->taskExecutionRepository = self::$kernel->getContainer()->get('task.storage.task_execution'); + + $command = $this->getCommand(); + + $this->application = new Application(self::$kernel); + $this->application->add($command); + + $this->command = $this->application->find($command->getName()); + $this->commandTester = new CommandTester($this->command); + + $this->purgeDatabase(); + } + + /** + * Create new task. + * + * @param string $workload + * @param CronExpression $cronExpression + * @param string $handlerClass + * + * @return TaskInterface + */ + protected function createTask($workload, CronExpression $cronExpression = null, $handlerClass = TestHandler::class) + { + $task = $this->taskRepository->create($handlerClass, $workload); + if ($cronExpression) { + $task->setInterval($cronExpression, new \DateTime(), new \DateTime('+1 year')); + } + $this->taskRepository->persist($task); + $this->taskRepository->flush(); + + return $task; + } + + /** + * Create task-execution. + * + * @param TaskInterface $task + * @param \DateTime $scheduleTime + * @param string $status + * + * @return TaskExecutionInterface + */ + protected function createTaskExecution(TaskInterface $task, \DateTime $scheduleTime, $status = TaskStatus::PLANNED) + { + $execution = $this->taskExecutionRepository->create($task, $scheduleTime); + $execution->setStatus($status); + $this->taskExecutionRepository->persist($execution); + $this->taskExecutionRepository->flush(); + + return $execution; + } + + /** + * Purge the Doctrine ORM database. + */ + protected function purgeDatabase() + { + if (!self::$kernel->getContainer()->has('doctrine')) { + return; + } + + $manager = $this->getEntityManager(); + $connection = $manager->getConnection(); + + if ($connection->getDriver() instanceof Driver) { + $connection->executeUpdate('SET foreign_key_checks = 0;'); + } + + $purger = new ORMPurger(); + $executor = new ORMExecutor($manager, $purger); + $referenceRepository = new ProxyReferenceRepository($manager); + $executor->setReferenceRepository($referenceRepository); + $executor->purge(); + + if ($connection->getDriver() instanceof Driver) { + $connection->executeUpdate('SET foreign_key_checks = 1;'); + } + } + + /** + * Returns entity-manager. + * + * @return EntityManagerInterface + */ + protected function getEntityManager() + { + return self::$kernel->getContainer()->get('doctrine')->getManager(); + } + + /** + * Returns command. + * + * @return Command + */ + abstract protected function getCommand(); +} diff --git a/tests/Functional/BootstrapTest.php b/tests/Functional/BootstrapTest.php index 1dab5c7..7e64c74 100644 --- a/tests/Functional/BootstrapTest.php +++ b/tests/Functional/BootstrapTest.php @@ -9,15 +9,18 @@ * with this source code in the file LICENSE. */ -namespace Functional; +namespace Task\TaskBundle\Tests\Functional; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Task\Scheduler\SchedulerInterface; +use Task\Scheduler\TaskSchedulerInterface; use Task\Storage\ArrayStorage\ArrayTaskExecutionRepository; use Task\Storage\ArrayStorage\ArrayTaskRepository; -use Task\TaskBundle\DoctrineStorage\TaskExecutionRepository; -use Task\TaskBundle\DoctrineStorage\TaskRepository; +use Task\TaskBundle\Entity\TaskExecutionRepository; +use Task\TaskBundle\Entity\TaskRepository; +/** + * Tests the service definitions. + */ class BootstrapTest extends KernelTestCase { public function testBootstrap() @@ -28,7 +31,7 @@ public function testBootstrap() $taskRepository = self::$kernel->getContainer()->get('task.storage.task'); $taskExecutionRepository = self::$kernel->getContainer()->get('task.storage.task_execution'); - $this->assertInstanceOf(SchedulerInterface::class, $scheduler); + $this->assertInstanceOf(TaskSchedulerInterface::class, $scheduler); switch (self::$kernel->getContainer()->getParameter('kernel.storage')) { case 'array': diff --git a/tests/Functional/Command/DebugTasksCommandTest.php b/tests/Functional/Command/DebugTasksCommandTest.php new file mode 100644 index 0000000..4119b92 --- /dev/null +++ b/tests/Functional/Command/DebugTasksCommandTest.php @@ -0,0 +1,113 @@ +createTask('Test workload 1'); + + /** @var TaskExecutionInterface[] $executions */ + $executions = [ + $this->createTaskExecution($task, new \DateTime('-1 hour'), TaskStatus::COMPLETE), + $this->createTaskExecution($task, new \DateTime('-2 hour'), TaskStatus::COMPLETE), + ]; + + $executions[0]->setResult(strrev($executions[0]->getWorkload())); + $executions[0]->setDuration(0.1); + $executions[1]->setResult(strrev($executions[1]->getWorkload())); + $executions[1]->setDuration(0.0001); + + $this->taskExecutionRepository->flush(); + + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + ] + ); + + $output = $this->commandTester->getDisplay(); + $this->assertContains($executions[0]->getUuid(), $output); + $this->assertContains($executions[1]->getUuid(), $output); + $this->assertContains('100000ms', $output); + $this->assertContains('100ms', $output); + $this->assertContains('completed', $output); + } + + public function testExecutePaginated() + { + $task = $this->createTask('Test workload 1'); + + /** @var TaskExecutionInterface[] $executions */ + $executions = [ + $this->createTaskExecution($task, new \DateTime('-1 hour')), + $this->createTaskExecution($task, new \DateTime('-2 hour')), + $this->createTaskExecution($task, new \DateTime('+1 hour')), + ]; + + $this->taskExecutionRepository->flush(); + + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + '--page-size' => 2, + ] + ); + + $output = $this->commandTester->getDisplay(); + $this->assertContains($executions[0]->getUuid(), $output); + $this->assertContains($executions[1]->getUuid(), $output); + $this->assertNotContains($executions[2]->getUuid(), $output); + + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + '--page' => 2, + '--page-size' => 2, + ] + ); + + $output = $this->commandTester->getDisplay(); + $this->assertNotContains($executions[0]->getUuid(), $output); + $this->assertNotContains($executions[1]->getUuid(), $output); + $this->assertContains($executions[2]->getUuid(), $output); + + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + '--page' => 3, + '--page-size' => 2, + ] + ); + + $output = $this->commandTester->getDisplay(); + $this->assertNotContains($executions[0]->getUuid(), $output); + $this->assertNotContains($executions[1]->getUuid(), $output); + $this->assertNotContains($executions[2]->getUuid(), $output); + } + + /** + * {@inheritdoc} + */ + protected function getCommand() + { + return self::$kernel->getContainer()->get('task.command.debug_tasks'); + } +} diff --git a/tests/Functional/Command/RunCommandTest.php b/tests/Functional/Command/RunCommandTest.php new file mode 100644 index 0000000..9f6daab --- /dev/null +++ b/tests/Functional/Command/RunCommandTest.php @@ -0,0 +1,121 @@ +createTask('Test workload 1'); + $laterTask = $this->createTask('Test workload 2'); + $intervalTask = $this->createTask('Test workload 3', CronExpression::factory('@daily')); + + /** @var TaskExecutionInterface[] $executions */ + $executions = [ + $this->createTaskExecution($singleTask, new \DateTime('-1 hour')), + $this->createTaskExecution($laterTask, new \DateTime('+1 hour')), + $this->createTaskExecution($intervalTask, new \DateTime('-2 hour')), + ]; + + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + ] + ); + + $this->assertEquals(TaskStatus::COMPLETE, $executions[0]->getStatus()); + $this->assertEquals(strrev('Test workload 1'), $executions[0]->getResult()); + $this->assertGreaterThan(0, $executions[0]->getDuration()); + $this->assertGreaterThanOrEqual($executions[0]->getStartTime(), $executions[0]->getEndTime()); + + $this->assertEquals(TaskStatus::PLANNED, $executions[1]->getStatus()); + $this->assertNull($executions[1]->getResult()); + $this->assertNull($executions[1]->getDuration()); + $this->assertNull($executions[1]->getStartTime()); + $this->assertNull($executions[1]->getEndTime()); + + $this->assertEquals(TaskStatus::COMPLETE, $executions[2]->getStatus()); + $this->assertEquals(strrev('Test workload 3'), $executions[2]->getResult()); + $this->assertGreaterThan(0, $executions[2]->getDuration()); + $this->assertGreaterThanOrEqual($executions[2]->getStartTime(), $executions[2]->getEndTime()); + + $result = $this->taskExecutionRepository->findAll(2, 3); + $this->assertCount(1, $result); + + $this->assertEquals($intervalTask, $result[0]->getTask()); + $this->assertEquals(TaskStatus::PLANNED, $result[0]->getStatus()); + $this->assertEquals(TestHandler::class, $result[0]->getHandlerClass()); + $this->assertEquals('Test workload 3', $result[0]->getWorkload()); + } + + public function testExecuteWithFail() + { + $singleTask = $this->createTask('Test workload 1', null, FailTestHandler::class); + $laterTask = $this->createTask('Test workload 2', null, FailTestHandler::class); + $intervalTask = $this->createTask('Test workload 3', CronExpression::factory('@daily'), FailTestHandler::class); + + /** @var TaskExecutionInterface[] $executions */ + $executions = [ + $this->createTaskExecution($singleTask, new \DateTime('-1 hour')), + $this->createTaskExecution($laterTask, new \DateTime('+1 hour')), + $this->createTaskExecution($intervalTask, new \DateTime('-2 hour')), + ]; + + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + ] + ); + + $this->assertEquals(TaskStatus::FAILED, $executions[0]->getStatus()); + $this->assertNull($executions[0]->getResult()); + $this->assertGreaterThan(0, $executions[0]->getDuration()); + $this->assertGreaterThanOrEqual($executions[0]->getStartTime(), $executions[0]->getEndTime()); + + $this->assertEquals(TaskStatus::PLANNED, $executions[1]->getStatus()); + $this->assertNull($executions[1]->getResult()); + $this->assertNull($executions[1]->getDuration()); + $this->assertNull($executions[1]->getStartTime()); + $this->assertNull($executions[1]->getEndTime()); + + $this->assertEquals(TaskStatus::FAILED, $executions[2]->getStatus()); + $this->assertNull($executions[2]->getResult()); + $this->assertGreaterThan(0, $executions[2]->getDuration()); + $this->assertGreaterThanOrEqual($executions[2]->getStartTime(), $executions[2]->getEndTime()); + + $result = $this->taskExecutionRepository->findAll(2, 3); + $this->assertCount(1, $result); + + $this->assertEquals($intervalTask, $result[0]->getTask()); + $this->assertEquals(TaskStatus::PLANNED, $result[0]->getStatus()); + $this->assertEquals(FailTestHandler::class, $result[0]->getHandlerClass()); + $this->assertEquals('Test workload 3', $result[0]->getWorkload()); + } + + /** + * {@inheritdoc} + */ + protected function getCommand() + { + return self::$kernel->getContainer()->get('task.command.run'); + } +} diff --git a/tests/Functional/Command/RunHandlerCommandTest.php b/tests/Functional/Command/RunHandlerCommandTest.php new file mode 100644 index 0000000..ddc9f7b --- /dev/null +++ b/tests/Functional/Command/RunHandlerCommandTest.php @@ -0,0 +1,77 @@ +commandTester->execute( + [ + 'command' => $this->command->getName(), + 'handlerClass' => TestHandler::class, + ], + [ + 'verbosity' => OutputInterface::VERBOSITY_VERBOSE, + ] + ); + + $output = $this->commandTester->getDisplay(); + $this->assertContains('No workload.', $output); + } + + public function testExecuteWithWorkload() + { + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + 'handlerClass' => TestHandler::class, + 'workload' => 'Test workload 1', + ], + [ + 'verbosity' => OutputInterface::VERBOSITY_VERBOSE, + ] + ); + + $output = $this->commandTester->getDisplay(); + $this->assertContains(strrev('Test workload 1'), $output); + } + + public function testExecuteWithWorkloadNoVerbosity() + { + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + 'handlerClass' => TestHandler::class, + 'workload' => 'Test workload 1', + ] + ); + + $output = $this->commandTester->getDisplay(); + $this->assertEquals('', $output); + } + + /** + * {@inheritdoc} + */ + protected function getCommand() + { + return self::$kernel->getContainer()->get('task.command.run_handler'); + } +} diff --git a/tests/Functional/Command/ScheduleTaskCommandTest.php b/tests/Functional/Command/ScheduleTaskCommandTest.php new file mode 100644 index 0000000..b7df0ea --- /dev/null +++ b/tests/Functional/Command/ScheduleTaskCommandTest.php @@ -0,0 +1,132 @@ +commandTester->execute( + [ + 'command' => $this->command->getName(), + 'handlerClass' => TestHandler::class, + ] + ); + + $tasks = $this->taskRepository->findAll(); + $this->assertCount(1, $tasks); + + $this->assertEquals(TestHandler::class, $tasks[0]->getHandlerClass()); + + $executions = $this->taskExecutionRepository->findAll(); + $this->assertCount(1, $executions); + + $this->assertEquals(TestHandler::class, $executions[0]->getHandlerClass()); + } + + public function testExecuteWithWorkload() + { + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + 'handlerClass' => TestHandler::class, + 'workload' => 'Test workload 1', + ] + ); + + $tasks = $this->taskRepository->findAll(); + $this->assertCount(1, $tasks); + + $this->assertEquals(TestHandler::class, $tasks[0]->getHandlerClass()); + $this->assertEquals('Test workload 1', $tasks[0]->getWorkload()); + } + + public function testExecuteWithWorkloadAndInterval() + { + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + 'handlerClass' => TestHandler::class, + 'workload' => 'Test workload 1', + '--cron-expression' => '0 * * * *', + ] + ); + + $tasks = $this->taskRepository->findAll(); + $this->assertCount(1, $tasks); + + $this->assertEquals(TestHandler::class, $tasks[0]->getHandlerClass()); + $this->assertEquals('Test workload 1', $tasks[0]->getWorkload()); + $this->assertEquals('0 * * * *', $tasks[0]->getInterval()); + } + + public function testExecuteWithWorkloadAndIntervalAndEndDate() + { + $date = new \DateTime('+1 day'); + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + 'handlerClass' => TestHandler::class, + 'workload' => 'Test workload 1', + '--cron-expression' => '0 * * * *', + '--end-date' => $date->format(\DateTime::RFC3339), + ] + ); + + $tasks = $this->taskRepository->findAll(); + $this->assertCount(1, $tasks); + + $this->assertEquals(TestHandler::class, $tasks[0]->getHandlerClass()); + $this->assertEquals('Test workload 1', $tasks[0]->getWorkload()); + $this->assertEquals('0 * * * *', $tasks[0]->getInterval()); + $this->assertEquals($date, $tasks[0]->getLastExecution()); + } + + public function testExecuteWithExecutionDate() + { + $date = new \DateTime('+1 day'); + $this->commandTester->execute( + [ + 'command' => $this->command->getName(), + 'handlerClass' => TestHandler::class, + 'workload' => 'Test workload 1', + '--execution-date' => '+1 day', + ] + ); + + $tasks = $this->taskRepository->findAll(); + $this->assertCount(1, $tasks); + + $this->assertEquals(TestHandler::class, $tasks[0]->getHandlerClass()); + $this->assertEquals($date, $tasks[0]->getFirstExecution()); + + $executions = $this->taskExecutionRepository->findAll(); + $this->assertCount(1, $executions); + + $this->assertEquals(TestHandler::class, $executions[0]->getHandlerClass()); + $this->assertEquals($date, $executions[0]->getScheduleTime()); + } + + /** + * {@inheritdoc} + */ + protected function getCommand() + { + return self::$kernel->getContainer()->get('task.command.schedule_task'); + } +} diff --git a/tests/Functional/FailTestHandler.php b/tests/Functional/FailTestHandler.php new file mode 100644 index 0000000..05f373f --- /dev/null +++ b/tests/Functional/FailTestHandler.php @@ -0,0 +1,28 @@ +taskHandlerFactory = self::$kernel->getContainer()->get('task.handler.factory'); } - public function testRun() + public function testCreate() { - $this->assertInstanceOf(\TestHandler::class, $this->taskHandlerFactory->create(\TestHandler::class)); + $this->assertInstanceOf(TestHandler::class, $this->taskHandlerFactory->create(TestHandler::class)); + } + + public function testCreateNotExists() + { + $this->setExpectedException(TaskHandlerNotExistsException::class); + + $this->taskHandlerFactory->create(\stdClass::class); } } diff --git a/tests/Functional/TestHandler.php b/tests/Functional/TestHandler.php new file mode 100644 index 0000000..399259e --- /dev/null +++ b/tests/Functional/TestHandler.php @@ -0,0 +1,32 @@ +prophesize(ContainerBuilder::class); + + $container->has(HandlerCompilerPass::REGISTRY_ID)->willReturn(true); + $container->findTaggedServiceIds(HandlerCompilerPass::HANDLER_TAG)->willReturn( + ['service1' => [], 'service2' => []] + ); + $container->getDefinition('service1')->willReturn(new Definition(\stdClass::class)); + $container->getDefinition('service2')->willReturn(new Definition(self::class)); + + $serviceDefinition = $this->prophesize(Definition::class); + $container->findDefinition(HandlerCompilerPass::REGISTRY_ID)->willReturn($serviceDefinition); + + $compilerPass = new HandlerCompilerPass(); + $compilerPass->process($container->reveal()); + + $serviceDefinition->replaceArgument( + 0, + [\stdClass::class => new Reference('service1'), self::class => new Reference('service2')] + )->shouldBeCalled(); + } + + public function testProcessNoTaggedService() + { + $container = $this->prophesize(ContainerBuilder::class); + + $container->has(HandlerCompilerPass::REGISTRY_ID)->willReturn(true); + $container->findTaggedServiceIds(HandlerCompilerPass::HANDLER_TAG)->willReturn([]); + + $serviceDefinition = $this->prophesize(Definition::class); + $container->findDefinition(HandlerCompilerPass::REGISTRY_ID)->willReturn($serviceDefinition); + + $compilerPass = new HandlerCompilerPass(); + $compilerPass->process($container->reveal()); + + $serviceDefinition->replaceArgument(0, [])->shouldBeCalled(); + } +} diff --git a/tests/Unit/EventListener/RunListenerTest.php b/tests/Unit/EventListener/RunListenerTest.php index f3938b4..656e95f 100644 --- a/tests/Unit/EventListener/RunListenerTest.php +++ b/tests/Unit/EventListener/RunListenerTest.php @@ -9,12 +9,15 @@ * with this source code in the file LICENSE. */ -namespace Unit\EventListener; +namespace Task\TaskBundle\Tests\Unit\EventListener; use Symfony\Component\EventDispatcher\Event; use Task\Runner\TaskRunnerInterface; use Task\TaskBundle\EventListener\RunListener; +/** + * Tests for class RunListener. + */ class RunListenerTest extends \PHPUnit_Framework_TestCase { public function testRun() diff --git a/tests/Unit/Handler/TaskHandlerFactoryTest.php b/tests/Unit/Handler/TaskHandlerFactoryTest.php new file mode 100644 index 0000000..c6b2089 --- /dev/null +++ b/tests/Unit/Handler/TaskHandlerFactoryTest.php @@ -0,0 +1,48 @@ + $handler]); + + $this->assertEquals($handler, $taskHandlerFactory->create(TestHandler::class)); + } + + public function testCreateNotExists() + { + $this->setExpectedException(TaskHandlerNotExistsException::class); + + $taskHandlerFactory = new TaskHandlerFactory([TestHandler::class => new TestHandler()]); + + $taskHandlerFactory->create(\stdClass::class); + } + + public function testCreateNoHandler() + { + $this->setExpectedException(TaskHandlerNotExistsException::class); + + $taskHandlerFactory = new TaskHandlerFactory([]); + + $taskHandlerFactory->create(\stdClass::class); + } +} diff --git a/tests/app/TestKernel.php b/tests/app/TestKernel.php index ab35657..2d49551 100644 --- a/tests/app/TestKernel.php +++ b/tests/app/TestKernel.php @@ -84,14 +84,3 @@ protected function initializeContainer() } } } - -class TestHandler implements \Task\Handler\TaskHandlerInterface -{ - /** - * {@inheritdoc} - */ - public function handle($workload) - { - return strrev($workload); - } -} diff --git a/tests/app/config/services.xml b/tests/app/config/services.xml index 63d1716..7af7798 100644 --- a/tests/app/config/services.xml +++ b/tests/app/config/services.xml @@ -3,7 +3,10 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - + + + +