* @copyright Copyright (c) 2019, ownCloud GmbH * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, * as published by the Free Software Foundation; * either version 3 of the License, or any later version. * * 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 * along with this program. If not, see * */ use Behat\Behat\Context\Context; use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Behat\Gherkin\Node\TableNode; use GuzzleHttp\Exception\GuzzleException; use PHPUnit\Framework\Assert; use TestHelpers\OcisHelper; use TestHelpers\SetupHelper; use Behat\Gherkin\Node\PyStringNode; require_once 'bootstrap.php'; /** * Occ context for test steps that test occ commands */ class OccContext implements Context { /** * * @var FeatureContext */ private $featureContext; /** * * @var ImportedCertificates */ private $importedCertificates = []; /** * * @var RemovedCertificates */ private $removedCertificates = []; /** * @var string lastDeletedJobId */ private $lastDeletedJobId; /** * @param string $cmd * * @return void * @throws Exception */ public function invokingTheCommand(string $cmd):void { $this->featureContext->setOccLastCode( $this->featureContext->runOcc([$cmd]) ); } /** * @param string $path * * @return void * @throws Exception */ public function importSecurityCertificateFromFileInTemporaryStorage(string $path):void { $this->invokingTheCommand("security:certificates:import " . TEMPORARY_STORAGE_DIR_ON_REMOTE_SERVER . "/$path"); if ($this->featureContext->getExitStatusCodeOfOccCommand() === 0) { $pathComponents = \explode("/", $path); $certificate = \end($pathComponents); \array_push($this->importedCertificates, $certificate); } } /** * @param string $cmd * @param string $envVariableName * @param string $envVariableValue * * @return void * @throws Exception */ public function invokingTheCommandWithEnvVariable( string $cmd, string $envVariableName, string $envVariableValue ):int { $args = [$cmd]; return( $this->featureContext->runOccWithEnvVariables( $args, [$envVariableName => $envVariableValue] ) ); } /** * @param string $mode * * @return void * @throws Exception */ public function changeBackgroundJobsModeUsingTheOccCommand(string $mode):void { $this->invokingTheCommand("background:$mode"); } /** * @param string $mountPoint * @param boolean $setting * * @return void * @throws Exception */ public function setExtStorageReadOnlyUsingTheOccCommand(string $mountPoint, bool $setting = true):void { $command = "files_external:option"; $mountId = $this->featureContext->getStorageId($mountPoint); $key = "read_only"; if ($setting) { $value = "1"; } else { $value = "0"; } $this->invokingTheCommand( "$command $mountId $key $value" ); } /** * @param string $mountPoint * @param boolean $enable * * @return void * @throws Exception */ public function setExtStorageSharingUsingTheOccCommand(string $mountPoint, bool $enable = true):void { $command = "files_external:option"; $mountId = $this->featureContext->getStorageId($mountPoint); $key = "enable_sharing"; $value = $enable ? "true" : "false"; $this->invokingTheCommand( "$command $mountId $key $value" ); } /** * @param string $mountPoint * @param string $setting "never" (switch it off) otherwise "Once every direct access" * * @return void * @throws Exception */ public function setExtStorageCheckChangesUsingTheOccCommand(string $mountPoint, string $setting):void { $command = "files_external:option"; $mountId = $this->featureContext->getStorageId($mountPoint); $key = "filesystem_check_changes"; if ($setting === "never") { $value = "0"; } else { $value = "1"; } $this->invokingTheCommand( "$command $mountId $key $value" ); } /** * @return void * @throws Exception */ public function scanFileSystemForAllUsersUsingTheOccCommand():void { $this->invokingTheCommand( "files:scan --all" ); } /** * @param string $user * * @return void * @throws Exception */ public function scanFileSystemForAUserUsingTheOccCommand(string $user):void { $user = $this->featureContext->getActualUsername($user); $this->invokingTheCommand( "files:scan $user" ); } /** * @param string $path * @param string|null $user * * @return void * @throws Exception */ public function scanFileSystemPathUsingTheOccCommand(string $path, ?string $user = null):void { $path = $this->featureContext->substituteInLineCodes( $path, $user ); $this->invokingTheCommand( "files:scan --path='$path'" ); } /** * @param string $group * * @return void * @throws Exception */ public function scanFileSystemForAGroupUsingTheOccCommand(string $group):void { $this->invokingTheCommand( "files:scan --group=$group" ); } /** * @param string $groups * * @return void * @throws Exception */ public function scanFileSystemForGroupsUsingTheOccCommand(string $groups):void { $this->invokingTheCommand( "files:scan --groups=$groups" ); } /** * @param string $mount * * @return void */ public function createLocalStorageMountUsingTheOccCommand(string $mount):void { $result = SetupHelper::createLocalStorageMount( $mount, $this->featureContext->getStepLineRef() ); $storageId = $result['storageId']; if (!is_numeric($storageId)) { throw new Exception( __METHOD__ . " storageId '$storageId' is not numeric" ); } $this->featureContext->setResultOfOccCommand($result); $this->featureContext->addStorageId($mount, (int) $storageId); } /** * @param string $key * @param string $value * @param string $app * * @return void * @throws Exception */ public function addConfigKeyWithValueInAppUsingTheOccCommand(string $key, string $value, string $app):void { $this->invokingTheCommand( "config:app:set --value ${value} ${app} ${key}" ); } /** * @param string $key * @param string $app * * @return void * @throws Exception */ public function deleteConfigKeyOfAppUsingTheOccCommand(string $key, string $app):void { $this->invokingTheCommand( "config:app:delete ${app} ${key}" ); } /** * @param string $key * @param string $value * @param string $type * * @return void * @throws Exception */ public function addSystemConfigKeyUsingTheOccCommand( string $key, string $value, string $type = "string" ):void { $this->invokingTheCommand( "config:system:set --value '${value}' --type ${type} ${key}" ); } /** * @param string $key * * @return void * @throws Exception */ public function deleteSystemConfigKeyUsingTheOccCommand(string $key):void { $this->invokingTheCommand( "config:system:delete ${key}" ); } /** * * @return void * @throws Exception */ public function cleanOrphanedRemoteStoragesUsingOccCommand():void { $this->invokingTheCommand( "sharing:cleanup-remote-storages" ); } /** * @param string $user * * @return void * @throws Exception */ public function emptyTrashBinOfUserUsingOccCommand(string $user):void { $user = $this->featureContext->getActualUsername($user); $this->invokingTheCommand( "trashbin:cleanup $user" ); } /** * Create a calendar for given user with given calendar name * * @param string $user * @param string $calendarName * * @return void * @throws Exception */ public function createCalendarForUserUsingOccCommand(string $user, string $calendarName):void { $this->invokingTheCommand("dav:create-calendar $user $calendarName"); } /** * Create an address book for given user with given address book name * * @param string $user * @param string $addressBookName * * @return void * @throws Exception */ public function createAnAddressBookForUserUsingOccCommand(string $user, string $addressBookName):void { $this->invokingTheCommand("dav:create-addressbook $user $addressBookName"); } /** * @return void * @throws Exception */ public function getAllJobsInBackgroundQueueUsingOccCommand():void { $this->invokingTheCommand( "background:queue:status" ); } /** * @param string $user * * @return void * @throws Exception */ public function deleteAllVersionsForUserUsingOccCommand(string $user = ""): void { $this->invokingTheCommand( "versions:cleanup $user" ); } /** * @param string $users space-separated usernames. E.g. "Alice Brian" (without ) * * @return void * @throws Exception */ public function deleteAllVersionsForMultipleUsersUsingOccCommand(string $users): void { $this->deleteAllVersionsForUserUsingOccCommand($users); } /** * @return void * @throws Exception */ public function deleteAllVersionsForAllUsersUsingOccCommand(): void { $this->deleteAllVersionsForUserUsingOccCommand(); } /** * @param string $user * * @return void * @throws Exception */ public function deleteExpiredVersionsForUserUsingOccCommand(string $user = ""): void { $this->invokingTheCommand( "versions:expire $user" ); } /** * @param string $users space-separated usernames. E.g. "Alice Brian" (without ) * * @return void * @throws Exception */ public function deleteExpiredVersionsForMultipleUsersUsingOccCommand(string $users): void { $this->deleteExpiredVersionsForUserUsingOccCommand($users); } /** * @return void * @throws Exception */ public function deleteExpiredVersionsForAllUsersUsingOccCommand(): void { $this->deleteExpiredVersionsForUserUsingOccCommand(); } /** * @param string $job * * @return void * @throws Exception */ public function deleteLastBackgroundJobUsingTheOccCommand(string $job):void { $match = $this->getLastJobIdForJob($job); if ($match === false) { throw new Exception("Couldn't find jobId for given job: $job"); } $this->invokingTheCommand( "background:queue:delete $match" ); $this->lastDeletedJobId = $match; } /** * List created local storage mount * * @return void * @throws Exception */ public function listLocalStorageMount():void { $this->invokingTheCommand('files_external:list --output=json'); } /** * @When the administrator lists all local storage mount points using the occ command * * List created local storage mount with --short * * @return void * @throws Exception */ public function listLocalStorageMountShort():void { $this->invokingTheCommand('files_external:list --short --output=json'); } /** * List created local storage mount with --mount-options * * @return void * @throws Exception */ public function listLocalStorageMountOptions():void { $this->invokingTheCommand('files_external:list --mount-options --output=json'); } /** * List available backends * * @return void * @throws Exception */ public function listAvailableBackends():void { $this->invokingTheCommand('files_external:backends --output=json'); } /** * List available backends of type * * @param String $type * * @return void * @throws Exception */ public function listAvailableBackendsOfType(string $type):void { $this->invokingTheCommand('files_external:backends ' . $type . ' --output=json'); } /** * List backend of type * * @param String $type * @param String $backend * * @return void * @throws Exception */ public function listBackendOfType(string $type, string $backend):void { $this->invokingTheCommand('files_external:backends ' . $type . ' ' . $backend . ' --output=json'); } /** * List created local storage mount with --show-password * * @return void * @throws Exception */ public function listLocalStorageShowPassword():void { $this->invokingTheCommand('files_external:list --show-password --output=json'); } /** * @Given the administrator has selected master key encryption type using the occ command * * @return void * @throws Exception */ public function theAdministratorHasSelectedMasterKeyEncryptionTypeUsingTheOccCommand():void { $this->featureContext->runOcc(['encryption:select-encryption-type', "masterkey --yes"]); } /** * @When the administrator imports security certificate from file :filename in temporary storage on the system under test * * @param string $filename * * @return void * @throws Exception */ public function theAdministratorImportsSecurityCertificateFromFile(string $filename):void { $this->importSecurityCertificateFromFileInTemporaryStorage($filename); } /** * @Given the administrator has imported security certificate from file :filename in temporary storage on the system under test * * @param string $filename * * @return void * @throws Exception */ public function theAdministratorHasImportedSecurityCertificateFromFile(string $filename):void { $this->importSecurityCertificateFromFileInTemporaryStorage($filename); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator removes the security certificate :certificate * * @param string $certificate * * @return void * @throws Exception */ public function theAdministratorRemovesTheSecurityCertificate(string $certificate):void { $this->invokingTheCommand("security:certificates:remove " . $certificate); \array_push($this->removedCertificates, $certificate); } /** * @When the administrator runs upgrade routines on local server using the occ command * * @return void */ public function theAdministratorRunsUpgradeRoutinesOnLocalServerUsingTheOccCommand():void { \system("./occ upgrade", $status); if ($status !== 0) { // if the above command fails make sure to turn off maintenance mode \system("./occ maintenance:mode --off"); } } /** * @Given the administrator has decrypted everything * * @return void * @throws Exception */ public function theAdministratorHasDecryptedEverything():void { $this->theAdministratorRunsEncryptionDecryptAllUsingTheOccCommand(); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator disables encryption using the occ command * * @return void * @throws Exception */ public function theAdministratorDisablesEncryptionUsingTheOccCommand():void { $this->invokingTheCommand("encryption:disable"); } /** * @When the administrator runs encryption decrypt all using the occ command * * @return void */ public function theAdministratorRunsEncryptionDecryptAllUsingTheOccCommand():void { \system("./occ maintenance:singleuser --on"); \system("./occ encryption:decrypt-all -c yes", $status); $this->featureContext->setResultOfOccCommand(["code" => $status, "stdOut" => "", "stdErr" => ""]); \system("./occ maintenance:singleuser --off"); } /** * @return bool */ public function theOccCommandExitStatusWasSuccess():bool { return ($this->featureContext->getExitStatusCodeOfOccCommand() === 0); } /** * @Then /^the command should have been successful$/ * * @return void * @throws Exception */ public function theCommandShouldHaveBeenSuccessful():void { $exceptions = $this->featureContext->findExceptions(); $exitStatusCode = $this->featureContext->getExitStatusCodeOfOccCommand(); if ($exitStatusCode !== 0) { $msg = "The command was not successful, exit code was " . $exitStatusCode . ".\n" . "stdOut was: '" . $this->featureContext->getStdOutOfOccCommand() . "'\n" . "stdErr was: '" . $this->featureContext->getStdErrOfOccCommand() . "'\n"; if (!empty($exceptions)) { $msg .= ' Exceptions: ' . \implode(', ', $exceptions); } if ($exitStatusCode === null) { $msg = "The occ command did not run "; } throw new Exception($msg); } elseif (!empty($exceptions)) { $msg = 'The command was successful but triggered exceptions: ' . \implode(', ', $exceptions); throw new Exception($msg); } } /** * @Then /^the command should have failed with exit code ([0-9]+)$/ * * @param int $exitCode * * @return void * @throws Exception */ public function theCommandFailedWithExitCode(int $exitCode):void { $exitStatusCode = $this->featureContext->getExitStatusCodeOfOccCommand(); Assert::assertEquals( (int) $exitCode, $exitStatusCode, "The command was expected to fail with exit code $exitCode but got {$exitStatusCode}" ); } /** * @Then /^the command output should be the text ((?:'[^']*')|(?:"[^"]*"))$/ * * @param string $text * * @return void * @throws Exception */ public function theCommandOutputShouldBeTheText(string $text):void { $text = \trim($text, $text[0]); $commandOutput = \trim($this->featureContext->getStdOutOfOccCommand()); Assert::assertEquals( $text, $commandOutput, "The command output did not match the expected text on stdout '$text'\n" . "The command output on stdout was:\n" . $commandOutput ); } /** * @Then /^the command should have failed with exception text "([^"]*)"$/ * * @param string $exceptionText * * @return void * @throws Exception */ public function theCommandFailedWithExceptionText(string $exceptionText):void { $exceptions = $this->featureContext->findExceptions(); Assert::assertNotEmpty( $exceptions, 'The command did not throw any exceptions' ); Assert::assertContains( $exceptionText, $exceptions, "The command did not throw any exception with the text '$exceptionText'" ); } /** * @Then /^the command output should contain the text ((?:'[^']*')|(?:"[^"]*"))$/ * * @param string $text * * @return void * @throws Exception */ public function theCommandOutputContainsTheText(string $text):void { // The capturing group of the regex always includes the quotes at each // end of the captured string, so trim them. $text = \trim($text, $text[0]); $commandOutput = $this->featureContext->getStdOutOfOccCommand(); $lines = SetupHelper::findLines( $commandOutput, $text ); Assert::assertGreaterThanOrEqual( 1, \count($lines), "The command output did not contain the expected text on stdout '$text'\n" . "The command output on stdout was:\n" . $commandOutput ); } /** * @Then /^the command output should contain the text ((?:'[^']*')|(?:"[^"]*")) about user "([^"]*)"$/ * * @param string $text * @param string $user * * @return void * @throws Exception */ public function theCommandOutputContainsTheTextAboutUser(string $text, string $user):void { // The capturing group of the regex always includes the quotes at each // end of the captured string, so trim them. $text = \trim($text, $text[0]); $text = $this->featureContext->substituteInLineCodes( $text, $user ); $commandOutput = $this->featureContext->getStdOutOfOccCommand(); $lines = SetupHelper::findLines( $commandOutput, $text ); Assert::assertGreaterThanOrEqual( 1, \count($lines), "The command output did not contain the expected text on stdout '$text'\n" . "The command output on stdout was:\n" . $commandOutput ); } /** * @Then /^the command error output should contain the text ((?:'[^']*')|(?:"[^"]*"))$/ * * @param string $text * * @return void * @throws Exception */ public function theCommandErrorOutputContainsTheText(string $text):void { // The capturing group of the regex always includes the quotes at each // end of the captured string, so trim them. $text = \trim($text, $text[0]); $commandOutput = $this->featureContext->getStdErrOfOccCommand(); $lines = SetupHelper::findLines( $commandOutput, $text ); Assert::assertGreaterThanOrEqual( 1, \count($lines), "The command output did not contain the expected text on stderr '$text'\n" . "The command output on stderr was:\n" . $commandOutput ); } /** * @Then the occ command JSON output should be empty * * @return void */ public function theOccCommandJsonOutputShouldNotReturnAnyData():void { Assert::assertEquals( \trim($this->featureContext->getStdOutOfOccCommand()), "[]", "Expected command output to be '[]' but got '" . \trim($this->featureContext->getStdOutOfOccCommand()) . "'" ); Assert::assertEmpty( $this->featureContext->getStdErrOfOccCommand(), "Expected occ command error to be empty but got '" . $this->featureContext->getStdErrOfOccCommand() . "'" ); } /** * @Then :noOfOrphanedShare orphaned remote storage should have been cleared * * @param int $noOfOrphanedShare * * @return void * @throws Exception */ public function theOrphanedRemoteStorageShouldBeCleared(int $noOfOrphanedShare):void { $this->theCommandShouldHaveBeenSuccessful(); $commandOutput = $this->featureContext->getStdOutOfOccCommand(); // removing blank lines $commandOutput = implode("\n", array_filter(explode("\n", $commandOutput))); // splitting strings based on newline into an array $outputLines = preg_split("/\r\n|\n|\r/", $commandOutput); // first line of command output contains total remote storage scanned $totalRemoteStorage = (int) filter_var($outputLines[0], FILTER_SANITIZE_NUMBER_INT); echo "totalremotestorage: $totalRemoteStorage"; // calculating total no of shares deleted from remote storage: first getting total length of the array // then minus 2 for first two lines of scan info message // then divide by 2 because each share delete has message of two line $totalSharesDeleted = ((\count($outputLines) - 2) / 2) / $totalRemoteStorage; Assert::assertEquals( $noOfOrphanedShare, $totalSharesDeleted, "The command was expected to delete '$noOfOrphanedShare' orphaned shares but only deleted '$totalSharesDeleted' orphaned shares." ); } /** * @When the administrator has set depth_infinity_allowed to :depth_infinity_allowed * * @param int $depthInfinityAllowed * * @return void * @throws Exception */ public function theAdministratorHasSetDepthInfinityAllowedTo($depthInfinityAllowed) { $depthInfinityAllowedString = (string) $depthInfinityAllowed; $this->addSystemConfigKeyUsingTheOccCommand( "dav.propfind.depth_infinity", $depthInfinityAllowedString ); if ($depthInfinityAllowedString === "0") { $this->featureContext->davPropfindDepthInfinityDisabled(); } else { $this->featureContext->davPropfindDepthInfinityEnabled(); } } /** * @Given the administrator has set the mail smtpmode to :smtpmode * * @param string $smtpmode * * @return void * @throws Exception */ public function theAdministratorHasSetTheMailSmtpmodeTo(string $smtpmode):void { $this->addSystemConfigKeyUsingTheOccCommand( "mail_smtpmode", $smtpmode ); } /** * @When the administrator sets the log level to :level using the occ command * * @param string $level * * @return void * @throws Exception */ public function theAdministratorSetsLogLevelUsingTheOccCommand(string $level):void { $this->invokingTheCommand( "log:manage --level $level" ); } /** * @When the administrator sets the timezone to :timezone using the occ command * * @param string $timezone * * @return void * @throws Exception */ public function theAdministratorSetsTimeZoneUsingTheOccCommand(string $timezone):void { $this->invokingTheCommand( "log:manage --timezone $timezone" ); } /** * @When the administrator sets the backend to :backend using the occ command * * @param string $backend * * @return void * @throws Exception */ public function theAdministratorSetsBackendUsingTheOccCommand(string $backend):void { $this->invokingTheCommand( "log:manage --backend $backend" ); } /** * @When the administrator enables the ownCloud backend using the occ command * * @return void * @throws Exception */ public function theAdministratorEnablesOwnCloudBackendUsingTheOccCommand():void { $this->invokingTheCommand( "log:owncloud --enable" ); } /** * @When the administrator sets the log file path to :path using the occ command * * @param string $path * * @return void * @throws Exception */ public function theAdministratorSetsLogFilePathUsingTheOccCommand(string $path):void { $this->invokingTheCommand( "log:owncloud --file $path" ); } /** * @When the administrator sets the log rotate file size to :size using the occ command * * @param string $size * * @return void * @throws Exception */ public function theAdministratorSetsLogRotateFileSizeUsingTheOccCommand(string $size):void { $this->invokingTheCommand( "log:owncloud --rotate-size $size" ); } /** * @Then the command output should be: * * @param PyStringNode $content * * @return void * @throws Exception */ public function theCommandOutputShouldBe(PyStringNode $content):void { $commandOutput = $this->featureContext->getStdOutOfOccCommand(); // removing blank lines $commandOutput = \implode("\n", \array_filter(\explode("\n", $commandOutput))); $content = \implode("\n", \array_filter(\explode("\n", $content->getRaw()))); Assert::assertEquals( $content, $commandOutput, "The command output was expected to be '$content' but got '$commandOutput'" ); } /** * @When the administrator changes the background jobs mode to :mode using the occ command * * @param string $mode * * @return void * @throws Exception */ public function theAdministratorChangesTheBackgroundJobsModeTo(string $mode):void { $this->changeBackgroundJobsModeUsingTheOccCommand($mode); } /** * @Given the administrator has changed the background jobs mode to :mode * * @param string $mode * * @return void * @throws Exception */ public function theAdministratorHasChangedTheBackgroundJobsModeTo(string $mode):void { $this->changeBackgroundJobsModeUsingTheOccCommand($mode); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator sets the external storage :mountPoint to read-only using the occ command * * @param string $mountPoint * * @return void * @throws Exception */ public function theAdminSetsTheExtStorageToReadOnly(string $mountPoint):void { $this->setExtStorageReadOnlyUsingTheOccCommand($mountPoint); } /** * @Given the administrator has set the external storage :mountPoint to read-only * * @param string $mountPoint * * @return void * @throws Exception */ public function theAdminHasSetTheExtStorageToReadOnly(string $mountPoint):void { $this->setExtStorageReadOnlyUsingTheOccCommand($mountPoint); $this->theCommandShouldHaveBeenSuccessful(); } /** * @Given the administrator has set the external storage :mountPoint to sharing * * @param string $mountPoint * * @return void * @throws Exception */ public function theAdminHasSetTheExtStorageToSharing(string $mountPoint):void { $this->setExtStorageSharingUsingTheOccCommand($mountPoint); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When /^the administrator (enables|disables) sharing for the external storage "([^"]*)" using the occ command$/ * * @param string $action * @param string $mountPoint * * @return void * @throws Exception */ public function theAdminDisablesSharingForTheExtStorage(string $action, string $mountPoint):void { $this->setExtStorageSharingUsingTheOccCommand($mountPoint, $action === "enables"); } /** * @When the administrator sets the external storage :mountPoint to be never scanned automatically using the occ command * * @param string $mountPoint * * @return void * @throws Exception */ public function theAdminSetsTheExtStorageToBeNeverScannedAutomatically(string $mountPoint):void { $this->setExtStorageCheckChangesUsingTheOccCommand($mountPoint, "never"); } /** * @Given the administrator has set the external storage :mountPoint to be never scanned automatically * * @param string $mountPoint * * @return void * @throws Exception */ public function theAdminHasSetTheExtStorageToBeNeverScannedAutomatically(string $mountPoint):void { $this->setExtStorageCheckChangesUsingTheOccCommand($mountPoint, "never"); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator scans the filesystem for all users using the occ command * * @return void * @throws Exception */ public function theAdministratorScansTheFilesystemForAllUsersUsingTheOccCommand():void { $this->scanFileSystemForAllUsersUsingTheOccCommand(); } /** * @Given the administrator has scanned the filesystem for all users * * @return void * @throws Exception */ public function theAdministratorHasScannedTheFilesystemForAllUsersUsingTheOccCommand():void { $this->scanFileSystemForAllUsersUsingTheOccCommand(); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator scans the filesystem for user :user using the occ command * * @param string $user * * @return void * @throws Exception */ public function theAdministratorScansTheFilesystemForUserUsingTheOccCommand(string $user):void { $this->scanFileSystemForAUserUsingTheOccCommand($user); } /** * @Given the administrator has scanned the filesystem for user :user * * @param string $user * * @return void * @throws Exception */ public function theAdministratorHasScannedTheFilesystemForUserUsingTheOccCommand(string $user):void { $this->scanFileSystemForAUserUsingTheOccCommand($user); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator scans the filesystem in path :path of user :user using the occ command * * @param string $path * @param string $user * * @return void * @throws Exception */ public function theAdministratorScansTheFilesystemInPathUsingTheOccCommand(string $path, string $user):void { $user = $this->featureContext->getActualUsername($user); $this->scanFileSystemPathUsingTheOccCommand($path, $user); } /** * @Given the administrator scans the filesystem in path :path * * @param string $path * * @return void * @throws Exception */ public function theAdministratorHasScannedTheFilesystemInPathUsingTheOccCommand(string $path):void { $this->scanFileSystemPathUsingTheOccCommand($path); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator scans the filesystem for group :group using the occ command * * Used to test the --group option of the files:scan command * * @param string $group a single group name * * @return void * @throws Exception */ public function theAdministratorScansTheFilesystemForGroupUsingTheOccCommand(string $group):void { $this->scanFileSystemForAGroupUsingTheOccCommand($group); } /** * @Given the administrator has scanned the filesystem for group :group * * Used to test the --group option of the files:scan command * * @param string $group a single group name * * @return void * @throws Exception */ public function theAdministratorHasScannedTheFilesystemForGroupUsingTheOccCommand(string $group):void { $this->scanFileSystemForAGroupUsingTheOccCommand($group); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator scans the filesystem for groups list :groups using the occ command * * Used to test the --groups option of the files:scan command * * @param string $groups a comma-separated list of group names * * @return void * @throws Exception */ public function theAdministratorScansTheFilesystemForGroupsUsingTheOccCommand(string $groups):void { $this->scanFileSystemForGroupsUsingTheOccCommand($groups); } /** * @Given the administrator has scanned the filesystem for groups list :groups * * Used to test the --groups option of the files:scan command * * @param string $groups a comma-separated list of group names * * @return void * @throws Exception */ public function theAdministratorHasScannedTheFilesystemForGroupsUsingTheOccCommand(string $groups):void { $this->scanFileSystemForGroupsUsingTheOccCommand($groups); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator cleanups the filesystem for all users using the occ command * * @return void * @throws Exception */ public function theAdministratorCleanupsTheFilesystemForAllUsersUsingTheOccCommand():void { $this->invokingTheCommand( "files:cleanup" ); } /** * @When the administrator creates the local storage mount :mount using the occ command * * @param string $mount * * @return void */ public function theAdministratorCreatesTheLocalStorageMountUsingTheOccCommand(string $mount):void { $this->createLocalStorageMountUsingTheOccCommand($mount); } /** * @Given the administrator has created the local storage mount :mount * * @param string $mount * * @return void * @throws Exception */ public function theAdministratorHasCreatedTheLocalStorageMountUsingTheOccCommand(string $mount):void { $this->createLocalStorageMountUsingTheOccCommand($mount); $this->theCommandShouldHaveBeenSuccessful(); } /** * @param string $action * @param string $userOrGroup * @param string $userOrGroupName * @param string $mountName * * @return void * @throws Exception */ public function addRemoveUserOrGroupToOrFromMount( string $action, string $userOrGroup, string $userOrGroupName, string $mountName ):void { if ($action === "adds" || $action === "added") { $action = "--add"; } else { $action = "--remove"; } if ($userOrGroup === "user") { $action = "$action-user"; $userOrGroupName = $this->featureContext->getActualUsername($userOrGroupName); } else { $action = "$action-group"; } $mountId = $this->featureContext->getStorageId($mountName); $this->featureContext->setOccLastCode( $this->featureContext->runOcc( [ 'files_external:applicable', $mountId, "$action ", "$userOrGroupName" ] ) ); } /** * @param string $mount * @param string $userOrGroup * * @return array * @throws Exception */ public function getListOfApplicableUserOrGroupForMount(string $mount, string $userOrGroup):array { $validArgs = ["users", "groups"]; if (!\in_array($userOrGroup, $validArgs)) { throw new Exception( "Invalid key provided. Expected:" . \implode(", ", $validArgs) . "Found: " . $userOrGroup ); } $mountId = $this->getMountIdForLocalStorage($mount); $this->featureContext->runOcc( [ 'files_external:applicable', $mountId, '--output=json' ] ); $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); return ($userOrGroup === "users") ? $commandOutput->users : $commandOutput->groups; } /** * @param string $action * @param string $userOrGroup * @param string $userOrGroupName * * @return void * @throws Exception */ public function addRemoveUserOrGroupToOrFromLastLocalMount( string $action, string $userOrGroup, string $userOrGroupName ):void { $storageIds = $this->featureContext->getStorageIds(); Assert::assertGreaterThan( 0, \count($storageIds), "addRemoveAsApplicableUserLastLocalMount no local mounts exist" ); $lastMountName = \end($storageIds); $this->addRemoveUserOrGroupToOrFromMount( $action, $userOrGroup, $userOrGroupName, $lastMountName ); } /** * @When /^the administrator (adds|removes) (user|group) "([^"]*)" (?:as|from) the applicable (?:user|group) for the last local storage mount using the occ command$/ * * @param string $action * @param string $userOrGroup * @param string $user * * @return void * @throws Exception */ public function theAdminAddsRemovesAsTheApplicableUserLastLocalMountUsingTheOccCommand( string $action, string $userOrGroup, string $user ):void { $this->addRemoveUserOrGroupToOrFromLastLocalMount( $action, $userOrGroup, $user ); } /** * @Given /^the administrator has (added|removed) (user|group) "([^"]*)" (?:as|from) the applicable (?:user|group) for the last local storage mount$/ * * @param string $action * @param string $userOrGroup * @param string $user * * @return void * @throws Exception */ public function theAdminHasAddedRemovedAsTheApplicableUserLastLocalMountUsingTheOccCommand( string $action, string $userOrGroup, string $user ):void { $this->addRemoveUserOrGroupToOrFromLastLocalMount( $action, $userOrGroup, $user ); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When /^the administrator (adds|removes) (user|group) "([^"]*)" (?:as|from) the applicable (?:user|group) for local storage mount "([^"]*)" using the occ command$/ * * @param string $action * @param string $userOrGroup * @param string $user * @param string $mount * * @return void * @throws Exception */ public function theAdminAddsRemovesAsTheApplicableUserForMountUsingTheOccCommand( string $action, string $userOrGroup, string $user, string $mount ):void { $user = $this->featureContext->getActualUsername($user); $this->addRemoveUserOrGroupToOrFromMount( $action, $userOrGroup, $user, $mount ); } /** * @Then /^the following (users|groups) should be listed as applicable for local storage mount "([^"]*)"$/ * * @param string $usersOrGroups comma separated lists eg: Alice, Brian * @param string $localStorage * @param TableNode $applicable * * @return void * @throws Exception */ public function theFollowingUsersOrGroupsShouldBeListedAsApplicable(string $usersOrGroups, string $localStorage, TableNode $applicable): void { $this->featureContext->verifyTableNodeRows( $applicable, [], ["users", "groups"] ); $expectedApplicableList = $applicable->getRowsHash(); $actualApplicableList = $this->getListOfApplicableUserOrGroupForMount($localStorage, $usersOrGroups); foreach ($expectedApplicableList as $expectedApplicable) { Assert::assertContains( $expectedApplicable, $actualApplicableList, __METHOD__ . $usersOrGroups . " not found!\nexpected: " . $expectedApplicable . " to be in the list [" . \implode(", ", $actualApplicableList) . "]." ); } } /** * @Then /^the applicable (users|groups) list should be empty for local storage mount "([^"]*)"$/ * * @param string $usersOrGroups * @param string $localStorage * * @return void * @throws Exception */ public function theApplicableUsersOrGroupsListShouldBeEmptyForLocalStorageMount(string $usersOrGroups, string $localStorage): void { $actualApplicableList = $this->getListOfApplicableUserOrGroupForMount($localStorage, $usersOrGroups); Assert::assertEquals( 0, \count($actualApplicableList), __METHOD__ . "Expected empty list for applicable " . $usersOrGroups . " but found: [" . \implode(", ", $actualApplicableList) . "]." ); } /** * @When the administrator removes all from the applicable users and groups for local storage mount :localStorage using the occ command * * @param string $localStorage * * @return void * @throws Exception */ public function theAdminRemovesAllForTheMountUsingOccCommand(string $localStorage):void { $mountId = $this->featureContext->getStorageId($localStorage); $this->featureContext->runOcc( [ 'files_external:applicable', $mountId, "--remove-all" ] ); } /** * @Given /^the administrator has (added|removed) (user|group) "([^"]*)" (?:as|from) the applicable (?:user|group) for local storage mount "([^"]*)"$/ * * @param string $action * @param string $userOrGroup * @param string $user * @param string $mount * * @return void * @throws Exception */ public function theAdminHasAddedRemovedTheApplicableUserForMountUsingTheOccCommand( string $action, string $userOrGroup, string $user, string $mount ):void { $user = $this->featureContext->getActualUsername($user); $this->addRemoveUserOrGroupToOrFromMount( $action, $userOrGroup, $user, $mount ); $this->theCommandShouldHaveBeenSuccessful(); // making plural "users" or "groups" $userOrGroup = $userOrGroup . "s"; $actualApplicableList = $this->getListOfApplicableUserOrGroupForMount($mount, $userOrGroup); if ($action === "added") { Assert::assertContains( $user, $actualApplicableList, __METHOD__ . " The expected applicable " . $userOrGroup . " is not present in the actual list of applicable " . $userOrGroup . " for mount point: " . $mount . ".\n" ); } else { Assert::assertNotContains( $user, $actualApplicableList, __METHOD__ . " The applicable " . $userOrGroup . " is present in the actual list of applicable " . $userOrGroup . " for mount point: " . $mount . ".\n" ); } } /** * @When the administrator configures the key :key with value :value for the local storage mount :localStorage * * @param string $key * @param string $value * @param string $localStorage * * @return void * @throws Exception */ public function adminConfiguresLocalStorageMountUsingTheOccCommand(string $key, string $value, string $localStorage):void { $mountId = $this->featureContext->getStorageId($localStorage); $this->featureContext->runOcc( [ "files_external:config", $mountId, $key, $value ] ); } /** * @When the administrator lists the available backends using the occ command * * @return void * @throws Exception */ public function adminListsAvailableBackendsUsingTheOccCommand():void { $this->listAvailableBackends(); } /** * @When the administrator lists the available backends of type :type using the occ command * * @param String $type * * @return void * @throws Exception */ public function adminListsAvailableBackendsOfTypeUsingTheOccCommand(string $type):void { $this->listAvailableBackendsOfType($type); } /** * @When the administrator lists the :backend backend of type :backendType using the occ command * * @param String $backend * @param String $backendType * * @return void * @throws Exception */ public function adminListsBackendOfTypeUsingTheOccCommand(string $backend, string $backendType):void { $this->listBackendOfType($backendType, $backend); } /** * @When the administrator lists configurations with the existing key :key for the local storage mount :localStorage * * @param string $key * @param string $localStorage * * @return void * @throws Exception */ public function adminListsConfigurationsWithExistingKeyForLocalStorageMountUsingTheOccCommand(string $key, string $localStorage):void { $mountId = $this->featureContext->getStorageId($localStorage); $this->featureContext->runOcc( [ "files_external:config", $mountId, $key, ] ); } /** * @Given the administrator has configured the key :key with value :value for the local storage mount :localStorage * * @param string $key * @param string $value * @param string $localStorage * * @return void * @throws Exception */ public function adminConfiguredLocalStorageMountUsingTheOccCommand(string $key, string $value, string $localStorage):void { $mountId = $this->featureContext->getStorageId($localStorage); $this->featureContext->runOcc( [ "files_external:config", $mountId, $key, $value ] ); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator lists the local storage using the occ command * * @return void * @throws Exception */ public function adminListsLocalStorageMountUsingTheOccCommand():void { $this->listLocalStorageMount(); } /** * @When the administrator lists the local storage with --short using the occ command * * @return void * @throws Exception */ public function adminListsLocalStorageMountShortUsingTheOccCommand():void { $this->listLocalStorageMountShort(); } /** * @When the administrator lists the local storage with --mount-options using the occ command * * @return void * @throws Exception */ public function adminListsLocalStorageMountOptionsUsingTheOccCommand():void { $this->listLocalStorageMountOptions(); } /** * @When the administrator lists the local storage with --show-password using the occ command * * @return void * @throws Exception */ public function adminListsLocalStorageShowPasswordUsingTheOccCommand():void { $this->listLocalStorageShowPassword(); } /** * @Then the following local storage should exist * * @param TableNode $mountPoints * * @return void */ public function theFollowingLocalStoragesShouldExist(TableNode $mountPoints):void { $createdLocalStorage = []; $expectedLocalStorages = $mountPoints->getColumnsHash(); $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); foreach ($commandOutput as $storageEntry) { $createdLocalStorage[$storageEntry->mount_id] = \ltrim($storageEntry->mount_point, '/'); } foreach ($expectedLocalStorages as $expectedStorageEntry) { Assert::assertContains( $expectedStorageEntry['localStorage'], $createdLocalStorage, "'" . \implode(', ', $createdLocalStorage) . "' does not contain '${expectedStorageEntry['localStorage']}' " . __METHOD__ ); } } /** * @Then the following local storage should not exist * * @param TableNode $mountPoints * * @return void * @throws Exception */ public function theFollowingLocalStoragesShouldNotExist(TableNode $mountPoints):void { $createdLocalStorage = []; $this->listLocalStorageMount(); $expectedLocalStorages = $mountPoints->getColumnsHash(); $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); foreach ($commandOutput as $i) { $createdLocalStorage[$i->mount_id] = \ltrim($i->mount_point, '/'); } foreach ($expectedLocalStorages as $i) { Assert::assertNotContains( $i['localStorage'], $createdLocalStorage, "{$i['localStorage']} exists but was not expected to exist" ); } } /** * @Then the following backend types should be listed: * * @param TableNode $table * * @return void * @throws Exception */ public function theFollowingBackendTypesShouldBeListed(TableNode $table):void { $expectedBackendTypes = $table->getColumnsHash(); foreach ($expectedBackendTypes as $expectedBackendTypeEntry) { Assert::assertArrayHasKey( 'backend-type', $expectedBackendTypeEntry, __METHOD__ . " The provided expected backend type entry '" . \implode(', ', $expectedBackendTypeEntry) . "' do not have key 'backend-type'" ); } $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); $keys = \array_keys((array) $commandOutput); foreach ($expectedBackendTypes as $backendTypesEntry) { Assert::assertContains( $backendTypesEntry['backend-type'], $keys, __METHOD__ . " ${backendTypesEntry['backend-type']} is not contained in '" . \implode(', ', $keys) . "' but was expected to be." ); } } /** * @Then the following authentication/storage backends should be listed: * * @param TableNode $table * * @return void * @throws Exception */ public function theFollowingBackendsShouldBeListed(TableNode $table):void { $expectedBackends = $table->getColumnsHash(); foreach ($expectedBackends as $expectedBackendEntry) { Assert::assertArrayHasKey( 'backends', $expectedBackendEntry, __METHOD__ . " The provided expected backend entry '" . \implode(', ', $expectedBackendEntry) . "' do not have key 'backends'" ); } $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); $keys = \array_keys((array) $commandOutput); foreach ($expectedBackends as $backendsEntry) { Assert::assertContains( $backendsEntry['backends'], $keys, __METHOD__ . " ${backendsEntry['backends']} is not contained in '" . \implode(', ', $keys) . "' but was expected to be." ); } } /** * @Then the following authentication/storage backend keys should be listed: * * @param TableNode $table * * @return void * @throws Exception */ public function theFollowingBackendKeysOfTypeShouldBeListed(TableNode $table):void { $expectedBackendKeys = $table->getColumnsHash(); foreach ($expectedBackendKeys as $expectedBackendKeyEntry) { Assert::assertArrayHasKey( 'backend-keys', $expectedBackendKeyEntry, __METHOD__ . " The provided expected backend key entry '" . \implode(', ', $expectedBackendKeyEntry) . "' do not have key 'backend-keys'" ); } $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); $keys = \array_keys((array) $commandOutput); foreach ($expectedBackendKeys as $backendKeysEntry) { Assert::assertContains( $backendKeysEntry['backend-keys'], $keys, __METHOD__ . " ${backendKeysEntry['backend-keys']} is not contained in '" . \implode(', ', $keys) . "' but was expected to be." ); } } /** * @Then the following local storage should be listed: * * @param TableNode $table * * @return void * @throws Exception */ public function theFollowingLocalStorageShouldBeListed(TableNode $table):void { $this->featureContext->verifyTableNodeColumns( $table, ['MountPoint', 'ApplicableUsers', 'ApplicableGroups'], ['Storage', 'AuthenticationType', 'Configuration', 'Options', 'Auth', 'Type'] ); $expectedLocalStorages = $table->getColumnsHash(); $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); foreach ($expectedLocalStorages as $expectedStorageEntry) { $isStorageEntryListed = false; foreach ($commandOutput as $listedStorageEntry) { if ($expectedStorageEntry["MountPoint"] === $listedStorageEntry->mount_point) { if (isset($expectedStorageEntry['Storage'])) { Assert::assertEquals( $expectedStorageEntry['Storage'], $listedStorageEntry->storage, "Storage column does not have the expected value for storage " . $expectedStorageEntry['MountPoint'] ); } if (isset($expectedStorageEntry['AuthenticationType'])) { Assert::assertEquals( $expectedStorageEntry['AuthenticationType'], $listedStorageEntry->authentication_type, "AuthenticationType column does not have the expected value for storage " . $expectedStorageEntry['MountPoint'] ); } if (isset($expectedStorageEntry['Auth'])) { Assert::assertEquals( $expectedStorageEntry['Auth'], $listedStorageEntry->auth, "Auth column does not have the expected value for storage " . $expectedStorageEntry['MountPoint'] ); } if (isset($expectedStorageEntry['Configuration'])) { if ($expectedStorageEntry['Configuration'] === '') { Assert::assertEquals( '', $listedStorageEntry->configuration, 'Configuration column should be empty but is ' . $listedStorageEntry->configuration ); } else { if (\is_string($listedStorageEntry->configuration)) { Assert::assertStringStartsWith( $expectedStorageEntry['Configuration'], $listedStorageEntry->configuration, "Configuration column does not start with the expected value for storage " . $expectedStorageEntry['Configuration'] ); } else { $item = \strtok($expectedStorageEntry['Configuration'], ':'); Assert::assertTrue( \property_exists($listedStorageEntry->configuration, $item), "$item was not found in the Configuration column" ); } } } if (isset($expectedStorageEntry['Options'])) { Assert::assertEquals( $expectedStorageEntry['Options'], $listedStorageEntry->options, "Options column does not have the expected value for storage " . $expectedStorageEntry['MountPoint'] ); } if (isset($expectedStorageEntry['ApplicableUsers'])) { if (\is_string($listedStorageEntry->applicable_users)) { if ($listedStorageEntry->applicable_users === '') { $listedApplicableUsers = []; } else { $listedApplicableUsers = \explode(', ', $listedStorageEntry->applicable_users); } } else { $listedApplicableUsers = $listedStorageEntry->applicable_users; } if ($expectedStorageEntry['ApplicableUsers'] === '') { Assert::assertEquals( [], $listedApplicableUsers, "ApplicableUsers was expected to be an empty array but was not empty" ); } else { $expectedApplicableUsers = \explode(', ', $expectedStorageEntry['ApplicableUsers']); foreach ($expectedApplicableUsers as $expectedApplicableUserEntry) { $expectedApplicableUserEntry = $this->featureContext->getActualUsername($expectedApplicableUserEntry); Assert::assertContains( $expectedApplicableUserEntry, $listedApplicableUsers, __METHOD__ . " '$expectedApplicableUserEntry' is not listed in '" . \implode(', ', $listedApplicableUsers) . "'" ); } } } if (isset($expectedStorageEntry['ApplicableGroups'])) { if (\is_string($listedStorageEntry->applicable_groups)) { if ($listedStorageEntry->applicable_groups === '') { $listedApplicableGroups = []; } else { $listedApplicableGroups = \explode(', ', $listedStorageEntry->applicable_groups); } } else { $listedApplicableGroups = $listedStorageEntry->applicable_groups; } if ($expectedStorageEntry['ApplicableGroups'] === '') { Assert::assertEquals( [], $listedApplicableGroups, "ApplicableGroups was expected to be an empty array but was not empty" ); Assert::assertEquals([], $listedApplicableGroups); } else { $expectedApplicableGroups = \explode(', ', $expectedStorageEntry['ApplicableGroups']); foreach ($expectedApplicableGroups as $expectedApplicableGroupEntry) { Assert::assertContains( $expectedApplicableGroupEntry, $listedApplicableGroups, __METHOD__ . " '$expectedApplicableGroupEntry' is not listed in '" . \implode(', ', $listedApplicableGroups) . "'" ); } } } if (isset($expectedStorageEntry['Type'])) { Assert::assertEquals( $expectedStorageEntry['Type'], $listedStorageEntry->type, "Type column does not have the expected value for storage " . $expectedStorageEntry['MountPoint'] ); } $isStorageEntryListed = true; break; } } Assert::assertTrue($isStorageEntryListed, __METHOD__ . " Expected local storage {$expectedStorageEntry['MountPoint']} not found"); } } /** * @Then the configuration output should be :expectedOutput * * @param string $expectedOutput * * @return void * @throws Exception */ public function theConfigurationOutputShouldBe(string $expectedOutput):void { $actualOutput = $this->featureContext->getStdOutOfOccCommand(); $trimmedOutput = \trim($actualOutput); Assert::assertEquals( $expectedOutput, $trimmedOutput, __METHOD__ . " The expected configuration output was '$expectedOutput', but got '$actualOutput' instead." ); } /** * @Then the following should be included in the configuration of local storage :localStorage: * * @param string $localStorage * @param TableNode $table * * @return void * @throws Exception */ public function theFollowingShouldBeIncludedInTheConfigurationOfLocalStorage(string $localStorage, TableNode $table):void { $expectedConfigurations = $table->getColumnsHash(); foreach ($expectedConfigurations as $expectedConfigurationEntry) { Assert::assertArrayHasKey( 'configuration', $expectedConfigurationEntry, __METHOD__ . " The provided expected configuration entry '" . \implode(', ', $expectedConfigurationEntry) . "' do not have key 'configuration'" ); } $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); $isStorageEntryListed = false; foreach ($commandOutput as $listedStorageEntry) { if ($listedStorageEntry->mount_point === $localStorage) { $isStorageEntryListed = true; $configurations = $listedStorageEntry->configuration; $configurationsSplitted = \explode(', ', $configurations); foreach ($expectedConfigurations as $expectedConfigArray) { foreach ($expectedConfigArray as $expectedConfigEntry) { Assert::assertContains( $expectedConfigEntry, $configurationsSplitted, __METHOD__ . " $expectedConfigEntry is not contained in '" . \implode(', ', $configurationsSplitted) . "' but was expected to be." ); } } break; } } Assert::assertTrue($isStorageEntryListed, "Expected local storage '$localStorage' not found "); } /** * @When the administrator adds an option with key :key and value :value for the local storage mount :localStorage * * @param string $key * @param string $value * @param string $localStorage * * @return void * @throws Exception */ public function adminAddsOptionForLocalStorageMountUsingTheOccCommand(string $key, string $value, string $localStorage):void { $mountId = $this->featureContext->getStorageId($localStorage); $this->featureContext->runOcc( [ "files_external:option", $mountId, $key, $value ] ); $this->theCommandShouldHaveBeenSuccessful(); } /** * @Then the following should be included in the options of local storage :localStorage: * * @param string $localStorage * @param TableNode $table * * @return void * @throws Exception */ public function theFollowingShouldBeIncludedInTheOptionsOfLocalStorage(string $localStorage, TableNode $table):void { $expectedOptions = $table->getColumnsHash(); foreach ($expectedOptions as $expectedOptionEntry) { Assert::assertArrayHasKey( 'options', $expectedOptionEntry, __METHOD__ . " The provided expected option '" . \implode(', ', $expectedOptionEntry) . "' do not have key 'option'" ); } $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); $isStorageEntryListed = false; foreach ($commandOutput as $listedStorageEntry) { if ($listedStorageEntry->mount_point === $localStorage) { $isStorageEntryListed = true; $options = $listedStorageEntry->options; $optionsSplitted = \explode(', ', $options); foreach ($expectedOptions as $expectedOptionArray) { foreach ($expectedOptionArray as $expectedOptionEntry) { Assert::assertContains( $expectedOptionEntry, $optionsSplitted, __METHOD__ . " $expectedOptionEntry is not contained in '" . \implode(', ', $optionsSplitted) . "' , but was expected to be." ); } } break; } } Assert::assertTrue($isStorageEntryListed, "Expected local storage '$localStorage' not found "); } /** * @Then the following should not be included in the options of local storage :localStorage: * * @param string $localStorage * @param TableNode $table * * @return void * @throws Exception */ public function theFollowingShouldNotBeIncludedInTheOptionsOfLocalStorage(string $localStorage, TableNode $table):void { $expectedOptions = $table->getColumnsHash(); foreach ($expectedOptions as $expectedOptionEntry) { Assert::assertArrayHasKey( 'options', $expectedOptionEntry, __METHOD__ . " The provided expected option '" . \implode(', ', $expectedOptionEntry) . "' do not have key 'options'" ); } $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); $isStorageEntryListed = false; foreach ($commandOutput as $listedStorageEntry) { if ($listedStorageEntry->mount_point === $localStorage) { $isStorageEntryListed = true; $options = $listedStorageEntry->options; $optionsSplitted = \explode(', ', $options); foreach ($expectedOptions as $expectedOptionArray) { foreach ($expectedOptionArray as $expectedOptionEntry) { Assert::assertNotContains( $expectedOptionEntry, $optionsSplitted, __METHOD__ . " $expectedOptionEntry is contained in '" . \implode(', ', $optionsSplitted) . "' , but was not expected to be." ); } } break; } } Assert::assertTrue($isStorageEntryListed, "Expected local storage '$localStorage' not found "); } /** * @When the administrator deletes local storage :folder using the occ command * * @param string $folder * * @return integer|boolean * @throws Exception */ public function administratorDeletesFolder(string $folder) { return $this->deleteLocalStorageFolderUsingTheOccCommand($folder); } /** * @Given the administrator has deleted local storage :folder using the occ command * * @param string $folder * * @return integer * @throws Exception */ public function administratorHasDeletedLocalStorageFolderUsingTheOccCommand(string $folder):int { $mount_id = $this->deleteLocalStorageFolderUsingTheOccCommand($folder); $this->theCommandShouldHaveBeenSuccessful(); return $mount_id; } /** * @param string $folder * * @return integer|null * @throws Exception */ public function getMountIdForLocalStorage(string $folder): ?int { $createdLocalStorage = []; $mount_id = null; $this->listLocalStorageMount(); $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); foreach ($commandOutput as $i) { $createdLocalStorage[$i->mount_id] = \ltrim($i->mount_point, '/'); } foreach ($createdLocalStorage as $key => $value) { if ($value === $folder) { $mount_id = $key; } } return (int) $mount_id; } /** * @param string $folder * @param bool $mustExist * * @return integer|bool * @throws Exception */ public function deleteLocalStorageFolderUsingTheOccCommand(string $folder, bool $mustExist = true) { $mount_id = $this->getMountIdForLocalStorage($folder); if (!isset($mount_id)) { if ($mustExist) { throw new Exception("Id not found for folder to be deleted"); } return false; } $this->invokingTheCommand('files_external:delete --yes ' . $mount_id); return $mount_id; } /** * @When the administrator exports the local storage mounts using the occ command * * @return void * @throws Exception */ public function theAdministratorExportsTheMountsUsingTheOccCommand():void { $this->invokingTheCommand('files_external:export'); } /** * @When the administrator imports the local storage mount from file :file using the occ command * * @param string $file * * @return void * @throws Exception */ public function theAdministratorImportsTheMountFromFileUsingTheOccCommand(string $file):void { $this->invokingTheCommand( 'files_external:import ' . TEMPORARY_STORAGE_DIR_ON_REMOTE_SERVER . "/$file" ); } /** * @Given /^the administrator has exported the (local|external) storage mounts using the occ command$/ * * @return void * @throws Exception */ public function theAdministratorHasExportedTheMountsUsingTheOccCommand():void { $this->invokingTheCommand('files_external:export'); $this->theCommandShouldHaveBeenSuccessful(); } /** * @Then the command should output configuration for local storage mount :mount * * @param string $mount * * @return void * @throws Exception */ public function theOutputShouldContainConfigurationForMount(string $mount):void { $actualConfig = null; $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); foreach ($commandOutput as $i) { if ($mount === \ltrim($i->mount_point, '/')) { $actualConfig = $i; break; } } Assert::assertNotNull($actualConfig, 'Configuration for local storage mount ' . $mount . ' not found.'); } /** * @When the administrator verifies the mount configuration for local storage :localStorage using the occ command * * @param string $localStorage * * @return void * @throws Exception */ public function theAdministratorVerifiesTheMountConfigurationForLocalStorageUsingTheOccCommand(string $localStorage):void { $this->listLocalStorageMount(); $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); foreach ($commandOutput as $entry) { if (\ltrim($entry->mount_point, '/') == $localStorage) { $mountId = $entry->mount_id; } } if (!isset($mountId)) { throw new Exception("Id not found for local storage $localStorage to be verified"); } $this->invokingTheCommand('files_external:verify ' . $mountId); } /** * @Then the following mount configuration information should be listed: * * @param TableNode $info * * @return void */ public function theFollowingInformationShouldBeListed(TableNode $info):void { $ResultArray = []; $expectedInfo = $info->getColumnsHash(); $commandOutput = $this->featureContext->getStdOutOfOccCommand(); $commandOutputSplitted = \preg_split("/[-]/", $commandOutput); $filteredArray = \array_filter(\array_map("trim", $commandOutputSplitted)); foreach ($filteredArray as $entry) { $keyValue = \preg_split("/[:]/", $entry); if (isset($keyValue[1])) { $ResultArray[$keyValue[0]] = $keyValue[1]; } else { $ResultArray[$keyValue[0]] = ""; } } foreach ($expectedInfo as $element) { Assert::assertEquals( $element, \array_map('trim', $ResultArray), __METHOD__ . " '" . \implode(', ', $element) . "' was expected to be listed, but is not listed in the mount configuration information" ); } } /** * @When the administrator list the repair steps using the occ command * * @return void * @throws Exception */ public function theAdministratorListTheRepairStepsUsingTheOccCommand():void { $this->invokingTheCommand('maintenance:repair --list'); } /** * @Then the background jobs mode should be :mode * * @param string $mode * * @return void * @throws Exception */ public function theBackgroundJobsModeShouldBe(string $mode):void { $this->invokingTheCommand( "config:app:get core backgroundjobs_mode" ); $lastOutput = $this->featureContext->getStdOutOfOccCommand(); Assert::assertEquals( $mode, \trim($lastOutput), "The background jobs mode was expected to be {$mode} but got '" . \trim($lastOutput) . "'" ); } /** * @Then the update channel should be :value * * @param string $value * * @return void * @throws Exception */ public function theUpdateChannelShouldBe(string $value):void { $this->invokingTheCommand( "config:app:get core OC_Channel" ); $lastOutput = $this->featureContext->getStdOutOfOccCommand(); Assert::assertEquals( $value, \trim($lastOutput), "The update channel was expected to be '$value' but got '" . \trim($lastOutput) . "'" ); } /** * @Then the log level should be :logLevel * * @param string $logLevel * * @return void * @throws Exception */ public function theLogLevelShouldBe(string $logLevel):void { $this->invokingTheCommand( "config:system:get loglevel" ); $lastOutput = $this->featureContext->getStdOutOfOccCommand(); Assert::assertEquals( $logLevel, \trim($lastOutput), "The log level was expected to be '$logLevel' but got '" . \trim($lastOutput) . "'" ); } /** * @When the administrator adds/updates config key :key with value :value in app :app using the occ command * * @param string $key * @param string $value * @param string $app * * @return void * @throws Exception */ public function theAdministratorAddsConfigKeyWithValueInAppUsingTheOccCommand(string $key, string $value, string $app):void { $this->addConfigKeyWithValueInAppUsingTheOccCommand( $key, $value, $app ); } /** * @Given the administrator has added config key :key with value :value in app :app * * @param string $key * @param string $value * @param string $app * * @return void * @throws Exception */ public function theAdministratorHasAddedConfigKeyWithValueInAppUsingTheOccCommand(string $key, string $value, string $app):void { $this->addConfigKeyWithValueInAppUsingTheOccCommand( $key, $value, $app ); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator deletes config key :key of app :app using the occ command * * @param string $key * @param string $app * * @return void * @throws Exception */ public function theAdministratorDeletesConfigKeyOfAppUsingTheOccCommand(string $key, string $app):void { $this->deleteConfigKeyOfAppUsingTheOccCommand($key, $app); } /** * @When the administrator adds/updates system config key :key with value :value using the occ command * @When the administrator adds/updates system config key :key with value :value and type :type using the occ command * * @param string $key * @param string $value * @param string $type * * @return void * @throws Exception */ public function theAdministratorAddsSystemConfigKeyWithValueUsingTheOccCommand( string $key, string $value, string $type = "string" ):void { $this->addSystemConfigKeyUsingTheOccCommand( $key, $value, $type ); } /** * @Given the administrator has added/updated system config key :key with value :value * @Given the administrator has added/updated system config key :key with value :value and type :type * * @param string $key * @param string $value * @param string $type * * @return void * @throws Exception */ public function theAdministratorHasAddedSystemConfigKeyWithValueUsingTheOccCommand( string $key, string $value, string $type = "string" ):void { $this->addSystemConfigKeyUsingTheOccCommand( $key, $value, $type ); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator deletes system config key :key using the occ command * * @param string $key * * @return void * @throws Exception */ public function theAdministratorDeletesSystemConfigKeyUsingTheOccCommand(string $key):void { $this->deleteSystemConfigKeyUsingTheOccCommand($key); } /** * @When the administrator empties the trashbin of user :user using the occ command * * @param string $user * * @return void * @throws Exception */ public function theAdministratorEmptiesTheTrashbinOfUserUsingTheOccCommand(string $user):void { $this->emptyTrashBinOfUserUsingOccCommand($user); } /** * @When the administrator deletes all the versions for user :user * @When the administrator tries to delete all the versions for user :user * * @param string $user * * @return void * @throws Exception */ public function theAdministratorDeletesAllTheVersionsForUser(string $user):void { $user = $this->featureContext->getActualUsername($user); $this->deleteAllVersionsForUserUsingOccCommand($user); } /** * @When the administrator cleanups all the orphaned remote storages of shares using the occ command * * @return void * @throws Exception */ public function theAdminCleanupsOrphanedRemoteStoragesOfSharesUsingOccCommand():void { $this->cleanOrphanedRemoteStoragesUsingOccCommand(); } /** * @When the administrator deletes all the versions for the following users: * * @param TableNode $usersTable * * @return void * @throws Exception */ public function theAdministratorDeletesAllTheVersionsForSpecificUsers(TableNode $usersTable):void { $this->featureContext->verifyTableNodeColumns($usersTable, ["username"]); $usernames = $usersTable->getHash(); $usernamesArray = []; foreach ($usernames as $username) { array_push($usernamesArray, $username["username"]); } $users = implode(" ", $usernamesArray); $this->deleteAllVersionsForMultipleUsersUsingOccCommand($users); } /** * @When the administrator deletes the file versions for all users * * @return void * @throws Exception */ public function theAdministratorDeletesVersionsForAllUsers(): void { $this->deleteAllVersionsForAllUsersUsingOccCommand(); } /** * @When the administrator deletes the expired versions for user :user * @When the administrator tries to delete the expired versions for user :user * * @param string $user * * @return void * @throws Exception */ public function theAdministratorDeletesExpiredVersionsForUser(string $user): void { $user = $this->featureContext->getActualUsername($user); $this->deleteExpiredVersionsForUserUsingOccCommand($user); } /** * @When the administrator deletes the expired versions for the following users: * * @param TableNode $usersTable * * @return void * @throws Exception */ public function theAdministratorDeletesExpiredVersionsForSpecificUsers(TableNode $usersTable): void { $this->featureContext->verifyTableNodeColumns($usersTable, ["username"]); $usernames = $usersTable->getHash(); $usernamesArray = []; foreach ($usernames as $username) { array_push($usernamesArray, $username["username"]); } $users = implode(" ", $usernamesArray); $this->deleteExpiredVersionsForMultipleUsersUsingOccCommand($users); } /** * @When the administrator deletes the expired versions for all users * * @return void * @throws Exception */ public function theAdministratorDeletesExpiredVersionsForAllUsers(): void { $this->deleteExpiredVersionsForAllUsersUsingOccCommand(); } /** * @When the administrator empties the trashbin of all users using the occ command * * @return void * @throws Exception */ public function theAdministratorEmptiesTheTrashbinOfAllUsersUsingTheOccCommand():void { $this->emptyTrashBinOfUserUsingOccCommand(''); } /** * @When the administrator creates a calendar for user :user with name :calendarName using the occ command * * @param string $user * @param string $calendarName * * @return void * @throws Exception */ public function theAdminCreatesACalendarForUserUsingTheOccCommand(string $user, string $calendarName):void { $user = $this->featureContext->getActualUsername($user); $this->createCalendarForUserUsingOccCommand($user, $calendarName); } /** * @When the administrator creates an address book for user :user with name :addressBookName using the occ command * * @param string $user * @param string $addressBookName * * @return void * @throws Exception */ public function theAdminCreatesAnAddressBookForUserUsingTheOccCommand(string $user, string $addressBookName):void { $user = $this->featureContext->getActualUsername($user); $this->createAnAddressBookForUserUsingOccCommand($user, $addressBookName); } /** * @When the administrator gets all the jobs in the background queue using the occ command * * @return void * @throws Exception */ public function theAdministratorGetsAllTheJobsInTheBackgroundQueueUsingTheOccCommand():void { $this->getAllJobsInBackgroundQueueUsingOccCommand(); } /** * @When the administrator deletes the last background job :job using the occ command * * @param string $job * * @return void * @throws Exception */ public function theAdministratorDeletesLastBackgroundJobUsingTheOccCommand(string $job):void { $this->deleteLastBackgroundJobUsingTheOccCommand($job); } /** * @Then the last deleted background job :job should not be listed in the background jobs queue * * @param string $job * * @return void * @throws Exception */ public function theLastDeletedJobShouldNotBeListedInTheJobsQueue(string $job):void { $jobId = $this->lastDeletedJobId; $match = $this->getLastJobIdForJob($job); if ($match) { Assert::assertNotEquals( $jobId, $match, "job $job with jobId $jobId" . " was not expected to be listed in background queue, but was" ); } } /** * @Then system config key :key should have value :value * * @param string $key * @param string $value * * @return void * @throws Exception */ public function systemConfigKeyShouldHaveValue(string $key, string $value):void { $config = \trim( SetupHelper::getSystemConfigValue( $key, $this->featureContext->getStepLineRef() ) ); Assert::assertSame( $value, $config, "The system config key '$key' was expected to have value '$value', but got '$config'" ); } /** * @Then the command output table should contain the following text: * * @param TableNode $table table of patterns to find with table title as 'table_column' * * @return void * @throws Exception */ public function theCommandOutputTableShouldContainTheFollowingText(TableNode $table):void { $commandOutput = $this->featureContext->getStdOutOfOccCommand(); $this->featureContext->verifyTableNodeColumns($table, ['table_column']); foreach ($table as $row) { $lines = SetupHelper::findLines( $commandOutput, $row['table_column'] ); Assert::assertNotEmpty( $lines, "Value: " . $row['table_column'] . " not found" ); } } /** * @Then system config key :key should not exist * * @param string $key * * @return void * @throws Exception */ public function systemConfigKeyShouldNotExist(string $key):void { Assert::assertEmpty( SetupHelper::getSystemConfig( $key, $this->featureContext->getStepLineRef() )['stdOut'], "The system config key '$key' was not expected to exist" ); } /** * @When the administrator lists the config keys * * @return void * @throws Exception */ public function theAdministratorListsTheConfigKeys():void { $this->invokingTheCommand( "config:list" ); } /** * @Then the command output should contain the apps configs * * @return void */ public function theCommandOutputShouldContainTheAppsConfigs():void { $config_list = \json_decode($this->featureContext->getStdOutOfOccCommand(), true); Assert::assertArrayHasKey( 'apps', $config_list, "The occ output does not contain apps configs" ); Assert::assertNotEmpty( $config_list['apps'], "The occ output does not contain apps configs" ); } /** * @Then the command output should contain the system configs * * @return void */ public function theCommandOutputShouldContainTheSystemConfigs():void { $config_list = \json_decode($this->featureContext->getStdOutOfOccCommand(), true); Assert::assertArrayHasKey( 'system', $config_list, "The occ output does not contain system configs" ); Assert::assertNotEmpty( $config_list['system'], "The occ output does not contain system configs" ); } /** * @Given the administrator has cleared the versions for user :user * * @param string $user * * @return void * @throws Exception */ public function theAdministratorHasClearedTheVersionsForUser(string $user):void { $user = $this->featureContext->getActualUsername($user); $this->deleteAllVersionsForUserUsingOccCommand($user); Assert::assertSame( "Delete versions of $user", \trim($this->featureContext->getStdOutOfOccCommand()) ); } /** * @Given the administrator has cleared the versions for all users * * @return void * @throws Exception */ public function theAdministratorHasClearedTheVersionsForAllUsers():void { $this->deleteAllVersionsForAllUsersUsingOccCommand(); Assert::assertStringContainsString( "Delete all versions", \trim($this->featureContext->getStdOutOfOccCommand()), "Expected 'Delete all versions' to be contained in the output of occ command: " . \trim($this->featureContext->getStdOutOfOccCommand()) ); } /** * get jobId of the latest job found of given job class * * @param string $job * * @return string|bool * @throws Exception */ public function getLastJobIdForJob(string $job) { $this->getAllJobsInBackgroundQueueUsingOccCommand(); $commandOutput = $this->featureContext->getStdOutOfOccCommand(); $lines = SetupHelper::findLines( $commandOutput, $job ); if (!$lines) { return false; } // find the jobId of the newest job among the jobs with given class $success = \preg_match("/\d+/", \end($lines), $match); if ($success) { return $match[0]; } return false; } /** * @Then the system config key :key from the last command output should match value :value of type :type * * @param string $key * @param string $value * @param string $type * * @return void */ public function theSystemConfigKeyFromLastCommandOutputShouldContainValue( string $key, string $value, string $type ):void { $configList = \json_decode( $this->featureContext->getStdOutOfOccCommand(), true ); $systemConfig = $configList['system']; // convert the value to it's respective type based on type given in the type column if ($type === 'boolean') { $value = $value === 'true' ? true : false; } elseif ($type === 'integer') { $value = (int) $value; } elseif ($type === 'json') { // if the expected value of the key is a json // match the value with the regular expression $actualKeyValuePair = \json_encode( $systemConfig[$key], JSON_UNESCAPED_SLASHES ); Assert::assertThat( $actualKeyValuePair, Assert::matchesRegularExpression($value) ); return; } if (!\array_key_exists($key, $systemConfig)) { Assert::fail( "system config doesn't contain key: " . $key ); } Assert::assertEquals( $value, $systemConfig[$key], "config: $key doesn't contain value: $value" ); } /** * @Given the administrator has enabled the external storage * * @return void * @throws Exception */ public function enableExternalStorageUsingOccAsAdmin():void { SetupHelper::runOcc( [ 'config:app:set', 'core', 'enable_external_storage', '--value=yes' ], $this->featureContext->getStepLineRef(), $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), $this->featureContext->getBaseUrl(), $this->featureContext->getOcPath() ); $response = SetupHelper::runOcc( [ 'config:app:get', 'core', 'enable_external_storage', ], $this->featureContext->getStepLineRef(), $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), $this->featureContext->getBaseUrl(), $this->featureContext->getOcPath() ); $status = \trim($response['stdOut']); Assert::assertEquals( 'yes', $status, "The external storage was expected to be enabled but got '$status'" ); } /** * @Given the administrator has added group :group to the exclude group from sharing list * * @param string $groups * multiple groups can be passed as comma separated string * * @return void * @throws Exception * @throws GuzzleException */ public function theAdministratorHasAddedGroupToTheExcludeGroupFromSharingList(string $groups):void { $groups = \explode(',', \trim($groups)); $groups = \array_map('trim', $groups); //removing whitespaces around group names $groups = '"' . \implode('","', $groups) . '"'; SetupHelper::runOcc( [ 'config:app:set', 'core', 'shareapi_exclude_groups_list', "--value='[$groups]'" ], $this->featureContext->getStepLineRef(), $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), $this->featureContext->getBaseUrl(), $this->featureContext->getOcPath() ); $response = SetupHelper::runOcc( [ 'config:app:get', 'core', 'shareapi_exclude_groups_list' ], $this->featureContext->getStepLineRef(), $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), $this->featureContext->getBaseUrl(), $this->featureContext->getOcPath() ); $excludedGroupsFromResponse = (\trim($response['stdOut'])); $excludedGroupsFromResponse = \trim($excludedGroupsFromResponse, '[]'); Assert::assertEquals( $groups, $excludedGroupsFromResponse, "'$groups' is not added to exclude groups from sharing list: '" . $excludedGroupsFromResponse . "' but was expected to be" ); } /** * @Given the administrator has enabled exclude groups from sharing * * @return void * @throws Exception */ public function theAdministratorHasEnabledExcludeGroupsFromSharingUsingTheWebui():void { SetupHelper::runOcc( [ "config:app:set", "core", "shareapi_exclude_groups", "--value=yes" ], $this->featureContext->getStepLineRef(), $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), $this->featureContext->getBaseUrl(), $this->featureContext->getOcPath() ); $response = SetupHelper::runOcc( [ "config:app:get", "core", "shareapi_exclude_groups" ], $this->featureContext->getStepLineRef(), $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), $this->featureContext->getBaseUrl(), $this->featureContext->getOcPath() ); $status = \trim($response['stdOut']); Assert::assertEquals( "yes", $status, "Exclude groups from sharing was expected to be 'yes'(enabled) but got '$status'" ); } /** * @Given /^the administrator has (enabled|disabled) the webUI lock file action$/ * * @param string $enabledOrDisabled * * @return void * @throws Exception */ public function theAdministratorHasEnabledTheWebUILockFileAction(string $enabledOrDisabled):void { $switch = ($enabledOrDisabled !== "disabled"); if ($switch) { $value = 'yes'; } else { $value = 'no'; } SetupHelper::runOcc( [ "config:app:set", "files", "enable_lock_file_action", "--value=$value" ], $this->featureContext->getStepLineRef(), $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), $this->featureContext->getBaseUrl(), $this->featureContext->getOcPath() ); $response = SetupHelper::runOcc( [ "config:app:get", "files", "enable_lock_file_action" ], $this->featureContext->getStepLineRef(), $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), $this->featureContext->getBaseUrl(), $this->featureContext->getOcPath() ); $status = \trim($response['stdOut']); Assert::assertEquals( $value, $status, "enable_lock_file_action was expected to be '$value'($enabledOrDisabled) but got '$status'" ); } /** * @When the administrator creates an external mount point with the following configuration about user :user using the occ command * * @param string $user * @param TableNode $settings * * necessary attributes inside $settings table: * 1. host - remote server url * 2. root - remote folder name -> mount path * 3. secure - true/false (http or https) * 4. user - remote server user username * 5. password - remote server user password * 6. mount_point - external storage name * 7. storage_backend - options: [local, owncloud, smb, googledrive, sftp, dav] * 8. authentication_backend - options: [null::null, password::password, password::sessioncredentials] * * @see [`php occ files_external:backends`] to view * detailed information of parameters used above * * @return void * @throws Exception */ public function createExternalMountPointUsingTheOccCommand(string $user, TableNode $settings):void { $userRenamed = $this->featureContext->getActualUsername($user); $this->featureContext->verifyTableNodeRows( $settings, ["host", "root", "storage_backend", "authentication_backend", "mount_point", "user", "password", "secure"] ); $extMntSettings = $settings->getRowsHash(); $extMntSettings['user'] = $this->featureContext->substituteInLineCodes( $extMntSettings['user'], $userRenamed ); $password = $this->featureContext->substituteInLineCodes( $extMntSettings['password'], $user ); $args = [ "files_external:create", "-c host=" . $this->featureContext->substituteInLineCodes($extMntSettings['host']), "-c root=" . $extMntSettings['root'], "-c secure=" . $extMntSettings['secure'], "-c user=" . $extMntSettings['user'], "-c password=" . $password, $extMntSettings['mount_point'], $extMntSettings['storage_backend'], $extMntSettings['authentication_backend'] ]; $this->featureContext->setOccLastCode( $this->featureContext->runOcc($args) ); // add to array of created storageIds $commandOutput = $this->featureContext->getStdOutOfOccCommand(); $mountId = \preg_replace('/\D/', '', $commandOutput); $this->featureContext->addStorageId($extMntSettings["mount_point"], (int) $mountId); } /** * @Given the administrator has created an external mount point with the following configuration about user :user using the occ command * * @param string $user * @param TableNode $settings * * @return void * @throws Exception */ public function adminHasCreatedAnExternalMountPointWithFollowingConfigUsingTheOccCommand(string $user, TableNode $settings):void { $this->createExternalMountPointUsingTheOccCommand($user, $settings); $this->theCommandShouldHaveBeenSuccessful(); } /** * @param string $mountPoint * * @return void * @throws Exception */ private function deleteExternalMountPointUsingTheAdmin(string $mountPoint):void { $mount_id = $this->administratorDeletesFolder($mountPoint); $this->featureContext->popStorageId($mount_id); } /** * @Given the administrator has deleted external storage with mount point :mountPoint * * @param string $mountPoint * * @return void * @throws Exception */ public function adminHasDeletedExternalMountPoint(string $mountPoint):void { $this->deleteExternalMountPointUsingTheAdmin($mountPoint); $this->theCommandShouldHaveBeenSuccessful(); } /** * @When the administrator deletes external storage with mount point :mountPoint * * @param string $mountPoint * * @return void * @throws Exception */ public function adminDeletesExternalMountPoint(string $mountPoint):void { $this->deleteExternalMountPointUsingTheAdmin($mountPoint); } /** * @Then mount point :mountPoint should not be listed as an external storage * * @param string $mountPoint * * @return void */ public function mountPointShouldNotBeListedAsAnExternalStorage(string $mountPoint):void { $commandOutput = \json_decode($this->featureContext->getStdOutOfOccCommand()); foreach ($commandOutput as $entry) { Assert::assertNotEquals($mountPoint, $entry->mount_point); } } /** * @Given the administrator has changed the database type to :dbType * * @param string $dbType * * @return void * @throws Exception */ public function theAdministratorHasChangedTheDatabaseType(string $dbType): void { $this->theAdministratorChangesTheDatabaseType($dbType); $exitStatusCode = $this->featureContext->getExitStatusCodeOfOccCommand(); if ($exitStatusCode !== 0) { $exceptions = $this->featureContext->findExceptions(); $commandErr = $this->featureContext->getStdErrOfOccCommand(); $sameTypeError = "Can not convert from $dbType to $dbType."; $lines = SetupHelper::findLines( $commandErr, $sameTypeError ); // pass if the same type error is found if (\count($lines) === 0) { $msg = "The command was not successful, exit code was " . $exitStatusCode . ".\n" . "stdOut was: '" . $this->featureContext->getStdOutOfOccCommand() . "'\n" . "stdErr was: '$commandErr'\n"; if (!empty($exceptions)) { $msg .= ' Exceptions: ' . \implode(', ', $exceptions); } throw new Exception($msg); } } } /** * @When the administrator changes the database type to :dbType * @When the administrator tries to change the database type to :dbType * * @param string $dbType * * @return void * @throws Exception */ public function theAdministratorChangesTheDatabaseType(string $dbType): void { $dbUser = "owncloud"; $dbHost = $dbType; $dbName = "owncloud"; $dbPass = "owncloud"; if ($dbType === "postgres") { $dbType = "pgsql"; } if ($dbType === "oracle") { $dbUser = "autotest"; $dbType = "oci"; } $this->invokingTheCommand("db:convert-type --password=$dbPass $dbType $dbUser $dbHost $dbName"); $this->featureContext->setDbConversionState(true); } /** * This will run after EVERY scenario. * It will set the properties for this object. * * @AfterScenario * * @return void * @throws Exception */ public function removeImportedCertificates():void { $remainingCertificates = \array_diff($this->importedCertificates, $this->removedCertificates); foreach ($remainingCertificates as $certificate) { $this->invokingTheCommand("security:certificates:remove " . $certificate); $this->theCommandShouldHaveBeenSuccessful(); } } /** * This will run after EVERY scenario. * Some local_storage tests import storage from an export file. In that case * we have not explicitly created the storage, and so we do not explicitly * know to delete it. So delete the local storage that is known to be used * in tests. * * @AfterScenario @local_storage * * @return void * @throws Exception */ public function removeLocalStorageIfExists():void { $this->deleteLocalStorageFolderUsingTheOccCommand('local_storage', false); $this->deleteLocalStorageFolderUsingTheOccCommand('local_storage2', false); $this->deleteLocalStorageFolderUsingTheOccCommand('local_storage3', false); $this->deleteLocalStorageFolderUsingTheOccCommand('TestMountPoint', false); } /** * This will run before EVERY scenario. * It will set the properties for this object. * * @BeforeScenario * * @param BeforeScenarioScope $scope * * @return void * @throws Exception */ public function before(BeforeScenarioScope $scope):void { // Get the environment $environment = $scope->getEnvironment(); // Get all the contexts you need in this context $this->featureContext = $environment->getContext('FeatureContext'); SetupHelper::init( $this->featureContext->getAdminUsername(), $this->featureContext->getAdminPassword(), $this->featureContext->getBaseUrl(), $this->featureContext->getOcPath() ); $ocVersion = SetupHelper::getSystemConfigValue( 'version', $this->featureContext->getStepLineRef() ); } /** * @Then /^the system config should have dbtype set as "([^"]*)"$/ * * @param string $value * * @return void * @throws GuzzleException */ public function theSystemConfigKeyShouldBeSetAs(string $value):void { $actual_value = SetupHelper::getSystemConfigValue( "dbtype", $this->featureContext->getStepLineRef() ); $actual_value = \str_replace("\n", "", $actual_value); Assert::assertEquals( $value, $actual_value, "System config mismatched.\n Expected dbType to be: " . $actual_value . "\n Found: " . $value ); } /** * @When the administrator lists migration status of app :app * * @param string $app * * @return void * @throws Exception */ public function theAdministratorListsMigrationStatusOfApp(string $app):void { $this->featureContext->setStdOutOfOccCommand(""); $this->featureContext->setOccLastCode( $this->featureContext->runOcc(['migrations:status', $app]) ); } /** * @Then the following migration status should have been listed * * @param TableNode $table * * @return void * @throws Exception */ public function theFollowingMigrationStatusShouldHaveBeenListed(TableNode $table): void { $actualOuput = $this->getMigrationStatusInfo(); $expectedOutput = $table->getRowsHash(); foreach ($expectedOutput as $key => $value) { try { $actualValue = $actualOuput[$key]; } catch (Exception $e) { Assert:: fail("Expected '$key' but not found!\nActual Migration status: " . \print_r($actualOuput, true)); } if ($this->isRegex($value)) { $match = preg_match($value, $actualValue); Assert:: assertEquals(1, $match, "Pattern '$value' is not matchable with value '$actualValue'"); } else { Assert:: assertEquals($value, $actualValue, "Expected '$key' to have value '$value' but got '$actualValue'"); } } } /** * @Then the Executed Migrations should equal the Available Migrations * * @return void * @throws Exception */ public function theExecutedMigrationsShouldEqualTheAvailableMigrations(): void { $migrationStatus = $this->getMigrationStatusInfo(); Assert:: assertEquals($migrationStatus["Executed Migrations"], $migrationStatus["Available Migrations"], "The 'Executed Migration' is not same as 'Available Migration'"); } /** * @param string $value * * @return int */ public function isRegex($value) { $regex = "/^\/[\s\S]+\/$/"; return preg_match($regex, $value); } /** * @return void */ public function getMigrationStatusInfo() { $commandOutput = $this->featureContext->getStdOutOfOccCommand(); $migrationStatus = []; if (!empty($commandOutput)) { $infoArr = explode("\n", $commandOutput); foreach ($infoArr as $info) { if (!empty($info)) { $row = \trim(\str_replace('>>', '', $info)); $rowCol = explode(":", $row); $migrationStatus[\trim($rowCol[0])] = \trim($rowCol[1]); } } return $migrationStatus; } else { throwException("Migration status information is empty!"); } } }