From 731e8daebc04d6645a6a962511981da38fb10635 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 16 Aug 2019 15:22:23 -0500 Subject: [PATCH 01/10] =?UTF-8?q?MQE-1650:=C2=A0=20Update=20MFTF=20configu?= =?UTF-8?q?ration=20to=20read=20Test=20entities=20from=20new=20location?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Page/MFTFDocPage.xml | 0 .../Section/ContentSection.xml | 0 .../Test/DevDocsTest.xml | 0 .../Util/ModuleResolver.php | 183 +++++++++++++++--- 4 files changed, 154 insertions(+), 29 deletions(-) rename dev/tests/functional/tests/MFTF/{DevDocs => DevDocsTest}/Page/MFTFDocPage.xml (100%) rename dev/tests/functional/tests/MFTF/{DevDocs => DevDocsTest}/Section/ContentSection.xml (100%) rename dev/tests/functional/tests/MFTF/{DevDocs => DevDocsTest}/Test/DevDocsTest.xml (100%) diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Page/MFTFDocPage.xml b/dev/tests/functional/tests/MFTF/DevDocsTest/Page/MFTFDocPage.xml similarity index 100% rename from dev/tests/functional/tests/MFTF/DevDocs/Page/MFTFDocPage.xml rename to dev/tests/functional/tests/MFTF/DevDocsTest/Page/MFTFDocPage.xml diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml b/dev/tests/functional/tests/MFTF/DevDocsTest/Section/ContentSection.xml similarity index 100% rename from dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml rename to dev/tests/functional/tests/MFTF/DevDocsTest/Section/ContentSection.xml diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocsTest/Test/DevDocsTest.xml similarity index 100% rename from dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml rename to dev/tests/functional/tests/MFTF/DevDocsTest/Test/DevDocsTest.xml diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 16e6037fa..939d457d3 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -9,6 +9,7 @@ use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; +use Symfony\Component\Config\Resource\DirectoryResource; use Symfony\Component\HttpFoundation\Response; /** @@ -38,6 +39,52 @@ class ModuleResolver */ const REGISTRAR_CLASS = "\Magento\Framework\Component\ComponentRegistrar"; + /** + * Vendor code path + */ + const VENDOR_CODE_PATH = DIRECTORY_SEPARATOR . "vendor"; + + /** + * App code path + */ + const APP_CODE_PATH = DIRECTORY_SEPARATOR . "app" . DIRECTORY_SEPARATOR . "code"; + + /** + * Dev test code path + */ + const DEV_TEST_CODE_PATH = DIRECTORY_SEPARATOR + . 'dev' + . DIRECTORY_SEPARATOR + . 'tests' + . DIRECTORY_SEPARATOR + . 'acceptance' + . DIRECTORY_SEPARATOR + . 'tests' + . DIRECTORY_SEPARATOR + . 'functional'; + + /** + * Pattern for Mftf directories + */ + const MFTF_DIR_PATTERN = 'Test' . DIRECTORY_SEPARATOR . 'Mftf'; + + /** + * Regex to match an invalid dev test code path + */ + const INVALID_DEV_TEST_CODE_PATH_REGEX = "~.+dev\\" + . DIRECTORY_SEPARATOR + . "tests\\" + . DIRECTORY_SEPARATOR + . "acceptance\\" + . DIRECTORY_SEPARATOR + . "tests\\" + . DIRECTORY_SEPARATOR + . "functional\\" + . DIRECTORY_SEPARATOR + . "\S+\\" + . DIRECTORY_SEPARATOR + . "FuncionalTest$~"; + /** * Enabled modules. * @@ -110,6 +157,13 @@ class ModuleResolver 'SampleTests', 'SampleTemplates' ]; + /** + * Registered module list in magento instance being tested + * + * @var array + */ + private $registeredModuleList = []; + /** * Get ModuleResolver instance. * @@ -235,17 +289,67 @@ private function aggregateTestModulePaths() $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; $modulePath = rtrim($modulePath, DIRECTORY_SEPARATOR); - $vendorCodePath = DIRECTORY_SEPARATOR . "vendor"; - $appCodePath = DIRECTORY_SEPARATOR . "app" . DIRECTORY_SEPARATOR . "code"; - + // Add known paths $codePathsToPattern = [ - $modulePath => '', - $magentoBaseCodePath . $vendorCodePath => 'Test' . DIRECTORY_SEPARATOR . 'Mftf', - $magentoBaseCodePath . $appCodePath => 'Test' . DIRECTORY_SEPARATOR . 'Mftf' + $magentoBaseCodePath . self::VENDOR_CODE_PATH => [ + [ + 'pattern' => 'Test' . DIRECTORY_SEPARATOR . 'Mftf', + 'level' => null + ], + [ + 'pattern' => '*-test', + 'level' => 1 + ] + ], + $magentoBaseCodePath . self::APP_CODE_PATH => [ + [ + 'pattern' => 'Test' . DIRECTORY_SEPARATOR . 'Mftf', + 'level' => null + ] + ], + $magentoBaseCodePath . self::DEV_TEST_CODE_PATH => [ + [ + 'pattern' => '*Test', + 'level' => 1 + ], + [ + 'pattern' => 'FunctionalTest' . DIRECTORY_SEPARATOR . '*', + 'level' => 1 + ] + ] ]; - foreach ($codePathsToPattern as $codePath => $pattern) { - $allModulePaths = array_merge_recursive($allModulePaths, $this->globRelevantPaths($codePath, $pattern)); + // Check if module path is a known path + $newPath = true; + foreach (array_keys($codePathsToPattern) as $key) { + if (strpos($modulePath, $key) !== false) { + $newPath = false; + } + } + + // Add module path if it's a new path + if ($newPath) { + $codePathsToPattern[$modulePath] = [ + [ + 'pattern' => 'Test' . DIRECTORY_SEPARATOR . 'Mftf', + 'level' => 0 + ], + [ + 'pattern' => '*Test', + 'level' => 0 + ] + ]; + } + + // Glob pattern for relevant paths + foreach ($codePathsToPattern as $codePath => $patterns) { + foreach ($patterns as $pattern) { + $allModulePaths = array_merge_recursive($allModulePaths, $this->globRelevantPaths( + $codePath, + $pattern['pattern'], + $pattern['level']) + ); + } } return $allModulePaths; @@ -258,35 +362,46 @@ private function aggregateTestModulePaths() * * @param string $testPath * @param string $pattern + * @param integer $level * @return array */ - private function globRelevantPaths($testPath, $pattern) + private function globRelevantPaths($testPath, $pattern, $level) { $modulePaths = []; $relevantPaths = []; if (file_exists($testPath)) { - $relevantPaths = $this->globRelevantWrapper($testPath, $pattern); + $relevantPaths = $this->globRelevantWrapper($testPath, $pattern, $level); } $allComponents = $this->getRegisteredModuleList(); foreach ($relevantPaths as $codePath) { - // Reduce magento/app/code/Magento/AdminGws/ to magento/app/code/Magento/AdminGws to read symlink + // Reduce magento/app/code/Magento/AdminGws/Test/MFTF to magento/app/code/Magento/AdminGws to read symlink // Symlinks must be resolved otherwise they will not match Magento's filepath to the module - $potentialSymlink = str_replace(DIRECTORY_SEPARATOR . $pattern, "", $codePath); - if (is_link($potentialSymlink)) { - $codePath = realpath($potentialSymlink) . DIRECTORY_SEPARATOR . $pattern; + if ($pattern == self::MFTF_DIR_PATTERN) { + $codePath = str_replace(DIRECTORY_SEPARATOR . self::MFTF_DIR_PATTERN, "", $codePath); } - - $mainModName = array_search($codePath, $allComponents) ?: basename(str_replace($pattern, '', $codePath)); - $modulePaths[$mainModName][] = $codePath; - - if (MftfApplicationConfig::getConfig()->verboseEnabled()) { - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->debug( - "including module", - ['module' => $mainModName, 'path' => $codePath] - ); + if (is_link($codePath)) { + $codePath = realpath($codePath); + } + $mainModName = array_search($codePath, $allComponents) ?: basename($codePath); + preg_match(self::INVALID_DEV_TEST_CODE_PATH_REGEX, $codePath, $match); + if (empty($match)) { + if ($pattern == self::MFTF_DIR_PATTERN) { + $modulePaths[$mainModName][] = $codePath . DIRECTORY_SEPARATOR . self::MFTF_DIR_PATTERN; + } else { + $modulePaths[$mainModName][] = $codePath; + } + + if (MftfApplicationConfig::getConfig()->verboseEnabled()) { + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->debug( + "including module", + ['module' => $mainModName, 'path' => $codePath] + ); + } + } else { + echo $codePath; } } @@ -295,18 +410,25 @@ private function globRelevantPaths($testPath, $pattern) /** * Glob wrapper for globRelevantPaths function + * When $level = null, it's recursion * * @param string $testPath * @param string $pattern + * @param integer $level * @return array */ - private static function globRelevantWrapper($testPath, $pattern) + private static function globRelevantWrapper($testPath, $pattern, $level = null) { - if ($pattern == "") { - return glob($testPath . '*' . DIRECTORY_SEPARATOR . '*' . $pattern); + $subDirectory = DIRECTORY_SEPARATOR . "*"; + if ($level !== null) { + $subDirectories = ''; + for ($i = 0; $i < $level; $i++) { + $subDirectories .= $subDirectory; + } + return glob($testPath . $subDirectories . DIRECTORY_SEPARATOR . $pattern, GLOB_ONLYDIR); } - $subDirectory = "*" . DIRECTORY_SEPARATOR; - $directories = glob($testPath . $subDirectory . $pattern, GLOB_ONLYDIR); + + $directories = glob($testPath . $subDirectory . DIRECTORY_SEPARATOR . $pattern, GLOB_ONLYDIR); foreach (glob($testPath . $subDirectory, GLOB_ONLYDIR) as $dir) { $directories = array_merge_recursive($directories, self::globRelevantWrapper($dir, $pattern)); } @@ -534,6 +656,10 @@ private function getModuleBlacklist() */ private function getRegisteredModuleList() { + if (!empty($this->registeredModuleList)) { + return $this->registeredModuleList; + } + if (array_key_exists('MAGENTO_BP', $_ENV)) { $autoloadPath = realpath(MAGENTO_BP . "/app/autoload.php"); if ($autoloadPath) { @@ -556,7 +682,6 @@ private function getRegisteredModuleList() array_walk($allComponents, function (&$value) { // Magento stores component paths with unix DIRECTORY_SEPARATOR, need to stay uniform and convert $value = realpath($value); - $value .= '/Test/Mftf'; }); return $allComponents; } catch (TestFrameworkException $e) { From eaaae5ad745d4ac72847f2cb3b6808207ee34c53 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Fri, 16 Aug 2019 19:53:10 -0500 Subject: [PATCH 02/10] =?UTF-8?q?MQE-1650:=C2=A0=20Update=20MFTF=20configu?= =?UTF-8?q?ration=20to=20read=20Test=20entities=20from=20new=20location?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Util/ModuleResolver.php | 70 ++++++++++++------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 939d457d3..130a23909 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -71,19 +71,19 @@ class ModuleResolver /** * Regex to match an invalid dev test code path */ - const INVALID_DEV_TEST_CODE_PATH_REGEX = "~.+dev\\" - . DIRECTORY_SEPARATOR - . "tests\\" - . DIRECTORY_SEPARATOR - . "acceptance\\" - . DIRECTORY_SEPARATOR - . "tests\\" - . DIRECTORY_SEPARATOR - . "functional\\" - . DIRECTORY_SEPARATOR - . "\S+\\" - . DIRECTORY_SEPARATOR - . "FuncionalTest$~"; + const INVALID_DEV_TEST_CODE_PATH_REGEX = "~^[^:*\\?\"<>|']+" + . self::DEV_TEST_CODE_PATH + . "/[^/:*\\?\"<>|']+/FunctionalTest$~"; + + /** + * Test module name suffix + */ + const TEST_MODULE_NAME_SUFFIX = 'Test'; + + /** + * Regex to match a test module name with suffix defined in TEST_MODULE_NAME_SUFFIX + */ + const TEST_MODULE_NAME_REGEX = "~\S+" . self::TEST_MODULE_NAME_SUFFIX . "$~"; /** * Enabled modules. @@ -309,7 +309,7 @@ private function aggregateTestModulePaths() ], $magentoBaseCodePath . self::DEV_TEST_CODE_PATH => [ [ - 'pattern' => '*Test', + 'pattern' => '*' . self::TEST_MODULE_NAME_SUFFIX, 'level' => 1 ], [ @@ -335,7 +335,7 @@ private function aggregateTestModulePaths() 'level' => 0 ], [ - 'pattern' => '*Test', + 'pattern' => '*' . self::TEST_MODULE_NAME_SUFFIX, 'level' => 0 ] ]; @@ -385,7 +385,9 @@ private function globRelevantPaths($testPath, $pattern, $level) if (is_link($codePath)) { $codePath = realpath($codePath); } + $mainModName = array_search($codePath, $allComponents) ?: basename($codePath); + preg_match(self::INVALID_DEV_TEST_CODE_PATH_REGEX, $codePath, $match); if (empty($match)) { if ($pattern == self::MFTF_DIR_PATTERN) { @@ -400,8 +402,6 @@ private function globRelevantPaths($testPath, $pattern, $level) ['module' => $mainModName, 'path' => $codePath] ); } - } else { - echo $codePath; } } @@ -463,16 +463,19 @@ private function getEnabledDirectoryPaths($enabledModules, $allModulePaths) { $enabledDirectoryPaths = []; foreach ($enabledModules as $magentoModuleName) { - if (!isset($this->knownDirectories[$magentoModuleName]) && !isset($allModulePaths[$magentoModuleName])) { - continue; - } elseif (isset($this->knownDirectories[$magentoModuleName]) - && !isset($allModulePaths[$magentoModuleName])) { + $magentoTestModuleName = $magentoModuleName . self::TEST_MODULE_NAME_SUFFIX; + if (isset($this->knownDirectories[$magentoModuleName]) && !isset($allModulePaths[$magentoModuleName])) { LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warn( "Known directory could not match to an existing path.", ['knownDirectory' => $magentoModuleName] ); } else { - $enabledDirectoryPaths[$magentoModuleName] = $allModulePaths[$magentoModuleName]; + if (isset($allModulePaths[$magentoModuleName])) { + $enabledDirectoryPaths[$magentoModuleName] = $allModulePaths[$magentoModuleName]; + } + if (isset($allModulePaths[$magentoTestModuleName])) { + $enabledDirectoryPaths[$magentoTestModuleName] = $allModulePaths[$magentoTestModuleName]; + } } } return $enabledDirectoryPaths; @@ -618,6 +621,18 @@ private function removeBlacklistModules($modulePaths) ['module' => $moduleName] ); } + + preg_match(self::TEST_MODULE_NAME_REGEX, $moduleName, $match); + if (!empty($match)) { + $relatedModuleName = substr($moduleName, 0, -strlen(self::TEST_MODULE_NAME_SUFFIX)); + if (in_array($relatedModuleName, $this->getModuleBlacklist())) { + unset($modulePathsResult[$moduleName]); + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( + "excluding module", + ['module' => $moduleName] + ); + } + } } return $modulePathsResult; @@ -671,19 +686,22 @@ private function getRegisteredModuleList() } try { - $allComponents = []; + $this->registeredModuleList = []; if (!class_exists(self::REGISTRAR_CLASS)) { throw new TestFrameworkException("Magento Installation not found when loading registered modules.\n"); } $components = new \Magento\Framework\Component\ComponentRegistrar(); foreach (self::PATHS as $componentType) { - $allComponents = array_merge($allComponents, $components->getPaths($componentType)); + $this->registeredModuleList = array_merge( + $this->registeredModuleList, + $components->getPaths($componentType) + ); } - array_walk($allComponents, function (&$value) { + array_walk($this->registeredModuleList, function (&$value) { // Magento stores component paths with unix DIRECTORY_SEPARATOR, need to stay uniform and convert $value = realpath($value); }); - return $allComponents; + return $this->registeredModuleList; } catch (TestFrameworkException $e) { LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warning( "$e" From 2f0ebfb8b1d36cf52d3da9409d8ea343b958461f Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Mon, 19 Aug 2019 16:14:32 -0500 Subject: [PATCH 03/10] =?UTF-8?q?MQE-1650:=C2=A0=20Update=20MFTF=20configu?= =?UTF-8?q?ration=20to=20read=20Test=20entities=20from=20new=20location?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Util/ModuleResolver.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 130a23909..6c93ceb08 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -344,10 +344,9 @@ private function aggregateTestModulePaths() // Glob pattern for relevant paths foreach ($codePathsToPattern as $codePath => $patterns) { foreach ($patterns as $pattern) { - $allModulePaths = array_merge_recursive($allModulePaths, $this->globRelevantPaths( - $codePath, - $pattern['pattern'], - $pattern['level']) + $allModulePaths = array_merge_recursive( + $allModulePaths, + $this->globRelevantPaths($codePath, $pattern['pattern'], $pattern['level']) ); } } @@ -360,8 +359,8 @@ private function aggregateTestModulePaths() * are returned as an associative array keyed by basename (the last dir excluding pattern) to an array containing * the matching path. * - * @param string $testPath - * @param string $pattern + * @param string $testPath + * @param string $pattern * @param integer $level * @return array */ @@ -412,8 +411,8 @@ private function globRelevantPaths($testPath, $pattern, $level) * Glob wrapper for globRelevantPaths function * When $level = null, it's recursion * - * @param string $testPath - * @param string $pattern + * @param string $testPath + * @param string $pattern * @param integer $level * @return array */ From ce6f72538fd8f0559f33945abe110936602ea420 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 20 Aug 2019 09:50:23 -0500 Subject: [PATCH 04/10] =?UTF-8?q?MQE-1650:=C2=A0=20Update=20MFTF=20configu?= =?UTF-8?q?ration=20to=20read=20Test=20entities=20from=20new=20location?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Util/ModulePathExtractorTest.php | 8 +- .../Util/ModuleResolverTest.php | 13 ++- .../Page/Config/Dom.php | 10 +- .../Test/Util/TestObjectExtractor.php | 6 +- .../Util/ModulePathExtractor.php | 102 +++++++++++++++--- .../Util/ModuleResolver.php | 102 ++++++++++++------ 6 files changed, 179 insertions(+), 62 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php index 5efa6384b..4b71a48a1 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php @@ -53,7 +53,7 @@ class ModulePathExtractorTest extends TestCase */ public function testGetMagentoModule() { - $modulePathExtractor = new ModulePathExtractor(); + $modulePathExtractor = ModulePathExtractor::getInstance(); $this->assertEquals( '[Analytics]', $modulePathExtractor->extractModuleName( @@ -68,7 +68,7 @@ public function testGetMagentoModule() */ public function testGetExtensionModule() { - $modulePathExtractor = new ModulePathExtractor(); + $modulePathExtractor = ModulePathExtractor::getInstance(); $this->assertEquals( '[Analytics]', $modulePathExtractor->extractModuleName( @@ -83,7 +83,7 @@ public function testGetExtensionModule() */ public function testMagentoModulePath() { - $modulePathExtractor = new ModulePathExtractor(); + $modulePathExtractor = ModulePathExtractor::getInstance(); $this->assertEquals( 'Magento', $modulePathExtractor->getExtensionPath( @@ -98,7 +98,7 @@ public function testMagentoModulePath() */ public function testExtensionModulePath() { - $modulePathExtractor = new ModulePathExtractor(); + $modulePathExtractor = ModulePathExtractor::getInstance(); $this->assertEquals( 'TestExtension', $modulePathExtractor->getExtensionPath( diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 248704adc..b56ac4bcc 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -68,6 +68,10 @@ public function testGetModulePathsAggregate() $this->setMockResolverProperties($resolver, null, [0 => "Magento_example"]); $this->assertEquals( [ + "example" . DIRECTORY_SEPARATOR . "paths", + "example" . DIRECTORY_SEPARATOR . "paths", + "example" . DIRECTORY_SEPARATOR . "paths", + "example" . DIRECTORY_SEPARATOR . "paths", "example" . DIRECTORY_SEPARATOR . "paths", "example" . DIRECTORY_SEPARATOR . "paths", "example" . DIRECTORY_SEPARATOR . "paths" @@ -94,6 +98,10 @@ public function testGetModulePathsLocations() $this->setMockResolverProperties($resolver, null, null); $this->assertEquals( [ + "example" . DIRECTORY_SEPARATOR . "paths", + "example" . DIRECTORY_SEPARATOR . "paths", + "example" . DIRECTORY_SEPARATOR . "paths", + "example" . DIRECTORY_SEPARATOR . "paths", "example" . DIRECTORY_SEPARATOR . "paths", "example" . DIRECTORY_SEPARATOR . "paths", "example" . DIRECTORY_SEPARATOR . "paths" @@ -160,7 +168,10 @@ function ($arg1, $arg2) { ); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, null, ["somePath"]); - $this->assertEquals(["lastPath", "lastPath"], $resolver->getModulesPath()); + $this->assertEquals( + ["lastPath", "lastPath", "lastPath", "lastPath", "lastPath", "lastPath", "lastPath"], + $resolver->getModulesPath() + ); TestLoggingUtil::getInstance()->validateMockLogStatement( 'info', 'excluding module', diff --git a/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php b/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php index bb6d08f58..22d051414 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php @@ -55,7 +55,7 @@ public function __construct( $schemaFile = null, $errorFormat = self::ERROR_FORMAT_DEFAULT ) { - $this->modulePathExtractor = new ModulePathExtractor(); + $this->modulePathExtractor = ModulePathExtractor::getInstance(); $this->validationUtil = new DuplicateNodeValidationUtil('name', $exceptionCollector); parent::__construct( $xml, @@ -87,13 +87,13 @@ public function initDom($xml, $filename = null) ); $pageNodes = $dom->getElementsByTagName('page'); $currentModule = - $this->modulePathExtractor->extractModuleName($filename) . - '_' . - $this->modulePathExtractor->getExtensionPath($filename); + $this->modulePathExtractor->getExtensionPath($filename) + . '_' + . $this->modulePathExtractor->extractModuleName($filename); foreach ($pageNodes as $pageNode) { $pageModule = $pageNode->getAttribute("module"); $pageName = $pageNode->getAttribute("name"); - if ($pageModule !== $currentModule) { + if ($pageModule != $currentModule) { if (MftfApplicationConfig::getConfig()->verboseEnabled()) { print( "Page Module does not match path Module. " . diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index acad18572..d24ca2902 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -11,6 +11,7 @@ use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; +use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\Validation\NameValidationUtil; /** @@ -64,7 +65,7 @@ public function __construct() $this->actionObjectExtractor = new ActionObjectExtractor(); $this->annotationExtractor = new AnnotationExtractor(); $this->testHookObjectExtractor = new TestHookObjectExtractor(); - $this->modulePathExtractor = new ModulePathExtractor(); + $this->modulePathExtractor = ModulePathExtractor::getInstance(); } /** @@ -94,7 +95,8 @@ public function extractTestData($testData) $filename = $testData['filename'] ?? null; $fileNames = explode(",", $filename); $baseFileName = $fileNames[0]; - $module = $this->modulePathExtractor->extractModuleName($baseFileName); + $module = ModuleResolver::getInstance() + ->trimTestModuleSuffix($this->modulePathExtractor->extractModuleName($baseFileName)); $testReference = $testData['extends'] ?? null; $testActions = $this->stripDescriptorTags( $testData, diff --git a/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php b/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php index 33e559ea8..d3aa48497 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php @@ -11,41 +11,111 @@ */ class ModulePathExtractor { - const MAGENTO = 'Magento'; + const SPLIT_DELIMITER = '_'; + + /** + * Test module paths + * + * @var array + */ + private $testModulePaths = []; + + /** + * ModulePathExtractor instance + * + * @var ModulePathExtractor + */ + private static $instance = null; + + /** + * Get ModulePathExtractor instance + * + * @return ModulePathExtractor + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new ModulePathExtractor(); + } + return self::$instance; + } + + /** + * ModulePathExtractor constructor + */ + private function __construct() + { + if (empty($this->testModulePaths)) { + $this->testModulePaths = ModuleResolver::getInstance()->getModulesPath(false); + } + } /** * Extracts module name from the path given + * * @param string $path * @return string */ public function extractModuleName($path) { - if (empty($path)) { - return "NO MODULE DETECTED"; - } - $paths = explode(DIRECTORY_SEPARATOR, $path); - if (count($paths) < 3) { + $key = $this->extractKeyByPath($path); + if (empty($key)) { return "NO MODULE DETECTED"; - } elseif ($paths[count($paths)-3] == "Mftf") { - // app/code/Magento/[Analytics]/Test/Mftf/Test/SomeText.xml - return $paths[count($paths)-5]; } - // dev/tests/acceptance/tests/functional/Magento/FunctionalTest/[Analytics]/Test/SomeText.xml - return $paths[count($paths)-3]; + $parts = $this->splitKeyForParts($key); + return isset($parts[1]) ? $parts[1] : "NO MODULE DETECTED"; } /** - * Extracts the extension form the path, Magento for dev/tests/acceptance, [name] before module otherwise + * Extracts vendor name for module from the path given + * * @param string $path * @return string */ public function getExtensionPath($path) { + $key = $this->extractKeyByPath($path); + if (empty($key)) { + return "NO VENDOR DETECTED"; + } + $parts = $this->splitKeyForParts($key); + return isset($parts[0]) ? $parts[0] : "NO VENDOR DETECTED"; + } + + /** + * Split key by SPLIT_DELIMITER and return parts array + * + * @param string $key + * @return array + */ + private function splitKeyForParts($key) + { + $parts = explode(self::SPLIT_DELIMITER, $key); + return count($parts) == 2 ? $parts : []; + } + + /** + * Extract module name key by path + * + * @param string $path + * @return string + */ + private function extractKeyByPath($path) + { + if (empty($path)) { + return ''; + } $paths = explode(DIRECTORY_SEPARATOR, $path); - if ($paths[count($paths)-3] == "Mftf") { - // app/code/[Magento]/Analytics/Test/Mftf/Test/SomeText.xml - return $paths[count($paths)-6]; + if (count($paths) < 3) { + return ''; + } + $paths = array_slice($paths, 0, count($paths)-2); + $shortenedPath = implode(DIRECTORY_SEPARATOR, $paths); + foreach ($this->testModulePaths as $key => $pathArr) { + if (isset($pathArr[0]) && $pathArr[0] == $shortenedPath) { + return $key; + } } - return self::MAGENTO; + return ''; } } diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 6c93ceb08..1f12eba4a 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -99,6 +99,13 @@ class ModuleResolver */ protected $enabledModulePaths = null; + /** + * Paths for non flattened enabled modules. + * + * @var array|null + */ + protected $enabledModulePathsNoFlatten = null; + /** * Configuration instance. * @@ -233,32 +240,22 @@ public function getEnabledModules() return $this->enabledModules; } - /** - * Return an array of module whitelist that not exist in target Magento instance. - * - * @return array - */ - protected function getModuleWhitelist() - { - $moduleWhitelist = getenv(self::MODULE_WHITELIST); - - if (empty($moduleWhitelist)) { - return []; - } - return array_map('trim', explode(',', $moduleWhitelist)); - } - /** * Return the modules path based on which modules are enabled in the target Magento instance. * + * @param boolean $flat * @return array */ - public function getModulesPath() + public function getModulesPath($flat = true) { - if (isset($this->enabledModulePaths)) { + if (isset($this->enabledModulePaths) && $flat) { return $this->enabledModulePaths; } + if (isset($this->enabledModulePathsNoFlatten) && !$flat) { + return $this->enabledModulePathsNoFlatten; + } + $allModulePaths = $this->aggregateTestModulePaths(); if (MftfApplicationConfig::getConfig()->forceGenerateEnabled()) { @@ -273,6 +270,44 @@ public function getModulesPath() return $this->enabledModulePaths; } + /** + * Sort files according module sequence. + * + * @param array $files + * @return array + */ + public function sortFilesByModuleSequence(array $files) + { + return $this->sequenceSorter->sort($files); + } + + /** + * Trim test module suffix from module name + * + * @param string $moduleName + * @return string + */ + public function trimTestModuleSuffix($moduleName) + { + preg_match(self::TEST_MODULE_NAME_REGEX, $moduleName, $match); + return empty($match) ? $moduleName : substr($moduleName, 0, -strlen(self::TEST_MODULE_NAME_SUFFIX)); + } + + /** + * Return an array of module whitelist that not exist in target Magento instance. + * + * @return array + */ + protected function getModuleWhitelist() + { + $moduleWhitelist = getenv(self::MODULE_WHITELIST); + + if (empty($moduleWhitelist)) { + return []; + } + return array_map('trim', explode(',', $moduleWhitelist)); + } + /** * Retrieves all module directories which might contain pertinent test code. * @@ -351,6 +386,14 @@ private function aggregateTestModulePaths() } } + foreach ($allModulePaths as $moduleName => $modulePath) { + $relatedModuleName = $this->trimTestModuleSuffix($moduleName); + if (($relatedModuleName != $moduleName) && isset($allModulePaths[$relatedModuleName])) { + $message = "Mftf tests cannot be in both $moduleName and $relatedModuleName modules. " + . "Please move all mftf tests to $relatedModuleName."; + throw new TestFrameworkException($message); + } + } return $allModulePaths; } @@ -571,17 +614,6 @@ protected function getAdminToken() return json_decode($response); } - /** - * Sort files according module sequence. - * - * @param array $files - * @return array - */ - public function sortFilesByModuleSequence(array $files) - { - return $this->sequenceSorter->sort($files); - } - /** * A wrapping method for any custom logic which needs to be applied to the module list * @@ -600,6 +632,9 @@ protected function applyCustomModuleMethods($modulesPath) ); }, $customModulePaths); + if (!isset($this->enabledModulePathsNoFlatten)) { + $this->enabledModulePathsNoFlatten = array_merge($modulePathsResult, $customModulePaths); + } return $this->flattenAllModulePaths(array_merge($modulePathsResult, $customModulePaths)); } @@ -613,18 +648,17 @@ private function removeBlacklistModules($modulePaths) { $modulePathsResult = $modulePaths; foreach ($modulePathsResult as $moduleName => $modulePath) { + // Remove module if it is in blacklist if (in_array($moduleName, $this->getModuleBlacklist())) { unset($modulePathsResult[$moduleName]); LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( "excluding module", ['module' => $moduleName] ); - } - - preg_match(self::TEST_MODULE_NAME_REGEX, $moduleName, $match); - if (!empty($match)) { - $relatedModuleName = substr($moduleName, 0, -strlen(self::TEST_MODULE_NAME_SUFFIX)); - if (in_array($relatedModuleName, $this->getModuleBlacklist())) { + } else { + // Remove test module if its magento module is in blacklist + $relatedModuleName = $this->trimTestModuleSuffix($moduleName); + if (($relatedModuleName != $moduleName) && in_array($relatedModuleName, $this->getModuleBlacklist())) { unset($modulePathsResult[$moduleName]); LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->info( "excluding module", From f0fd7a07e4808d51e4caebf31369dd2415e6f4ba Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 20 Aug 2019 10:07:34 -0500 Subject: [PATCH 05/10] =?UTF-8?q?MQE-1650:=C2=A0=20Update=20MFTF=20configu?= =?UTF-8?q?ration=20to=20read=20Test=20entities=20from=20new=20location?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 1f12eba4a..9658d7c38 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -312,6 +312,7 @@ protected function getModuleWhitelist() * Retrieves all module directories which might contain pertinent test code. * * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ private function aggregateTestModulePaths() { From 560cc3273a61de5ff7a9ad8b3b73dc1479a103a2 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 21 Aug 2019 10:13:28 -0500 Subject: [PATCH 06/10] MQE-1650: Update MFTF configuration to read Test entities from new location --- .../Util/ModulePathExtractorTest.php | 187 +++++++++++------- .../Util/ModuleResolverTest.php | 6 +- .../Page/Config/Dom.php | 2 +- .../Test/Util/TestObjectExtractor.php | 2 +- .../Util/ModulePathExtractor.php | 22 +-- .../Util/ModuleResolver.php | 90 +++++++-- 6 files changed, 200 insertions(+), 109 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php index 4b71a48a1..d60180ab8 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php @@ -6,104 +6,147 @@ namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; +use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; -use PHPUnit\Framework\TestCase; +use Magento\FunctionalTestingFramework\Util\ModuleResolver; +use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\ObjectManager; +use Magento\FunctionalTestingFramework\ObjectManagerFactory; -class ModulePathExtractorTest extends TestCase +class ModulePathExtractorTest extends MagentoTestCase { - const EXTENSION_PATH = "app" - . DIRECTORY_SEPARATOR - . "code" - . DIRECTORY_SEPARATOR - . "TestExtension" - . DIRECTORY_SEPARATOR - . "[Analytics]" - . DIRECTORY_SEPARATOR - . "Test" - . DIRECTORY_SEPARATOR - . "Mftf" - . DIRECTORY_SEPARATOR - . "Test" - . DIRECTORY_SEPARATOR - . "SomeText.xml"; + /** + * Mock test module paths + * + * @var array + */ + private $mockTestModulePaths = [ + 'Magento_ModuleA' => ['/base/path/app/code/Magento/ModuleA/Test/Mftf'], + 'VendorB_ModuleB' => ['/base/path/app/code/VendorB/ModuleB/Test/Mftf'], + 'Magento_ModuleC' => ['/base/path/dev/tests/acceptance/tests/functional/Magento/ModuleCTest'], + 'VendorD_ModuleD' => ['/base/path/dev/tests/acceptance/tests/functional/VendorD/ModuleDTest'], + 'SomeModuleE' => ['/base/path/dev/tests/acceptance/tests/functional/FunctionalTest/SomeModuleE'], + 'Magento_ModuleF' => ['/base/path/vendor/magento/module-modulef/Test/Mftf'], + 'VendorG_ModuleG' => ['/base/path/vendor/vendorg/module-moduleg-test'], + ]; + + /** + * Validate module for app/code path + * + * @throws \Exception + */ + public function testGetModuleAppCode() + { + $mockPath = '/base/path/app/code/Magento/ModuleA/Test/Mftf/Test/SomeTest.xml'; + $this->setUpMockModuleResolver($this->mockTestModulePaths); + $extractor = new ModulePathExtractor(); + $this->assertEquals('ModuleA', $extractor->extractModuleName($mockPath)); + } + + /** + * Validate vendor for app/code path + * + * @throws \Exception + */ + public function testGetVendorAppCode() + { + $mockPath = '/base/path/app/code/VendorB/ModuleB/Test/Mftf/Test/SomeTest.xml'; + $this->setUpMockModuleResolver($this->mockTestModulePaths); + $extractor = new ModulePathExtractor(); + $this->assertEquals('VendorB', $extractor->getExtensionPath($mockPath)); + } - const MAGENTO_PATH = "dev" - . DIRECTORY_SEPARATOR - . "tests" - . DIRECTORY_SEPARATOR - . "acceptance" - . DIRECTORY_SEPARATOR - . "tests" - . DIRECTORY_SEPARATOR - . "functional" - . DIRECTORY_SEPARATOR - . "Magento" - . DIRECTORY_SEPARATOR - . "FunctionalTest" - . DIRECTORY_SEPARATOR - . "[Analytics]" - . DIRECTORY_SEPARATOR - . "Test" - . DIRECTORY_SEPARATOR - . "SomeText.xml"; + /** + * Validate module for dev/tests path + * + * @throws \Exception + */ + public function testGetModuleDevTests() + { + $mockPath = '/base/path/dev/tests/acceptance/tests/functional/Magento/ModuleCTest/Test/SomeTest.xml'; + $this->setUpMockModuleResolver($this->mockTestModulePaths); + $extractor = new ModulePathExtractor(); + $this->assertEquals('ModuleC', $extractor->extractModuleName($mockPath)); + } + + /** + * Validate vendor for dev/tests path + * + * @throws \Exception + */ + public function testGetVendorDevTests() + { + $mockPath = '/base/path/dev/tests/acceptance/tests/functional/VendorD/ModuleDTest/Test/SomeTest.xml'; + $this->setUpMockModuleResolver($this->mockTestModulePaths); + $extractor = new ModulePathExtractor(); + $this->assertEquals('VendorD', $extractor->getExtensionPath($mockPath)); + } /** - * Validate correct module is returned for dev/tests path + * Validate module with no _ + * * @throws \Exception */ - public function testGetMagentoModule() + public function testGetModule() { - $modulePathExtractor = ModulePathExtractor::getInstance(); - $this->assertEquals( - '[Analytics]', - $modulePathExtractor->extractModuleName( - self::MAGENTO_PATH - ) - ); + $mockPath = '/base/path/dev/tests/acceptance/tests/functional/FunctionalTest/SomeModuleE/Test/SomeTest.xml'; + $this->setUpMockModuleResolver($this->mockTestModulePaths); + $extractor = new ModulePathExtractor(); + $this->assertEquals('NO MODULE DETECTED', $extractor->extractModuleName($mockPath)); } /** - * Validate correct module is returned for extension path + * Validate module for vendor/tests path + * * @throws \Exception */ - public function testGetExtensionModule() + public function testGetModuleVendorDir() { - $modulePathExtractor = ModulePathExtractor::getInstance(); - $this->assertEquals( - '[Analytics]', - $modulePathExtractor->extractModuleName( - self::EXTENSION_PATH - ) - ); + $mockPath = '/base/path/vendor/magento/module-modulef/Test/Mftf/Test/SomeTest.xml'; + $this->setUpMockModuleResolver($this->mockTestModulePaths); + $extractor = new ModulePathExtractor(); + $this->assertEquals('ModuleF', $extractor->extractModuleName($mockPath)); } /** - * Validate Magento is returned for dev/tests/acceptance + * Validate vendor for vendor path + * * @throws \Exception */ - public function testMagentoModulePath() + public function testGetVendorVendorDir() { - $modulePathExtractor = ModulePathExtractor::getInstance(); - $this->assertEquals( - 'Magento', - $modulePathExtractor->getExtensionPath( - self::MAGENTO_PATH - ) - ); + $mockPath = '/base/path/vendor/vendorg/module-moduleg-test/Test/SomeTest.xml'; + $this->setUpMockModuleResolver($this->mockTestModulePaths); + $extractor = new ModulePathExtractor(); + $this->assertEquals('VendorG', $extractor->getExtensionPath($mockPath)); } /** - * Validate correct extension path is returned + * Setup mock ModuleResolver + * + * @param array $testModulePaths + * @return void * @throws \Exception */ - public function testExtensionModulePath() + private function setUpMockModuleResolver($testModulePaths) { - $modulePathExtractor = ModulePathExtractor::getInstance(); - $this->assertEquals( - 'TestExtension', - $modulePathExtractor->getExtensionPath( - self::EXTENSION_PATH - ) - ); + $mockConfig = AspectMock::double(MftfApplicationConfig::class, ['forceGenerateEnabled' => false]); + $instance = AspectMock::double(ObjectManager::class, ['create' => $mockConfig->make(), 'get' => null])->make(); + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + + $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + + $mockResolver = AspectMock::double(ModuleResolver::class, ['getAdminToken' => false, 'globRelevantPaths' => []]); + $instance = AspectMock::double(ObjectManager::class, ['create' => $mockResolver->make(), 'get' => null]) + ->make(); + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + + $resolver = ModuleResolver::getInstance(); + $property = new \ReflectionProperty(ModuleResolver::class, 'enabledModulePathsNoFlatten'); + $property->setAccessible(true); + $property->setValue($resolver, $testModulePaths); } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index b56ac4bcc..97fdd5170 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -157,8 +157,8 @@ public function testGetModulePathsBlacklist() null, null, null, - function ($arg1, $arg2) { - if ($arg2 === "") { + function ($arg1, $arg2, $arg3) { + if ($arg3 === null) { $mockValue = ["somePath" => "somePath"]; } else { $mockValue = ["lastPath" => "lastPath"]; @@ -169,7 +169,7 @@ function ($arg1, $arg2) { $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, null, ["somePath"]); $this->assertEquals( - ["lastPath", "lastPath", "lastPath", "lastPath", "lastPath", "lastPath", "lastPath"], + ["lastPath", "lastPath", "lastPath", "lastPath", "lastPath"], $resolver->getModulesPath() ); TestLoggingUtil::getInstance()->validateMockLogStatement( diff --git a/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php b/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php index 22d051414..a67cb1f1e 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php +++ b/src/Magento/FunctionalTestingFramework/Page/Config/Dom.php @@ -55,7 +55,7 @@ public function __construct( $schemaFile = null, $errorFormat = self::ERROR_FORMAT_DEFAULT ) { - $this->modulePathExtractor = ModulePathExtractor::getInstance(); + $this->modulePathExtractor = new ModulePathExtractor(); $this->validationUtil = new DuplicateNodeValidationUtil('name', $exceptionCollector); parent::__construct( $xml, diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php index d24ca2902..f4eb7b5a7 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestObjectExtractor.php @@ -65,7 +65,7 @@ public function __construct() $this->actionObjectExtractor = new ActionObjectExtractor(); $this->annotationExtractor = new AnnotationExtractor(); $this->testHookObjectExtractor = new TestHookObjectExtractor(); - $this->modulePathExtractor = ModulePathExtractor::getInstance(); + $this->modulePathExtractor = new ModulePathExtractor(); } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php b/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php index d3aa48497..c962782b1 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModulePathExtractor.php @@ -20,30 +20,10 @@ class ModulePathExtractor */ private $testModulePaths = []; - /** - * ModulePathExtractor instance - * - * @var ModulePathExtractor - */ - private static $instance = null; - - /** - * Get ModulePathExtractor instance - * - * @return ModulePathExtractor - */ - public static function getInstance() - { - if (!self::$instance) { - self::$instance = new ModulePathExtractor(); - } - return self::$instance; - } - /** * ModulePathExtractor constructor */ - private function __construct() + public function __construct() { if (empty($this->testModulePaths)) { $this->testModulePaths = ModuleResolver::getInstance()->getModulesPath(false); diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 9658d7c38..3da1e287f 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -73,7 +73,23 @@ class ModuleResolver */ const INVALID_DEV_TEST_CODE_PATH_REGEX = "~^[^:*\\?\"<>|']+" . self::DEV_TEST_CODE_PATH - . "/[^/:*\\?\"<>|']+/FunctionalTest$~"; + . "/[^/:*\\?\"<>|']+/" + . self::DEPRECATED_DEV_TEST_SHORT_NAME + . "$~"; + + /** + * Short directory name for deprecated path + */ + const DEPRECATED_DEV_TEST_SHORT_NAME = 'FunctionalTest'; + + /** + * Regex to match deprecated dev test code path + */ + const DEPRECATED_DEV_TEST_CODE_PATH_REGEX = "~^[^:*\\?\"<>|']+" + . self::DEV_TEST_CODE_PATH + . "/[^/:*\\?\"<>|']+/" + . self::DEPRECATED_DEV_TEST_SHORT_NAME + . "/[^:*\\?\"<>|']+~"; /** * Test module name suffix @@ -199,6 +215,7 @@ private function __construct() * Return an array of enabled modules of target Magento instance. * * @return array + * @throws TestFrameworkException */ public function getEnabledModules() { @@ -312,7 +329,7 @@ protected function getModuleWhitelist() * Retrieves all module directories which might contain pertinent test code. * * @return array - * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @throws TestFrameworkException */ private function aggregateTestModulePaths() { @@ -349,7 +366,7 @@ private function aggregateTestModulePaths() 'level' => 1 ], [ - 'pattern' => 'FunctionalTest' . DIRECTORY_SEPARATOR . '*', + 'pattern' => self::DEPRECATED_DEV_TEST_SHORT_NAME . DIRECTORY_SEPARATOR . '*', 'level' => 1 ] ] @@ -387,14 +404,9 @@ private function aggregateTestModulePaths() } } - foreach ($allModulePaths as $moduleName => $modulePath) { - $relatedModuleName = $this->trimTestModuleSuffix($moduleName); - if (($relatedModuleName != $moduleName) && isset($allModulePaths[$relatedModuleName])) { - $message = "Mftf tests cannot be in both $moduleName and $relatedModuleName modules. " - . "Please move all mftf tests to $relatedModuleName."; - throw new TestFrameworkException($message); - } - } + // Validate module paths + $this->validateModulePaths($allModulePaths); + return $allModulePaths; } @@ -752,4 +764,60 @@ private function getBackendUrl() { return getenv('MAGENTO_BACKEND_BASE_URL') ?: getenv('MAGENTO_BASE_URL'); } + + /** + * Validate module paths for violation and deprecations + * + * @param array $modulePaths + * @return void + * @throws + */ + private function validateModulePaths($modulePaths) + { + $foundDeprecate = false; + // Check tests should be in one location per module + foreach ($modulePaths as $moduleName => $modulePath) { + // Check tests in deprecated path + if (!$foundDeprecate) { + preg_match(self::DEPRECATED_DEV_TEST_CODE_PATH_REGEX, $modulePath[0], $match); + if (!empty($match)) { + $foundDeprecate = true; + } + } + $relatedModuleName = $this->trimTestModuleSuffix($moduleName); + if (($relatedModuleName != $moduleName) && isset($allModulePaths[$relatedModuleName])) { + $message = "Mftf tests cannot be in both $moduleName and $relatedModuleName modules. " + . "Please move all mftf tests to $relatedModuleName."; + throw new TestFrameworkException($message); + } + } + + if ($foundDeprecate) { + $deprecaedPath = ltrim( + self::DEV_TEST_CODE_PATH + . DIRECTORY_SEPARATOR + . '' + . DIRECTORY_SEPARATOR + . self::DEPRECATED_DEV_TEST_SHORT_NAME + . DIRECTORY_SEPARATOR, + '/' + ); + + $suggestedPath = ltrim( + self::DEV_TEST_CODE_PATH + . DIRECTORY_SEPARATOR + . '' + . DIRECTORY_SEPARATOR, + '/' + ); + + // Suppress print during unit testing + if (MftfApplicationConfig::getConfig()->getPhase() !== MftfApplicationConfig::UNIT_TEST_PHASE) { + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warning( + "DEPRECATION: $deprecaedPath is deprecated! Please move mftf test modules to $suggestedPath" + ); + print ("\nDEPRECATION: $deprecaedPath is deprecated! Please move mftf tests to $suggestedPath\n\n"); + } + } + } } From 9d17360074dcf485856ced269df41f60d869af2f Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 21 Aug 2019 14:48:08 -0500 Subject: [PATCH 07/10] MQE-1650: Update MFTF configuration to read Test entities from new location - update unit tests --- .../Suite/Handlers/SuiteObjectHandlerTest.php | 7 +++ .../Suite/SuiteGeneratorTest.php | 4 +- .../Test/Handlers/TestObjectHandlerTest.php | 26 +++++--- .../Test/Util/ObjectExtensionUtilTest.php | 3 + .../Util/ModulePathExtractorTest.php | 62 +++++++------------ .../unit/Util/MockModuleResolverBuilder.php | 57 +++++++++++++++++ .../Util/ModuleResolver.php | 4 +- 7 files changed, 113 insertions(+), 50 deletions(-) create mode 100644 dev/tests/unit/Util/MockModuleResolverBuilder.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php index 99125a9e3..5bf29507c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/Handlers/SuiteObjectHandlerTest.php @@ -15,9 +15,16 @@ use Magento\FunctionalTestingFramework\Util\MagentoTestCase; use tests\unit\Util\SuiteDataArrayBuilder; use tests\unit\Util\TestDataArrayBuilder; +use tests\unit\Util\MockModuleResolverBuilder; class SuiteObjectHandlerTest extends MagentoTestCase { + public function setUp() + { + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup(); + } + /** * Tests basic parsing and accesors of suite object and suite object supporting classes */ diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php index eb6298afc..29158b0f5 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Suite/SuiteGeneratorTest.php @@ -20,10 +20,10 @@ use tests\unit\Util\SuiteDataArrayBuilder; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\TestLoggingUtil; +use tests\unit\Util\MockModuleResolverBuilder; class SuiteGeneratorTest extends MagentoTestCase { - /** * Setup entry append and clear for Suite Generator */ @@ -42,6 +42,8 @@ public static function setUpBeforeClass() public function setUp() { TestLoggingUtil::getInstance()->setMockLoggingUtil(); + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup(); } /** diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 1dbeb50db..65fe0b6be 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -8,7 +8,6 @@ use AspectMock\Test as AspectMock; -use Go\Aop\Aspect; use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler; @@ -16,10 +15,10 @@ use Magento\FunctionalTestingFramework\Test\Objects\TestHookObject; use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Test\Parsers\TestDataParser; -use Magento\FunctionalTestingFramework\Test\Util\ActionObjectExtractor; use Magento\FunctionalTestingFramework\Test\Util\TestObjectExtractor; use Magento\FunctionalTestingFramework\Util\MagentoTestCase; use tests\unit\Util\TestDataArrayBuilder; +use tests\unit\Util\MockModuleResolverBuilder; class TestObjectHandlerTest extends MagentoTestCase { @@ -40,10 +39,13 @@ public function testGetTestObject() ->withTestActions() ->build(); + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup(); $this->setMockParserOutput(['tests' => $mockData]); // run object handler method $toh = TestObjectHandler::getInstance(); + $mockConfig = AspectMock::double(TestObjectHandler::class, ['initTestData' => false]); $actualTestObject = $toh->getObject($testDataArrayBuilder->testName); // perform asserts @@ -130,6 +132,8 @@ public function testGetTestsByGroup() ->withTestActions() ->build(); + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup(); $this->setMockParserOutput(['tests' => array_merge($includeTest, $excludeTest)]); // execute test method @@ -150,16 +154,20 @@ public function testGetTestsByGroup() public function testGetTestWithModuleName() { // set up Test Data - $moduleExpected = "SomeTestModule"; + $moduleExpected = "SomeModuleName"; + $moduleExpectedTest = $moduleExpected . "Test"; $filepath = DIRECTORY_SEPARATOR . - "user" . + "user" . DIRECTORY_SEPARATOR . "magento2ce" . DIRECTORY_SEPARATOR . "dev" . DIRECTORY_SEPARATOR . "tests" . DIRECTORY_SEPARATOR . "acceptance" . DIRECTORY_SEPARATOR . "tests" . DIRECTORY_SEPARATOR . - $moduleExpected . DIRECTORY_SEPARATOR . - "Tests" . DIRECTORY_SEPARATOR . + "functional" . DIRECTORY_SEPARATOR . + "Vendor" . DIRECTORY_SEPARATOR . + $moduleExpectedTest; + $file = $filepath . DIRECTORY_SEPARATOR . + "Test" . DIRECTORY_SEPARATOR . "text.xml"; // set up mock data $testDataArrayBuilder = new TestDataArrayBuilder(); @@ -169,8 +177,12 @@ public function testGetTestWithModuleName() ->withAfterHook() ->withBeforeHook() ->withTestActions() - ->withFileName($filepath) + ->withFileName($file) ->build(); + + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup(['Vendor_' . $moduleExpected => [$filepath]]); + $this->setMockParserOutput(['tests' => $mockData]); // Execute Test Method $toh = TestObjectHandler::getInstance(); diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php index b023b16c7..3b43ba00f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php @@ -20,6 +20,7 @@ use PHPUnit\Framework\TestCase; use tests\unit\Util\TestDataArrayBuilder; use tests\unit\Util\TestLoggingUtil; +use tests\unit\Util\MockModuleResolverBuilder; class ObjectExtensionUtilTest extends TestCase { @@ -30,6 +31,8 @@ class ObjectExtensionUtilTest extends TestCase public function setUp() { TestLoggingUtil::getInstance()->setMockLoggingUtil(); + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup(); } /** diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php index d60180ab8..4fb18d383 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModulePathExtractorTest.php @@ -6,13 +6,9 @@ namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; -use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\Util\ModulePathExtractor; -use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\MagentoTestCase; -use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; -use Magento\FunctionalTestingFramework\ObjectManager; -use Magento\FunctionalTestingFramework\ObjectManagerFactory; +use tests\unit\Util\MockModuleResolverBuilder; class ModulePathExtractorTest extends MagentoTestCase { @@ -39,7 +35,9 @@ class ModulePathExtractorTest extends MagentoTestCase public function testGetModuleAppCode() { $mockPath = '/base/path/app/code/Magento/ModuleA/Test/Mftf/Test/SomeTest.xml'; - $this->setUpMockModuleResolver($this->mockTestModulePaths); + + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('ModuleA', $extractor->extractModuleName($mockPath)); } @@ -52,7 +50,9 @@ public function testGetModuleAppCode() public function testGetVendorAppCode() { $mockPath = '/base/path/app/code/VendorB/ModuleB/Test/Mftf/Test/SomeTest.xml'; - $this->setUpMockModuleResolver($this->mockTestModulePaths); + + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('VendorB', $extractor->getExtensionPath($mockPath)); } @@ -65,7 +65,9 @@ public function testGetVendorAppCode() public function testGetModuleDevTests() { $mockPath = '/base/path/dev/tests/acceptance/tests/functional/Magento/ModuleCTest/Test/SomeTest.xml'; - $this->setUpMockModuleResolver($this->mockTestModulePaths); + + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('ModuleC', $extractor->extractModuleName($mockPath)); } @@ -78,7 +80,9 @@ public function testGetModuleDevTests() public function testGetVendorDevTests() { $mockPath = '/base/path/dev/tests/acceptance/tests/functional/VendorD/ModuleDTest/Test/SomeTest.xml'; - $this->setUpMockModuleResolver($this->mockTestModulePaths); + + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('VendorD', $extractor->getExtensionPath($mockPath)); } @@ -91,7 +95,9 @@ public function testGetVendorDevTests() public function testGetModule() { $mockPath = '/base/path/dev/tests/acceptance/tests/functional/FunctionalTest/SomeModuleE/Test/SomeTest.xml'; - $this->setUpMockModuleResolver($this->mockTestModulePaths); + + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('NO MODULE DETECTED', $extractor->extractModuleName($mockPath)); } @@ -104,7 +110,9 @@ public function testGetModule() public function testGetModuleVendorDir() { $mockPath = '/base/path/vendor/magento/module-modulef/Test/Mftf/Test/SomeTest.xml'; - $this->setUpMockModuleResolver($this->mockTestModulePaths); + + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('ModuleF', $extractor->extractModuleName($mockPath)); } @@ -117,36 +125,10 @@ public function testGetModuleVendorDir() public function testGetVendorVendorDir() { $mockPath = '/base/path/vendor/vendorg/module-moduleg-test/Test/SomeTest.xml'; - $this->setUpMockModuleResolver($this->mockTestModulePaths); + + $resolverMock = new MockModuleResolverBuilder(); + $resolverMock->setup($this->mockTestModulePaths); $extractor = new ModulePathExtractor(); $this->assertEquals('VendorG', $extractor->getExtensionPath($mockPath)); } - - /** - * Setup mock ModuleResolver - * - * @param array $testModulePaths - * @return void - * @throws \Exception - */ - private function setUpMockModuleResolver($testModulePaths) - { - $mockConfig = AspectMock::double(MftfApplicationConfig::class, ['forceGenerateEnabled' => false]); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockConfig->make(), 'get' => null])->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - - $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); - $property->setAccessible(true); - $property->setValue(null); - - $mockResolver = AspectMock::double(ModuleResolver::class, ['getAdminToken' => false, 'globRelevantPaths' => []]); - $instance = AspectMock::double(ObjectManager::class, ['create' => $mockResolver->make(), 'get' => null]) - ->make(); - AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); - - $resolver = ModuleResolver::getInstance(); - $property = new \ReflectionProperty(ModuleResolver::class, 'enabledModulePathsNoFlatten'); - $property->setAccessible(true); - $property->setValue($resolver, $testModulePaths); - } } diff --git a/dev/tests/unit/Util/MockModuleResolverBuilder.php b/dev/tests/unit/Util/MockModuleResolverBuilder.php new file mode 100644 index 000000000..a994d393d --- /dev/null +++ b/dev/tests/unit/Util/MockModuleResolverBuilder.php @@ -0,0 +1,57 @@ + ['/base/path/app/code/Magento/Module/Test/Mftf']]; + + /** + * Setup mock ModuleResolver + * + * @param array $paths + * @return void + * @throws \Exception + */ + public function setup($paths = null) + { + if (!empty($path)) { + $paths = $this->defaultPaths; + } + + $mockConfig = AspectMock::double(MftfApplicationConfig::class, ['forceGenerateEnabled' => false]); + $instance = AspectMock::double(ObjectManager::class, ['create' => $mockConfig->make(), 'get' => null])->make(); + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + + $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + + $mockResolver = AspectMock::double( + ModuleResolver::class, + ['getAdminToken' => false, 'globRelevantPaths' => []] + ); + $instance = AspectMock::double(ObjectManager::class, ['create' => $mockResolver->make(), 'get' => null]) + ->make(); + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + + $resolver = ModuleResolver::getInstance(); + $property = new \ReflectionProperty(ModuleResolver::class, 'enabledModulePathsNoFlatten'); + $property->setAccessible(true); + $property->setValue($resolver, $paths); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 3da1e287f..1f779d40a 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -770,7 +770,7 @@ private function getBackendUrl() * * @param array $modulePaths * @return void - * @throws + * @throws TestFrameworkException */ private function validateModulePaths($modulePaths) { @@ -785,7 +785,7 @@ private function validateModulePaths($modulePaths) } } $relatedModuleName = $this->trimTestModuleSuffix($moduleName); - if (($relatedModuleName != $moduleName) && isset($allModulePaths[$relatedModuleName])) { + if (($relatedModuleName != $moduleName) && isset($modulePaths[$relatedModuleName])) { $message = "Mftf tests cannot be in both $moduleName and $relatedModuleName modules. " . "Please move all mftf tests to $relatedModuleName."; throw new TestFrameworkException($message); From 94f0e26fffc039166ee94ebc419afe9d436ecf9e Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 21 Aug 2019 17:02:35 -0500 Subject: [PATCH 08/10] MQE-1650: Update MFTF configuration to read Test entities from new location - update unit tests --- .../Util/ModuleResolverTest.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 97fdd5170..6ea11130f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -86,6 +86,11 @@ public function testGetModulePathsAggregate() */ public function testGetModulePathsLocations() { + // clear test object handler value to inject parsed content + $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + $this->mockForceGenerate(false); $mockResolver = $this->setMockResolverClass( true, @@ -115,18 +120,19 @@ public function testGetModulePathsLocations() // Define the Module paths from default TESTS_MODULE_PATH $modulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; - $mockResolver->verifyInvoked('globRelevantPaths', [$modulePath, '']); + $mockResolver->verifyInvoked('globRelevantPaths', [$magentoBaseCodePath . '/vendor', 'Test/Mftf', null]); + $mockResolver->verifyInvoked('globRelevantPaths', [$magentoBaseCodePath . '/vendor', '*-test', 1]); + $mockResolver->verifyInvoked('globRelevantPaths', [$magentoBaseCodePath . '/app/code', 'Test/Mftf', null]); $mockResolver->verifyInvoked( 'globRelevantPaths', - [$magentoBaseCodePath . DIRECTORY_SEPARATOR . "vendor" , 'Test' . DIRECTORY_SEPARATOR .'Mftf'] + [$magentoBaseCodePath . '/dev/tests/acceptance/tests/functional', '*Test', 1] ); $mockResolver->verifyInvoked( 'globRelevantPaths', - [ - $magentoBaseCodePath . DIRECTORY_SEPARATOR . "app" . DIRECTORY_SEPARATOR . "code", - 'Test' . DIRECTORY_SEPARATOR .'Mftf' - ] + [$magentoBaseCodePath . '/dev/tests/acceptance/tests/functional', 'FunctionalTest/*', 1] ); + $mockResolver->verifyInvoked('globRelevantPaths', [$modulePath, 'Test/Mftf', 0]); + $mockResolver->verifyInvoked('globRelevantPaths', [$modulePath, '*Test', 0]); } /** From adf9d82ee58ce90f8647b1bfff9ed23cd106cd86 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Thu, 22 Aug 2019 09:05:49 -0500 Subject: [PATCH 09/10] MQE-1650: Update MFTF configuration to read Test entities from new location - update unit tests --- .../Test/Handlers/TestObjectHandlerTest.php | 10 ++++++++++ dev/tests/unit/Util/MockModuleResolverBuilder.php | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 65fe0b6be..08571b507 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -210,4 +210,14 @@ private function setMockParserOutput($data) ->make(); // bypass the private constructor AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); } + + /** + * After method functionality + * + * @return void + */ + public function tearDown() + { + AspectMock::clean(); + } } diff --git a/dev/tests/unit/Util/MockModuleResolverBuilder.php b/dev/tests/unit/Util/MockModuleResolverBuilder.php index a994d393d..706067f88 100644 --- a/dev/tests/unit/Util/MockModuleResolverBuilder.php +++ b/dev/tests/unit/Util/MockModuleResolverBuilder.php @@ -21,7 +21,7 @@ class MockModuleResolverBuilder private $defaultPaths = ['Magento_Module' => ['/base/path/app/code/Magento/Module/Test/Mftf']]; /** - * Setup mock ModuleResolver + * Mock ModuleResolver builder * * @param array $paths * @return void @@ -43,7 +43,7 @@ public function setup($paths = null) $mockResolver = AspectMock::double( ModuleResolver::class, - ['getAdminToken' => false, 'globRelevantPaths' => []] + ['getAdminToken' => false, 'globRelevantPaths' => [], 'getEnabledModules' => []] ); $instance = AspectMock::double(ObjectManager::class, ['create' => $mockResolver->make(), 'get' => null]) ->make(); From fec2a5e54ae5f44ec974a205b6eaf731c41edd5b Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Thu, 22 Aug 2019 15:50:05 -0500 Subject: [PATCH 10/10] MQE-1650: Update MFTF configuration to read Test entities from new location - update unit tests, verification tests --- .../Util/ModuleResolverTest.php | 6 +- .../TestModule/Page/SamplePage.xml | 14 ++-- .../Util/ModuleResolver.php | 79 ++++++++++++++++--- 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 6ea11130f..6acf81b53 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -131,8 +131,8 @@ public function testGetModulePathsLocations() 'globRelevantPaths', [$magentoBaseCodePath . '/dev/tests/acceptance/tests/functional', 'FunctionalTest/*', 1] ); - $mockResolver->verifyInvoked('globRelevantPaths', [$modulePath, 'Test/Mftf', 0]); - $mockResolver->verifyInvoked('globRelevantPaths', [$modulePath, '*Test', 0]); + $mockResolver->verifyInvoked('globRelevantPaths', [$modulePath, 'Test/Mftf', null]); + $mockResolver->verifyInvoked('globRelevantPaths', [$modulePath, '*', 0]); } /** @@ -175,7 +175,7 @@ function ($arg1, $arg2, $arg3) { $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, null, ["somePath"]); $this->assertEquals( - ["lastPath", "lastPath", "lastPath", "lastPath", "lastPath"], + ["lastPath", "lastPath", "lastPath", "lastPath"], $resolver->getModulesPath() ); TestLoggingUtil::getInstance()->validateMockLogStatement( diff --git a/dev/tests/verification/TestModule/Page/SamplePage.xml b/dev/tests/verification/TestModule/Page/SamplePage.xml index bf8f99615..07494d88f 100644 --- a/dev/tests/verification/TestModule/Page/SamplePage.xml +++ b/dev/tests/verification/TestModule/Page/SamplePage.xml @@ -8,25 +8,25 @@ - +
- +
- +
- +
- +
- +
- +
diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 1f779d40a..d7b4829cf 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -40,20 +40,19 @@ class ModuleResolver const REGISTRAR_CLASS = "\Magento\Framework\Component\ComponentRegistrar"; /** - * Vendor code path + * const for vendor */ - const VENDOR_CODE_PATH = DIRECTORY_SEPARATOR . "vendor"; + const VENDOR = 'vendor'; /** - * App code path + * const for app/code */ - const APP_CODE_PATH = DIRECTORY_SEPARATOR . "app" . DIRECTORY_SEPARATOR . "code"; + const APP_CODE = 'app' . DIRECTORY_SEPARATOR . "code"; /** - * Dev test code path + * const for dev/tests/acceptance/tests/functional */ - const DEV_TEST_CODE_PATH = DIRECTORY_SEPARATOR - . 'dev' + const DEV_TEST = 'dev' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR @@ -63,6 +62,21 @@ class ModuleResolver . DIRECTORY_SEPARATOR . 'functional'; + /** + * Vendor code path + */ + const VENDOR_CODE_PATH = DIRECTORY_SEPARATOR . self::VENDOR; + + /** + * App code path + */ + const APP_CODE_PATH = DIRECTORY_SEPARATOR . self::APP_CODE; + + /** + * Dev test code path + */ + const DEV_TEST_CODE_PATH = DIRECTORY_SEPARATOR . self::DEV_TEST; + /** * Pattern for Mftf directories */ @@ -101,6 +115,21 @@ class ModuleResolver */ const TEST_MODULE_NAME_REGEX = "~\S+" . self::TEST_MODULE_NAME_SUFFIX . "$~"; + /** + * Regex to grab vendor name in vendor + */ + const VENDOR_NAME_REGEX_V = "~.+\\/" . self::VENDOR . "\/(?<" . self::VENDOR . ">[^\/]+)\/.+~"; + + /** + * Regex to grab vendor name in app/code + */ + const VENDOR_NAME_REGEX_A = "~.+\\/" . self::APP_CODE . "\/(?<" . self::VENDOR . ">[^\/]+)\/.+~"; + + /** + * Regex to grab vendor name dev/tests + */ + const VENDOR_NAME_REGEX_D = "~.+\\/" . self::DEV_TEST . "\/(?<" . self::VENDOR . ">[^\/]+)\/.+~"; + /** * Enabled modules. * @@ -384,12 +413,12 @@ private function aggregateTestModulePaths() if ($newPath) { $codePathsToPattern[$modulePath] = [ [ - 'pattern' => 'Test' . DIRECTORY_SEPARATOR . 'Mftf', + 'pattern' => '*', 'level' => 0 ], [ - 'pattern' => '*' . self::TEST_MODULE_NAME_SUFFIX, - 'level' => 0 + 'pattern' => 'Test' . DIRECTORY_SEPARATOR . 'Mftf', + 'level' => null ] ]; } @@ -432,6 +461,8 @@ private function globRelevantPaths($testPath, $pattern, $level) $allComponents = $this->getRegisteredModuleList(); foreach ($relevantPaths as $codePath) { + $possibleVendorName = $this->getPossibleVendorName($codePath); + // Reduce magento/app/code/Magento/AdminGws/Test/MFTF to magento/app/code/Magento/AdminGws to read symlink // Symlinks must be resolved otherwise they will not match Magento's filepath to the module if ($pattern == self::MFTF_DIR_PATTERN) { @@ -441,7 +472,7 @@ private function globRelevantPaths($testPath, $pattern, $level) $codePath = realpath($codePath); } - $mainModName = array_search($codePath, $allComponents) ?: basename($codePath); + $mainModName = array_search($codePath, $allComponents) ?: $possibleVendorName . '_' . basename($codePath); preg_match(self::INVALID_DEV_TEST_CODE_PATH_REGEX, $codePath, $match); if (empty($match)) { @@ -820,4 +851,30 @@ private function validateModulePaths($modulePaths) } } } + + /** + * Return possible vendor name from a path given + * + * @param string $path + * @return string + */ + private function getPossibleVendorName($path) + { + $possibleVendorName = 'Unknown'; + $regexs = [ + self::VENDOR_NAME_REGEX_A, + self::VENDOR_NAME_REGEX_D, + self::VENDOR_NAME_REGEX_V + ]; + + foreach ($regexs as $regex) { + $match = []; + preg_match($regex, $path, $match); + if (isset($match[self::VENDOR])) { + $possibleVendorName = ucfirst($match[self::VENDOR]); + return $possibleVendorName; + } + } + return $possibleVendorName; + } }