diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php new file mode 100644 index 000000000..bac14113d --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/FilePathFormatterTest.php @@ -0,0 +1,84 @@ +assertEquals($expectedPath, FilePathFormatter::format($path, $withTrailingSeparator)); + } else { + // Assert no exception + FilePathFormatter::format($path, $withTrailingSeparator); + $this->assertTrue(true); + } + } + + /** + * Test file format with exception + * + * @dataProvider formatExceptionDataProvider + * @param string $path + * @param boolean $withTrailingSeparator + * @return void + * @throws TestFrameworkException + */ + public function testFormatWithException($path, $withTrailingSeparator) + { + $this->expectException(TestFrameworkException::class); + $this->expectExceptionMessage("Invalid or non-existing file: $path\n"); + FilePathFormatter::format($path, $withTrailingSeparator); + } + + /** + * Data input + * + * @return array + */ + public function formatDataProvider() + { + $path1 = rtrim(TESTS_BP, '/'); + $path2 = $path1 . DIRECTORY_SEPARATOR; + return [ + [$path1, null, $path1], + [$path1, false, $path1], + [$path1, true, $path2], + [$path2, null, $path1], + [$path2, false, $path1], + [$path2, true, $path2], + [__DIR__. DIRECTORY_SEPARATOR . basename(__FILE__), null, __FILE__], + ['', null, null] // Empty string is valid + ]; + } + + /** + * Invalid data input + * + * @return array + */ + public function formatExceptionDataProvider() + { + return [ + ['abc', null], + ['X://some\dir/@', null], + ]; + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php new file mode 100644 index 000000000..c66c9558c --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/Path/UrlFormatterTest.php @@ -0,0 +1,91 @@ +assertEquals($expectedPath, UrlFormatter::format($path, $withTrailingSeparator)); + } + + /** + * Test url format with exception + * + * @dataProvider formatExceptionDataProvider + * @param string $path + * @param boolean $withTrailingSeparator + * @return void + * @throws TestFrameworkException + */ + public function testFormatWithException($path, $withTrailingSeparator) + { + $this->expectException(TestFrameworkException::class); + $this->expectExceptionMessage("Invalid url: $path\n"); + UrlFormatter::format($path, $withTrailingSeparator); + } + + /** + * Data input + * + * @return array + */ + public function formatDataProvider() + { + $url1 = 'http://magento.local/index.php'; + $url2 = $url1 . '/'; + $url3 = 'https://www.example.com/index.php/admin'; + $url4 = $url3 . '/'; + $url5 = 'www.google.com'; + $url6 = 'http://www.google.com/'; + $url7 = 'http://127.0.0.1:8200'; + $url8 = 'wwøw.goåoøgle.coøm'; + $url9 = 'http://www.google.com'; + return [ + [$url1, null, $url1], + [$url1, false, $url1], + [$url1, true, $url2], + [$url2, null, $url1], + [$url2, false, $url1], + [$url2, true, $url2], + [$url3, null, $url3], + [$url3, false, $url3], + [$url3, true, $url4], + [$url4, null, $url3], + [$url4, false, $url3], + [$url4, true, $url4], + [$url5, true, $url6], + [$url7, false, $url7], + [$url8, false, $url9], + ]; + } + + /** + * Invalid data input + * + * @return array + */ + public function formatExceptionDataProvider() + { + return [ + ['', null], + ]; + } +} diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index d2242fb52..485ef6411 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -6,11 +6,13 @@ namespace tests\verification\Tests; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Suite\SuiteGenerator; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\Manifest\DefaultTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\ParallelTestManifest; use Magento\FunctionalTestingFramework\Util\Manifest\TestManifestFactory; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use PHPUnit\Util\Filesystem; use Symfony\Component\Yaml\Yaml; use tests\unit\Util\TestLoggingUtil; @@ -413,11 +415,11 @@ public static function tearDownAfterClass() * Getter for manifest file path * * @return string + * @throws TestFrameworkException */ private static function getManifestFilePath() { - return TESTS_BP . - DIRECTORY_SEPARATOR . + return FilePathFormatter::format(TESTS_BP) . "verification" . DIRECTORY_SEPARATOR . "_generated" . diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php index 2376b3cf1..3a976944b 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Primary.php @@ -6,8 +6,10 @@ namespace Magento\FunctionalTestingFramework\Config\FileResolver; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Iterator\File; use Magento\FunctionalTestingFramework\Config\FileResolverInterface; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; /** * Provides the list of global configuration files. @@ -54,6 +56,7 @@ private function getFilePaths($filename, $scope) * @param string $filename * @param string $scope * @return array + * @throws TestFrameworkException */ private function getPathPatterns($filename, $scope) { @@ -69,8 +72,9 @@ private function getPathPatterns($filename, $scope) $defaultPath . DIRECTORY_SEPARATOR . $scope . DIRECTORY_SEPARATOR . $filename, $defaultPath . DIRECTORY_SEPARATOR . $scope . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . $filename, - FW_BP . DIRECTORY_SEPARATOR . $scope . DIRECTORY_SEPARATOR . $filename, - FW_BP . DIRECTORY_SEPARATOR . $scope . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR . $filename + FilePathFormatter::format(FW_BP) . $scope . DIRECTORY_SEPARATOR . $filename, + FilePathFormatter::format(FW_BP) . $scope . DIRECTORY_SEPARATOR . '*' . DIRECTORY_SEPARATOR + . $filename ]; } return str_replace(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, $patterns); diff --git a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php index 3b0940b28..4ebb11942 100644 --- a/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php +++ b/src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php @@ -7,7 +7,9 @@ namespace Magento\FunctionalTestingFramework\Config\FileResolver; use Magento\FunctionalTestingFramework\Config\FileResolverInterface; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Iterator\File; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; class Root extends Module { @@ -20,12 +22,13 @@ class Root extends Module * @param string $filename * @param string $scope * @return array|\Iterator,\Countable + * @throws TestFrameworkException */ public function get($filename, $scope) { // first pick up the root level test suite dir $paths = glob( - TESTS_BP . DIRECTORY_SEPARATOR . self::ROOT_SUITE_DIR + FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR . DIRECTORY_SEPARATOR . $filename ); diff --git a/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php b/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php index a92f536a3..869c58373 100644 --- a/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php +++ b/src/Magento/FunctionalTestingFramework/Config/SchemaLocator.php @@ -6,6 +6,9 @@ namespace Magento\FunctionalTestingFramework\Config; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; + /** * Configuration schema locator. */ @@ -30,12 +33,14 @@ class SchemaLocator implements \Magento\FunctionalTestingFramework\Config\Schema * * @param string $schemaPath * @param string|null $perFileSchema + * @throws TestFrameworkException */ public function __construct($schemaPath, $perFileSchema = null) { - if (constant('FW_BP') && file_exists(FW_BP . DIRECTORY_SEPARATOR . $schemaPath)) { - $this->schemaPath = FW_BP . DIRECTORY_SEPARATOR . $schemaPath; - $this->perFileSchema = $perFileSchema === null ? null : FW_BP . DIRECTORY_SEPARATOR . $perFileSchema; + if (constant('FW_BP') && file_exists(FilePathFormatter::format(FW_BP) . $schemaPath)) { + $this->schemaPath = FilePathFormatter::format(FW_BP) . $schemaPath; + $this->perFileSchema = $perFileSchema === null ? null : FilePathFormatter::format(FW_BP) + . $perFileSchema; } else { $path = dirname(dirname(dirname(__DIR__))); $path = str_replace('\\', DIRECTORY_SEPARATOR, $path); diff --git a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php index 5afaf17c5..0953e9d68 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BaseGenerateCommand.php @@ -8,7 +8,9 @@ namespace Magento\FunctionalTestingFramework\Console; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -57,10 +59,11 @@ protected function configure() * @param OutputInterface $output * @param bool $verbose * @return void + * @throws TestFrameworkException */ protected function removeGeneratedDirectory(OutputInterface $output, bool $verbose) { - $generatedDirectory = TESTS_MODULE_PATH . DIRECTORY_SEPARATOR . TestGenerator::GENERATED_DIR; + $generatedDirectory = FilePathFormatter::format(TESTS_MODULE_PATH) . TestGenerator::GENERATED_DIR; if (file_exists($generatedDirectory)) { DirSetupUtil::rmdirRecursive($generatedDirectory); diff --git a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php index 5102a3fdf..02dfcda82 100644 --- a/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/BuildProjectCommand.php @@ -18,6 +18,7 @@ use Symfony\Component\Process\Process; use Magento\FunctionalTestingFramework\Util\Env\EnvProcessor; use Symfony\Component\Yaml\Yaml; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; /** * Class BuildProjectCommand @@ -28,7 +29,6 @@ class BuildProjectCommand extends Command { const DEFAULT_YAML_INLINE_DEPTH = 10; - const CREDENTIALS_FILE_PATH = TESTS_BP . DIRECTORY_SEPARATOR . '.credentials.example'; /** * Env processor manages .env files. @@ -41,6 +41,7 @@ class BuildProjectCommand extends Command * Configures the current command. * * @return void + * @throws TestFrameworkException */ protected function configure() { @@ -52,7 +53,7 @@ protected function configure() InputOption::VALUE_NONE, 'upgrade existing MFTF tests according to last major release requirements' ); - $this->envProcessor = new EnvProcessor(TESTS_BP . DIRECTORY_SEPARATOR . '.env'); + $this->envProcessor = new EnvProcessor(FilePathFormatter::format(TESTS_BP) . '.env'); $env = $this->envProcessor->getEnv(); foreach ($env as $key => $value) { $this->addOption($key, null, InputOption::VALUE_REQUIRED, '', $value); @@ -65,8 +66,7 @@ protected function configure() * @param InputInterface $input * @param OutputInterface $output * @return void - * @throws \Symfony\Component\Console\Exception\LogicException - * + * @throws \Exception * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ protected function execute(InputInterface $input, OutputInterface $output) @@ -109,7 +109,7 @@ function ($type, $buffer) use ($output) { if ($input->getOption('upgrade')) { $upgradeCommand = new UpgradeTestsCommand(); - $upgradeOptions = new ArrayInput(['path' => TESTS_MODULE_PATH]); + $upgradeOptions = new ArrayInput(['path' => FilePathFormatter::format(TESTS_MODULE_PATH)]); $upgradeCommand->run($upgradeOptions, $output); } } @@ -119,6 +119,7 @@ function ($type, $buffer) use ($output) { * * @param OutputInterface $output * @return void + * @throws TestFrameworkException */ private function generateConfigFiles(OutputInterface $output) { @@ -126,45 +127,48 @@ private function generateConfigFiles(OutputInterface $output) //Find travel path from codeception.yml to FW_BP $relativePath = $fileSystem->makePathRelative(FW_BP, TESTS_BP); - if (!$fileSystem->exists(TESTS_BP . DIRECTORY_SEPARATOR . 'codeception.yml')) { + if (!$fileSystem->exists(FilePathFormatter::format(TESTS_BP) . 'codeception.yml')) { // read in the codeception.yml file - $configDistYml = Yaml::parse(file_get_contents(realpath(FW_BP . "/etc/config/codeception.dist.yml"))); + $configDistYml = Yaml::parse(file_get_contents( + realpath(FilePathFormatter::format(FW_BP) . "etc/config/codeception.dist.yml") + )); $configDistYml['paths']['support'] = $relativePath . 'src/Magento/FunctionalTestingFramework'; $configDistYml['paths']['envs'] = $relativePath . 'etc/_envs'; $configYmlText = Yaml::dump($configDistYml, self::DEFAULT_YAML_INLINE_DEPTH); // dump output to new codeception.yml file - file_put_contents(TESTS_BP . DIRECTORY_SEPARATOR . 'codeception.yml', $configYmlText); + file_put_contents(FilePathFormatter::format(TESTS_BP) . 'codeception.yml', $configYmlText); $output->writeln("codeception.yml configuration successfully applied."); } - $output->writeln("codeception.yml applied to " . TESTS_BP . DIRECTORY_SEPARATOR . 'codeception.yml'); + $output->writeln("codeception.yml applied to " . FilePathFormatter::format(TESTS_BP) . 'codeception.yml'); // copy the functional suite yml, will only copy if there are differences between the template the destination $fileSystem->copy( - realpath(FW_BP . '/etc/config/functional.suite.dist.yml'), - TESTS_BP . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml' + realpath(FilePathFormatter::format(FW_BP) . 'etc/config/functional.suite.dist.yml'), + FilePathFormatter::format(TESTS_BP) . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml' ); $output->writeln('functional.suite.yml configuration successfully applied.'); $output->writeln("functional.suite.yml applied to " . - TESTS_BP . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml'); + FilePathFormatter::format(TESTS_BP) . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml'); $fileSystem->copy( - FW_BP . '/etc/config/.credentials.example', - self::CREDENTIALS_FILE_PATH + FilePathFormatter::format(FW_BP) . 'etc/config/.credentials.example', + FilePathFormatter::format(TESTS_BP) . '.credentials.example' ); // copy command.php into magento instance - if (MAGENTO_BP === FW_BP) { + if (FilePathFormatter::format(MAGENTO_BP, false) + === FilePathFormatter::format(FW_BP, false)) { $output->writeln('MFTF standalone detected, command.php copy not applied.'); } else { $fileSystem->copy( - realpath(FW_BP . '/etc/config/command.php'), - TESTS_BP . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR .'command.php' + realpath(FilePathFormatter::format(FW_BP) . 'etc/config/command.php'), + FilePathFormatter::format(TESTS_BP) . "utils" . DIRECTORY_SEPARATOR .'command.php' ); $output->writeln('command.php copied to ' . - TESTS_BP . DIRECTORY_SEPARATOR . "utils" . DIRECTORY_SEPARATOR .'command.php'); + FilePathFormatter::format(TESTS_BP) . "utils" . DIRECTORY_SEPARATOR .'command.php'); } // Remove and Create Log File diff --git a/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php b/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php index b2b2c01f3..641cfe1ed 100644 --- a/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/CleanProjectCommand.php @@ -7,6 +7,8 @@ namespace Magento\FunctionalTestingFramework\Console; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -16,21 +18,6 @@ class CleanProjectCommand extends Command { - const CONFIGURATION_FILES = [ - // codeception.yml file for top level config - TESTS_BP . DIRECTORY_SEPARATOR . 'codeception.yml', - // functional.suite.yml for test execution config - TESTS_BP . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml', - // Acceptance Tester Actions generated by codeception - FW_BP . '/src/Magento/FunctionalTestingFramework/_generated', - // AcceptanceTester Class generated by codeception - FW_BP . '/src/Magento/FunctionalTestingFramework/AcceptanceTester.php' - ]; - - const GENERATED_FILES = [ - TESTS_MODULE_PATH . '/_generated' - ]; - /** * Configures the current command. * @@ -52,22 +39,40 @@ protected function configure() * @param OutputInterface $output * @return void * @throws \Symfony\Component\Console\Exception\LogicException + * @throws TestFrameworkException */ protected function execute(InputInterface $input, OutputInterface $output) { + $configFiles = [ + // codeception.yml file for top level config + FilePathFormatter::format(TESTS_BP) . 'codeception.yml', + // functional.suite.yml for test execution config + FilePathFormatter::format(TESTS_BP) . 'tests' . DIRECTORY_SEPARATOR . 'functional.suite.yml', + // Acceptance Tester Actions generated by codeception + FilePathFormatter::format(FW_BP) . 'src/Magento/FunctionalTestingFramework/_generated', + // AcceptanceTester Class generated by codeception + FilePathFormatter::format(FW_BP) . 'src/Magento/FunctionalTestingFramework/AcceptanceTester.php' + ]; + + $generatedFiles = [ + FilePathFormatter::format(TESTS_MODULE_PATH) . '_generated' + ]; + $isHardReset = $input->getOption('hard'); $fileSystem = new Filesystem(); $finder = new Finder(); - $finder->files()->name('*.php')->in(realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Group/')); + $finder->files()->name('*.php')->in( + realpath(FilePathFormatter::format(FW_BP) . 'src/Magento/FunctionalTestingFramework/Group/') + ); $filesForRemoval = []; // include config files if user specifies a hard reset for deletion if ($isHardReset) { - $filesForRemoval = array_merge($filesForRemoval, self::CONFIGURATION_FILES); + $filesForRemoval = array_merge($filesForRemoval, $configFiles); } // include the files mftf generates during test execution in TESTS_BP for deletion - $filesForRemoval = array_merge($filesForRemoval, self::GENERATED_FILES); + $filesForRemoval = array_merge($filesForRemoval, $generatedFiles); if ($output->isVerbose()) { $output->writeln('Deleting Files:'); diff --git a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php index 1147704c0..f953deb16 100644 --- a/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/GenerateDevUrnCommand.php @@ -9,6 +9,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -109,24 +110,32 @@ protected function execute(InputInterface $input, OutputInterface $output) /** * Generates urn => location array for all MFTF schema. * @return array + * @throws TestFrameworkException */ private function generateResourcesArray() { $resourcesArray = [ 'urn:magento:mftf:DataGenerator/etc/dataOperation.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd'), 'urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd'), 'urn:magento:mftf:Page/etc/PageObject.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd'), 'urn:magento:mftf:Page/etc/SectionObject.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd'), 'urn:magento:mftf:Test/etc/actionGroupSchema.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd'), 'urn:magento:mftf:Test/etc/testSchema.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd'), + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd'), 'urn:magento:mftf:Suite/etc/suiteSchema.xsd' => - realpath(FW_BP . '/src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd') + realpath(FilePathFormatter::format(FW_BP) + . 'src/Magento/FunctionalTestingFramework/Suite/etc/suiteSchema.xsd') ]; return $resourcesArray; } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php index e487d16cf..37a90bb77 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunManifestCommand.php @@ -13,6 +13,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; class RunManifestCommand extends Command { @@ -31,6 +32,13 @@ class RunManifestCommand extends Command */ private $failedTests = []; + /** + * Path for a failed test + * + * @var string + */ + private $testsFailedFile; + /** * Configure the run:manifest command. * @@ -53,6 +61,14 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { + $testsOutputDir = FilePathFormatter::format(TESTS_BP) . + "tests" . + DIRECTORY_SEPARATOR . + "_output" . + DIRECTORY_SEPARATOR; + + $this->testsFailedFile = $testsOutputDir . "failed"; + $path = $input->getArgument("path"); if (!file_exists($path)) { @@ -117,8 +133,8 @@ private function runManifestLine(string $manifestLine, OutputInterface $output) */ private function aggregateFailed() { - if (file_exists(RunTestFailedCommand::TESTS_FAILED_FILE)) { - $currentFile = file(RunTestFailedCommand::TESTS_FAILED_FILE, FILE_IGNORE_NEW_LINES); + if (file_exists($this->testsFailedFile)) { + $currentFile = file($this->testsFailedFile, FILE_IGNORE_NEW_LINES); $this->failedTests = array_merge( $this->failedTests, $currentFile @@ -133,8 +149,8 @@ private function aggregateFailed() */ private function deleteFailedFile() { - if (file_exists(RunTestFailedCommand::TESTS_FAILED_FILE)) { - unlink(RunTestFailedCommand::TESTS_FAILED_FILE); + if (file_exists($this->testsFailedFile)) { + unlink($this->testsFailedFile); } } @@ -146,7 +162,7 @@ private function deleteFailedFile() private function writeFailedFile() { foreach ($this->failedTests as $test) { - file_put_contents(RunTestFailedCommand::TESTS_FAILED_FILE, $test . "\n", FILE_APPEND); + file_put_contents($this->testsFailedFile, $test . "\n", FILE_APPEND); } } } diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php index 77b8be513..373256cfc 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestCommand.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputArgument; @@ -122,8 +123,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function runTests(array $tests, OutputInterface $output) { $codeceptionCommand = realpath(PROJECT_ROOT . '/vendor/bin/codecept') . ' run functional '; - $testsDirectory = TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . + $testsDirectory = FilePathFormatter::format(TESTS_MODULE_PATH) . TestGenerator::GENERATED_DIR . DIRECTORY_SEPARATOR . TestGenerator::DEFAULT_DIR . diff --git a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php index 336fd5d87..5f0596a7f 100644 --- a/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php @@ -8,6 +8,7 @@ namespace Magento\FunctionalTestingFramework\Console; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -22,20 +23,20 @@ class RunTestFailedCommand extends BaseGenerateCommand */ const DEFAULT_TEST_GROUP = 'default'; - const TESTS_OUTPUT_DIR = TESTS_BP . - DIRECTORY_SEPARATOR . - "tests" . - DIRECTORY_SEPARATOR . - "_output" . - DIRECTORY_SEPARATOR; - - const TESTS_FAILED_FILE = self::TESTS_OUTPUT_DIR . "failed"; - const TESTS_RERUN_FILE = self::TESTS_OUTPUT_DIR . "rerun_tests"; - const TESTS_MANIFEST_FILE= TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . - "_generated" . - DIRECTORY_SEPARATOR . - "testManifest.txt"; + /** + * @var string + */ + private $testsFailedFile; + + /** + * @var string + */ + private $testsReRunFile; + + /** + * @var string + */ + private $testsManifestFile; /** * @var array @@ -68,6 +69,19 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output): int { + $testsOutputDir = FilePathFormatter::format(TESTS_BP) . + "tests" . + DIRECTORY_SEPARATOR . + "_output" . + DIRECTORY_SEPARATOR; + + $this->testsFailedFile = $testsOutputDir . "failed"; + $this->testsReRunFile = $testsOutputDir . "rerun_tests"; + $this->testsManifestFile= FilePathFormatter::format(TESTS_MODULE_PATH) . + "_generated" . + DIRECTORY_SEPARATOR . + "testManifest.txt"; + $force = $input->getOption('force'); $debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility $allowSkipped = $input->getOption('allow-skipped'); @@ -115,15 +129,15 @@ function ($type, $buffer) use ($output) { $output->write($buffer); } )); - if (file_exists(self::TESTS_FAILED_FILE)) { + if (file_exists($this->testsFailedFile)) { $this->failedList = array_merge( $this->failedList, - $this->readFailedTestFile(self::TESTS_FAILED_FILE) + $this->readFailedTestFile($this->testsFailedFile) ); } } foreach ($this->failedList as $test) { - $this->writeFailedTestToFile($test, self::TESTS_FAILED_FILE); + $this->writeFailedTestToFile($test, $this->testsFailedFile); } return $returnCode; @@ -138,12 +152,12 @@ private function getFailedTestList() { $failedTestDetails = ['tests' => [], 'suites' => []]; - if (realpath(self::TESTS_FAILED_FILE)) { - $testList = $this->readFailedTestFile(self::TESTS_FAILED_FILE); + if (realpath($this->testsFailedFile)) { + $testList = $this->readFailedTestFile($this->testsFailedFile); foreach ($testList as $test) { if (!empty($test)) { - $this->writeFailedTestToFile($test, self::TESTS_RERUN_FILE); + $this->writeFailedTestToFile($test, $this->testsReRunFile); $testInfo = explode(DIRECTORY_SEPARATOR, $test); $testName = explode(":", $testInfo[count($testInfo) - 1])[1]; $suiteName = $testInfo[count($testInfo) - 2]; @@ -184,7 +198,7 @@ private function getFailedTestList() */ private function readTestManifestFile() { - return file(self::TESTS_MANIFEST_FILE, FILE_IGNORE_NEW_LINES); + return file($this->testsManifestFile, FILE_IGNORE_NEW_LINES); } /** @@ -202,6 +216,7 @@ private function readFailedTestFile($filePath) * Writes the test name to a file if it does not already exist * * @param string $test + * @param string $filePath * @return void */ private function writeFailedTestToFile($test, $filePath) diff --git a/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php b/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php index 4d1ce0334..65e8c61e7 100644 --- a/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php +++ b/src/Magento/FunctionalTestingFramework/Console/SetupEnvCommand.php @@ -7,6 +7,8 @@ namespace Magento\FunctionalTestingFramework\Console; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Exception\InvalidOptionException; @@ -27,12 +29,13 @@ class SetupEnvCommand extends Command * Configures the current command. * * @return void + * @throws TestFrameworkException */ protected function configure() { $this->setName('setup:env') ->setDescription("Generate .env file."); - $this->envProcessor = new EnvProcessor(TESTS_BP . DIRECTORY_SEPARATOR . '.env'); + $this->envProcessor = new EnvProcessor(FilePathFormatter::format(TESTS_BP) . '.env'); $env = $this->envProcessor->getEnv(); foreach ($env as $key => $value) { $this->addOption($key, null, InputOption::VALUE_REQUIRED, '', $value); diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php index 0514cfe57..94ff40069 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/CredentialStore.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\FileStorage; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage\VaultStorage; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; class CredentialStore { @@ -63,7 +64,7 @@ private function __construct() if ($cvAddress !== false && $cvSecretPath !== false) { try { $this->credStorage[self::ARRAY_KEY_FOR_VAULT] = new VaultStorage( - rtrim($cvAddress, '/'), + UrlFormatter::format($cvAddress, false), '/' . trim($cvSecretPath, '/') ); } catch (TestFrameworkException $e) { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php index 064610c79..be77a6de2 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/SecretStorage/FileStorage.php @@ -6,10 +6,10 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Handlers\SecretStorage; -use Magento\FunctionalTestingFramework\Console\BuildProjectCommand; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; class FileStorage extends BaseStorage { @@ -71,7 +71,7 @@ private function readInCredentialsFile() $credsFilePath = str_replace( '.credentials.example', '.credentials', - BuildProjectCommand::CREDENTIALS_FILE_PATH + FilePathFormatter::format(TESTS_BP) . '.credentials.example' ); if (!file_exists($credsFilePath)) { diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php index b6c3f29ec..e27da3718 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AbstractExecutor.php @@ -6,6 +6,8 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; /** @@ -23,9 +25,10 @@ abstract class AbstractExecutor implements CurlInterface /** * Returns base URL for Magento instance * @return string + * @throws TestFrameworkException */ public function getBaseUrl(): string { - return getenv('MAGENTO_BASE_URL'); + return UrlFormatter::format(getenv('MAGENTO_BASE_URL')); } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php index 4e11f5cec..86b3b742f 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/AdminExecutor.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; @@ -59,11 +60,20 @@ public function __construct($removeBackend) /** * Returns base URL for Magento backend instance * @return string + * @throws TestFrameworkException */ public function getBaseUrl(): string { - $backendHost = getenv('MAGENTO_BACKEND_BASE_URL') ?: parent::getBaseUrl(); - return $backendHost . getenv('MAGENTO_BACKEND_NAME') . '/'; + $backendHost = getenv('MAGENTO_BACKEND_BASE_URL') + ? + UrlFormatter::format(getenv('MAGENTO_BACKEND_BASE_URL')) + : + parent::getBaseUrl(); + return empty(getenv('MAGENTO_BACKEND_NAME')) + ? + $backendHost + : + $backendHost . getenv('MAGENTO_BACKEND_NAME') . '/'; } /** diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php index 281eaa24d..494ce8f97 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/Curl/WebapiExecutor.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; @@ -75,24 +76,32 @@ public function __construct($storeCode = null) /** * Returns base URL for Magento Web API instance * @return string + * @throws TestFrameworkException */ public function getBaseUrl(): string { - $baseUrl = parent::getBaseUrl(); - $webapiHost = getenv('MAGENTO_RESTAPI_SERVER_HOST'); $webapiPort = getenv("MAGENTO_RESTAPI_SERVER_PORT"); $webapiProtocol = getenv("MAGENTO_RESTAPI_SERVER_PROTOCOL"); - if ($webapiHost) { - $baseUrl = sprintf('%s://%s/', $webapiProtocol, $webapiHost); + if ($webapiHost && $webapiProtocol) { + $baseUrl = UrlFormatter::format( + sprintf('%s://%s', $webapiProtocol, $webapiHost), + false + ); + } elseif ($webapiHost) { + $baseUrl = UrlFormatter::format(sprintf('%s', $webapiProtocol, $webapiHost), false); + } + + if (!isset($baseUrl)) { + $baseUrl = rtrim(parent::getBaseUrl(), '/'); } if ($webapiPort) { - $baseUrl = rtrim($baseUrl, '/') . ':' . $webapiPort . '/'; + $baseUrl .= ':' . $webapiPort; } - return $baseUrl; + return $baseUrl . '/'; } /** @@ -175,22 +184,23 @@ public function close() * Builds and returns URL for request, appending storeCode if needed. * @param string $resource * @return string + * @throws TestFrameworkException */ public function getFormattedUrl($resource) { $urlResult = $this->getBaseUrl() . 'rest/'; if ($this->storeCode != null) { - $urlResult .= $this->storeCode . "/"; + $urlResult .= $this->storeCode . '/'; } - $urlResult .= trim($resource, "/"); + $urlResult .= trim($resource, '/'); return $urlResult; } /** * Return admin auth token. * - * @throws TestFrameworkException * @return string + * @throws TestFrameworkException */ public function getAuthToken() { diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index c1ab892d7..73311e0fa 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -16,6 +16,7 @@ use Codeception\Util\Uri; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\WebapiExecutor; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; use Magento\FunctionalTestingFramework\Util\ConfigSanitizerUtil; use Yandex\Allure\Adapter\AllureException; @@ -872,7 +873,11 @@ private function curlExecMagentoCLI($command, $arguments): string str_replace('index.php', '', rtrim($this->config['url'], '/')), '/' ); - $apiURL = $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'); + + $apiURL = UrlFormatter::format( + $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'), + false + ); $restExecutor = new WebapiExecutor(); $executor = new CurlTransport(); diff --git a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php index 9f0045d19..4df7daa75 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Suite; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Suite\Generators\GroupClassGenerator; @@ -15,9 +16,14 @@ use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\Manifest\BaseTestManifest; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\TestGenerator; use Symfony\Component\Yaml\Yaml; +/** + * Class SuiteGenerator + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class SuiteGenerator { const YAML_CODECEPTION_DIST_FILENAME = 'codeception.dist.yml'; @@ -128,11 +134,12 @@ public function generateSuite($suiteName) * @return void * @throws TestReferenceException * @throws XmlException + * @throws TestFrameworkException */ private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteName = null) { $relativePath = TestGenerator::GENERATED_DIR . DIRECTORY_SEPARATOR . $suiteName; - $fullPath = TESTS_MODULE_PATH . DIRECTORY_SEPARATOR . $relativePath . DIRECTORY_SEPARATOR; + $fullPath = FilePathFormatter::format(TESTS_MODULE_PATH) . $relativePath . DIRECTORY_SEPARATOR; DirSetupUtil::createGroupDir($fullPath); @@ -348,9 +355,10 @@ private static function getYamlFileContents() * Static getter for the Config yml filepath (as path cannot be stored in a const) * * @return string + * @throws TestFrameworkException */ private static function getYamlConfigFilePath() { - return TESTS_BP . DIRECTORY_SEPARATOR; + return FilePathFormatter::format(TESTS_BP); } } diff --git a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php index 7ef3d5e8c..2e4d7f9dd 100644 --- a/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php @@ -13,6 +13,7 @@ use Magento\FunctionalTestingFramework\Test\Util\BaseObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestHookObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; class SuiteObjectExtractor extends BaseObjectExtractor @@ -259,8 +260,7 @@ private function resolveFilePathTestNames($filename, $moduleName = null) { $filepath = $filename; if (!strstr($filepath, DIRECTORY_SEPARATOR)) { - $filepath = TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . + $filepath = FilePathFormatter::format(TESTS_MODULE_PATH) . $moduleName . DIRECTORY_SEPARATOR . 'Test' . @@ -293,8 +293,7 @@ private function resolveModulePathTestNames($moduleName) { $testObjects = []; $xmlFiles = glob( - TESTS_MODULE_PATH . - DIRECTORY_SEPARATOR . + FilePathFormatter::format(TESTS_MODULE_PATH) . $moduleName . DIRECTORY_SEPARATOR . 'Test' . diff --git a/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php b/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php index ce5740493..3b92b48e4 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/ConfigSanitizerUtil.php @@ -7,6 +7,8 @@ namespace Magento\FunctionalTestingFramework\Util; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; /** * Class ConfigSanitizerUtil @@ -24,7 +26,7 @@ public static function sanitizeWebDriverConfig($config, $params = ['url', 'selen self::validateConfigBasedVars($config); if (in_array('url', $params)) { - $config['url'] = self::sanitizeUrl($config['url']); + $config['url'] = UrlFormatter::format($config['url']); } if (in_array('selenium', $params)) { @@ -80,71 +82,4 @@ private static function validateConfigBasedVars($config) } } } - - /** - * Sanitizes and returns given URL. - * @param string $url - * @return string - */ - public static function sanitizeUrl($url) - { - if (strlen($url) == 0 && !MftfApplicationConfig::getConfig()->forceGenerateEnabled()) { - trigger_error("MAGENTO_BASE_URL must be defined in .env", E_USER_ERROR); - } - - if (filter_var($url, FILTER_VALIDATE_URL) === true) { - return rtrim($url, "/") . "/"; - } - - $urlParts = parse_url($url); - - if (!isset($urlParts['scheme'])) { - $urlParts['scheme'] = "http"; - } - if (!isset($urlParts['host'])) { - $urlParts['host'] = rtrim($urlParts['path'], "/"); - $urlParts['host'] = str_replace("//", "/", $urlParts['host']); - unset($urlParts['path']); - } - - if (!isset($urlParts['path'])) { - $urlParts['path'] = "/"; - } else { - $urlParts['path'] = rtrim($urlParts['path'], "/") . "/"; - } - - return str_replace("///", "//", self::buildUrl($urlParts)); - } - - /** - * Returns url from $parts given, used with parse_url output for convenience. - * This only exists because of deprecation of http_build_url, which does the exact same thing as the code below. - * @param array $parts - * @return string - */ - private static function buildUrl(array $parts) - { - $get = function ($key) use ($parts) { - return isset($parts[$key]) ? $parts[$key] : null; - }; - - $pass = $get('pass'); - $user = $get('user'); - $userinfo = $pass !== null ? "$user:$pass" : $user; - $port = $get('port'); - $scheme = $get('scheme'); - $query = $get('query'); - $fragment = $get('fragment'); - $authority = - ($userinfo !== null ? "$userinfo@" : '') . - $get('host') . - ($port ? ":$port" : ''); - - return - (strlen($scheme) ? "$scheme:" : '') . - (strlen($authority) ? "//$authority" : '') . - $get('path') . - (strlen($query) ? "?$query" : '') . - (strlen($fragment) ? "#$fragment" : ''); - } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Env/EnvProcessor.php b/src/Magento/FunctionalTestingFramework/Util/Env/EnvProcessor.php index f09ab63fa..86f7fa89d 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Env/EnvProcessor.php +++ b/src/Magento/FunctionalTestingFramework/Util/Env/EnvProcessor.php @@ -7,6 +7,9 @@ namespace Magento\FunctionalTestingFramework\Util\Env; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; + /** * Helper class EnvProcessor for reading and writing .env files. * @@ -45,13 +48,14 @@ class EnvProcessor /** * EnvProcessor constructor. * @param string $envFile + * @throws TestFrameworkException */ public function __construct( string $envFile = '' ) { $this->envFile = $envFile; $this->envExists = file_exists($envFile); - $this->envExampleFile = realpath(FW_BP . "/etc/config/.env.example"); + $this->envExampleFile = realpath(FilePathFormatter::format(FW_BP) . "etc/config/.env.example"); } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php b/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php index 7ac128f28..97fdada21 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Logger/LoggingUtil.php @@ -6,6 +6,8 @@ namespace Magento\FunctionalTestingFramework\Util\Logger; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Monolog\Handler\StreamHandler; use Monolog\Logger; @@ -82,9 +84,10 @@ public function getLogger($className): MftfLogger * Function which returns a static path to the the log file. * * @return string + * @throws TestFrameworkException */ public function getLoggingPath(): string { - return TESTS_BP . DIRECTORY_SEPARATOR . "mftf.log"; + return FilePathFormatter::format(TESTS_BP) . "mftf.log"; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php b/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php index 1cfa6559e..fd7d885bf 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php +++ b/src/Magento/FunctionalTestingFramework/Util/Manifest/TestManifestFactory.php @@ -6,7 +6,9 @@ namespace Magento\FunctionalTestingFramework\Util\Manifest; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; use Magento\FunctionalTestingFramework\Util\TestGenerator; class TestManifestFactory @@ -26,11 +28,11 @@ private function __construct() * @param array $suiteConfiguration * @param string $testPath * @return BaseTestManifest + * @throws TestFrameworkException */ public static function makeManifest($runConfig, $suiteConfiguration, $testPath = TestGenerator::DEFAULT_DIR) { - $testDirFullPath = TESTS_MODULE_PATH - . DIRECTORY_SEPARATOR + $testDirFullPath = FilePathFormatter::format(TESTS_MODULE_PATH) . TestGenerator::GENERATED_DIR . DIRECTORY_SEPARATOR . $testPath; diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index c9c050878..aa9a08ddb 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -9,6 +9,8 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; +use Magento\FunctionalTestingFramework\Util\Path\UrlFormatter; use Symfony\Component\HttpFoundation\Response; /** @@ -201,7 +203,7 @@ public function getEnabledModules() $token = $this->getAdminToken(); - $url = ConfigSanitizerUtil::sanitizeUrl(getenv('MAGENTO_BASE_URL')) . $this->moduleUrl; + $url = UrlFormatter::format(getenv('MAGENTO_BASE_URL')) . $this->moduleUrl; $headers = [ 'Authorization: Bearer ' . $token, @@ -313,11 +315,11 @@ private function aggregateTestModulePaths() $allModulePaths = []; // Define the Module paths from magento bp - $magentoBaseCodePath = MAGENTO_BP; + $magentoBaseCodePath = FilePathFormatter::format(MAGENTO_BP, false); // Define the Module paths from default TESTS_MODULE_PATH $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; - $modulePath = rtrim($modulePath, DIRECTORY_SEPARATOR); + $modulePath = FilePathFormatter::format($modulePath, false); $vendorCodePath = DIRECTORY_SEPARATOR . self::VENDOR; $appCodePath = DIRECTORY_SEPARATOR . self::APP_CODE; @@ -415,15 +417,16 @@ private static function globRelevantWrapper($testPath, $pattern) * Aggregate all code paths with test module composer json files * * @return array + * @throws TestFrameworkException */ private function aggregateTestModulePathsFromComposerJson() { // Define the module paths - $magentoBaseCodePath = MAGENTO_BP; + $magentoBaseCodePath = FilePathFormatter::format(MAGENTO_BP, false); // Define the module paths from default TESTS_MODULE_PATH $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; - $modulePath = rtrim($modulePath, DIRECTORY_SEPARATOR); + $modulePath = FilePathFormatter::format($modulePath, false); $searchCodePaths = [ $magentoBaseCodePath . DIRECTORY_SEPARATOR . self::DEV_TESTS, @@ -677,7 +680,7 @@ private function printMagentoVersionInfo() if (MftfApplicationConfig::getConfig()->forceGenerateEnabled()) { return; } - $url = ConfigSanitizerUtil::sanitizeUrl(getenv('MAGENTO_BASE_URL')) . $this->versionUrl; + $url = UrlFormatter::format(getenv('MAGENTO_BASE_URL')) . $this->versionUrl; LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( "Fetching version information.", ['url' => $url] @@ -718,7 +721,7 @@ public function getAdminToken() throw new TestFrameworkException($message, $context); } - $url = ConfigSanitizerUtil::sanitizeUrl($this->getBackendUrl()) . $this->adminTokenUrl; + $url = $this->getBackendUrl() . $this->adminTokenUrl; $data = [ 'username' => $login, 'password' => $password @@ -886,7 +889,15 @@ private function getRegisteredModuleList() */ private function getBackendUrl() { - return getenv('MAGENTO_BACKEND_BASE_URL') ?: getenv('MAGENTO_BASE_URL'); + try { + if (getenv('MAGENTO_BACKEND_BASE_URL')) { + return UrlFormatter::format(getenv('MAGENTO_BACKEND_BASE_URL')); + } else { + return UrlFormatter::format(getenv('MAGENTO_BASE_URL')); + } + } catch (TestFrameworkException $e) { + return null; + } } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php b/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php new file mode 100644 index 000000000..8b496e739 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/Path/FilePathFormatter.php @@ -0,0 +1,31 @@ +#%";/?:@&= + $sanitizedUrl = filter_var($sanitizedUrl, FILTER_SANITIZE_URL); + + if (false === $sanitizedUrl) { + throw new TestFrameworkException("Invalid url: $url\n"); + } + + // Validate URL according to http://www.faqs.org/rfcs/rfc2396 + $validUrl = filter_var($sanitizedUrl, FILTER_VALIDATE_URL); + + if (false !== $validUrl) { + return $withTrailingSeparator ? $validUrl . '/' : $validUrl; + } + + // Validation might be failed due to missing URL scheme or host, attempt to build them and re-validate + $validUrl = filter_var(self::buildUrl($sanitizedUrl), FILTER_VALIDATE_URL); + + if (false !== $validUrl) { + return $withTrailingSeparator ? $validUrl . '/' : $validUrl; + } + + throw new TestFrameworkException("Invalid url: $url\n"); + } + + /** + * Try to build missing url scheme and host + * + * @param string $url + * @return string + */ + private static function buildUrl($url) + { + $urlParts = parse_url($url); + + if (!isset($urlParts['scheme'])) { + $urlParts['scheme'] = 'http'; + } + + if (!isset($urlParts['host'])) { + $urlParts['host'] = rtrim($urlParts['path'], '/'); + $urlParts['host'] = str_replace("//", '/', $urlParts['host']); + unset($urlParts['path']); + } + + if (isset($urlParts['path'])) { + $urlParts['path'] = rtrim($urlParts['path'], '/'); + } + + return str_replace("///", "//", self::merge($urlParts)); + } + + /** + * Returns url from $parts given, used with parse_url output for convenience. + * This only exists because of deprecation of http_build_url, which does the exact same thing as the code below. + * @param array $parts + * @return string + */ + private static function merge(array $parts) + { + $get = function ($key) use ($parts) { + return isset($parts[$key]) ? $parts[$key] : null; + }; + + $pass = $get('pass'); + $user = $get('user'); + $userinfo = $pass !== null ? "$user:$pass" : $user; + $port = $get('port'); + $scheme = $get('scheme'); + $query = $get('query'); + $fragment = $get('fragment'); + $authority = + ($userinfo !== null ? "$userinfo@" : '') . + $get('host') . + ($port ? ":$port" : ''); + + return + (strlen($scheme) ? "$scheme:" : '') . + (strlen($authority) ? "//$authority" : '') . + $get('path') . + (strlen($query) ? "?$query" : '') . + (strlen($fragment) ? "#$fragment" : ''); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 2909ab1dc..7b0d2916e 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -10,6 +10,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\PersistedObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler; use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler; @@ -26,6 +27,7 @@ use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; +use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter; /** * Class TestGenerator @@ -103,14 +105,14 @@ class TestGenerator * @param string $exportDir * @param array $tests * @param boolean $debug + * @throws TestFrameworkException */ private function __construct($exportDir, $tests, $debug = false) { // private constructor for factory $this->exportDirName = $exportDir ?? self::DEFAULT_DIR; $exportDir = $exportDir ?? self::DEFAULT_DIR; - $this->exportDirectory = TESTS_MODULE_PATH - . DIRECTORY_SEPARATOR + $this->exportDirectory = FilePathFormatter::format(TESTS_MODULE_PATH) . self::GENERATED_DIR . DIRECTORY_SEPARATOR . $exportDir; diff --git a/src/Magento/FunctionalTestingFramework/_bootstrap.php b/src/Magento/FunctionalTestingFramework/_bootstrap.php index e401123b6..f3bb099d0 100644 --- a/src/Magento/FunctionalTestingFramework/_bootstrap.php +++ b/src/Magento/FunctionalTestingFramework/_bootstrap.php @@ -61,7 +61,7 @@ defined('MAGENTO_BP') || define('MAGENTO_BP', realpath(PROJECT_ROOT)); // TODO REMOVE THIS CODE ONCE WE HAVE STOPPED SUPPORTING dev/tests/acceptance PATH // define TEST_PATH and TEST_MODULE_PATH -defined('TESTS_BP') || define('TESTS_BP', realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'dev/tests/acceptance/')); +defined('TESTS_BP') || define('TESTS_BP', realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'dev/tests/acceptance')); $RELATIVE_TESTS_MODULE_PATH = '/tests/functional/Magento/FunctionalTest'; defined('TESTS_MODULE_PATH') || define(