diff --git a/.travis.yml b/.travis.yml
index a9929d7..278c510 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -38,7 +38,7 @@ before_script:
- STORAGE=doctrine tests/app/console doctrine:schema:create
script:
- - phpunit -c phpunit.xml.dist --coverage-clover=coverage.clover
+ - vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover=coverage.clover
after_script:
- if [[ $CODE_COVERAGE == 'true' ]]; then wget https://scrutinizer-ci.com/ocular.phar ; fi
diff --git a/UPGRADE.md b/UPGRADE.md
index f95553c..25a2b82 100644
--- a/UPGRADE.md
+++ b/UPGRADE.md
@@ -1,8 +1,18 @@
UPGRADE
=======
+- [1.1.0](#1.1.0)
- [0.4.0](#0.4.0)
+### 1.1.0
+
+In the database table `ta_tasks` a new field was introduced. Run following
+command to update the table.
+
+```bash
+bin/console doctrine:schema:update
+```
+
### 0.4.0
#### Identifier of tasks and executions
diff --git a/composer.json b/composer.json
index dd1e232..37c18da 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,7 @@
],
"require": {
"php": "~5.5 || ~7.0",
- "php-task/php-task": "^1.0",
+ "php-task/php-task": "dev-develop",
"symfony/http-kernel": "^2.6 || ^3.0",
"symfony/dependency-injection": "^2.6 || ^3.0",
"symfony/config": "^2.6 || ^3.0",
diff --git a/src/Builder/NotSupportedMethodException.php b/src/Builder/NotSupportedMethodException.php
new file mode 100644
index 0000000..12e7201
--- /dev/null
+++ b/src/Builder/NotSupportedMethodException.php
@@ -0,0 +1,64 @@
+property = $property;
+ $this->task = $task;
+ }
+
+ /**
+ * Returns property.
+ *
+ * @return string
+ */
+ public function getProperty()
+ {
+ return $this->property;
+ }
+
+ /**
+ * Returns task.
+ *
+ * @return TaskInterface
+ */
+ public function getTask()
+ {
+ return $this->task;
+ }
+}
diff --git a/src/Builder/TaskBuilder.php b/src/Builder/TaskBuilder.php
new file mode 100644
index 0000000..8b6e3e6
--- /dev/null
+++ b/src/Builder/TaskBuilder.php
@@ -0,0 +1,42 @@
+task instanceof Task) {
+ throw new NotSupportedMethodException('systemKey', $this->task);
+ }
+
+ $this->task->setSystemKey($systemKey);
+
+ return $this;
+ }
+}
diff --git a/src/Builder/TaskBuilderFactory.php b/src/Builder/TaskBuilderFactory.php
new file mode 100644
index 0000000..aed0a26
--- /dev/null
+++ b/src/Builder/TaskBuilderFactory.php
@@ -0,0 +1,30 @@
+systemTasks = $systemTasks;
+ $this->scheduler = $scheduler;
+ $this->taskRepository = $taskRepository;
+ $this->taskExecutionRepository = $taskExecutionRepository;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function configure()
+ {
+ $this->setDescription('Schedule system-tasks')->setHelp(
+ <<<'EOT'
+The %command.name% command schedules configured system tasks.
+
+ $ %command.full_name%
+
+You can configure them by extending the task.system_task array in your config file.
+EOT
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $output->writeln(sprintf('Schedule %s system-tasks:', count($this->systemTasks)));
+ $output->writeln('');
+
+ foreach ($this->systemTasks as $systemKey => $systemTask) {
+ try {
+ $this->processSystemTask($systemKey, $systemTask, $output);
+ } catch (\Exception $exception) {
+ $output->writeln(
+ sprintf(
+ ' * System-task "%s" failed because of: %s',
+ $systemKey,
+ $exception->getMessage()
+ )
+ );
+ }
+ }
+
+ foreach ($this->taskRepository->findSystemTasks() as $task) {
+ if (!in_array($task->getSystemKey(), array_keys($this->systemTasks)) && ($this->disableTask($task))) {
+ $output->writeln(
+ sprintf(' * System-task "%s" was disabled', $task->getSystemKey())
+ );
+ }
+ }
+
+ $output->writeln('');
+ $output->writeln('System-tasks successfully scheduled');
+ }
+
+ /**
+ * Process single system task.
+ *
+ * @param string $systemKey
+ * @param array $systemTask
+ * @param OutputInterface $output
+ */
+ private function processSystemTask($systemKey, array $systemTask, OutputInterface $output)
+ {
+ if (!$systemTask['enabled']) {
+ if ($this->disableSystemTask($systemKey)) {
+ $output->writeln(sprintf(' * System-task "%s" was disabled', $systemKey));
+ }
+
+ return;
+ }
+
+ if ($task = $this->taskRepository->findBySystemKey($systemKey)) {
+ $this->updateTask($systemKey, $systemTask, $task);
+
+ $output->writeln(sprintf(' * System-task "%s" was updated', $systemKey));
+
+ return;
+ }
+
+ /** @var TaskBuilder $builder */
+ $builder = $this->scheduler->createTask($systemTask['handler_class'], $systemTask['workload']);
+ $builder->setSystemKey($systemKey);
+ if ($systemTask['cron_expression']) {
+ $builder->cron($systemTask['cron_expression']);
+ }
+
+ $builder->schedule();
+
+ $output->writeln(sprintf(' * System-task "%s" was created', $systemKey));
+ }
+
+ /**
+ * Disable task identified by system-key.
+ *
+ * @param string $systemKey
+ *
+ * @return bool
+ */
+ private function disableSystemTask($systemKey)
+ {
+ if (!$task = $this->taskRepository->findBySystemKey($systemKey)) {
+ return false;
+ }
+
+ $this->disableTask($task);
+
+ return true;
+ }
+
+ /**
+ * Disable given task identified.
+ *
+ * @param TaskInterface $task
+ *
+ * @return bool
+ */
+ public function disableTask(TaskInterface $task)
+ {
+ $task->setInterval($task->getInterval(), $task->getFirstExecution(), new \DateTime());
+
+ return $this->abortPending($task);
+ }
+
+ /**
+ * Update given task.
+ *
+ * @param string $systemKey
+ * @param array $systemTask
+ * @param TaskInterface $task
+ */
+ private function updateTask($systemKey, array $systemTask, TaskInterface $task)
+ {
+ if ($task->getHandlerClass() !== $systemTask['handler_class']
+ || $task->getWorkload() !== $systemTask['workload']
+ ) {
+ throw new \InvalidArgumentException(
+ sprintf('No update of handle-class or workload is supported for system-task "%s".', $systemKey)
+ );
+ }
+
+ if ($task->getInterval() === $systemTask['cron_expression']) {
+ return;
+ }
+
+ $task->setInterval(CronExpression::factory($systemTask['cron_expression']), $task->getFirstExecution());
+
+ $this->abortPending($task);
+ $this->scheduler->scheduleTasks();
+ }
+
+ /**
+ * Abort pending execution for given task.
+ *
+ * @param TaskInterface $task
+ *
+ * @return bool
+ */
+ private function abortPending(TaskInterface $task)
+ {
+ if (!$execution = $this->taskExecutionRepository->findPending($task)) {
+ return false;
+ }
+
+ $execution->setStatus(TaskStatus::ABORTED);
+ $this->taskExecutionRepository->save($execution);
+
+ return true;
+ }
+}
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index 5997ef2..7e8ba92 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -49,6 +49,16 @@ public function getConfigTreeBuilder()
->end()
->end()
->end()
+ ->arrayNode('system_tasks')
+ ->prototype('array')
+ ->children()
+ ->booleanNode('enabled')->defaultTrue()->end()
+ ->scalarNode('handler_class')->end()
+ ->variableNode('workload')->defaultNull()->end()
+ ->scalarNode('cron_expression')->end()
+ ->end()
+ ->end()
+ ->end()
->end();
return $treeBuilder;
diff --git a/src/DependencyInjection/TaskExtension.php b/src/DependencyInjection/TaskExtension.php
index 9fd77aa..c22ec65 100644
--- a/src/DependencyInjection/TaskExtension.php
+++ b/src/DependencyInjection/TaskExtension.php
@@ -34,6 +34,9 @@ public function load(array $configs, ContainerBuilder $container)
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
+ $container->setParameter('task.system_tasks', $config['system_tasks']);
+ $container->setParameter('task.storage', $config['storage']);
+
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load(sprintf('storage/%s.xml', $config['storage']));
$loader->load('task_event_listener.xml');
diff --git a/src/Entity/Task.php b/src/Entity/Task.php
index 24a1fd7..9dbafa2 100644
--- a/src/Entity/Task.php
+++ b/src/Entity/Task.php
@@ -24,6 +24,11 @@ class Task extends BaseTask
*/
private $intervalExpression;
+ /**
+ * @var string
+ */
+ private $systemKey;
+
/**
* @return mixed
*/
@@ -32,6 +37,9 @@ public function getIntervalExpression()
return $this->intervalExpression;
}
+ /**
+ * {@inheritdoc}
+ */
public function getInterval()
{
if (null === $this->interval && null !== $this->intervalExpression) {
@@ -50,4 +58,28 @@ public function setInterval(CronExpression $interval, \DateTime $firstExecution
$this->intervalExpression = $interval->getExpression();
}
+
+ /**
+ * Returns system-key.
+ *
+ * @return string
+ */
+ public function getSystemKey()
+ {
+ return $this->systemKey;
+ }
+
+ /**
+ * Set system-key.
+ *
+ * @param string $systemKey
+ *
+ * @return $this
+ */
+ public function setSystemKey($systemKey)
+ {
+ $this->systemKey = $systemKey;
+
+ return $this;
+ }
}
diff --git a/src/Entity/TaskRepository.php b/src/Entity/TaskRepository.php
index 9970a0d..026762b 100644
--- a/src/Entity/TaskRepository.php
+++ b/src/Entity/TaskRepository.php
@@ -12,6 +12,7 @@
namespace Task\TaskBundle\Entity;
use Doctrine\ORM\EntityRepository;
+use Doctrine\ORM\NoResultException;
use Task\Storage\TaskRepositoryInterface;
use Task\TaskInterface;
@@ -97,4 +98,37 @@ public function findEndBefore(\DateTime $dateTime)
->getQuery()
->getResult();
}
+
+ /**
+ * Returns task identified by system-key.
+ *
+ * @param string $systemKey
+ *
+ * @return TaskInterface
+ */
+ public function findBySystemKey($systemKey)
+ {
+ try {
+ return $this->createQueryBuilder('t')
+ ->where('t.systemKey = :systemKey')
+ ->setParameter('systemKey', $systemKey)
+ ->getQuery()
+ ->getSingleResult();
+ } catch (NoResultException $exception) {
+ return;
+ }
+ }
+
+ /**
+ * Returns all system-task.
+ *
+ * @return TaskInterface[]
+ */
+ public function findSystemTasks()
+ {
+ return $this->createQueryBuilder('t')
+ ->where('t.systemKey IS NOT NULL')
+ ->getQuery()
+ ->getResult();
+ }
}
diff --git a/src/Resources/config/doctrine/Task.orm.xml b/src/Resources/config/doctrine/Task.orm.xml
index b3e06f5..2c6ddca 100644
--- a/src/Resources/config/doctrine/Task.orm.xml
+++ b/src/Resources/config/doctrine/Task.orm.xml
@@ -17,6 +17,7 @@
+
diff --git a/src/Resources/config/scheduler.xml b/src/Resources/config/scheduler.xml
index 9ccad0f..983dd6a 100644
--- a/src/Resources/config/scheduler.xml
+++ b/src/Resources/config/scheduler.xml
@@ -3,7 +3,7 @@
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 fb22e29..731a509 100644
--- a/src/Resources/config/storage/doctrine.xml
+++ b/src/Resources/config/storage/doctrine.xml
@@ -16,5 +16,15 @@
TaskBundle:TaskExecution
+
+
+ task:schedule:system-tasks
+ %task.system_tasks%
+
+
+
+
+
+
diff --git a/tests/Functional/BaseDatabaseTestCase.php b/tests/Functional/BaseDatabaseTestCase.php
index 7fefd31..92cffd3 100644
--- a/tests/Functional/BaseDatabaseTestCase.php
+++ b/tests/Functional/BaseDatabaseTestCase.php
@@ -7,6 +7,10 @@
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
+use Task\TaskBundle\Entity\Task;
+use Task\TaskBundle\Entity\TaskExecution;
+use Task\TaskInterface;
+use Task\TaskStatus;
/**
* Extends kernel-test-case with additional functions/properties.
@@ -52,4 +56,33 @@ protected function purgeDatabase()
$connection->executeUpdate('SET foreign_key_checks = 1;');
}
}
+
+ /**
+ * Create a new task.
+ *
+ * @param string $handlerClass
+ *
+ * @return Task
+ */
+ protected function createTask($handlerClass = TestHandler::class)
+ {
+ return new Task($handlerClass);
+ }
+
+ /**
+ * Create a new task-execution.
+ *
+ * @param TaskInterface $task
+ * @param \DateTime $scheduleTime
+ * @param string $status
+ *
+ * @return TaskExecution
+ */
+ protected function createTaskExecution(TaskInterface $task, \DateTime $scheduleTime, $status = TaskStatus::PLANNED)
+ {
+ $execution = new TaskExecution($task, $task->getHandlerClass(), $scheduleTime);
+ $execution->setStatus($status);
+
+ return $execution;
+ }
}
diff --git a/tests/Functional/Command/RunHandlerCommandTest.php b/tests/Functional/Command/RunHandlerCommandTest.php
index ddc9f7b..d3a5dee 100644
--- a/tests/Functional/Command/RunHandlerCommandTest.php
+++ b/tests/Functional/Command/RunHandlerCommandTest.php
@@ -9,7 +9,7 @@
* with this source code in the file LICENSE.
*/
-namespace Functional\Command;
+namespace Task\TaskBundle\Functional\Command;
use Symfony\Component\Console\Output\OutputInterface;
use Task\TaskBundle\Tests\Functional\BaseCommandTestCase;
diff --git a/tests/Functional/Command/ScheduleSystemTasksCommandTest.php b/tests/Functional/Command/ScheduleSystemTasksCommandTest.php
new file mode 100644
index 0000000..3c935a0
--- /dev/null
+++ b/tests/Functional/Command/ScheduleSystemTasksCommandTest.php
@@ -0,0 +1,44 @@
+getContainer()->getParameter('kernel.storage') !== 'doctrine') {
+ return $this->markTestSkipped('This testcase will only be called for doctrine storage.');
+ }
+
+ parent::setUp();
+ }
+
+ public function testExecute()
+ {
+ $this->commandTester->execute(
+ [
+ 'command' => $this->command->getName(),
+ ]
+ );
+
+ $output = $this->commandTester->getDisplay();
+ $this->assertContains('System-tasks successfully scheduled', $output);
+
+ $taskRepository = self::$kernel->getContainer()->get('task.repository.task');
+ $this->assertNotNull($taskRepository->findBySystemKey('testing'));
+ }
+
+ /**
+ * Returns command.
+ *
+ * @return Command
+ */
+ protected function getCommand()
+ {
+ return self::$kernel->getContainer()->get('task.command.schedule_system_tasks');
+ }
+}
diff --git a/tests/Functional/Command/ScheduleTaskCommandTest.php b/tests/Functional/Command/ScheduleTaskCommandTest.php
index b88696a..85d1451 100644
--- a/tests/Functional/Command/ScheduleTaskCommandTest.php
+++ b/tests/Functional/Command/ScheduleTaskCommandTest.php
@@ -9,7 +9,7 @@
* with this source code in the file LICENSE.
*/
-namespace Functional\Command;
+namespace Task\TaskBundle\Functional\Command;
use Task\TaskBundle\Tests\Functional\BaseCommandTestCase;
use Task\TaskBundle\Tests\Functional\TestHandler;
diff --git a/tests/Functional/Entity/TaskExecutionRepositoryTest.php b/tests/Functional/Entity/TaskExecutionRepositoryTest.php
index 5a11391..f5cb54e 100644
--- a/tests/Functional/Entity/TaskExecutionRepositoryTest.php
+++ b/tests/Functional/Entity/TaskExecutionRepositoryTest.php
@@ -6,9 +6,7 @@
use Task\Storage\TaskExecutionRepositoryInterface;
use Task\Storage\TaskRepositoryInterface;
use Task\TaskBundle\Entity\Task;
-use Task\TaskBundle\Entity\TaskExecution;
use Task\TaskBundle\Tests\Functional\BaseDatabaseTestCase;
-use Task\TaskBundle\Tests\Functional\TestHandler;
use Task\TaskInterface;
use Task\TaskStatus;
@@ -197,33 +195,4 @@ private function save(TaskInterface $task = null, \DateTime $scheduleTime = null
return $execution;
}
-
- /**
- * Create a new task.
- *
- * @param string $handlerClass
- *
- * @return TaskInterface
- */
- private function createTask($handlerClass = TestHandler::class)
- {
- return new Task($handlerClass);
- }
-
- /**
- * Create a new task-execution.
- *
- * @param TaskInterface $task
- * @param \DateTime $scheduleTime
- * @param string $status
- *
- * @return TaskExecutionInterface
- */
- private function createTaskExecution(TaskInterface $task, \DateTime $scheduleTime, $status = TaskStatus::PLANNED)
- {
- $execution = new TaskExecution($task, $task->getHandlerClass(), $scheduleTime);
- $execution->setStatus($status);
-
- return $execution;
- }
}
diff --git a/tests/Functional/Entity/TaskRepositoryTest.php b/tests/Functional/Entity/TaskRepositoryTest.php
new file mode 100644
index 0000000..760e02f
--- /dev/null
+++ b/tests/Functional/Entity/TaskRepositoryTest.php
@@ -0,0 +1,66 @@
+taskRepository = self::$kernel->getContainer()->get('task.storage.task');
+ }
+
+ public function testFindBySystemKey()
+ {
+ if (self::$kernel->getContainer()->getParameter('kernel.storage') !== 'doctrine') {
+ return $this->markTestSkipped('This testcase will only be called for doctrine storage.');
+ }
+
+ $task = $this->createTask();
+ $task->setSystemKey('test');
+
+ $this->taskRepository->save($task);
+
+ $result = $this->taskRepository->findBySystemKey('test');
+ $this->assertEquals($task->getUuid(), $result->getUuid());
+ }
+
+ public function testFindBySystemKeyNotFound()
+ {
+ if (self::$kernel->getContainer()->getParameter('kernel.storage') !== 'doctrine') {
+ return $this->markTestSkipped('This testcase will only be called for doctrine storage.');
+ }
+
+ $task = $this->createTask();
+ $this->taskRepository->save($task);
+
+ $this->assertNull($this->taskRepository->findBySystemKey('test'));
+ }
+
+ public function testFindSystemTasks()
+ {
+ if (self::$kernel->getContainer()->getParameter('kernel.storage') !== 'doctrine') {
+ return $this->markTestSkipped('This testcase will only be called for doctrine storage.');
+ }
+
+ $task1 = $this->createTask();
+ $task1->setSystemKey('test');
+ $this->taskRepository->save($task1);
+
+ $task2 = $this->createTask();
+ $this->taskRepository->save($task2);
+
+ $result = $this->taskRepository->findSystemTasks();
+ $this->assertCount(1, $result);
+ $this->assertEquals($task1->getUuid(), $result[0]->getUuid());
+ }
+}
diff --git a/tests/Unit/Builder/TaskBuilderFactoryTest.php b/tests/Unit/Builder/TaskBuilderFactoryTest.php
new file mode 100644
index 0000000..edb6f9d
--- /dev/null
+++ b/tests/Unit/Builder/TaskBuilderFactoryTest.php
@@ -0,0 +1,24 @@
+prophesize(TaskInterface::class);
+ $scheduler = $this->prophesize(TaskSchedulerInterface::class);
+
+ $taskBuilderFactory = new TaskBuilderFactory();
+
+ $this->assertInstanceOf(
+ TaskBuilder::class,
+ $taskBuilderFactory->createTaskBuilder($task->reveal(), $scheduler->reveal())
+ );
+ }
+}
diff --git a/tests/Unit/Builder/TaskBuilderTest.php b/tests/Unit/Builder/TaskBuilderTest.php
new file mode 100644
index 0000000..24a7b23
--- /dev/null
+++ b/tests/Unit/Builder/TaskBuilderTest.php
@@ -0,0 +1,34 @@
+prophesize(Task::class);
+ $scheduler = $this->prophesize(TaskSchedulerInterface::class);
+
+ $taskBuilder = new TaskBuilder($task->reveal(), $scheduler->reveal());
+ $taskBuilder->setSystemKey('test');
+
+ $task->setSystemKey('test')->shouldBeCalled();
+ }
+
+ public function testSetSystemKeyNotSupported()
+ {
+ $this->setExpectedException(NotSupportedMethodException::class);
+
+ $task = $this->prophesize(TaskInterface::class);
+ $scheduler = $this->prophesize(TaskSchedulerInterface::class);
+
+ $taskBuilder = new TaskBuilder($task->reveal(), $scheduler->reveal());
+ $taskBuilder->setSystemKey('test');
+ }
+}
diff --git a/tests/Unit/Command/ScheduleSystemTasksCommandTest.php b/tests/Unit/Command/ScheduleSystemTasksCommandTest.php
new file mode 100644
index 0000000..23e2e93
--- /dev/null
+++ b/tests/Unit/Command/ScheduleSystemTasksCommandTest.php
@@ -0,0 +1,293 @@
+scheduler = $this->prophesize(TaskSchedulerInterface::class);
+ $this->taskRepository = $this->prophesize(TaskRepository::class);
+ $this->taskExecutionRepository = $this->prophesize(TaskExecutionRepositoryInterface::class);
+ }
+
+ /**
+ * @param array $systemTasks
+ *
+ * @return ScheduleSystemTasksCommand
+ */
+ protected function createCommand(array $systemTasks)
+ {
+ return new ScheduleSystemTasksCommand(
+ 'task:schedule:system-tasks',
+ $systemTasks,
+ $this->scheduler->reveal(),
+ $this->taskRepository->reveal(),
+ $this->taskExecutionRepository->reveal()
+ );
+ }
+
+ public function testExecute()
+ {
+ $command = $this->createCommand(
+ [
+ 'testing' => [
+ 'enabled' => true,
+ 'handler_class' => TestHandler::class,
+ 'workload' => 'test',
+ 'cron_expression' => '* * * * *',
+ ],
+ ]
+ );
+
+ $task = $this->prophesize(Task::class);
+ $task->getSystemKey()->willReturn('testing');
+
+ $taskBuilder = $this->prophesize(TaskBuilder::class);
+
+ $this->taskRepository->findBySystemKey('testing')->willReturn(null);
+ $this->taskRepository->findSystemTasks()->willReturn([$task->reveal()]);
+
+ $this->scheduler->createTask(TestHandler::class, 'test')->shouldBeCalled()->willReturn($taskBuilder->reveal());
+
+ $taskBuilder->setSystemKey('testing')->shouldBeCalled();
+ $taskBuilder->cron('* * * * *')->shouldBeCalled();
+ $taskBuilder->schedule()->shouldBeCalled();
+
+ $command->run(
+ $this->prophesize(InputInterface::class)->reveal(),
+ $this->prophesize(OutputInterface::class)->reveal()
+ );
+ }
+
+ public function testExecuteMultiple()
+ {
+ $command = $this->createCommand(
+ [
+ 'testing-1' => [
+ 'enabled' => true,
+ 'handler_class' => TestHandler::class,
+ 'workload' => 'test-1',
+ 'cron_expression' => '* * * * *',
+ ],
+ 'testing-2' => [
+ 'enabled' => true,
+ 'handler_class' => TestHandler::class,
+ 'workload' => 'test-2',
+ 'cron_expression' => '* * * * *',
+ ],
+ ]
+ );
+
+ $task1 = $this->prophesize(Task::class);
+ $task1->getSystemKey()->willReturn('testing-1');
+ $task2 = $this->prophesize(Task::class);
+ $task2->getSystemKey()->willReturn('testing-2');
+
+ $this->taskRepository->findBySystemKey('testing-1')->willReturn(null);
+ $this->taskRepository->findBySystemKey('testing-2')->willReturn(null);
+ $this->taskRepository->findSystemTasks()->willReturn([$task1->reveal(), $task2->reveal()]);
+
+ $taskBuilder1 = $this->prophesize(TaskBuilder::class);
+ $this->scheduler->createTask(TestHandler::class, 'test-1')->shouldBeCalled()->willReturn(
+ $taskBuilder1->reveal()
+ );
+ $taskBuilder1->setSystemKey('testing-1')->shouldBeCalled();
+ $taskBuilder1->cron('* * * * *')->shouldBeCalled();
+ $taskBuilder1->schedule()->shouldBeCalled();
+
+ $taskBuilder2 = $this->prophesize(TaskBuilder::class);
+ $this->scheduler->createTask(TestHandler::class, 'test-2')->shouldBeCalled()->willReturn(
+ $taskBuilder2->reveal()
+ );
+ $taskBuilder2->setSystemKey('testing-2')->shouldBeCalled();
+ $taskBuilder2->cron('* * * * *')->shouldBeCalled();
+ $taskBuilder2->schedule()->shouldBeCalled();
+
+ $command->run(
+ $this->prophesize(InputInterface::class)->reveal(),
+ $this->prophesize(OutputInterface::class)->reveal()
+ );
+ }
+
+ public function testExecuteDisable()
+ {
+ $command = $this->createCommand(
+ [
+ 'testing' => [
+ 'enabled' => false,
+ 'handler_class' => TestHandler::class,
+ 'workload' => 'test',
+ 'cron_expression' => '* * * * *',
+ ],
+ ]
+ );
+
+ $task = $this->prophesize(Task::class);
+ $task->getInterval()->willReturn(CronExpression::factory('* * * * *'));
+ $task->getFirstExecution()->willReturn(new \DateTime());
+ $task->getSystemKey()->willReturn('testing');
+
+ $task->setInterval(
+ $task->reveal()->getInterval(),
+ $task->reveal()->getFirstExecution(),
+ Argument::that(
+ function ($date) {
+ return $date <= new \DateTime('+1 Minute');
+ }
+ )
+ )->shouldBeCalled();
+
+ $this->taskRepository->findBySystemKey('testing')->willReturn($task->reveal());
+ $this->taskRepository->findSystemTasks()->willReturn([$task->reveal()]);
+
+ $execution = $this->prophesize(TaskExecutionInterface::class);
+ $execution->setStatus(TaskStatus::ABORTED);
+
+ $this->taskExecutionRepository->findPending($task->reveal())->willReturn($execution->reveal());
+ $this->taskExecutionRepository->save($execution->reveal())->shouldBeCalled();
+
+ $command->run(
+ $this->prophesize(InputInterface::class)->reveal(),
+ $this->prophesize(OutputInterface::class)->reveal()
+ );
+ }
+
+ public function testExecuteUpdate()
+ {
+ $command = $this->createCommand(
+ [
+ 'testing' => [
+ 'enabled' => true,
+ 'handler_class' => TestHandler::class,
+ 'workload' => 'test',
+ 'cron_expression' => '* * * * *',
+ ],
+ ]
+ );
+
+ $task = $this->prophesize(Task::class);
+ $task->getSystemKey()->willReturn('testing');
+ $task->getHandlerClass()->willReturn(TestHandler::class);
+ $task->getWorkload()->willReturn('test');
+ $task->getInterval()->willReturn(CronExpression::factory('@daily'));
+ $task->getFirstExecution()->willReturn(new \DateTime());
+
+ $task->setInterval(CronExpression::factory('* * * * *'), $task->reveal()->getFirstExecution())->shouldBeCalled(
+ );
+
+ $this->taskRepository->findBySystemKey('testing')->willReturn($task->reveal());
+ $this->taskRepository->findSystemTasks()->willReturn([$task->reveal()]);
+
+ $execution = $this->prophesize(TaskExecutionInterface::class);
+ $execution->setStatus(TaskStatus::ABORTED);
+
+ $this->taskExecutionRepository->findPending($task->reveal())->willReturn($execution->reveal());
+ $this->taskExecutionRepository->save($execution->reveal())->shouldBeCalled();
+
+ $this->scheduler->scheduleTasks()->shouldBeCalled();
+
+ $command->run(
+ $this->prophesize(InputInterface::class)->reveal(),
+ $this->prophesize(OutputInterface::class)->reveal()
+ );
+ }
+
+ public function testExecuteUpdateNotSupported()
+ {
+ $command = $this->createCommand(
+ [
+ 'testing' => [
+ 'enabled' => true,
+ 'handler_class' => TestHandler::class,
+ 'workload' => 'test',
+ 'cron_expression' => '* * * * *',
+ ],
+ ]
+ );
+
+ $task = $this->prophesize(Task::class);
+ $task->getSystemKey()->willReturn('testing');
+ $task->getHandlerClass()->willReturn('not-existing');
+ $task->getWorkload()->willReturn('new-workload');
+ $task->getInterval()->willReturn(CronExpression::factory('@daily'));
+ $task->getFirstExecution()->willReturn(new \DateTime());
+
+ $task->setInterval(Argument::cetera())->shouldNotBeCalled();
+
+ $this->taskRepository->findBySystemKey('testing')->willReturn($task->reveal());
+ $this->taskRepository->findSystemTasks()->willReturn([$task->reveal()]);
+
+ $this->taskExecutionRepository->save(Argument::cetera())->shouldNotBeCalled();
+
+ $this->scheduler->scheduleTasks()->shouldNotBeCalled();
+
+ $command->run(
+ $this->prophesize(InputInterface::class)->reveal(),
+ $this->prophesize(OutputInterface::class)->reveal()
+ );
+ }
+
+ public function testExecuteRemove()
+ {
+ $command = $this->createCommand([]);
+
+ $task = $this->prophesize(Task::class);
+ $task->getInterval()->willReturn(CronExpression::factory('* * * * *'));
+ $task->getFirstExecution()->willReturn(new \DateTime());
+ $task->getSystemKey()->willReturn('testing');
+
+ $task->setInterval(
+ $task->reveal()->getInterval(),
+ $task->reveal()->getFirstExecution(),
+ Argument::that(
+ function ($date) {
+ return $date <= new \DateTime('+1 Minute');
+ }
+ )
+ )->shouldBeCalled();
+
+ $this->taskRepository->findBySystemKey('testing')->willReturn($task->reveal());
+ $this->taskRepository->findSystemTasks()->willReturn([$task->reveal()]);
+
+ $execution = $this->prophesize(TaskExecutionInterface::class);
+ $execution->setStatus(TaskStatus::ABORTED);
+
+ $this->taskExecutionRepository->findPending($task->reveal())->willReturn($execution->reveal());
+ $this->taskExecutionRepository->save($execution->reveal())->shouldBeCalled();
+
+ $command->run(
+ $this->prophesize(InputInterface::class)->reveal(),
+ $this->prophesize(OutputInterface::class)->reveal()
+ );
+ }
+}
diff --git a/tests/Unit/DependencyInjection/HandlerCompilerPassTest.php b/tests/Unit/DependencyInjection/HandlerCompilerPassTest.php
index fdbf2a4..62bac6b 100644
--- a/tests/Unit/DependencyInjection/HandlerCompilerPassTest.php
+++ b/tests/Unit/DependencyInjection/HandlerCompilerPassTest.php
@@ -9,7 +9,7 @@
* with this source code in the file LICENSE.
*/
-namespace Unit\DependencyInjection;
+namespace Task\TaskBundle\Unit\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
diff --git a/tests/app/config/config.doctrine.yml b/tests/app/config/config.doctrine.yml
index 288a06c..bf2bcab 100644
--- a/tests/app/config/config.doctrine.yml
+++ b/tests/app/config/config.doctrine.yml
@@ -1,5 +1,11 @@
task:
storage: doctrine
+ system_tasks:
+ testing:
+ enabled: true
+ handler_class: Task\TaskBundle\Tests\Functional\TestHandler
+ workload: ['test']
+ cron_expression: '* * * * *'
doctrine:
orm: