diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5a98fda --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: +- package-ecosystem: composer + directory: "/" + schedule: + interval: daily + time: "04:00" + open-pull-requests-limit: 10 diff --git a/README.md b/README.md index 2611063..4fae1e3 100644 --- a/README.md +++ b/README.md @@ -17,22 +17,26 @@ It requires **PHP >= 7.1.0** and **Nette Framework >= 2.4.0**. It is very simple to use it because configuration is only in method annotations. Example class with tasks follows. ```php -class CronTasks { +class CronTasks +{ /** * @cronner-task E-mail sending * @cronner-period 1 day * @cronner-days working days * @cronner-time 23:30 - 05:00 */ - public function sendEmails() { + public function sendEmails(): void + { // Code which sends all your e-mails } + /** * @cronner-task Important data replication * @cronner-period 3 hours */ - public function replicateImportantData() { + public function replicateImportantData(): void + { // Replication code } } @@ -51,7 +55,7 @@ However you can specify service manually if it is not autowireable. ```neon cronner: - timestampStorage: @myCoolTimestampStorage + timestampStorage: myCoolTimestampStorage ``` Or you can change the directory for default storage. @@ -72,14 +76,17 @@ automatically. However you can still add new task objects by your own using `add Then you can use it very easily in `Presenter` ```php -class CronPresenter extends \Nette\Application\UI\Presenter { +class CronPresenter extends \Nette\Application\UI\Presenter +{ /** * @var \stekycz\Cronner\Cronner * @inject */ public $cronner; - public function actionCron() { + + public function actionCron(): void + { $this->cronner->run(); } } diff --git a/composer.json b/composer.json index 1408982..2b51da7 100644 --- a/composer.json +++ b/composer.json @@ -23,19 +23,19 @@ }, "require": { "php": ">=7.1.0", - "tracy/tracy": "^2.4", - "nette/di": "^2.4", - "nette/bootstrap": "^2.4", - "nette/utils": "^2.4", + "tracy/tracy": "^2.6", + "nette/di": "^3.0", + "nette/bootstrap": "^3.0", + "nette/utils": "^3.0", "nette/reflection": "^2.4", - "nette/safe-stream": "^2.3", + "nette/safe-stream": "^2.4", "bileto/critical-section": "^2.1" }, "require-dev": { "nette/tester": "^1.7", - "jakub-onderka/php-parallel-lint": "^0.9", + "jakub-onderka/php-parallel-lint": "^1.0", "mockery/mockery": "^0.9", - "phpstan/phpstan": "^0.8" + "phpstan/phpstan": "^1.2" }, "suggest": { }, diff --git a/src/Cronner/Bar/Tasks.php b/src/Cronner/Bar/Tasks.php index c59fbd2..2c91030 100644 --- a/src/Cronner/Bar/Tasks.php +++ b/src/Cronner/Bar/Tasks.php @@ -4,24 +4,24 @@ namespace stekycz\Cronner\Bar; + use stekycz\Cronner\Cronner; use Tracy\IBarPanel; -class Tasks implements IBarPanel +final class Tasks implements IBarPanel { - use \Nette\SmartObject; - /** - * @var Cronner - */ - protected $cronner; + /** @var Cronner */ + private $cronner; + public function __construct(Cronner $cronner) { $this->cronner = $cronner; } - public function getPanel() : string + + public function getPanel(): string { $tasks = []; foreach ($this->cronner->getTasks() as $task) { @@ -37,7 +37,8 @@ public function getPanel() : string return ob_get_clean(); } - public function getTab() : string + + public function getTab(): string { ob_start(); $count = $this->cronner->countTasks(); @@ -45,5 +46,4 @@ public function getTab() : string return ob_get_clean(); } - } diff --git a/src/Cronner/Bar/templates/panel.phtml b/src/Cronner/Bar/templates/panel.phtml index 27c34fb..2a099b6 100644 --- a/src/Cronner/Bar/templates/panel.phtml +++ b/src/Cronner/Bar/templates/panel.phtml @@ -1,13 +1,18 @@

Cronner

+ No tasks defined.
'; + } + ?> $task): ?> @@ -31,4 +36,4 @@
- \ No newline at end of file + diff --git a/src/Cronner/Cronner.php b/src/Cronner/Cronner.php index b0fa8d2..dff0836 100644 --- a/src/Cronner/Cronner.php +++ b/src/Cronner/Cronner.php @@ -4,13 +4,15 @@ namespace stekycz\Cronner; + +use Bileto\CriticalSection\ICriticalSection; +use DateTime; +use DateTimeInterface; use Exception; use Nette\Reflection\ClassType; -use DateTimeInterface; -use DateTime; +use Nette\SmartObject; use Nette\Utils\Strings; use ReflectionMethod; -use Bileto\CriticalSection\ICriticalSection; use stekycz\Cronner\Exceptions\DuplicateTaskNameException; use stekycz\Cronner\Exceptions\InvalidArgumentException; use stekycz\Cronner\Exceptions\RuntimeException; @@ -25,65 +27,40 @@ */ class Cronner { - use \Nette\SmartObject; - - /** - * @var callable[] - */ - public $onTaskBegin = array(); + use SmartObject; - /** - * @var callable[] - */ - public $onTaskFinished = array(); + /** @var callable[] */ + public $onTaskBegin = []; - /** - * @var callable[] - */ - public $onTaskError = array(); + /** @var callable[] */ + public $onTaskFinished = []; - /** - * @var Task[] - */ - private $tasks = array(); + /** @var callable[] */ + public $onTaskError = []; - /** - * @var string[] - */ - private $registeredTaskObjects = array(); + /** @var Task[] */ + private $tasks = []; - /** - * @var ITimestampStorage - */ + /** @var string[] */ + private $registeredTaskObjects = []; + + /** @var ITimestampStorage */ private $timestampStorage; - /** - * @var ICriticalSection - */ + /** @var ICriticalSection */ private $criticalSection; - /** - * @var int Max execution time of PHP script in seconds - */ + /** @var int Max execution time of PHP script in seconds */ private $maxExecutionTime; - /** - * @var bool - */ - private $skipFailedTask = TRUE; + /** @var bool */ + private $skipFailedTask = true; + /** - * @param ITimestampStorage $timestampStorage - * @param ICriticalSection $criticalSection * @param int|null $maxExecutionTime It is used only when Cronner runs - * @param bool $skipFailedTask */ - public function __construct( - ITimestampStorage $timestampStorage, - ICriticalSection $criticalSection, - int $maxExecutionTime = NULL, - bool $skipFailedTask = TRUE - ) + public function __construct(ITimestampStorage $timestampStorage, ICriticalSection $criticalSection, int $maxExecutionTime = null, bool $skipFailedTask = true) { $this->setTimestampStorage($timestampStorage); $this->criticalSection = $criticalSection; @@ -94,58 +71,60 @@ public function __construct( }; } + /** * @return Task[] */ - public function getTasks() : array + public function getTasks(): array { return $this->tasks; } - public function setTimestampStorage(ITimestampStorage $timestampStorage) : self + + public function setTimestampStorage(ITimestampStorage $timestampStorage): self { $this->timestampStorage = $timestampStorage; return $this; } + /** - * Sets max execution time for Cronner. It is used only when Cronner runs. - * - * @param int|null $maxExecutionTime - * @return Cronner - * @throws InvalidArgumentException + * Sets flag that thrown exceptions will not be thrown but cached and logged. */ - public function setMaxExecutionTime(int $maxExecutionTime = NULL) : self + public function setSkipFailedTask(bool $skipFailedTask = true): self { - if ($maxExecutionTime !== NULL && $maxExecutionTime <= 0) { - throw new InvalidArgumentException("Max execution time must be NULL or non negative number."); - } - $this->maxExecutionTime = $maxExecutionTime; + $this->skipFailedTask = $skipFailedTask; return $this; } + /** - * Sets flag that thrown exceptions will not be thrown but cached and logged. + * Returns max execution time for Cronner. It does not load INI value. */ - public function setSkipFailedTask(bool $skipFailedTask = TRUE) : self + public function getMaxExecutionTime(): ?int { - $this->skipFailedTask = $skipFailedTask; - - return $this; + return !is_null($this->maxExecutionTime) ? $this->maxExecutionTime : null; } + /** - * Returns max execution time for Cronner. It does not load INI value. + * Sets max execution time for Cronner. It is used only when Cronner runs. * - * @return int|null + * @throws InvalidArgumentException */ - public function getMaxExecutionTime() + public function setMaxExecutionTime(?int $maxExecutionTime = null): self { - return !is_null($this->maxExecutionTime) ? $this->maxExecutionTime : NULL; + if ($maxExecutionTime !== null && $maxExecutionTime <= 0) { + throw new InvalidArgumentException("Max execution time must be NULL or non negative number."); + } + $this->maxExecutionTime = $maxExecutionTime; + + return $this; } + /** * Adds task case to be processed when cronner runs. If tasks * with name which is already added are given then throws @@ -155,7 +134,7 @@ public function getMaxExecutionTime() * @return Cronner * @throws InvalidArgumentException */ - public function addTasks($tasks) : self + public function addTasks($tasks): self { $tasksId = $this->createIdFromObject($tasks); if (in_array($tasksId, $this->registeredTaskObjects)) { @@ -178,15 +157,16 @@ public function addTasks($tasks) : self return $this; } + /** * Runs all cron tasks. */ - public function run(DateTimeInterface $now = NULL) + public function run(DateTimeInterface $now = null) { - if ($now === NULL) { + if ($now === null) { $now = new DateTime(); } - if ($this->maxExecutionTime !== NULL) { + if ($this->maxExecutionTime !== null) { set_time_limit($this->maxExecutionTime); } @@ -209,38 +189,40 @@ public function run(DateTimeInterface $now = NULL) } if ($e instanceof RuntimeException) { throw $e; // Throw exception if it is Cronner Runtime exception - } elseif ($this->skipFailedTask === FALSE) { + } elseif ($this->skipFailedTask === false) { throw $e; // Throw exception if failed task should not be skipped } } } } + /** * Returns count of added task objects. */ - public function countTaskObjects() : int + public function countTaskObjects(): int { return count($this->registeredTaskObjects); } + /** * Returns count of added tasks. */ - public function countTasks() : int + public function countTasks(): int { return count($this->tasks); } + /** * Creates and returns identification string for given object. * * @param object $tasks * @return string */ - private function createIdFromObject($tasks) : string + private function createIdFromObject($tasks): string { return sha1(get_class($tasks)); } - } diff --git a/src/Cronner/DI/CronnerExtension.php b/src/Cronner/DI/CronnerExtension.php index 0e8c373..c7547f7 100644 --- a/src/Cronner/DI/CronnerExtension.php +++ b/src/Cronner/DI/CronnerExtension.php @@ -4,174 +4,121 @@ namespace stekycz\Cronner\DI; + +use Bileto\CriticalSection\CriticalSection; +use Bileto\CriticalSection\Driver\FileDriver; use Nette\Configurator; use Nette\DI\Compiler; use Nette\DI\CompilerExtension; -use Nette\DI\ContainerBuilder; -use Nette\DI\ServiceDefinition; -use Nette\DI\Statement; +use Nette\DI\Definitions\ServiceDefinition; +use Nette\DI\Definitions\Statement; +use Nette\DI\Extensions\InjectExtension; +use Nette\DI\Helpers; use Nette\PhpGenerator\ClassType; -use Nette\Utils\Json; -use Nette\Utils\Validators; -use Bileto\CriticalSection\CriticalSection; -use Bileto\CriticalSection\Driver\FileDriver; -use Bileto\CriticalSection\Driver\IDriver; +use Nette\Schema\Expect; +use Nette\Schema\Schema; use stekycz\Cronner\Bar\Tasks; use stekycz\Cronner\Cronner; -use stekycz\Cronner\ITimestampStorage; use stekycz\Cronner\TimestampStorage\FileStorage; +use Tracy\Bar; -class CronnerExtension extends CompilerExtension +final class CronnerExtension extends CompilerExtension { + private const TASKS_TAG = 'cronner.tasks'; - const TASKS_TAG = 'cronner.tasks'; - const DEFAULT_STORAGE_CLASS = FileStorage::class; - const DEFAULT_STORAGE_DIRECTORY = '%tempDir%/cronner'; + public static function register(Configurator $configurator): void + { + $configurator->onCompile[] = static function (Configurator $config, Compiler $compiler): void { + $compiler->addExtension('cronner', new CronnerExtension()); + }; + } - /** - * @var array - */ - public $defaults = [ - 'timestampStorage' => NULL, - 'maxExecutionTime' => NULL, - 'criticalSectionTempDir' => "%tempDir%/critical-section", - 'criticalSectionDriver' => NULL, - 'tasks' => [], - 'bar' => '%debugMode%', - ]; - public function loadConfiguration() + public function getConfigSchema(): Schema { - $container = $this->getContainerBuilder(); - - $config = $this->getConfig($this->defaults); - Validators::assert($config['timestampStorage'], 'string|object|null', 'Timestamp storage definition'); - Validators::assert($config['maxExecutionTime'], 'integer|null', 'Script max execution time'); - Validators::assert($config['criticalSectionTempDir'], 'string|null', 'Critical section files directory path (for critical section files driver only)'); - Validators::assert($config['criticalSectionDriver'], 'string|object|null', 'Critical section driver definition'); - - $storage = $this->createServiceByConfig( - $container, - $this->prefix('timestampStorage'), - $config['timestampStorage'], - ITimestampStorage::class, - self::DEFAULT_STORAGE_CLASS, - [ - self::DEFAULT_STORAGE_DIRECTORY, - ] - ); - - $criticalSectionDriver = $this->createServiceByConfig( - $container, - $this->prefix('criticalSectionDriver'), - $config['criticalSectionDriver'], - IDriver::class, - FileDriver::class, - [ - $config['criticalSectionTempDir'], - ] - ); - - $criticalSection = $container->addDefinition($this->prefix("criticalSection")) - ->setClass(CriticalSection::class, [ - $criticalSectionDriver, - ]) - ->setAutowired(FALSE) - ->setInject(FALSE); - - $runner = $container->addDefinition($this->prefix('runner')) - ->setClass(Cronner::class, [ - $storage, - $criticalSection, - $config['maxExecutionTime'], - array_key_exists('debugMode', $config) ? !$config['debugMode'] : TRUE, - ]); + return Expect::structure([ + 'assets' => Expect::arrayOf(Expect::string()), + 'timestampStorage' => Expect::string(), + 'maxExecutionTime' => Expect::int(), + 'criticalSectionTempDir' => Expect::string(), + 'criticalSectionDriver' => Expect::string(), + 'tasks' => Expect::array(), + 'bar' => Expect::bool(), + ])->castTo('array'); + } + + + public function loadConfiguration(): void + { + /** @var mixed[] $config */ + $config = $this->config; + $builder = $this->getContainerBuilder(); + + if ($config['timestampStorage'] === null) { + $builder->addDefinition($this->prefix('fileStorage')) + ->setFactory(FileStorage::class) + ->setArgument('directory', $builder->parameters['tempDir'] . '/cronner') + ->addTag(InjectExtension::TAG_INJECT, false); + } + if ($config['criticalSectionDriver'] === null) { + $builder->addDefinition($this->prefix('criticalSectionDriver')) + ->setFactory(FileDriver::class) + ->setArgument('lockFilesDir', $builder->parameters['tempDir'] . '/critical-section'); + } + + $builder->addDefinition($this->prefix('criticalSection')) + ->setFactory(CriticalSection::class) + ->setArgument('driver', $builder->getDefinitionByType($config['criticalSectionDriver'] ?? FileDriver::class)) + ->addTag(InjectExtension::TAG_INJECT, false); - Validators::assert($config['tasks'], 'array'); - foreach ($config['tasks'] as $task) { - $def = $container->addDefinition($this->prefix('task.' . md5(is_string($task) ? $task : sprintf('%s-%s', $task->getEntity(), Json::encode($task))))); - list($def->factory) = Compiler::filterArguments([ + $builder->addDefinition($this->prefix('runner')) + ->setFactory(Cronner::class) + ->setArgument('maxExecutionTime', $config['maxExecutionTime']) + ->setArgument('skipFailedTask', array_key_exists('debugMode', $config) ? !$config['debugMode'] : true); + + foreach ($config['tasks'] ?? [] as $task) { + $def = $builder->addDefinition($this->prefix('task.' . md5(is_string($task) ? $task : $task->getEntity() . '-' . json_encode($task)))); + [$def->factory] = Helpers::filterArguments([ is_string($task) ? new Statement($task) : $task, ]); if (class_exists($def->factory->entity)) { - $def->setClass($def->factory->entity); + $def->setFactory($def->factory->entity); } - $def->setAutowired(FALSE); - $def->setInject(FALSE); + $def->setAutowired(false); + $def->addTag(InjectExtension::TAG_INJECT, false); $def->addTag(self::TASKS_TAG); } - if ($config['bar'] && class_exists('Tracy\Bar')) { - $container->addDefinition($this->prefix('bar')) - ->setClass(Tasks::class, [ - $this->prefix('@runner'), - $this->prefix('@timestampStorage'), - ]); + if ($config['bar'] ?? false) { + $builder->addDefinition($this->prefix('bar')) + ->setFactory(Tasks::class); } } - public function beforeCompile() + + public function beforeCompile(): void { $builder = $this->getContainerBuilder(); + /** @var ServiceDefinition $runner */ $runner = $builder->getDefinition($this->prefix('runner')); foreach (array_keys($builder->findByTag(self::TASKS_TAG)) as $serviceName) { $runner->addSetup('addTasks', ['@' . $serviceName]); } } - public function afterCompile(ClassType $class) - { - $builder = $this->getContainerBuilder(); - $init = $class->getMethod('initialize'); - - if ($builder->hasDefinition($this->prefix('bar'))) { - $init->addBody('$this->getByType(?)->addPanel($this->getService(?));', [ - 'Tracy\Bar', - $this->prefix('bar'), - ]); - } - } - - public static function register(Configurator $configurator) - { - $configurator->onCompile[] = function (Configurator $config, Compiler $compiler) { - $compiler->addExtension('cronner', new CronnerExtension()); - }; - } - private function createServiceByConfig( - ContainerBuilder $container, - string $serviceName, - $config, - string $fallbackType, - string $fallbackClass, - array $fallbackArguments - ) : ServiceDefinition + public function afterCompile(ClassType $class): void { - if (is_string($config) && $container->getServiceName($config)) { - $definition = $container->addDefinition($serviceName) - ->setFactory($config); - } elseif ($config instanceof Statement) { - $definition = $container->addDefinition($serviceName) - ->setClass($config->entity, $config->arguments); - } else { - $foundServiceName = $container->getByType($fallbackType); - if ($foundServiceName) { - $definition = $container->addDefinition($serviceName) - ->setFactory('@' . $foundServiceName); - } else { - $definition = $container->addDefinition($serviceName) - ->setClass($fallbackClass, $container->expand($fallbackArguments)); - } + if ($this->getContainerBuilder()->hasDefinition($this->prefix('bar'))) { + $class->getMethod('initialize') + ->addBody('$this->getByType(?)->addPanel($this->getService(?));', [ + Bar::class, + $this->prefix('bar'), + ]); } - - return $definition - ->setAutowired(FALSE) - ->setInject(FALSE); } - } diff --git a/src/Cronner/Exceptions/DuplicateTaskNameException.php b/src/Cronner/Exceptions/DuplicateTaskNameException.php index 2731f8c..70479f2 100644 --- a/src/Cronner/Exceptions/DuplicateTaskNameException.php +++ b/src/Cronner/Exceptions/DuplicateTaskNameException.php @@ -4,7 +4,7 @@ namespace stekycz\Cronner\Exceptions; -class DuplicateTaskNameException extends InvalidArgumentException -{ +final class DuplicateTaskNameException extends InvalidArgumentException +{ } diff --git a/src/Cronner/Exceptions/EmptyTaskNameException.php b/src/Cronner/Exceptions/EmptyTaskNameException.php index 02c962e..cfa2205 100644 --- a/src/Cronner/Exceptions/EmptyTaskNameException.php +++ b/src/Cronner/Exceptions/EmptyTaskNameException.php @@ -4,7 +4,7 @@ namespace stekycz\Cronner\Exceptions; -class EmptyTaskNameException extends InvalidArgumentException -{ +final class EmptyTaskNameException extends InvalidArgumentException +{ } diff --git a/src/Cronner/Exceptions/InvalidArgumentException.php b/src/Cronner/Exceptions/InvalidArgumentException.php index a0c730a..7e28164 100644 --- a/src/Cronner/Exceptions/InvalidArgumentException.php +++ b/src/Cronner/Exceptions/InvalidArgumentException.php @@ -4,7 +4,7 @@ namespace stekycz\Cronner\Exceptions; + class InvalidArgumentException extends \InvalidArgumentException { - } diff --git a/src/Cronner/Exceptions/InvalidParameterException.php b/src/Cronner/Exceptions/InvalidParameterException.php index 30f8d0d..ecb8d33 100644 --- a/src/Cronner/Exceptions/InvalidParameterException.php +++ b/src/Cronner/Exceptions/InvalidParameterException.php @@ -4,7 +4,7 @@ namespace stekycz\Cronner\Exceptions; -class InvalidParameterException extends InvalidArgumentException -{ +final class InvalidParameterException extends InvalidArgumentException +{ } diff --git a/src/Cronner/Exceptions/InvalidTaskNameException.php b/src/Cronner/Exceptions/InvalidTaskNameException.php index e54d370..cbc1dab 100644 --- a/src/Cronner/Exceptions/InvalidTaskNameException.php +++ b/src/Cronner/Exceptions/InvalidTaskNameException.php @@ -4,7 +4,7 @@ namespace stekycz\Cronner\Exceptions; -class InvalidTaskNameException extends InvalidArgumentException -{ +final class InvalidTaskNameException extends InvalidArgumentException +{ } diff --git a/src/Cronner/Exceptions/RuntimeException.php b/src/Cronner/Exceptions/RuntimeException.php index 879eee7..0571151 100644 --- a/src/Cronner/Exceptions/RuntimeException.php +++ b/src/Cronner/Exceptions/RuntimeException.php @@ -4,7 +4,7 @@ namespace stekycz\Cronner\Exceptions; -class RuntimeException extends \RuntimeException -{ +final class RuntimeException extends \RuntimeException +{ } diff --git a/src/Cronner/ITimestampStorage.php b/src/Cronner/ITimestampStorage.php index c28e707..1dc1ef2 100644 --- a/src/Cronner/ITimestampStorage.php +++ b/src/Cronner/ITimestampStorage.php @@ -4,6 +4,7 @@ namespace stekycz\Cronner; + use DateTimeInterface; interface ITimestampStorage @@ -11,23 +12,16 @@ interface ITimestampStorage /** * Sets name of current task. - * - * @param string|null $taskName */ - public function setTaskName(string $taskName = NULL); + public function setTaskName(?string $taskName = null): void; /** * Saves current date and time as last invocation time. - * - * @param DateTimeInterface $now */ - public function saveRunTime(DateTimeInterface $now); + public function saveRunTime(DateTimeInterface $now): void; /** * Returns date and time of last cron task invocation. - * - * @return DateTimeInterface|null */ - public function loadLastRunTime(); - + public function loadLastRunTime(): ?DateTimeInterface; } diff --git a/src/Cronner/Tasks/Parameters.php b/src/Cronner/Tasks/Parameters.php index c1a4db9..3c10419 100644 --- a/src/Cronner/Tasks/Parameters.php +++ b/src/Cronner/Tasks/Parameters.php @@ -4,29 +4,32 @@ namespace stekycz\Cronner\Tasks; + use DateTimeInterface; use Nette; use Nette\Reflection\Method; use Nette\Utils\Strings; -use stekycz\Cronner\Exceptions\InvalidArgumentException; final class Parameters { - use \Nette\SmartObject; + use Nette\SmartObject; - const TASK = 'cronner-task'; - const PERIOD = 'cronner-period'; - const DAYS = 'cronner-days'; - const DAYS_OF_MONTH = 'cronner-days-of-month'; - const TIME = 'cronner-time'; + public const TASK = 'cronner-task'; - /** - * @var array - */ + public const PERIOD = 'cronner-period'; + + public const DAYS = 'cronner-days'; + + public const DAYS_OF_MONTH = 'cronner-days-of-month'; + + public const TIME = 'cronner-time'; + + /** @var mixed[] */ private $values; + /** - * @param array $values + * @param mixed[] $values */ public function __construct(array $values) { @@ -36,118 +39,120 @@ public function __construct(array $values) $this->values = $values; } - public function getName() : string + + /** + * Parse cronner values from annotations. + */ + public static function parseParameters(Method $method, \DateTimeInterface $now): array + { + $taskName = null; + if ($method->hasAnnotation(Parameters::TASK)) { + $className = $method->getDeclaringClass()->getName(); + $methodName = $method->getName(); + $taskName = $className . ' - ' . $methodName; + } + + $taskAnnotation = $method->getAnnotation(Parameters::TASK); + + $parameters = [ + static::TASK => is_string($taskAnnotation) + ? Parser::parseName($taskAnnotation) + : $taskName, + static::PERIOD => $method->hasAnnotation(Parameters::PERIOD) + ? Parser::parsePeriod((string) $method->getAnnotation(Parameters::PERIOD)) + : null, + static::DAYS => $method->hasAnnotation(Parameters::DAYS) + ? Parser::parseDays((string) $method->getAnnotation(Parameters::DAYS)) + : null, + static::DAYS_OF_MONTH => $method->hasAnnotation(Parameters::DAYS_OF_MONTH) + ? Parser::parseDaysOfMonth((string) $method->getAnnotation(Parameters::DAYS_OF_MONTH), $now) + : null, + static::TIME => $method->hasAnnotation(Parameters::TIME) + ? Parser::parseTimes((string) $method->getAnnotation(Parameters::TIME)) + : null, + ]; + + return $parameters; + } + + + public function getName(): string { return $this->values[static::TASK]; } - public function isTask() : bool + + public function isTask(): bool { return Strings::length($this->values[static::TASK]) > 0; } + /** * Returns true if today is allowed day of week. */ - public function isInDay(DateTimeInterface $now) : bool + public function isInDay(DateTimeInterface $now): bool { - if (($days = $this->values[static::DAYS]) !== NULL) { + if (($days = $this->values[static::DAYS]) !== null) { return in_array($now->format('D'), $days); } - return TRUE; + return true; } + /** * Returns true if today is allowed day of month. */ - public function isInDayOfMonth(DateTimeInterface $now) : bool + public function isInDayOfMonth(DateTimeInterface $now): bool { - if (($days = $this->values[static::DAYS_OF_MONTH]) !== NULL) { - return in_array($now->format('j'), $days); + if (($days = $this->values[static::DAYS_OF_MONTH]) !== null) { + return in_array($now->format('j'), $days, true); } - return TRUE; + return true; } + /** * Returns true if current time is in allowed range. */ - public function isInTime(DateTimeInterface $now) : bool + public function isInTime(DateTimeInterface $now): bool { if ($times = $this->values[static::TIME]) { foreach ($times as $time) { if ($time['to'] && $time['to'] >= $now->format('H:i') && $time['from'] <= $now->format('H:i')) { // Is in range with precision to minutes - return TRUE; - } elseif ($time['from'] == $now->format('H:i')) { + return true; + } + if ($time['from'] === $now->format('H:i')) { // Is in specific minute - return TRUE; + return true; } } - return FALSE; + return false; } - return TRUE; + return true; } + /** * Returns true if current time is next period of invocation. */ - public function isNextPeriod(DateTimeInterface $now, DateTimeInterface $lastRunTime = NULL) : bool + public function isNextPeriod(DateTimeInterface $now, DateTimeInterface $lastRunTime = null): bool { - if ( - $lastRunTime !== NULL - && !$lastRunTime instanceof \DateTimeImmutable - && !$lastRunTime instanceof \DateTime - ) { - throw new InvalidArgumentException; + if ($lastRunTime !== null && !$lastRunTime instanceof \DateTimeImmutable && !$lastRunTime instanceof \DateTime) { + throw new \InvalidArgumentException; } - if (isset($this->values[static::PERIOD]) && $this->values[static::PERIOD]) { // Prevent run task on next cronner run because of a few seconds shift $now = Nette\Utils\DateTime::from($now)->modifyClone('+5 seconds'); - return $lastRunTime === NULL || $lastRunTime->modify('+ ' . $this->values[static::PERIOD]) <= $now; - } - - return TRUE; - } - - /** - * Parse cronner values from annotations. - */ - public static function parseParameters(Method $method, \DateTime $now) : array - { - $taskName = NULL; - if ($method->hasAnnotation(Parameters::TASK)) { - $className = $method->getDeclaringClass()->getName(); - $methodName = $method->getName(); - $taskName = $className . ' - ' . $methodName; + return $lastRunTime === null || $lastRunTime->modify('+ ' . $this->values[static::PERIOD]) <= $now; } - $taskAnnotation = $method->getAnnotation(Parameters::TASK); - - $parameters = [ - static::TASK => is_string($taskAnnotation) - ? Parser::parseName($taskAnnotation) - : $taskName, - static::PERIOD => $method->hasAnnotation(Parameters::PERIOD) - ? Parser::parsePeriod((string) $method->getAnnotation(Parameters::PERIOD)) - : NULL, - static::DAYS => $method->hasAnnotation(Parameters::DAYS) - ? Parser::parseDays((string) $method->getAnnotation(Parameters::DAYS)) - : NULL, - static::DAYS_OF_MONTH => $method->hasAnnotation(Parameters::DAYS_OF_MONTH) - ? Parser::parseDaysOfMonth((string) $method->getAnnotation(Parameters::DAYS_OF_MONTH), $now) - : NULL, - static::TIME => $method->hasAnnotation(Parameters::TIME) - ? Parser::parseTimes((string) $method->getAnnotation(Parameters::TIME)) - : NULL, - ]; - - return $parameters; + return true; } - } diff --git a/src/Cronner/Tasks/Parser.php b/src/Cronner/Tasks/Parser.php index 0bc26db..545c967 100644 --- a/src/Cronner/Tasks/Parser.php +++ b/src/Cronner/Tasks/Parser.php @@ -4,151 +4,136 @@ namespace stekycz\Cronner\Tasks; + use Nette\Utils\Strings; use stekycz\Cronner\Exceptions\InvalidParameterException; -class Parser +final class Parser { - use \Nette\SmartObject; - /** * Parses name of cron task. - * - * @param string $annotation - * @return string|null */ - public static function parseName(string $annotation) + public static function parseName(string $annotation): ?string { $name = Strings::trim($annotation); - $name = Strings::length($name) > 0 ? $name : NULL; + $name = Strings::length($name) > 0 ? $name : null; return $name; } + /** * Parses period of cron task. If annotation is invalid throws exception. * - * @param string $annotation - * @return string|null * @throws InvalidParameterException */ - public static function parsePeriod(string $annotation) + public static function parsePeriod(string $annotation): ?string { - $period = NULL; + $period = null; $annotation = Strings::trim($annotation); if (Strings::length($annotation)) { - if (strtotime('+ ' . $annotation) === FALSE) { + if (strtotime('+ ' . $annotation) === false) { throw new InvalidParameterException( - "Given period parameter '" . $annotation . "' must be valid for strtotime() with '+' sign as its prefix (added by Cronner automatically)." + 'Given period parameter "' . $annotation . '" must be valid for strtotime() ' + . 'with "+" (plus) sign as its prefix (added by Cronner automatically).' ); } $period = $annotation; } - return $period ?: NULL; + return $period ?: null; } + /** - * Parses allowed days for cron task. If annotation is invalid - * throws exception. + * Parses allowed days for cron task. If annotation is invalid throws exception. * - * @param string $annotation * @return string[]|null * @throws InvalidParameterException */ - public static function parseDays(string $annotation) + public static function parseDays(string $annotation): ?array { static $validValues = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun',]; - $days = NULL; + $days = null; $annotation = Strings::trim($annotation); if (Strings::length($annotation)) { $days = static::translateToDayNames($annotation); $days = static::expandDaysRange($days); foreach ($days as $day) { - if (!in_array($day, $validValues)) { - throw new InvalidParameterException( - "Given day parameter '" . $day . "' must be one from " . implode(', ', $validValues) . "." - ); + if (in_array($day, $validValues, true) === false) { + throw new InvalidParameterException("Given day parameter '" . $day . "' must be one from " . implode(', ', $validValues) . "."); } } $days = array_values(array_intersect($validValues, $days)); } - return $days ?: NULL; + return $days ?: null; } + /** - * Parses allowed days om month for cron task. If annotation is invalid - * throws exception. - * @param string $annotation - * @param DateTimeInterface $now + * Parses allowed days om month for cron task. If annotation is invalid throws exception. + * * @return string[]|null * @throws InvalidParameterException */ - public static function parseDaysOfMonth(string $annotation, \DateTime $now) + public static function parseDaysOfMonth(string $annotation, \DateTimeInterface $now): ?array { - $days = NULL; + $days = null; $annotation = Strings::trim($annotation); if (Strings::length($annotation)) { - $days = static::splitMultipleValues($annotation); - $days = static::expandDaysOfMonthRange($days); + $days = static::expandDaysOfMonthRange(static::splitMultipleValues($annotation)); - $dayInMonthCount = cal_days_in_month(CAL_GREGORIAN, (int)$now->format('n'), (int)$now->format('Y')); + $dayInMonthCount = cal_days_in_month(CAL_GREGORIAN, (int) $now->format('n'), (int) $now->format('Y')); foreach ($days as $day) { if (($day < 1 || $day > 31) || !is_numeric($day)) { - throw new InvalidParameterException( - "Given day parameter '" . $day . "' must be numeric from range 1-31." - ); + throw new InvalidParameterException("Given day parameter '" . $day . "' must be numeric from range 1-31."); } - - if ($day > $dayInMonthCount) { - if (!in_array($dayInMonthCount, $days)) { - $days[] = $dayInMonthCount; - } + if ($day > $dayInMonthCount && !in_array($dayInMonthCount, $days, true)) { + $days[] = $dayInMonthCount; } } } - return $days ?: NULL; + return $days ?: null; } + /** * Parses allowed time ranges for cron task. If annotation is invalid * throws exception. * - * @param string $annotation * @return string[][]|null * @throws InvalidParameterException */ - public static function parseTimes(string $annotation) + public static function parseTimes(string $annotation): ?array { - $times = NULL; + $times = null; $annotation = Strings::trim($annotation); - if (Strings::length($annotation)) { - if ($values = static::splitMultipleValues($annotation)) { - $times = []; - foreach ($values as $time) { - $times = array_merge($times, static::parseOneTime($time)); - } - usort($times, function ($a, $b) { - return $a < $b ? -1 : ($a > $b ? 1 : 0); - }); + if (Strings::length($annotation) && $values = static::splitMultipleValues($annotation)) { + $times = []; + foreach ($values as $time) { + // TODO: Fix by https://php.baraja.cz/mergovani-velkeho-pole + $times = array_merge($times, static::parseOneTime($time)); // TODO: Slow merge algorithm } + usort($times, static function ($a, $b) { + return $a < $b ? -1 : ($a > $b ? 1 : 0); + }); } - return $times ?: NULL; + return $times ?: null; } + /** * Translates given annotation to day names. * - * @param string $annotation * @return string[] */ - private static function translateToDayNames(string $annotation) : array + private static function translateToDayNames(string $annotation): array { static $workingDays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri',]; static $weekend = ['Sat', 'Sun',]; @@ -171,6 +156,7 @@ private static function translateToDayNames(string $annotation) : array return array_unique($days); } + /** * Expands given day names and day ranges to day names only. The day range must be * in "Mon-Fri" format. @@ -178,24 +164,24 @@ private static function translateToDayNames(string $annotation) : array * @param string[] $days * @return string[] */ - private static function expandDaysRange(array $days) : array + private static function expandDaysRange(array $days): array { static $dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun',]; $expandedValues = []; foreach ($days as $day) { if (Strings::match($day, '~^\w{3}\s*-\s*\w{3}$~u')) { - list($begin, $end) = Strings::split($day, '~\s*-\s*~'); - $started = FALSE; + [$begin, $end] = Strings::split($day, '~\s*-\s*~'); + $started = false; foreach ($dayNames as $dayName) { if ($dayName === $begin) { - $started = TRUE; + $started = true; } if ($started) { $expandedValues[] = $dayName; } if ($dayName === $end) { - $started = FALSE; + $started = false; } } } else { @@ -206,62 +192,61 @@ private static function expandDaysRange(array $days) : array return array_unique($expandedValues); } + /** * Expands given day of month ranges to array. * * @param string[] $days * @return string[] */ - private static function expandDaysOfMonthRange(array $days) : array + private static function expandDaysOfMonthRange(array $days): array { $expandedValues = []; foreach ($days as $day) { if (Strings::match($day, '~^(3[01]|[12][0-9]|[1-9])\s*-\s*(3[01]|[12][0-9]|[1-9])$~u')) { - list($begin, $end) = Strings::split($day, '~\s*-\s*~'); - + [$begin, $end] = Strings::split($day, '~\s*-\s*~'); for ($i = $begin; $i <= $end; $i++) { - if (!in_array($i, $expandedValues)) { + if (!in_array($i, $expandedValues, true)) { $expandedValues[] = $i; } } - } else { - if (!in_array($day, $expandedValues)) { - $expandedValues[] = $day; - } + } elseif (!in_array($day, $expandedValues, true)) { + $expandedValues[] = $day; } } return array_unique($expandedValues); } + /** * Splits given annotation by comma into array. * - * @param string $annotation * @return string[] */ - private static function splitMultipleValues(string $annotation) : array + private static function splitMultipleValues(string $annotation): array { return Strings::split($annotation, '/\s*,\s*/'); } + /** * Returns True if time in valid format is given, False otherwise. */ - private static function isValidTime(string $time) : bool + private static function isValidTime(string $time): bool { return (bool) Strings::match($time, '/^\d{2}:\d{2}$/u'); } + /** * Parses one time annotation. If it is invalid throws exception. * - * @param string $time * @return string[][] * @throws InvalidParameterException */ - private static function parseOneTime(string $time) : array + private static function parseOneTime(string $time): array { $time = static::translateToTimes($time); $parts = Strings::split($time, '/\s*-\s*/'); @@ -271,20 +256,21 @@ private static function parseOneTime(string $time) : array ); } $times = []; - if (static::isTimeOverMidnight($parts[0], isset($parts[1]) ? $parts[1] : NULL)) { + if (static::isTimeOverMidnight($parts[0], $parts[1] ?? null)) { $times[] = static::timePartsToArray('00:00', $parts[1]); $times[] = static::timePartsToArray($parts[0], '23:59'); } else { - $times[] = static::timePartsToArray($parts[0], isset($parts[1]) ? $parts[1] : NULL); + $times[] = static::timePartsToArray($parts[0], $parts[1] ?? null); } return $times; } + /** * Translates given annotation to day names. */ - private static function translateToTimes(string $time) : string + private static function translateToTimes(string $time): string { static $translationMap = [ 'morning' => '06:00 - 11:59', @@ -298,23 +284,24 @@ private static function translateToTimes(string $time) : string return array_key_exists($time, $translationMap) ? $translationMap[$time] : $time; } + /** * Returns True if given times includes midnight, False otherwise. */ - private static function isTimeOverMidnight(string $from, string $to = NULL) : bool + private static function isTimeOverMidnight(string $from, string $to = null): bool { - return $to !== NULL && $to < $from; + return $to !== null && $to < $from; } + /** * Returns array structure with given times. */ - private static function timePartsToArray(string $from, string $to = NULL) : array + private static function timePartsToArray(string $from, string $to = null): array { return [ 'from' => $from, 'to' => $to, ]; } - } diff --git a/src/Cronner/Tasks/Task.php b/src/Cronner/Tasks/Task.php index 375ef3a..ada71c9 100644 --- a/src/Cronner/Tasks/Task.php +++ b/src/Cronner/Tasks/Task.php @@ -4,49 +4,37 @@ namespace stekycz\Cronner\Tasks; -use DateTime; + use DateTimeInterface; use Nette\Reflection\Method; -use ReflectionClass; use stekycz\Cronner\ITimestampStorage; final class Task { use \Nette\SmartObject; - /** - * @var object - */ + /** @var object */ private $object; - /** - * @var Method - */ + /** @var Method */ private $method; - /** - * @var ITimestampStorage - */ + /** @var ITimestampStorage */ private $timestampStorage; - /** - * @var Parameters|null - */ - private $parameters = NULL; + /** @var Parameters|null */ + private $parameters; + + /** @var \DateTimeInterface|null */ + private $now; - /** - * @var DateTimeInterface|null - */ - private $now = NULL; /** * Creates instance of one task. * * @param object $object - * @param Method $method - * @param ITimestampStorage $timestampStorage */ - public function __construct($object, Method $method, ITimestampStorage $timestampStorage, DateTimeInterface $now = NULL) + public function __construct($object, Method $method, ITimestampStorage $timestampStorage, DateTimeInterface $now = null) { $this->object = $object; $this->method = $method; @@ -54,35 +42,45 @@ public function __construct($object, Method $method, ITimestampStorage $timestam $this->setNow($now); } - public function getObjectName() : string + + public function getObjectName(): string { return get_class($this->object); } - public function getMethodReflection() : Method + + public function getMethodReflection(): Method { return $this->method; } - public function getObjectPath() : string - { - $reflection = new ReflectionClass($this->object); - return $reflection->getFileName(); + public function getObjectPath(): string + { + try { + return (new \ReflectionClass($this->object))->getFileName(); + } catch (\Throwable $e) { + throw new \RuntimeException('Object "' . \get_class($this->object) . '" is broken: ' . $e->getMessage(), $e->getCode(), $e); + } } + /** * Returns True if given parameters should be run. */ - public function shouldBeRun(DateTimeInterface $now = NULL) : bool + public function shouldBeRun(DateTimeInterface $now = null): bool { - if ($now === NULL) { - $now = new DateTime(); + if ($now === null) { + try { + $now = new \DateTime('now'); + } catch (\Throwable $e) { + throw new \RuntimeException('Datetime error: ' . $e->getMessage(), $e->getCode(), $e); + } } $parameters = $this->getParameters(); if (!$parameters->isTask()) { - return FALSE; + return false; } $this->timestampStorage->setTaskName($parameters->getName()); @@ -92,12 +90,14 @@ public function shouldBeRun(DateTimeInterface $now = NULL) : bool && $parameters->isInDayOfMonth($now); } - public function getName() : string + + public function getName(): string { return $this->getParameters()->getName(); } - public function __invoke(DateTimeInterface $now) + + public function __invoke(\DateTimeInterface $now) { $this->method->invoke($this->object); $this->timestampStorage->setTaskName($this->getName()); @@ -105,34 +105,44 @@ public function __invoke(DateTimeInterface $now) $this->timestampStorage->setTaskName(); } - /** - * Returns instance of parsed parameters. - */ - private function getParameters() : Parameters + + public function getNow(): \DateTimeInterface { - if ($this->parameters === NULL) { - $this->parameters = new Parameters(Parameters::parseParameters($this->method, $this->getNow())); + if ($this->now === null) { + try { + $this->now = new \DateTime('now'); + } catch (\Throwable $e) { + throw new \RuntimeException('Datetime error: ' . $e->getMessage(), $e->getCode(), $e); + } } - return $this->parameters; + return $this->now; } - public function setNow($now) + public function setNow(?\DateTimeInterface $now): void { - if ($now === NULL) { - $now = new DateTime(); + if ($now === null) { + try { + $now = new \DateTime('now'); + } catch (\Throwable $e) { + throw new \RuntimeException('Datetime error: ' . $e->getMessage(), $e->getCode(), $e); + } } $this->now = $now; } - public function getNow() + + /** + * Returns instance of parsed parameters. + */ + private function getParameters(): Parameters { - if ($this->now === NULL) { - $this->now = new DateTime(); + if ($this->parameters === null) { + $this->parameters = new Parameters(Parameters::parseParameters($this->method, $this->getNow())); } - return $this->now; + + return $this->parameters; } } - diff --git a/src/Cronner/TimestampStorage/DummyStorage.php b/src/Cronner/TimestampStorage/DummyStorage.php index 3c84211..6869393 100644 --- a/src/Cronner/TimestampStorage/DummyStorage.php +++ b/src/Cronner/TimestampStorage/DummyStorage.php @@ -4,41 +4,39 @@ namespace stekycz\Cronner\TimestampStorage; + use DateTimeInterface; +use Nette\SmartObject; use stekycz\Cronner\ITimestampStorage; -class DummyStorage implements ITimestampStorage +final class DummyStorage implements ITimestampStorage { - use \Nette\SmartObject; + use SmartObject; + /** * Sets name of current task. - * - * @param string|null $taskName */ - public function setTaskName(string $taskName = NULL) + public function setTaskName(?string $taskName = null): void { // Dummy } + /** * Saves current date and time as last invocation time. - * - * @param DateTimeInterface $now */ - public function saveRunTime(DateTimeInterface $now) + public function saveRunTime(DateTimeInterface $now): void { // Dummy } + /** * Returns date and time of last cron task invocation. - * - * @return DateTimeInterface|null */ - public function loadLastRunTime() + public function loadLastRunTime(): ?DateTimeInterface { - return NULL; // Dummy + return null; // Dummy } - } diff --git a/src/Cronner/TimestampStorage/FileStorage.php b/src/Cronner/TimestampStorage/FileStorage.php index 70e7123..eec0ad4 100644 --- a/src/Cronner/TimestampStorage/FileStorage.php +++ b/src/Cronner/TimestampStorage/FileStorage.php @@ -4,8 +4,10 @@ namespace stekycz\Cronner\TimestampStorage; + use DateTime; use DateTimeInterface; +use Nette\SmartObject; use Nette\Utils\FileSystem; use Nette\Utils\SafeStream; use Nette\Utils\Strings; @@ -15,23 +17,17 @@ class FileStorage implements ITimestampStorage { - use \Nette\SmartObject; + use SmartObject; - const DATETIME_FORMAT = 'Y-m-d H:i:s O'; + public const DATETIME_FORMAT = 'Y-m-d H:i:s O'; - /** - * @var string - */ + /** @var string */ private $directory; - /** - * @var string|NULL - */ - private $taskName = NULL; + /** @var string|null */ + private $taskName; + - /** - * @param string $directory - */ public function __construct(string $directory) { SafeStream::register(); @@ -40,57 +36,54 @@ public function __construct(string $directory) $this->directory = $directory; } + /** * Sets name of current task. - * - * @param string|null $taskName */ - public function setTaskName(string $taskName = NULL) + public function setTaskName(?string $taskName = null): void { - if ($taskName !== NULL && Strings::length($taskName) <= 0) { + if ($taskName !== null && Strings::length($taskName) <= 0) { throw new InvalidTaskNameException('Given task name is not valid.'); } $this->taskName = $taskName; } + /** * Saves current date and time as last invocation time. - * - * @param DateTimeInterface $now */ - public function saveRunTime(DateTimeInterface $now) + public function saveRunTime(DateTimeInterface $now): void { $filepath = $this->buildFilePath(); file_put_contents($filepath, $now->format(self::DATETIME_FORMAT)); } + /** * Returns date and time of last cron task invocation. - * - * @return DateTimeInterface|null */ - public function loadLastRunTime() + public function loadLastRunTime(): ?DateTimeInterface { - $date = NULL; + $date = null; $filepath = $this->buildFilePath(); if (file_exists($filepath)) { $date = file_get_contents($filepath); $date = DateTime::createFromFormat(self::DATETIME_FORMAT, $date); } - return $date ? $date : NULL; + return $date ? $date : null; } + /** * Builds file path from directory and task name. */ - private function buildFilePath() : string + private function buildFilePath(): string { - if ($this->taskName === NULL) { + if ($this->taskName === null) { throw new EmptyTaskNameException('Task name was not set.'); } return SafeStream::PROTOCOL . '://' . $this->directory . '/' . sha1($this->taskName); } - } diff --git a/tests/CronnerTests/Cronner.phpt b/tests/CronnerTests/Cronner.phpt index 3aa77d5..b1c0c75 100644 --- a/tests/CronnerTests/Cronner.phpt +++ b/tests/CronnerTests/Cronner.phpt @@ -8,14 +8,14 @@ declare(strict_types=1); namespace stekycz\Cronner\tests; + +use Bileto\CriticalSection\ICriticalSection; use Exception; use Mockery; use Nette\Utils\DateTime; use stdClass; -use Bileto\CriticalSection\ICriticalSection; use stekycz\Cronner\Cronner; use stekycz\Cronner\Exceptions\DuplicateTaskNameException; -use stekycz\Cronner\Exceptions\InvalidArgumentException; use stekycz\Cronner\ITimestampStorage; use stekycz\Cronner\Tasks\Task; use stekycz\Cronner\tests\objects\AnotherSimpleTestObject; @@ -30,55 +30,34 @@ require_once(__DIR__ . "/bootstrap.php"); class CronnerTest extends \TestCase { - /** - * @var Cronner - */ + /** @var Cronner */ private $cronner; - /** - * @var ITimestampStorage - */ + /** @var ITimestampStorage */ private $timestampStorage; - protected function setUp() - { - parent::setUp(); - $timestampStorage = Mockery::mock(ITimestampStorage::class); - $timestampStorage->shouldReceive('setTaskName'); - $timestampStorage->shouldReceive('saveRunTime'); - $timestampStorage->shouldReceive('loadLastRunTime')->andReturn(new DateTime('2013-02-04 08:00:00')); - $this->timestampStorage = $timestampStorage; - - $criticalSection = Mockery::mock(ICriticalSection::class); - $criticalSection->shouldReceive("enter")->andReturn(TRUE); - $criticalSection->shouldReceive("leave")->andReturn(TRUE); - $criticalSection->shouldReceive("isEntered")->andReturn(FALSE); - - $this->cronner = new Cronner($this->timestampStorage, $criticalSection); - $this->cronner->onTaskBegin = []; - $this->cronner->onTaskFinished = []; - $this->cronner->onTaskError = []; - } /** * @dataProvider dataProviderSetMaxExecutionTime * @param int|null $expected * @param int|null $value */ - public function testCanSetMaxExecutionTime(int $expected = NULL, int $value = NULL) + public function testCanSetMaxExecutionTime(int $expected = null, int $value = null) { $this->cronner->setMaxExecutionTime($value); Assert::same($expected, $this->cronner->getMaxExecutionTime()); } - public function dataProviderSetMaxExecutionTime() : array + + public function dataProviderSetMaxExecutionTime(): array { return [ [1234, 1234], - [NULL, NULL], + [null, null], ]; } + /** * @dataProvider dataProviderSetMaxExecutionTimeError * @throws \TypeError @@ -88,6 +67,7 @@ class CronnerTest extends \TestCase $this->cronner->setMaxExecutionTime($value); } + public function dataProviderSetMaxExecutionTimeError() { return [ @@ -98,12 +78,13 @@ class CronnerTest extends \TestCase [0.0], ['0.0'], ['nejaky blabol'], - [TRUE], - [FALSE], + [true], + [false], [new stdClass()], ]; } + /** * @dataProvider dataProviderSetMaxExecutionTimeWrongValue * @throws \stekycz\Cronner\Exceptions\InvalidArgumentException @@ -113,6 +94,7 @@ class CronnerTest extends \TestCase $this->cronner->setMaxExecutionTime($value); } + public function dataProviderSetMaxExecutionTimeWrongValue() { return [ @@ -121,12 +103,14 @@ class CronnerTest extends \TestCase ]; } + public function testAcceptsTasksObjectWithTaskMethods() { $this->cronner->addTasks(new stdClass()); Assert::equal(1, $this->cronner->countTaskObjects()); } + /** * @throws \stekycz\Cronner\Exceptions\InvalidArgumentException */ @@ -137,6 +121,7 @@ class CronnerTest extends \TestCase $this->cronner->addTasks($tasks); } + public function testProcessesAllAddedTasks() { $now = new DateTime('2013-02-04 09:30:00'); @@ -150,6 +135,7 @@ class CronnerTest extends \TestCase $this->cronner->run($now); } + public function testCanSetOnTaskBeginCallback() { $this->cronner->onTaskBegin[] = function (Cronner $cronner, Task $task) { @@ -158,6 +144,7 @@ class CronnerTest extends \TestCase Assert::equal(1, count($this->cronner->onTaskBegin)); } + public function testCanSetOnTaskFinishedCallback() { $this->cronner->onTaskFinished[] = function (Cronner $cronner, Task $task) { @@ -166,6 +153,7 @@ class CronnerTest extends \TestCase Assert::equal(1, count($this->cronner->onTaskFinished)); } + public function testCanSetOnTaskErrorCallback() { $this->cronner->onTaskError[] = function (Cronner $cronner, Exception $e, Task $task) { @@ -174,12 +162,13 @@ class CronnerTest extends \TestCase Assert::equal(1, count($this->cronner->onTaskError)); } + public function testIsAbleToContinueWithNextTaskWhenOneTaskThrowException() { $now = new DateTime('2013-02-04 09:30:00'); $logCallback = Mockery::mock(stdClass::class); - $logCallback->shouldReceive('logError')->once()->andReturnUsing( function (Exception $e, Task $task) { + $logCallback->shouldReceive('logError')->once()->andReturnUsing(function (Exception $e, Task $task) { Assert::equal('Test 01', $e->getMessage()); }); $logCallback->shouldReceive('logBegin')->twice(); @@ -201,6 +190,7 @@ class CronnerTest extends \TestCase $this->cronner->run($now); } + public function testAddingTwoTestsWithTheSameNameInOneObject() { $cronner = $this->cronner; @@ -209,6 +199,7 @@ class CronnerTest extends \TestCase }, DuplicateTaskNameException::class); } + public function testAddingTwoTestsWithTheSameNameInMoreObjects() { $cronner = $this->cronner; @@ -218,6 +209,26 @@ class CronnerTest extends \TestCase }, DuplicateTaskNameException::class); } + + protected function setUp() + { + parent::setUp(); + $timestampStorage = Mockery::mock(ITimestampStorage::class); + $timestampStorage->shouldReceive('setTaskName'); + $timestampStorage->shouldReceive('saveRunTime'); + $timestampStorage->shouldReceive('loadLastRunTime')->andReturn(new DateTime('2013-02-04 08:00:00')); + $this->timestampStorage = $timestampStorage; + + $criticalSection = Mockery::mock(ICriticalSection::class); + $criticalSection->shouldReceive("enter")->andReturn(true); + $criticalSection->shouldReceive("leave")->andReturn(true); + $criticalSection->shouldReceive("isEntered")->andReturn(false); + + $this->cronner = new Cronner($this->timestampStorage, $criticalSection); + $this->cronner->onTaskBegin = []; + $this->cronner->onTaskFinished = []; + $this->cronner->onTaskError = []; + } } run(new CronnerTest()); diff --git a/tests/CronnerTests/DI/CronnerExtension.phpt b/tests/CronnerTests/DI/CronnerExtension.phpt index aaccfb5..d4c7c77 100644 --- a/tests/CronnerTests/DI/CronnerExtension.phpt +++ b/tests/CronnerTests/DI/CronnerExtension.phpt @@ -6,10 +6,10 @@ namespace stekycz\Cronner\tests\DI; + +use Bileto\CriticalSection\CriticalSection; use Nette\Configurator; use Nette\DI\Compiler; -use Nette\DI\Statement; -use Bileto\CriticalSection\CriticalSection; use stekycz\Cronner\Cronner; use stekycz\Cronner\DI\CronnerExtension; use stekycz\Cronner\TimestampStorage\DummyStorage; @@ -21,26 +21,9 @@ require_once(__DIR__ . "/../bootstrap.php"); class CronnerExtensionTest extends \TestCase { - /** - * @var Compiler - */ + /** @var Compiler */ private $compiler; - protected function setUp() - { - parent::setUp(); - $this->compiler = new Compiler(); - $this->compiler->addConfig([ - 'parameters' => [ - 'appDir' => __DIR__ . '/../..', - 'wwwDir' => __DIR__ . '/../..', - 'tempDir' => TEMP_DIR, - 'debugMode' => FALSE, - 'productionMode' => TRUE, - ], - ]); - $this->compiler->addExtension('cronner', new CronnerExtension()); - } public function testDefaultConfiguration() { @@ -51,19 +34,21 @@ class CronnerExtensionTest extends \TestCase $criticalSection = $compiler->getContainerBuilder()->getDefinition('cronner.criticalSection'); $runner = $compiler->getContainerBuilder()->getDefinition('cronner.runner'); - Assert::same(FileStorage::class, $timestampStorage->getClass()); - Assert::same(CriticalSection::class, $criticalSection->getClass()); - Assert::same(Cronner::class, $runner->getClass()); + Assert::same(FileStorage::class, $timestampStorage->getType()); + Assert::same(CriticalSection::class, $criticalSection->getType()); + Assert::same(Cronner::class, $runner->getType()); } + public function testCompleteConfiguration() { $compiler = $this->compiler; + $compiler->getContainerBuilder()->addDefinition('cronner.dummyStorage')->setFactory(DummyStorage::class); $compiler->addConfig([ 'cronner' => [ - 'timestampStorage' => new Statement(DummyStorage::class), + 'timestampStorage' => DummyStorage::class, 'maxExecutionTime' => 120, - 'criticalSectionTempDir' => '%tempDir%/cronner', + 'criticalSectionTempDir' => __DIR__ . '../../tmp/cronner', ], ]); $compiler->compile(); @@ -72,11 +57,12 @@ class CronnerExtensionTest extends \TestCase $criticalSection = $compiler->getContainerBuilder()->getDefinition('cronner.criticalSection'); $runner = $compiler->getContainerBuilder()->getDefinition('cronner.runner'); - Assert::same(DummyStorage::class, $timestampStorage->getClass()); - Assert::same(CriticalSection::class, $criticalSection->getClass()); - Assert::same(Cronner::class, $runner->getClass()); + Assert::same(DummyStorage::class, $timestampStorage->getType()); + Assert::same(CriticalSection::class, $criticalSection->getType()); + Assert::same(Cronner::class, $runner->getType()); } + public function testRegisterTasks() { \Tester\Helpers::purge(__DIR__ . '/../../tmp/'); @@ -91,6 +77,22 @@ class CronnerExtensionTest extends \TestCase Assert::same(2, count($cronner->getTasks())); } + + protected function setUp() + { + parent::setUp(); + $this->compiler = new Compiler(); + $this->compiler->addConfig([ + 'parameters' => [ + 'appDir' => __DIR__ . '/../..', + 'wwwDir' => __DIR__ . '/../..', + 'tempDir' => TEMP_DIR, + 'debugMode' => false, + 'productionMode' => true, + ], + ]); + $this->compiler->addExtension('cronner', new CronnerExtension()); + } } run(new CronnerExtensionTest()); diff --git a/tests/CronnerTests/Tasks/Parameters.phpt b/tests/CronnerTests/Tasks/Parameters.phpt index 42af0ae..c8459f2 100644 --- a/tests/CronnerTests/Tasks/Parameters.phpt +++ b/tests/CronnerTests/Tasks/Parameters.phpt @@ -8,6 +8,7 @@ declare(strict_types=1); namespace stekycz\Cronner\tests\Tasks; + use DateTime; use DateTimeInterface; use Nette; @@ -30,21 +31,23 @@ class ParametersTest extends \TestCase Assert::equal($expected, $params->getName()); } - public function dataProviderGetName() : array + + public function dataProviderGetName(): array { return [ ['Name of task', [Parameters::TASK => 'Name of task',]], ['0', [Parameters::TASK => '0',]], ['', [Parameters::TASK => ' ',]], ['', [Parameters::TASK => '',]], - ['', [Parameters::TASK => TRUE,]], - ['', [Parameters::TASK => FALSE,]], - ['', [Parameters::TASK => NULL,]], + ['', [Parameters::TASK => true,]], + ['', [Parameters::TASK => false,]], + ['', [Parameters::TASK => null,]], ['', [Parameters::TASK => 0,]], ['', []], ]; } + /** * @dataProvider dataProviderIsTask * @param bool $expected @@ -56,21 +59,23 @@ class ParametersTest extends \TestCase Assert::equal($expected, $params->isTask()); } - public function dataProviderIsTask() : array + + public function dataProviderIsTask(): array { return [ - [TRUE, [Parameters::TASK => 'Name of task',]], - [TRUE, [Parameters::TASK => '0',]], - [FALSE, [Parameters::TASK => ' ',]], - [FALSE, [Parameters::TASK => '',]], - [FALSE, [Parameters::TASK => TRUE,]], - [FALSE, [Parameters::TASK => FALSE,]], - [FALSE, [Parameters::TASK => NULL,]], - [FALSE, [Parameters::TASK => 0,]], - [FALSE, []], + [true, [Parameters::TASK => 'Name of task',]], + [true, [Parameters::TASK => '0',]], + [false, [Parameters::TASK => ' ',]], + [false, [Parameters::TASK => '',]], + [false, [Parameters::TASK => true,]], + [false, [Parameters::TASK => false,]], + [false, [Parameters::TASK => null,]], + [false, [Parameters::TASK => 0,]], + [false, []], ]; } + /** * @dataProvider dataProviderIsNextPeriod * @param bool $expected @@ -78,84 +83,86 @@ class ParametersTest extends \TestCase * @param DateTimeInterface|null $lastRunTime * @param array $parameters */ - public function testDetectsIfNowIsInNextPeriod(bool $expected, DateTimeInterface $now, DateTimeInterface $lastRunTime = NULL, array $parameters) + public function testDetectsIfNowIsInNextPeriod(bool $expected, DateTimeInterface $now, DateTimeInterface $lastRunTime = null, array $parameters) { $params = new Parameters($parameters); Assert::same($expected, $params->isNextPeriod($now, $lastRunTime)); } - public function dataProviderIsNextPeriod() : array + + public function dataProviderIsNextPeriod(): array { return [ [ - TRUE, + true, new \DateTimeImmutable('2013-02-03 17:00:00'), new \DateTimeImmutable('2013-02-03 16:54:59'), [Parameters::PERIOD => '5 minutes',], ], [ - TRUE, + true, new Nette\Utils\DateTime('2013-02-03 17:00:00'), new Nette\Utils\DateTime('2013-02-03 16:54:59'), [Parameters::PERIOD => '5 minutes',], ], [ - TRUE, + true, new Nette\Utils\DateTime('2013-02-03 17:00:00'), new Nette\Utils\DateTime('2013-02-03 16:55:00'), [Parameters::PERIOD => '5 minutes',], ], [ - TRUE, + true, new Nette\Utils\DateTime('2013-02-03 17:00:00'), new Nette\Utils\DateTime('2013-02-03 16:55:01'), [Parameters::PERIOD => '5 minutes',], ], [ - TRUE, + true, new Nette\Utils\DateTime('2013-02-03 17:00:00'), new Nette\Utils\DateTime('2013-02-03 16:55:05'), [Parameters::PERIOD => '5 minutes',], ], [ - FALSE, + false, new Nette\Utils\DateTime('2013-02-03 17:00:00'), new Nette\Utils\DateTime('2013-02-03 16:55:06'), [Parameters::PERIOD => '5 minutes',], ], [ - FALSE, + false, new Nette\Utils\DateTime('2013-02-03 17:00:00'), new Nette\Utils\DateTime('2013-02-03 16:55:01'), [Parameters::PERIOD => '1 hour',], ], [ - TRUE, + true, new Nette\Utils\DateTime('2013-02-03 17:00:00'), new Nette\Utils\DateTime('2013-02-03 16:00:00'), [Parameters::PERIOD => '1 hour',], ], [ - TRUE, + true, new Nette\Utils\DateTime('2013-02-03 17:00:00'), new Nette\Utils\DateTime('2013-02-03 16:00:00'), [], ], [ - TRUE, + true, new Nette\Utils\DateTime('2013-02-03 17:00:00'), - NULL, + null, [Parameters::PERIOD => '1 hour',], ], [ - TRUE, + true, new Nette\Utils\DateTime('2013-02-03 17:00:00'), - NULL, + null, [], ], ]; } + /** * @dataProvider dataProviderIsInDay * @param bool $expected @@ -168,43 +175,45 @@ class ParametersTest extends \TestCase Assert::equal($expected, $params->isInDay($now)); } - public function dataProviderIsInDay() : array + + public function dataProviderIsInDay(): array { return [ // One day - [TRUE, [Parameters::DAYS => ['Mon',],], new Nette\Utils\DateTime('2013-02-11 12:34:56')], - [FALSE, [Parameters::DAYS => ['Mon',],], new Nette\Utils\DateTime('2013-02-12 12:34:56')], - [TRUE, [Parameters::DAYS => ['Tue',],], new Nette\Utils\DateTime('2013-02-12 12:34:56')], - [FALSE, [Parameters::DAYS => ['Tue',],], new Nette\Utils\DateTime('2013-02-13 12:34:56')], - [TRUE, [Parameters::DAYS => ['Wed',],], new Nette\Utils\DateTime('2013-02-13 12:34:56')], - [FALSE, [Parameters::DAYS => ['Wed',],], new Nette\Utils\DateTime('2013-02-14 12:34:56')], - [TRUE, [Parameters::DAYS => ['Thu',],], new Nette\Utils\DateTime('2013-02-14 12:34:56')], - [FALSE, [Parameters::DAYS => ['Thu',],], new Nette\Utils\DateTime('2013-02-15 12:34:56')], - [TRUE, [Parameters::DAYS => ['Fri',],], new Nette\Utils\DateTime('2013-02-15 12:34:56')], - [FALSE, [Parameters::DAYS => ['Fri',],], new Nette\Utils\DateTime('2013-02-16 12:34:56')], - [TRUE, [Parameters::DAYS => ['Sat',],], new Nette\Utils\DateTime('2013-02-16 12:34:56')], - [FALSE, [Parameters::DAYS => ['Sat',],], new Nette\Utils\DateTime('2013-02-17 12:34:56')], - [TRUE, [Parameters::DAYS => ['Sun',],], new Nette\Utils\DateTime('2013-02-17 12:34:56')], - [FALSE, [Parameters::DAYS => ['Sun',],], new Nette\Utils\DateTime('2013-02-18 12:34:56')], + [true, [Parameters::DAYS => ['Mon',],], new Nette\Utils\DateTime('2013-02-11 12:34:56')], + [false, [Parameters::DAYS => ['Mon',],], new Nette\Utils\DateTime('2013-02-12 12:34:56')], + [true, [Parameters::DAYS => ['Tue',],], new Nette\Utils\DateTime('2013-02-12 12:34:56')], + [false, [Parameters::DAYS => ['Tue',],], new Nette\Utils\DateTime('2013-02-13 12:34:56')], + [true, [Parameters::DAYS => ['Wed',],], new Nette\Utils\DateTime('2013-02-13 12:34:56')], + [false, [Parameters::DAYS => ['Wed',],], new Nette\Utils\DateTime('2013-02-14 12:34:56')], + [true, [Parameters::DAYS => ['Thu',],], new Nette\Utils\DateTime('2013-02-14 12:34:56')], + [false, [Parameters::DAYS => ['Thu',],], new Nette\Utils\DateTime('2013-02-15 12:34:56')], + [true, [Parameters::DAYS => ['Fri',],], new Nette\Utils\DateTime('2013-02-15 12:34:56')], + [false, [Parameters::DAYS => ['Fri',],], new Nette\Utils\DateTime('2013-02-16 12:34:56')], + [true, [Parameters::DAYS => ['Sat',],], new Nette\Utils\DateTime('2013-02-16 12:34:56')], + [false, [Parameters::DAYS => ['Sat',],], new Nette\Utils\DateTime('2013-02-17 12:34:56')], + [true, [Parameters::DAYS => ['Sun',],], new Nette\Utils\DateTime('2013-02-17 12:34:56')], + [false, [Parameters::DAYS => ['Sun',],], new Nette\Utils\DateTime('2013-02-18 12:34:56')], // Empty days - [FALSE, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-11 12:34:56')], - [FALSE, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-12 12:34:56')], - [FALSE, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-13 12:34:56')], - [FALSE, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-14 12:34:56')], - [FALSE, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-15 12:34:56')], - [FALSE, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-16 12:34:56')], - [FALSE, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-17 12:34:56')], + [false, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-11 12:34:56')], + [false, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-12 12:34:56')], + [false, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-13 12:34:56')], + [false, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-14 12:34:56')], + [false, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-15 12:34:56')], + [false, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-16 12:34:56')], + [false, [Parameters::DAYS => [],], new Nette\Utils\DateTime('2013-02-17 12:34:56')], // Without days - [TRUE, [Parameters::DAYS => NULL,], new Nette\Utils\DateTime('2013-02-11 12:34:56')], - [TRUE, [Parameters::DAYS => NULL,], new Nette\Utils\DateTime('2013-02-12 12:34:56')], - [TRUE, [Parameters::DAYS => NULL,], new Nette\Utils\DateTime('2013-02-13 12:34:56')], - [TRUE, [Parameters::DAYS => NULL,], new Nette\Utils\DateTime('2013-02-14 12:34:56')], - [TRUE, [Parameters::DAYS => NULL,], new Nette\Utils\DateTime('2013-02-15 12:34:56')], - [TRUE, [Parameters::DAYS => NULL,], new Nette\Utils\DateTime('2013-02-16 12:34:56')], - [TRUE, [Parameters::DAYS => NULL,], new Nette\Utils\DateTime('2013-02-17 12:34:56')], + [true, [Parameters::DAYS => null,], new Nette\Utils\DateTime('2013-02-11 12:34:56')], + [true, [Parameters::DAYS => null,], new Nette\Utils\DateTime('2013-02-12 12:34:56')], + [true, [Parameters::DAYS => null,], new Nette\Utils\DateTime('2013-02-13 12:34:56')], + [true, [Parameters::DAYS => null,], new Nette\Utils\DateTime('2013-02-14 12:34:56')], + [true, [Parameters::DAYS => null,], new Nette\Utils\DateTime('2013-02-15 12:34:56')], + [true, [Parameters::DAYS => null,], new Nette\Utils\DateTime('2013-02-16 12:34:56')], + [true, [Parameters::DAYS => null,], new Nette\Utils\DateTime('2013-02-17 12:34:56')], ]; } + /** * @dataProvider dataProviderIsInTime * @param bool $expected @@ -218,53 +227,54 @@ class ParametersTest extends \TestCase Assert::equal($expected, $params->isInTime($now)); } - public function dataProviderIsInTime() : array + + public function dataProviderIsInTime(): array { return [ // One minute [ - TRUE, + true, [ Parameters::TIME => [ [ 'from' => '11:00', - 'to' => NULL, + 'to' => null, ], ], ], '2013-02-11 11:00:00', ], [ - TRUE, + true, [ Parameters::TIME => [ [ 'from' => '11:00', - 'to' => NULL, + 'to' => null, ], ], ], '2013-02-11 11:00:59', ], [ - FALSE, + false, [ Parameters::TIME => [ [ 'from' => '11:00', - 'to' => NULL, + 'to' => null, ], ], ], '2013-02-11 10:59:59', ], [ - FALSE, + false, [ Parameters::TIME => [ [ 'from' => '11:00', - 'to' => NULL, + 'to' => null, ], ], ], @@ -272,7 +282,7 @@ class ParametersTest extends \TestCase ], // Range [ - TRUE, + true, [ Parameters::TIME => [ [ @@ -284,7 +294,7 @@ class ParametersTest extends \TestCase '2013-02-11 11:00:00', ], [ - TRUE, + true, [ Parameters::TIME => [ [ @@ -296,7 +306,7 @@ class ParametersTest extends \TestCase '2013-02-11 11:30:00', ], [ - TRUE, + true, [ Parameters::TIME => [ ['from' => '11:00', 'to' => '12:00',], @@ -305,7 +315,7 @@ class ParametersTest extends \TestCase '2013-02-11 12:00:59', ], [ - FALSE, + false, [ Parameters::TIME => [ ['from' => '11:00', 'to' => '12:00',], @@ -314,7 +324,7 @@ class ParametersTest extends \TestCase '2013-02-11 10:59:59', ], [ - FALSE, + false, [ Parameters::TIME => [ ['from' => '11:00', 'to' => '12:00',], @@ -324,13 +334,13 @@ class ParametersTest extends \TestCase ], // Empty [ - TRUE, + true, [Parameters::TIME => [],], '2013-02-11 12:00:00', ], [ - TRUE, - [Parameters::TIME => NULL,], + true, + [Parameters::TIME => null,], '2013-02-11 12:00:00', ], ]; diff --git a/tests/CronnerTests/Tasks/ParametersParsing.phpt b/tests/CronnerTests/Tasks/ParametersParsing.phpt index d5e6db3..ed9a67a 100644 --- a/tests/CronnerTests/Tasks/ParametersParsing.phpt +++ b/tests/CronnerTests/Tasks/ParametersParsing.phpt @@ -8,26 +8,20 @@ declare(strict_types=1); namespace stekycz\Cronner\tests\Tasks; + +use DateTime; use stekycz\Cronner\Tasks\Parameters; use stekycz\Cronner\tests\objects\TestObject; use Tester\Assert; -use DateTime; require_once(__DIR__ . "/../bootstrap.php"); class ParametersParsingTest extends \TestCase { - /** - * @var object - */ + /** @var object */ private $object; - protected function setUp() - { - parent::setUp(); - $this->object = new TestObject(); - } /** * @dataProvider dataProviderParse @@ -42,7 +36,7 @@ class ParametersParsingTest extends \TestCase return; } - Assert::same($expected, + Assert::same($expected, Parameters::parseParameters( (new \Nette\Reflection\ClassType($this->object))->getMethod($methodName), new DateTime('NOW') @@ -50,16 +44,17 @@ class ParametersParsingTest extends \TestCase ); } - public function dataProviderParse() : array + + public function dataProviderParse(): array { return [ [ [ Parameters::TASK => 'E-mail notifications', Parameters::PERIOD => '5 minutes', - Parameters::DAYS => NULL, - Parameters::DAYS_OF_MONTH => NULL, - Parameters::TIME => NULL, + Parameters::DAYS => null, + Parameters::DAYS_OF_MONTH => null, + Parameters::TIME => null, ], 'test01', ], @@ -68,7 +63,7 @@ class ParametersParsingTest extends \TestCase Parameters::TASK => 'stekycz\Cronner\tests\objects\TestObject - test02', Parameters::PERIOD => '1 hour', Parameters::DAYS => ['Mon', 'Wed', 'Fri',], - Parameters::DAYS_OF_MONTH => NULL, + Parameters::DAYS_OF_MONTH => null, Parameters::TIME => [ [ 'from' => '09:00', @@ -87,7 +82,7 @@ class ParametersParsingTest extends \TestCase Parameters::TASK => 'Test 3', Parameters::PERIOD => '17 minutes', Parameters::DAYS => ['Mon', 'Tue', 'Wed', 'Thu', 'Fri',], - Parameters::DAYS_OF_MONTH => NULL, + Parameters::DAYS_OF_MONTH => null, Parameters::TIME => [ [ 'from' => '09:00', @@ -102,14 +97,21 @@ class ParametersParsingTest extends \TestCase Parameters::TASK => 'Test 4', Parameters::PERIOD => '1 day', Parameters::DAYS => ['Sat', 'Sun',], - Parameters::DAYS_OF_MONTH => NULL, - Parameters::TIME => NULL, + Parameters::DAYS_OF_MONTH => null, + Parameters::TIME => null, ], 'test04', ], ]; } + + protected function setUp() + { + parent::setUp(); + $this->object = new TestObject(); + } + } run(new ParametersParsingTest()); diff --git a/tests/CronnerTests/Tasks/Parser.phpt b/tests/CronnerTests/Tasks/Parser.phpt index c914ed1..3eb29a1 100644 --- a/tests/CronnerTests/Tasks/Parser.phpt +++ b/tests/CronnerTests/Tasks/Parser.phpt @@ -8,8 +8,8 @@ declare(strict_types=1); namespace stekycz\Cronner\tests\Tasks; + use stdClass; -use stekycz\Cronner\Exceptions\InvalidParameterException; use stekycz\Cronner\Tasks\Parser; use Tester\Assert; @@ -28,7 +28,8 @@ class ParserTest extends \TestCase Assert::equal($expected, Parser::parseName($annotation)); } - public function dataProviderParseName() : array + + public function dataProviderParseName(): array { return [ ['Testovací úkol', 'Testovací úkol'], @@ -37,14 +38,15 @@ class ParserTest extends \TestCase ['false', 'false'], ['0', '0'], ['1', '1'], - [NULL, TRUE], - [NULL, FALSE], - [NULL, 0], - [NULL, 1], - [NULL, new stdClass()], + [null, true], + [null, false], + [null, 0], + [null, 1], + [null, new stdClass()], ]; } + /** * @dataProvider dataProviderParsePeriod * @param string $expected @@ -55,7 +57,8 @@ class ParserTest extends \TestCase Assert::equal($expected, Parser::parsePeriod($annotation)); } - public function dataProviderParsePeriod() : array + + public function dataProviderParsePeriod(): array { return [ ['5 minutes', '5 minutes'], @@ -66,6 +69,7 @@ class ParserTest extends \TestCase ]; } + /** * @dataProvider dataProviderParsePeriodError * @param string $annotation @@ -76,7 +80,8 @@ class ParserTest extends \TestCase Parser::parsePeriod($annotation); } - public function dataProviderParsePeriodError() : array + + public function dataProviderParsePeriodError(): array { return [ ['nejaky blabol'], @@ -87,6 +92,7 @@ class ParserTest extends \TestCase ]; } + /** * @dataProvider dataProviderParseDays * @param string[] $expected @@ -97,7 +103,8 @@ class ParserTest extends \TestCase Assert::equal($expected, Parser::parseDays($annotation)); } - public function dataProviderParseDays() : array + + public function dataProviderParseDays(): array { return [ // Regular and simple values @@ -130,6 +137,7 @@ class ParserTest extends \TestCase ]; } + /** * @dataProvider dataProviderParseDaysError * @param string $annotation @@ -140,7 +148,8 @@ class ParserTest extends \TestCase Parser::parseDays($annotation); } - public function dataProviderParseDaysError() : array + + public function dataProviderParseDaysError(): array { return [ ['nejaky blabol'], @@ -151,6 +160,7 @@ class ParserTest extends \TestCase ]; } + /** * @dataProvider dataProviderParseTimes * @param string[][] $expected @@ -161,7 +171,8 @@ class ParserTest extends \TestCase Assert::equal($expected, Parser::parseTimes($annotation)); } - public function dataProviderParseTimes() : array + + public function dataProviderParseTimes(): array { return [ // Basic @@ -169,7 +180,7 @@ class ParserTest extends \TestCase [ [ 'from' => '11:00', - 'to' => NULL, + 'to' => null, ], ], '11:00', @@ -188,11 +199,11 @@ class ParserTest extends \TestCase [ [ 'from' => '11:00', - 'to' => NULL, + 'to' => null, ], [ 'from' => '17:00', - 'to' => NULL, + 'to' => null, ], ], '11:00, 17:00', @@ -358,6 +369,7 @@ class ParserTest extends \TestCase ]; } + /** * @dataProvider dataProviderParseTimesError * @param string $annotation @@ -368,7 +380,8 @@ class ParserTest extends \TestCase Parser::parseTimes($annotation); } - public function dataProviderParseTimesError() : array + + public function dataProviderParseTimesError(): array { return [ ['nejaky blabol'], @@ -378,7 +391,6 @@ class ParserTest extends \TestCase ['1'], ]; } - } run(new ParserTest()); diff --git a/tests/CronnerTests/Tasks/Task.phpt b/tests/CronnerTests/Tasks/Task.phpt index b09c734..08dccf0 100644 --- a/tests/CronnerTests/Tasks/Task.phpt +++ b/tests/CronnerTests/Tasks/Task.phpt @@ -8,6 +8,7 @@ declare(strict_types=1); namespace stekycz\Cronner\tests\Tasks; + use Mockery; use Nette; use Nette\Reflection\Method; @@ -21,16 +22,9 @@ require_once(__DIR__ . "/../bootstrap.php"); class TaskTest extends \TestCase { - /** - * @var object - */ + /** @var object */ private $object; - protected function setUp() - { - parent::setUp(); - $this->object = new TestObject(); - } public function testInvokesTaskWithSavingLastRunTime() { @@ -45,6 +39,7 @@ class TaskTest extends \TestCase Assert::$counter++; // Hack for nette tester } + /** * @dataProvider dataProviderShouldBeRun * @param bool $expected @@ -53,10 +48,10 @@ class TaskTest extends \TestCase * @param string $now * @param string|null $lastRunTime */ - public function testChecksIfCanBeRun(bool $expected, int $loads, string $methodName, string $now, string $lastRunTime = NULL) + public function testChecksIfCanBeRun(bool $expected, int $loads, string $methodName, string $now, string $lastRunTime = null) { $now = new Nette\Utils\DateTime($now); - $lastRunTime = $lastRunTime ? new Nette\Utils\DateTime($lastRunTime) : NULL; + $lastRunTime = $lastRunTime ? new Nette\Utils\DateTime($lastRunTime) : null; $method = (new \Nette\Reflection\ClassType($this->object))->getMethod($methodName); @@ -68,22 +63,24 @@ class TaskTest extends \TestCase Assert::same($expected, $task->shouldBeRun($now)); } - public function dataProviderShouldBeRun() : array + + public function dataProviderShouldBeRun(): array { return [ // Test 01 - [TRUE, 1, 'test01', '2013-02-01 12:00:00', NULL], - [TRUE, 1, 'test01', '2013-02-01 12:10:00', '2013-02-01 12:00:00'], - [FALSE, 1, 'test01', '2013-02-01 12:04:00', '2013-02-01 12:00:00'], + [true, 1, 'test01', '2013-02-01 12:00:00', null], + [true, 1, 'test01', '2013-02-01 12:10:00', '2013-02-01 12:00:00'], + [false, 1, 'test01', '2013-02-01 12:04:00', '2013-02-01 12:00:00'], // Test 02 - [FALSE, 0, 'test02', '2013-02-05 12:00:00', NULL], - [FALSE, 0, 'test02', '2013-02-04 12:00:00', NULL], - [FALSE, 1, 'test02', '2013-02-04 09:30:00', '2013-02-04 09:00:00'], - [TRUE, 1, 'test02', '2013-02-04 09:30:00', NULL], - [TRUE, 1, 'test02', '2013-02-04 09:30:00', '2013-02-03 15:30:00'], + [false, 0, 'test02', '2013-02-05 12:00:00', null], + [false, 0, 'test02', '2013-02-04 12:00:00', null], + [false, 1, 'test02', '2013-02-04 09:30:00', '2013-02-04 09:00:00'], + [true, 1, 'test02', '2013-02-04 09:30:00', null], + [true, 1, 'test02', '2013-02-04 09:30:00', '2013-02-03 15:30:00'], ]; } + public function testShouldBeRunOnShortLaterRun() { $timestampStorage = Mockery::mock(ITimestampStorage::class); @@ -95,6 +92,12 @@ class TaskTest extends \TestCase Assert::true($task->shouldBeRun(new Nette\Utils\DateTime('2014-08-15 09:17:00'))); } + + protected function setUp() + { + parent::setUp(); + $this->object = new TestObject(); + } } run(new TaskTest()); diff --git a/tests/CronnerTests/TimestampStorage/FileStorage.phpt b/tests/CronnerTests/TimestampStorage/FileStorage.phpt index 8fd3aed..cb18ae7 100644 --- a/tests/CronnerTests/TimestampStorage/FileStorage.phpt +++ b/tests/CronnerTests/TimestampStorage/FileStorage.phpt @@ -8,11 +8,10 @@ declare(strict_types=1); namespace stekycz\Cronner\tests\TimestampStorage; + use DateTime; use Nette; use Nette\Utils\FileSystem; -use stdClass; -use stekycz\Cronner\Exceptions\InvalidTaskNameException; use stekycz\Cronner\TimestampStorage\FileStorage; use Tester\Assert; @@ -21,53 +20,43 @@ require_once(__DIR__ . "/../bootstrap.php"); class FileStorageTest extends \TestCase { - /** - * @var FileStorage - */ + /** @var FileStorage */ private $storage; - protected function setUp() - { - parent::setUp(); - FileSystem::createDir(static::getTempDirPath()); - $this->storage = new FileStorage(static::getTempDirPath()); - } - - protected function tearDown() - { - parent::tearDown(); - FileSystem::delete(static::getTempDirPath()); - } private static function getTempDirPath() { return TEMP_DIR . '/cronner'; } + public function testIsAbleToSetTaskName() { $this->storage->setTaskName('Test task 1'); - $this->storage->setTaskName(NULL); + $this->storage->setTaskName(null); $this->storage->setTaskName(); Assert::$counter++; // Hack for nette tester } + /** * @dataProvider dataProviderSetTaskName * @throws \stekycz\Cronner\Exceptions\InvalidTaskNameException */ - public function testThrowsExceptionOnInvalidTaskName(string $taskName = NULL) + public function testThrowsExceptionOnInvalidTaskName(string $taskName = null) { $this->storage->setTaskName($taskName); } - public function dataProviderSetTaskName() : array + + public function dataProviderSetTaskName(): array { return [ [''], ]; } + /** * Tests that saving do not throws any exception. * @@ -89,7 +78,8 @@ class FileStorageTest extends \TestCase Assert::equal($date->format('Y-m-d H:i:s O'), $lastRunTime->format('Y-m-d H:i:s O')); } - public function dataProviderSaveRunTime() : array + + public function dataProviderSaveRunTime(): array { return [ [new Nette\Utils\DateTime('2013-01-30 17:30:00')], @@ -98,6 +88,7 @@ class FileStorageTest extends \TestCase ]; } + public function testSavesLastRunTimeByTaskName() { $date = new DateTime('2013-01-30 17:30:00'); @@ -125,6 +116,23 @@ class FileStorageTest extends \TestCase Assert::equal($date->format('Y-m-d H:i:s O'), $lastRunTime->format('Y-m-d H:i:s O')); } + + protected function setUp() + { + parent::setUp(); + FileSystem::createDir(static::getTempDirPath()); + $this->storage = new FileStorage(static::getTempDirPath()); + } + + + protected function tearDown() + { + parent::tearDown(); + try { + FileSystem::delete(static::getTempDirPath()); + } catch (Nette\IOException $e) { + } + } } run(new FileStorageTest()); diff --git a/tests/CronnerTests/bootstrap.php b/tests/CronnerTests/bootstrap.php index 1dfe91b..3a45873 100644 --- a/tests/CronnerTests/bootstrap.php +++ b/tests/CronnerTests/bootstrap.php @@ -10,17 +10,15 @@ function run(Tester\TestCase $testCase) { - $testCase->run(isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : NULL); + $testCase->run(isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : null); } abstract class TestCase extends Tester\TestCase { - protected function tearDown() { Mockery::close(); } - } return $autoloader; diff --git a/tests/CronnerTests/config/config.neon b/tests/CronnerTests/config/config.neon index 0e7b24a..61ccc13 100644 --- a/tests/CronnerTests/config/config.neon +++ b/tests/CronnerTests/config/config.neon @@ -4,7 +4,6 @@ extensions: services: fooService: stekycz\Cronner\tests\objects\FooService - cronner: tasks: - stekycz\Cronner\tests\objects\SimpleTestObjectWithDependency(@fooService) diff --git a/tests/CronnerTests/objects/AnotherSimpleTestObject.php b/tests/CronnerTests/objects/AnotherSimpleTestObject.php index 1b1b5d5..16e8ba7 100644 --- a/tests/CronnerTests/objects/AnotherSimpleTestObject.php +++ b/tests/CronnerTests/objects/AnotherSimpleTestObject.php @@ -4,15 +4,16 @@ namespace stekycz\Cronner\tests\objects; + class AnotherSimpleTestObject { use \Nette\SmartObject; + /** * @cronner-task Test */ public function test01() { } - } diff --git a/tests/CronnerTests/objects/AnotherSimpleTestObjectWithDependency.php b/tests/CronnerTests/objects/AnotherSimpleTestObjectWithDependency.php index 208a689..8aa5048 100644 --- a/tests/CronnerTests/objects/AnotherSimpleTestObjectWithDependency.php +++ b/tests/CronnerTests/objects/AnotherSimpleTestObjectWithDependency.php @@ -2,13 +2,14 @@ namespace stekycz\Cronner\tests\objects; + class AnotherSimpleTestObjectWithDependency { - public function __construct(FooService $service) { } + /** * @cronner-task */ diff --git a/tests/CronnerTests/objects/FooService.php b/tests/CronnerTests/objects/FooService.php index 425a143..f2397e4 100644 --- a/tests/CronnerTests/objects/FooService.php +++ b/tests/CronnerTests/objects/FooService.php @@ -2,12 +2,11 @@ namespace stekycz\Cronner\tests\objects; + class FooService { - public function __construct() { } - } diff --git a/tests/CronnerTests/objects/NextSimpleTestObject.php b/tests/CronnerTests/objects/NextSimpleTestObject.php index 84e1cc7..cf27d11 100644 --- a/tests/CronnerTests/objects/NextSimpleTestObject.php +++ b/tests/CronnerTests/objects/NextSimpleTestObject.php @@ -4,15 +4,16 @@ namespace stekycz\Cronner\tests\objects; + class NextSimpleTestObject { use \Nette\SmartObject; + /** * @cronner-task Test */ public function test01() { } - } diff --git a/tests/CronnerTests/objects/SameTaskNameObject.php b/tests/CronnerTests/objects/SameTaskNameObject.php index 03c4b45..7d340f1 100644 --- a/tests/CronnerTests/objects/SameTaskNameObject.php +++ b/tests/CronnerTests/objects/SameTaskNameObject.php @@ -4,10 +4,12 @@ namespace stekycz\Cronner\tests\objects; + class SameTaskNameObject { use \Nette\SmartObject; + /** * @cronner-task Test */ @@ -15,11 +17,11 @@ public function test01() { } + /** * @cronner-task Test */ public function test02() { } - } diff --git a/tests/CronnerTests/objects/SimpleTestObjectWithDependency.php b/tests/CronnerTests/objects/SimpleTestObjectWithDependency.php index ed639b6..d795163 100644 --- a/tests/CronnerTests/objects/SimpleTestObjectWithDependency.php +++ b/tests/CronnerTests/objects/SimpleTestObjectWithDependency.php @@ -2,9 +2,9 @@ namespace stekycz\Cronner\tests\objects; + class SimpleTestObjectWithDependency { - public function __construct(FooService $service) { } @@ -16,4 +16,3 @@ public function run() { } } - diff --git a/tests/CronnerTests/objects/TestExceptionObject.php b/tests/CronnerTests/objects/TestExceptionObject.php index 661e3cc..e4207e0 100644 --- a/tests/CronnerTests/objects/TestExceptionObject.php +++ b/tests/CronnerTests/objects/TestExceptionObject.php @@ -4,12 +4,14 @@ namespace stekycz\Cronner\tests\objects; + use Exception; class TestExceptionObject { use \Nette\SmartObject; + /** * @cronner-task * @cronner-period 5 minutes @@ -19,6 +21,7 @@ public function test01() throw new Exception('Test 01'); } + /** * @cronner-task * @cronner-period 5 minutes @@ -26,5 +29,4 @@ public function test01() public function test02() { } - } diff --git a/tests/CronnerTests/objects/TestObject.php b/tests/CronnerTests/objects/TestObject.php index 648c05d..7dfcdc8 100644 --- a/tests/CronnerTests/objects/TestObject.php +++ b/tests/CronnerTests/objects/TestObject.php @@ -4,10 +4,12 @@ namespace stekycz\Cronner\tests\objects; + class TestObject { use \Nette\SmartObject; + /** * @cronner-task * @cronner-period 1 day @@ -16,6 +18,7 @@ public function __construct() { } + /** * @cronner-task E-mail notifications * @cronner-period 5 minutes @@ -24,6 +27,7 @@ public function test01() { } + /** * @cronner-task * @cronner-period 1 hour @@ -34,6 +38,7 @@ public function test02() { } + /** * @cronner-task Test 3 * @cronner-period 17 minutes @@ -44,6 +49,7 @@ public function test03() { } + /** * @cronner-task Test 4 * @cronner-period 1 day @@ -52,5 +58,4 @@ public function test03() public function test04() { } - }