From dc0869fc124185c29b05569f9ffa85d26a43288c Mon Sep 17 00:00:00 2001 From: "Eloy Lafuente (stronk7)" Date: Sat, 24 Jun 2023 19:28:51 +0200 Subject: [PATCH 1/2] MDL-78570 behat: Remove the skip-passed legacy option This option (--skip-passed) was implemented because of some bugs in the initial versions of Behat 3 with the --rerun option. After Behat 3.2.0 those bugs were fixed and we switched back to use the upstream --rerun option, abandoning --skip-passed. More yet, this option wasn't ever documented much, neither in docs or cli. So it's time to remove it, one less thing to maintain for nothing. Note that this commit is a 99.99% revert of the original one that was applied to the moodle-behat-extension (now in core): https://github.com/moodlehq/moodle-behat-extension/commit/c4b25158d212509b --- .../FilesystemSkipPassedListLocator.php | 106 ---------- .../ServiceContainer/BehatExtension.php | 48 ----- .../Tester/Cli/SkipPassedController.php | 196 ------------------ 3 files changed, 350 deletions(-) delete mode 100644 lib/behat/extension/Moodle/BehatExtension/Locator/FilesystemSkipPassedListLocator.php delete mode 100644 lib/behat/extension/Moodle/BehatExtension/Tester/Cli/SkipPassedController.php diff --git a/lib/behat/extension/Moodle/BehatExtension/Locator/FilesystemSkipPassedListLocator.php b/lib/behat/extension/Moodle/BehatExtension/Locator/FilesystemSkipPassedListLocator.php deleted file mode 100644 index 933d8a25703..00000000000 --- a/lib/behat/extension/Moodle/BehatExtension/Locator/FilesystemSkipPassedListLocator.php +++ /dev/null @@ -1,106 +0,0 @@ -. - -namespace Moodle\BehatExtension\Locator; - -use Behat\Behat\Gherkin\Specification\LazyFeatureIterator; -use Behat\Gherkin\Gherkin; -use Behat\Testwork\Specification\Locator\SpecificationLocator; -use Behat\Testwork\Specification\NoSpecificationsIterator; -use Behat\Testwork\Suite\Suite; - -// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod - -/** - * Skips gherkin features using a file with the list of scenarios. - * - * @package core - * @copyright 2016 onwards Rajesh Taneja - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class FilesystemSkipPassedListLocator implements SpecificationLocator { - /** - * @var Gherkin - */ - private $gherkin; - - /** - * Initializes locator. - * - * @param Gherkin $gherkin - */ - public function __construct(Gherkin $gherkin) { - $this->gherkin = $gherkin; - } - - /** - * Returns array of strings representing examples of supported specification locators. - * - * @return string[] - */ - public function getLocatorExamples() { - return []; - } - - /** - * Locates specifications and wraps them into iterator. - * - * @param Suite $suite - * @param string $locator - * - * @return SpecificationIterator - */ - public function locateSpecifications(Suite $suite, $locator) { - if (!$locator || !is_file($locator) || 'passed' !== pathinfo($locator, PATHINFO_EXTENSION)) { - return new NoSpecificationsIterator($suite); - } - - $scenarios = json_decode(trim(file_get_contents($locator)), true); - if (empty($scenarios) || empty($scenarios[$suite->getName()])) { - return new NoSpecificationsIterator($suite); - } - - $suitepaths = $this->getSuitePaths($suite); - - $scenarios = array_diff($suitepaths, array_values($scenarios[$suite->getName()])); - - return new LazyFeatureIterator($suite, $this->gherkin, $scenarios); - } - - /** - * Returns array of feature paths configured for the provided suite. - * - * @param Suite $suite - * - * @return string[] - * - * @throws SuiteConfigurationException If `paths` setting is not an array - */ - private function getSuitePaths(Suite $suite) { - if (!is_array($suite->getSetting('paths'))) { - throw new SuiteConfigurationException( - sprintf( - '"paths" setting of the "%s" suite is expected to be an array, %s given.', - $suite->getName(), - gettype($suite->getSetting('paths')) - ), - $suite->getName() - ); - } - - return $suite->getSetting('paths'); - } -} diff --git a/lib/behat/extension/Moodle/BehatExtension/ServiceContainer/BehatExtension.php b/lib/behat/extension/Moodle/BehatExtension/ServiceContainer/BehatExtension.php index f7af26a63a3..c7cae1d81fe 100644 --- a/lib/behat/extension/Moodle/BehatExtension/ServiceContainer/BehatExtension.php +++ b/lib/behat/extension/Moodle/BehatExtension/ServiceContainer/BehatExtension.php @@ -25,7 +25,6 @@ use Behat\Testwork\Output\ServiceContainer\OutputExtension; use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface; use Behat\Testwork\ServiceContainer\ExtensionManager; use Behat\Testwork\ServiceContainer\ServiceProcessor; -use Behat\Testwork\Specification\ServiceContainer\SpecificationExtension; use Behat\Testwork\Suite\ServiceContainer\SuiteExtension; use Moodle\BehatExtension\Driver\WebDriverFactory; use Moodle\BehatExtension\Output\Formatter\MoodleProgressFormatterFactory; @@ -51,9 +50,6 @@ class BehatExtension implements ExtensionInterface { /** @var string Extension configuration ID */ const MOODLE_ID = 'moodle'; - /** @var string Gherkin ID */ - const GHERKIN_ID = 'gherkin'; - /** @var ServiceProcessor */ private $processor; @@ -100,10 +96,6 @@ class BehatExtension implements ExtensionInterface { // Load namespace alias. $this->alias_old_namespaces(); - - // Load skip passed controller and list locator. - $this->loadSkipPassedController($container, $config['passed_cache']); - $this->loadFilesystemSkipPassedScenariosListLocator($container); } /** @@ -166,38 +158,6 @@ class BehatExtension implements ExtensionInterface { ]); } - /** - * Loads skip passed controller. - * - * @param ContainerBuilder $container - * @param null|string $cachepath - */ - protected function loadSkipPassedController(ContainerBuilder $container, $cachepath) { - $definition = new Definition('Moodle\BehatExtension\Tester\Cli\SkipPassedController', [ - new Reference(EventDispatcherExtension::DISPATCHER_ID), - $cachepath, - $container->getParameter('paths.base') - ]); - $definition->addTag(CliExtension::CONTROLLER_TAG, ['priority' => 200]); - $container->setDefinition(CliExtension::CONTROLLER_TAG . '.passed', $definition); - } - - /** - * Loads filesystem passed scenarios list locator. - * - * @param ContainerBuilder $container - */ - private function loadFilesystemSkipPassedScenariosListLocator(ContainerBuilder $container) { - $definition = new Definition('Moodle\BehatExtension\Locator\FilesystemSkipPassedListLocator', [ - new Reference(self::GHERKIN_ID) - ]); - $definition->addTag(SpecificationExtension::LOCATOR_TAG, ['priority' => 50]); - $container->setDefinition( - SpecificationExtension::LOCATOR_TAG . '.filesystem_skip_passed_scenarios_list', - $definition - ); - } - /** * Loads definition printers. * @@ -277,14 +237,6 @@ class BehatExtension implements ExtensionInterface { ->scalarNode('moodledirroot') ->defaultNull() ->end() - ->scalarNode('passed_cache') - ->info('Sets the passed cache path') - ->defaultValue( - is_writable(sys_get_temp_dir()) - ? sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'behat_passed_cache' - : null - ) - ->end() ->end() ->end(); // phpcs:enable PEAR.WhiteSpace.ObjectOperatorIndent.Incorrect diff --git a/lib/behat/extension/Moodle/BehatExtension/Tester/Cli/SkipPassedController.php b/lib/behat/extension/Moodle/BehatExtension/Tester/Cli/SkipPassedController.php deleted file mode 100644 index 36f9a7d1c97..00000000000 --- a/lib/behat/extension/Moodle/BehatExtension/Tester/Cli/SkipPassedController.php +++ /dev/null @@ -1,196 +0,0 @@ -. - -namespace Moodle\BehatExtension\Tester\Cli; - -use Behat\Behat\EventDispatcher\Event\AfterScenarioTested; -use Behat\Behat\EventDispatcher\Event\ExampleTested; -use Behat\Behat\EventDispatcher\Event\ScenarioTested; -use Behat\Testwork\Cli\Controller; -use Behat\Testwork\EventDispatcher\Event\ExerciseCompleted; -use Behat\Testwork\Tester\Result\TestResult; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; - -// phpcs:disable moodle.NamingConventions.ValidFunctionName.LowercaseMethod - -/** - * Caches passed scenarios and skip only them if `--skip-passed` option provided. - * - * @package core - * @copyright 2016 onwards Rajesh Taneja - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class SkipPassedController implements Controller { - /** - * @var EventDispatcherInterface - */ - private $eventdispatcher; - - /** - * @var null|string - */ - private $cachepath; - - /** - * @var string - */ - private $key; - - /** - * @var string[] - */ - private $lines = []; - - /** - * @var string - */ - private $basepath; - - /** - * Initializes controller. - * - * @param EventDispatcherInterface $eventdispatcher - * @param null|string $cachepath - * @param string $basepath - */ - public function __construct(EventDispatcherInterface $eventdispatcher, $cachepath, $basepath) { - $this->eventdispatcher = $eventdispatcher; - $this->cachepath = null !== $cachepath ? rtrim($cachepath, DIRECTORY_SEPARATOR) : null; - $this->basepath = $basepath; - } - - /** - * Configures command to be executable by the controller. - * - * @param Command $command - */ - public function configure(Command $command) { - $command->addOption('--skip-passed', null, InputOption::VALUE_NONE, - 'Skip scenarios that passed during last execution.' - ); - } - - /** - * Executes controller. - * - * @param InputInterface $input - * @param OutputInterface $output - * - * @return null|integer - */ - public function execute(InputInterface $input, OutputInterface $output) { - if (!$input->getOption('skip-passed')) { - // If no skip option is passed then remove any old file which we are saving. - if (!$this->getFileName()) { - return; - } - if (file_exists($this->getFileName())) { - unlink($this->getFileName()); - } - return; - } - - $this->eventdispatcher->addListener(ScenarioTested::AFTER, [$this, 'collectPassedScenario'], -50); - $this->eventdispatcher->addListener(ExampleTested::AFTER, [$this, 'collectPassedScenario'], -50); - $this->eventdispatcher->addListener(ExerciseCompleted::AFTER, [$this, 'writeCache'], -50); - $this->key = $this->generateKey($input); - - if (!$this->getFileName() || !file_exists($this->getFileName())) { - return; - } - $input->setArgument('paths', $this->getFileName()); - - $existing = json_decode(file_get_contents($this->getFileName()), true); - if (!empty($existing)) { - $this->lines = array_merge_recursive($existing, $this->lines); - } - } - - /** - * Records scenario if it is passed. - * - * @param AfterScenarioTested $event - */ - public function collectPassedScenario(AfterScenarioTested $event) { - if (!$this->getFileName()) { - return; - } - - $feature = $event->getFeature(); - $suitename = $event->getSuite()->getName(); - - if ( - ($event->getTestResult()->getResultCode() !== TestResult::PASSED) && - ($event->getTestResult()->getResultCode() !== TestResult::SKIPPED) - ) { - unset($this->lines[$suitename][$feature->getFile()]); - return; - } - - $this->lines[$suitename][$feature->getFile()] = $feature->getFile(); - } - - /** - * Writes passed scenarios cache. - */ - public function writeCache() { - if (!$this->getFileName()) { - return; - } - if (0 === count($this->lines)) { - return; - } - file_put_contents($this->getFileName(), json_encode($this->lines)); - } - - /** - * Generates cache key. - * - * @param InputInterface $input - * - * @return string - */ - private function generateKey(InputInterface $input) { - return md5( - $input->getParameterOption(['--profile', '-p']) . - $input->getOption('suite') . - implode(' ', $input->getOption('name')) . - implode(' ', $input->getOption('tags')) . - $input->getOption('role') . - $input->getArgument('paths') . - $this->basepath - ); - } - - /** - * Returns cache filename (if exists). - * - * @return null|string - */ - private function getFileName() { - if (null === $this->cachepath || null === $this->key) { - return null; - } - if (!is_dir($this->cachepath)) { - mkdir($this->cachepath, 0777); - } - return $this->cachepath . DIRECTORY_SEPARATOR . $this->key . '.passed'; - } -} From 17bfc2ab0103d9864a2d9025b71e89aa20359274 Mon Sep 17 00:00:00 2001 From: "Eloy Lafuente (stronk7)" Date: Sat, 24 Jun 2023 19:58:06 +0200 Subject: [PATCH 2/2] MDL-78570 behat: Document the removal of the skip-passed option --- lib/upgrade.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/upgrade.txt b/lib/upgrade.txt index 333a6708329..218295eb42e 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -30,6 +30,8 @@ information provided here is intended especially for developers. - core_useragent::get_device_type_cfg_var_name() - theme_is_device_locked() - theme_get_locked_theme_for_device() +* Legacy (and custom) Behat --skip-passed option has been removed completely. Please, use the standard + --rerun option that provides exactly the same (execution of failed scenarios only). === 4.2 ===