diff --git a/Makefile b/Makefile
index 7c9ba55..5c9b494 100644
--- a/Makefile
+++ b/Makefile
@@ -73,7 +73,7 @@ test-php-unit-dbg: ../../lib/composer/bin/phpunit
test-php-style: ## Run php-cs-fixer and check owncloud code-style
test-php-style: vendor-bin/owncloud-codestyle/vendor vendor-bin/php_codesniffer/vendor
$(PHP_CS_FIXER) fix -v --diff --diff-format udiff --allow-risky yes --dry-run
- $(PHP_CODESNIFFER) --runtime-set ignore_warnings_on_exit --standard=phpcs.xml tests/acceptance
+ $(PHP_CODESNIFFER) --runtime-set ignore_warnings_on_exit --standard=phpcs.xml tests/acceptance lib/Command
.PHONY: test-php-style-fix
test-php-style-fix: ## Run php-cs-fixer and fix code style issues
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 8aa2760..3c7677d 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -9,6 +9,9 @@
+
+ OCA\Testing\Command\CreateMultiUser
+
diff --git a/lib/Command/CreateMultiUser.php b/lib/Command/CreateMultiUser.php
new file mode 100644
index 0000000..d15104c
--- /dev/null
+++ b/lib/Command/CreateMultiUser.php
@@ -0,0 +1,169 @@
+
+ *
+ * @copyright Copyright (c) 2018, ownCloud GmbH
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see
+ *
+ */
+
+namespace OCA\Testing\Command;
+
+use OC\Core\Command\Base;
+use OCP\ILogger;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ *
+ * @author Tom Needham
+ * Creates, provisions and logs in/out database users.
+ *
+ */
+class CreateMultiUser extends Base {
+
+ /**
+ * @var IUserManager
+ */
+ protected $userManager;
+ /**
+ * @var IUserSession
+ */
+ protected $session;
+ /**
+ * @var ILogger
+ */
+ protected $logger;
+
+ /**
+ *
+ * @param IUserManager $userManager
+ * @param IUserSession $session
+ * @param ILogger $logger
+ *
+ * @return void
+ */
+ public function __construct(
+ IUserManager $userManager, IUserSession $session, ILogger $logger
+ ) {
+ $this->userManager = $userManager;
+ $this->session = $session;
+ $this->logger = $logger;
+ parent::__construct();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see \OC\Core\Command\Base::configure()
+ *
+ * @return void
+ */
+ protected function configure() {
+ parent::configure();
+
+ $defaultUidPrefix = 'zombie-' . \time() . '-';
+
+ $this
+ ->setName('testing:createusers')
+ ->setDescription('Creates and provisions multiple users for testing')
+ ->addOption(
+ 'prefix', 'p',
+ InputOption::VALUE_REQUIRED, 'userid prefix for created users',
+ $defaultUidPrefix
+ )
+ ->addArgument('numUsers', InputArgument::REQUIRED);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see \Symfony\Component\Console\Command\Command::execute()
+ *
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ *
+ * @return int|null null or 0 if everything went fine, or an error code
+ */
+ protected function execute(
+ InputInterface $input, OutputInterface $output
+ ) {
+ $numUsersArgument = $input->getArgument('numUsers');
+ if (\is_array($numUsersArgument)) {
+ throw new \Exception("invalid argument");
+ } else {
+ $num = (int) $numUsersArgument;
+ }
+ $prefix = $input->getOption('prefix');
+ $progress = new ProgressBar($output, $num);
+ $progress->setFormatDefinition(
+ "custom",
+ " %current%/%max% [%bar%] %percent:3s%% Elapsed:%elapsed:6s% " .
+ " Estimated:%estimated:-6s% Remaining:%remaining% %message%\n"
+ );
+ $progress->setFormat('custom');
+ $usersCreated = 0;
+ $start = \round(\microtime(true) * 1000);
+ for ($i = 0; $i < $num; $i++) {
+ // Create a user and log them in
+ $uid = $this->getUid($prefix, (string)$i);
+ $msElapsed = \round(\microtime(true) * 1000) - $start;
+ $rate = \round($usersCreated / ($msElapsed / 1000), 1);
+ $progress->setMessage("Creating [$uid] Rate: $rate users/second");
+ try {
+ $this->userManager->createUser($uid, $uid);
+ $this->fakeLoginAndLogout($uid);
+ $usersCreated++;
+ } catch (\Exception $e) {
+ $error = $e->getMessage();
+ $this->logger->logException($e);
+ $output->writeln(
+ "Failed to create user with error: $error"
+ );
+ return 1;
+ }
+ $progress->advance();
+ }
+ $progress->finish();
+ return null;
+ }
+
+ /**
+ *
+ * @param string $prefix
+ * @param string $i
+ *
+ * @return string
+ */
+ protected function getUid($prefix, $i) {
+ return $prefix . $i;
+ }
+
+ /**
+ *
+ * @param string $uid
+ *
+ * @return void
+ */
+ private function fakeLoginAndLogout($uid) {
+ $this->session->login($uid, $uid);
+ $this->session->logout();
+ }
+}