From 5700373b931c2cdb0ed0998ca0a4df41b7708174 Mon Sep 17 00:00:00 2001 From: KevinBKozan Date: Thu, 7 Jun 2018 10:16:58 -0500 Subject: [PATCH 1/3] MQE-1043: MFTF force flag should ignore the magento base url even when valid - ModuleResolver now completely ignores trying to get enabledModules if --force is set - Shuffled around exception throwing for faster failure - Fix for MQE-1017 included, exceptions are now more verbose and precise as to when they are thrown. --- .../Exceptions/TestFrameworkException.php | 12 +++- .../Util/ModuleResolver.php | 60 +++++++++++-------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Exceptions/TestFrameworkException.php b/src/Magento/FunctionalTestingFramework/Exceptions/TestFrameworkException.php index 9374feebe..3820e25d9 100644 --- a/src/Magento/FunctionalTestingFramework/Exceptions/TestFrameworkException.php +++ b/src/Magento/FunctionalTestingFramework/Exceptions/TestFrameworkException.php @@ -6,6 +6,8 @@ namespace Magento\FunctionalTestingFramework\Exceptions; +use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; + /** * Class TestFrameworkException */ @@ -14,9 +16,17 @@ class TestFrameworkException extends \Exception /** * TestFrameworkException constructor. * @param string $message + * @param array $context + * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ - public function __construct($message) + public function __construct($message, $context = []) { + list($childClass, $callingClass) = debug_backtrace(false, 2); + LoggingUtil::getInstance()->getLogger($callingClass['class'])->error( + $message, + $context + ); + parent::__construct($message); } } diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index a32486aba..1b9f3ce2b 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\Util; use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; /** @@ -138,10 +139,6 @@ public function getEnabledModules() } $token = $this->getAdminToken(); - if (!$token || !is_string($token)) { - $this->enabledModules = []; - return $this->enabledModules; - } $url = ConfigSanitizerUtil::sanitizeUrl(getenv('MAGENTO_BASE_URL')) . $this->moduleUrl; @@ -157,10 +154,17 @@ public function getEnabledModules() $response = curl_exec($ch); if (!$response) { - $this->enabledModules = []; - } else { - $this->enabledModules = json_decode($response); + $message = "Could not retrieve Modules from Magento Instance."; + $context = [ + "Admin Module List Url" => $url, + "MAGENTO_ADMIN_USERNAME" => getenv("MAGENTO_ADMIN_USERNAME"), + "MAGENTO_ADMIN_PASSWORD" => getenv("MAGENTO_ADMIN_PASSWORD"), + ]; + throw new TestFrameworkException($message, $context); } + + $this->enabledModules = json_decode($response); + return $this->enabledModules; } @@ -190,25 +194,14 @@ public function getModulesPath() return $this->enabledModulePaths; } - $enabledModules = $this->getEnabledModules(); - if (empty($enabledModules) && !MftfApplicationConfig::getConfig()->forceGenerateEnabled()) { - $errorMsg = 'Could not retrieve enabled modules from provided MAGENTO_BASE_URL ' . - 'please make sure Magento is available at this url'; - LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->error( - $errorMsg, - ['MAGENTO_BASE_URL' => getenv('MAGENTO_BASE_URL')] - ); - trigger_error($errorMsg, E_USER_ERROR); - } - $allModulePaths = $this->aggregateTestModulePaths(); - if (empty($enabledModules)) { + if (MftfApplicationConfig::getConfig()->forceGenerateEnabled()) { $this->enabledModulePaths = $this->applyCustomModuleMethods($allModulePaths); return $this->enabledModulePaths; } - $enabledModules = array_merge($enabledModules, $this->getModuleWhitelist()); + $enabledModules = array_merge($this->getEnabledModules(), $this->getModuleWhitelist()); $enabledDirectoryPaths = $this->getEnabledDirectoryPaths($enabledModules, $allModulePaths); $this->enabledModulePaths = $this->applyCustomModuleMethods($enabledDirectoryPaths); @@ -325,9 +318,15 @@ private function getEnabledDirectoryPaths($enabledModules, $allModulePaths) { $enabledDirectoryPaths = []; foreach ($enabledModules as $magentoModuleName) { - $moduleShortName = explode('_', $magentoModuleName)[1]; + // Magento_Backend -> Backend or DevDocs -> DevDocs (if whitelisted has no underscore) + $moduleShortName = explode('_', $magentoModuleName)[1] ?? $magentoModuleName; if (!isset($this->knownDirectories[$moduleShortName]) && !isset($allModulePaths[$moduleShortName])) { continue; + } elseif (isset($this->knownDirectories[$moduleShortName]) && !isset($allModulePaths[$moduleShortName])) { + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warn( + "Known directory could not match to an existing path.", + ['knownDirectory' => $moduleShortName] + ); } else { $enabledDirectoryPaths[$moduleShortName] = $allModulePaths[$moduleShortName]; } @@ -342,7 +341,6 @@ private function getEnabledDirectoryPaths($enabledModules, $allModulePaths) */ private function printMagentoVersionInfo() { - if (MftfApplicationConfig::getConfig()->forceGenerateEnabled()) { return; } @@ -377,7 +375,13 @@ protected function getAdminToken() $login = $_ENV['MAGENTO_ADMIN_USERNAME'] ?? null; $password = $_ENV['MAGENTO_ADMIN_PASSWORD'] ?? null; if (!$login || !$password || !isset($_ENV['MAGENTO_BASE_URL'])) { - return false; + $message = "Cannot retrieve API token without credentials and base url, please fill out .env."; + $context = [ + "MAGENTO_BASE_URL" => getenv("MAGENTO_BASE_URL"), + "MAGENTO_ADMIN_USERNAME" => getenv("MAGENTO_ADMIN_USERNAME"), + "MAGENTO_ADMIN_PASSWORD" => getenv("MAGENTO_ADMIN_PASSWORD"), + ]; + throw new TestFrameworkException($message, $context); } $url = ConfigSanitizerUtil::sanitizeUrl($_ENV['MAGENTO_BASE_URL']) . $this->adminTokenUrl; @@ -398,9 +402,17 @@ protected function getAdminToken() curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($ch); + if (!$response) { - return $response; + $message = "Could not retrieve API token from Magento Instance."; + $context = [ + "Admin Integration Token Url" => $url, + "MAGENTO_ADMIN_USERNAME" => getenv("MAGENTO_ADMIN_USERNAME"), + "MAGENTO_ADMIN_PASSWORD" => getenv("MAGENTO_ADMIN_PASSWORD"), + ]; + throw new TestFrameworkException($message, $context); } + return json_decode($response); } From 3f1be46111eb02e85285d0eece84afb8b39faa35 Mon Sep 17 00:00:00 2001 From: KevinBKozan Date: Tue, 12 Jun 2018 10:34:42 -0500 Subject: [PATCH 2/3] MQE-1043: MFTF force flag should ignore the magento base url even when valid - CR fixes --- .../Util/ModuleResolverTest.php | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 85f09d325..18f4dbccb 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -9,6 +9,8 @@ use AspectMock\Proxy\Verifier; use AspectMock\Test as AspectMock; +use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\ObjectManager; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; @@ -166,15 +168,41 @@ function ($arg1, $arg2) { } /** - * Validate that getEnabledModules returns correctly with no admin token + * Validate that getEnabledModules errors out when no Admin Token is returned and --force is false * @throws \Exception */ public function testGetModulePathsNoAdminToken() { + // Set --force to false + $this->mockForceGenerate(false); + + // Mock ModuleResolver and $enabledModulesPath $this->setMockResolverClass(false, null, ["example" . DIRECTORY_SEPARATOR . "paths"], []); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, null); - $this->assertEquals(["example" . DIRECTORY_SEPARATOR . "paths"], $resolver->getModulesPath()); + + // Cannot Generate if no --force was passed in and no Admin Token is returned succesfully + $this->expectException(TestFrameworkException::class); + $resolver->getModulesPath(); + } + + /** + * Validates that getAdminToken is not called when --force is enabled + */ + public function testGetAdminTokenNotCalledWhenForce() + { + // Set --force to true + $this->mockForceGenerate(true); + + // Mock ModuleResolver and applyCustomModuleMethods() + $mockResolver = $this->setMockResolverClass(); + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, null); + $resolver->getModulesPath(); + $mockResolver->verifyNeverInvoked("getAdminToken"); + + // verifyNeverInvoked does not add to assertion count + $this->addToAssertionCount(1); } /** @@ -260,6 +288,25 @@ private function setMockResolverProperties($instance, $mockPaths = null, $mockMo $property->setValue($instance, $mockBlacklist); } + /** + * Mocks MftfApplicationConfig->forceGenerateEnabled() + * @param $forceGenerate + * @throws \Exception + * @return void + */ + private function mockForceGenerate($forceGenerate) + { + $mockConfig = AspectMock::double( + MftfApplicationConfig::class, + ['forceGenerateEnabled' => $forceGenerate] + ); + $instance = AspectMock::double( + ObjectManager::class, + ['create' => $mockConfig->make(), 'get' => null] + )->make(); + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + } + /** * After method functionality * @return void From 25a32bd3debedfa723704ffb4dbc908a6c17e08c Mon Sep 17 00:00:00 2001 From: KevinBKozan Date: Wed, 13 Jun 2018 08:27:26 -0500 Subject: [PATCH 3/3] MQE-1043: MFTF force flag should ignore the magento base url even when valid - Unit test updates to maintain coverage. --- .../Util/ModuleResolverTest.php | 58 ++++++++++++++++--- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 18f4dbccb..15aa4ad9d 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -56,9 +56,10 @@ public function testGetModulePathsAlreadySet() */ public function testGetModulePathsAggregate() { - $this->setMockResolverClass(false, null, null, null, ["example" . DIRECTORY_SEPARATOR . "paths"]); + $this->mockForceGenerate(false); + $this->setMockResolverClass(false, null, null, null, ["example" => "example" . DIRECTORY_SEPARATOR . "paths"]); $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null); + $this->setMockResolverProperties($resolver, null, [0 => "Magento_example"]); $this->assertEquals( [ "example" . DIRECTORY_SEPARATOR . "paths", @@ -75,12 +76,13 @@ public function testGetModulePathsAggregate() */ public function testGetModulePathsLocations() { + $this->mockForceGenerate(false); $mockResolver = $this->setMockResolverClass( - false, - null, + true, + [0 => "magento_example"], null, null, - ["example" . DIRECTORY_SEPARATOR . "paths"] + ["example" => "example" . DIRECTORY_SEPARATOR . "paths"] ); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, null); @@ -205,6 +207,43 @@ public function testGetAdminTokenNotCalledWhenForce() $this->addToAssertionCount(1); } + /** + * Verify the getAdminToken method returns throws an exception if ENV is not fully loaded. + */ + public function testGetAdminTokenWithMissingEnv() + { + // Set --force to true + $this->mockForceGenerate(false); + + // Unset env + unset($_ENV['MAGENTO_ADMIN_USERNAME']); + + // Mock ModuleResolver and applyCustomModuleMethods() + $mockResolver = $this->setMockResolverClass(); + $resolver = ModuleResolver::getInstance(); + + // Expect exception + $this->expectException(TestFrameworkException::class); + $resolver->getModulesPath(); + } + + /** + * Verify the getAdminToken method returns throws an exception if Token was bad. + */ + public function testGetAdminTokenWithBadResponse() + { + // Set --force to true + $this->mockForceGenerate(false); + + // Mock ModuleResolver and applyCustomModuleMethods() + $mockResolver = $this->setMockResolverClass(); + $resolver = ModuleResolver::getInstance(); + + // Expect exception + $this->expectException(TestFrameworkException::class); + $resolver->getModulesPath(); + } + /** * Function used to set mock for parser return and force init method to run between tests. * @@ -233,7 +272,7 @@ private function setMockResolverClass( if (isset($mockToken)) { $mockMethods['getAdminToken'] = $mockToken; } - if (isset($mockModules)) { + if (isset($mockGetModules)) { $mockMethods['getEnabledModules'] = $mockGetModules; } if (isset($mockCustomMethods)) { @@ -248,7 +287,7 @@ private function setMockResolverClass( if (isset($mockCustomModules)) { $mockMethods['getCustomModulePaths'] = $mockCustomModules; } - $mockMethods['printMagentoVersionInfo'] = null; +// $mockMethods['printMagentoVersionInfo'] = null; $mockResolver = AspectMock::double( ModuleResolver::class, @@ -313,6 +352,11 @@ private function mockForceGenerate($forceGenerate) */ protected function tearDown() { + // re set env + if (!isset($_ENV['MAGENTO_ADMIN_USERNAME'])) { + $_ENV['MAGENTO_ADMIN_USERNAME'] = "admin"; + } + AspectMock::clean(); } }