diff --git a/README.md b/README.md index bc58be0..c6c90fe 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,25 @@ Pull requests should be made to the **develop** branch. - Source code: https://github.com/ixis/codeception-module-drupal-user-registry +## Creating or deleting users using the command line + +Once this module is installed in a Codeception test suite the following commands can be used to create and delete test users (from the root of the test suite): + + # Create test users for all defined roles. + vendor/bin/drupal-user-registry users:create + + # Delete test users for all defined roles. + vendor/bin/drupal-user-registry users:delete + +These commands will default to using the **acceptance** suite to determine the alias on which Drush will run from the suite's configuration. To run the commands using a suite other than **acceptance**, pass the suite name as an argument: + + # Create test users for all defined roles in the front-end suite configuration. + vendor/bin/drupal-user-registry users:create front-end + + # Delete test users for all defined roles in the front-end suite configuration. + vendor/bin/drupal-user-registry users:delete front-end + + ## Acknowledgements Thanks to [Andy Rigby](https://github.com/ixisandyr) for the storage code and inspiration. diff --git a/bin/drupal-user-registry b/bin/drupal-user-registry new file mode 100755 index 0000000..3465603 --- /dev/null +++ b/bin/drupal-user-registry @@ -0,0 +1,13 @@ +#!/usr/bin/env php +add(new CreateTestUsersCommand()); +$app->add(new DeleteTestUsersCommand()); +$app->run(); diff --git a/composer.json b/composer.json index f15c70d..8d8f8f9 100644 --- a/composer.json +++ b/composer.json @@ -31,5 +31,7 @@ "psr-4": { "Codeception\\Module\\": "src" } - } + }, + + "bin": ["bin/drupal-user-registry"] } diff --git a/src/Drupal/UserRegistry/Command/CreateTestUsersCommand.php b/src/Drupal/UserRegistry/Command/CreateTestUsersCommand.php new file mode 100644 index 0000000..f39aafe --- /dev/null +++ b/src/Drupal/UserRegistry/Command/CreateTestUsersCommand.php @@ -0,0 +1,61 @@ +setName('users:create') + ->setDescription('Create test users.') + ->addArgument( + 'suite', + InputArgument::OPTIONAL, + "Which suite configuration to use. Defaults to 'acceptance'." + ); + } + + /** + * Execute command: create any defined test users on the configured Drush alias. + * + * @todo Codeception debug calls won't work here. + * + * @param InputInterface $input + * The command input. + * + * @param OutputInterface $output + * The command output. + * + * @return int|null|void + * + * @throws ModuleException + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + // The suite name can be passed as an argument. Without it, the command defaults to 'acceptance'. + $suiteName = $input->getArgument('suite'); + if (!$suiteName) { + $suiteName = 'acceptance'; + } + + $this->getTestUsers($suiteName); + $this->testUserManager->createUsers($this->users); + } +} diff --git a/src/Drupal/UserRegistry/Command/DeleteTestUsersCommand.php b/src/Drupal/UserRegistry/Command/DeleteTestUsersCommand.php new file mode 100644 index 0000000..076b9d3 --- /dev/null +++ b/src/Drupal/UserRegistry/Command/DeleteTestUsersCommand.php @@ -0,0 +1,61 @@ +setName('users:delete') + ->setDescription('Delete test users.') + ->addArgument( + 'suite', + InputArgument::OPTIONAL, + "Which suite configuration to use. Defaults to 'acceptance'." + ); + } + + /** + * Execute command: create any defined test users on the configured Drush alias. + * + * @todo Codeception debug calls won't work here. + * + * @param InputInterface $input + * The command input. + * + * @param OutputInterface $output + * The command output. + * + * @return int|null|void + * + * @throws ModuleException + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + // The suite name can be passed as an argument. Without it, the command defaults to 'acceptance'. + $suiteName = $input->getArgument('suite'); + if (!$suiteName) { + $suiteName = 'acceptance'; + } + + $this->getTestUsers($suiteName); + $this->testUserManager->deleteUsers($this->users); + } +} diff --git a/src/Drupal/UserRegistry/Command/TestUsersCommandTrait.php b/src/Drupal/UserRegistry/Command/TestUsersCommandTrait.php new file mode 100644 index 0000000..d3e4f67 --- /dev/null +++ b/src/Drupal/UserRegistry/Command/TestUsersCommandTrait.php @@ -0,0 +1,56 @@ +users = $moduleConfigStorage->load(); + $this->testUserManager = new DrushTestUserManager($config, $moduleConfigStorage); + } +} diff --git a/tests/_support/FunctionalHelper.php b/tests/_support/FunctionalHelper.php index a69bccb..9cab964 100644 --- a/tests/_support/FunctionalHelper.php +++ b/tests/_support/FunctionalHelper.php @@ -2,6 +2,8 @@ namespace Codeception\Module; +use Codeception\Module\Drupal\UserRegistry\Storage\ModuleConfigStorage; + /** * Define custom actions for functional tests. * @@ -9,4 +11,21 @@ */ class FunctionalHelper extends \Codeception\Module { + /** + * Helper to translate role names to test usernames. + * + * @todo This code is copied from ModuleConfigStorage::load(), where it's a bit buried. Needs refactoring. + * + * @see ModuleConfigStorage::load() + * + * @param string $role + * The name of the role to translate into a test username. + * + * @return string + */ + public function getTestUsername($role) + { + $roleNameSuffix = preg_replace(ModuleConfigStorage::DRUPAL_ROLE_TO_USERNAME_PATTERN, ".", $role); + return ModuleConfigStorage::DRUPAL_USERNAME_PREFIX . "." . $roleNameSuffix; + } } diff --git a/tests/functional.suite.yml b/tests/functional.suite.yml index fe34ac5..820037e 100644 --- a/tests/functional.suite.yml +++ b/tests/functional.suite.yml @@ -3,7 +3,32 @@ # class_name: FunctionalTester modules: - enabled: [Db, FunctionalHelper] + enabled: [Asserts, Db, FunctionalHelper] + config: + # Used for command line tests. + DrupalUserRegistry: + defaultPass: "foobar" + users: + administrator: + name: test.administrator + email: test.administrator@example.com + pass: "foo" + roles: [ administrator, editor ] + root: true + editor: + name: test.editor + email: editor@example.com + roles: [ editor, moderator ] + moderator: + name: "test.moderator" + email: "sub.editor@example.com" + roles: [ moderator ] + authenticated: + name: authenticated + email: authenticated@example.com + roles: [ "authenticated user" ] + drush-alias: "@d7.local" + env: # Override Db module configuration to run on local. local: diff --git a/tests/functional/CommandCest.php b/tests/functional/CommandCest.php new file mode 100644 index 0000000..0989c36 --- /dev/null +++ b/tests/functional/CommandCest.php @@ -0,0 +1,89 @@ +app = new Application(); + $this->app->add(new CreateTestUsersCommand()); + $this->app->add(new DeleteTestUsersCommand()); + } + + /** + * Tear down any created console application. + * + * @param FunctionalTester $I + */ + public function _after(FunctionalTester $I) + { +// unset($this->app); + } + + /** + * @param FunctionalTester $I + */ + public function testCreateUsersCommand(FunctionalTester $I) + { + $command = $this->app->find("users:create"); + $tester = new \Symfony\Component\Console\Tester\CommandTester($command); + + $tester->execute( + array( + "command" => $command->getName(), + "suite" => "unit", + ) + ); + + // @todo Configs are a bit muxed ip... + $config = Fixtures::get("validModuleConfig"); + foreach ($config["users"] as $user => $userDetails) { + $I->seeInDatabase("users", array("name" => $userDetails["name"])); + } + } + + /** + * @before testCreateUsersCommand + * + * @param FunctionalTester $I + */ + public function testCreateAndDeleteUsersCommand(FunctionalTester $I) + { + $command = $this->app->find("users:delete"); + $tester = new \Symfony\Component\Console\Tester\CommandTester($command); + + $tester->execute( + array( + "command" => $command->getName(), + "suite" => "unit", + ) + ); + + // @todo Configs are a bit muxed ip... + $config = Fixtures::get("validModuleConfig"); + foreach ($config["users"] as $user => $userDetails) { + $I->dontSeeInDatabase("users", array("name" => $userDetails["name"])); + } + } +} diff --git a/tests/unit.suite.yml b/tests/unit.suite.yml index 9314168..aa898c9 100644 --- a/tests/unit.suite.yml +++ b/tests/unit.suite.yml @@ -4,3 +4,27 @@ class_name: UnitTester modules: enabled: [UnitHelper] + config: + # Used for command line tests. + DrupalUserRegistry: + defaultPass: "foobar" + users: + administrator: + name: test.administrator + email: test.administrator@example.com + pass: "foo" + roles: [ administrator, editor ] + root: true + editor: + name: test.editor + email: editor@example.com + roles: [ editor, moderator ] + moderator: + name: "test.moderator" + email: "sub.editor@example.com" + roles: [ moderator ] + authenticated: + name: authenticated + email: authenticated@example.com + roles: [ "authenticated user" ] + drush-alias: "@d7.local" diff --git a/tests/unit/CommandTest.php b/tests/unit/CommandTest.php new file mode 100644 index 0000000..40e30bd --- /dev/null +++ b/tests/unit/CommandTest.php @@ -0,0 +1,46 @@ +add(new CreateTestUsersCommand()); + $command = $app->find("users:create"); + $tester = new \Symfony\Component\Console\Tester\CommandTester($command); + + $tester->execute( + array( + "command" => $command->getName(), + "suite" => "unit", + ) + ); + + // @todo Verify...? + } +} diff --git a/tests/unit/TestUsersCommandTraitTest.php b/tests/unit/TestUsersCommandTraitTest.php new file mode 100644 index 0000000..4210ed7 --- /dev/null +++ b/tests/unit/TestUsersCommandTraitTest.php @@ -0,0 +1,27 @@ +setExpectedException('\Codeception\Exception\Module'); + $this->getTestUsers("unit", array("invalid" => "config")); + } +}