From 9891e5d25898e4c8fb93899c5fe45addfcf5f7e5 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 2 Oct 2019 11:42:51 -0500 Subject: [PATCH 1/4] MQE-1750: unit tests --- .../Composer/ComposerInstallTest.php | 66 +++ .../Composer/ComposerPackageTest.php | 172 +++++++ .../Composer/_files/dir1/dir2/composer.json | 21 + .../Composer/_files/dir1/dir2/composer.lock | 149 ++++++ .../_files/dir1/dir2/dir31/composer.json | 10 + .../dir1/dir2/dir31/dir41/composer.json | 11 + .../_files/dir1/dir2/dir32/composer.json | 11 + .../dir1/dir2/dir32/dir41/composer.json | 10 + .../dir1/dir2/dir32/dir42/composer.json | 10 + .../Util/ComposerModuleResolverTest.php | 162 +++++++ .../Util/ModuleResolverTest.php | 437 ++++++++++++++++-- .../Util/ComposerModuleResolver.php | 18 +- .../Util/ModuleResolver.php | 36 +- 13 files changed, 1055 insertions(+), 58 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/composer.json create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/composer.lock create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir31/composer.json create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir31/dir41/composer.json create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/composer.json create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/dir41/composer.json create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/dir42/composer.json create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Util/ComposerModuleResolverTest.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php new file mode 100644 index 000000000..4eb047457 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php @@ -0,0 +1,66 @@ +assertTrue(self::$composer->isMftfTestPackage('magento/module2-functional-test')); + } + + /** + * Test isMagentoPackage() + */ + public function testIsMagentoPackage() + { + $this->assertTrue(self::$composer->isMagentoPackage('magento/module-authorization')); + } + + /** + * Test isInstalledPackageOfType() + */ + public function testIsInstalledPackageOfType() + { + $this->assertTrue( + self::$composer->isInstalledPackageOfType('composer/composer', 'library') + ); + } + + /** + * Test getInstalledTestPackages() + */ + public function testGetInstalledTestPackages() + { + $output = self::$composer->getInstalledTestPackages(); + $this->assertCount(1, $output); + $this->assertArrayHasKey('magento/module2-functional-test', $output); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php new file mode 100644 index 000000000..04ace7b19 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php @@ -0,0 +1,172 @@ +assertEquals($expected, self::$composer->getName()); + } + + /** + * Test getType() + */ + public function testGetType() + { + $expected = 'magento2-functional-test-module'; + $this->assertEquals($expected, self::$composer->getType()); + } + + /** + * Test getVersion() + */ + public function testGetVersion() + { + $expected = '1.0.0'; + $this->assertEquals($expected, self::$composer->getVersion()); + } + + /** + * Test getDescription() + */ + public function testGetDescription() + { + $expected = 'MFTF tests for magento'; + $this->assertEquals($expected, self::$composer->getDescription()); + } + + /** + * Test getRequires() + */ + public function testGetRequires() + { + $expected = 'magento/magento2-functional-testing-framework'; + $output = self::$composer->getRequires(); + $this->assertCount(1, $output); + $this->assertArrayHasKey($expected, $output); + } + + /** + * Test getDevRequires() + */ + public function testGetDevRequires() + { + $expected = ['phpunit/phpunit']; + $this->assertEquals($expected, array_keys(self::$composer->getDevRequires())); + } + + /** + * Test getSuggests() + */ + public function testGetSuggests() + { + $expected = [ + 'magento/module-one', + 'magento/module-module-x', + 'magento/module-two', + 'magento/module-module-y', + 'magento/module-module-z', + 'magento/module-three', + 'magento/module-four' + ]; + $this->assertEquals($expected, array_keys(self::$composer->getSuggests())); + } + + /** + * Test getSuggestedMagentoModules() + */ + public function testGetSuggestedMagentoModules() + { + $expected = [ + 'Magento_ModuleX', + 'Magento_ModuleY', + 'Magento_ModuleZ' + ]; + $this->assertEquals($expected, self::$composer->getSuggestedMagentoModules()); + } + + /** + * Test isMftfTestPackage() + */ + public function testIsMftfTestPackage() + { + $this->assertTrue(self::$composer->isMftfTestPackage()); + } + + /** + * Test getRequiresForPackage() + */ + public function testGetRequiresForPackage() + { + $expected = [ + 'php', + 'ext-curl', + 'allure-framework/allure-codeception', + 'codeception/codeception', + 'consolidation/robo', + 'csharpru/vault-php', + 'csharpru/vault-php-guzzle6-transport', + 'flow/jsonpath', + 'fzaninotto/faker', + 'monolog/monolog', + 'mustache/mustache', + 'symfony/process', + 'vlucas/phpdotenv' + ]; + $this->assertEquals( + $expected, + array_keys(self::$composer->getRequiresForPackage('magento/magento2-functional-testing-framework', '2.5.0')) + ); + } + + /** + * Test isPackageRequiredInComposerJson() + */ + public function testIsPackageRequiredInComposerJson() + { + $this->assertTrue( + self::$composer->isPackageRequiredInComposerJson('magento/magento2-functional-testing-framework') + ); + } + + /** + * Test getRootPackage() + */ + public function testGetRootPackage() + { + $this->assertInstanceOf( + RootPackage::class, + self::$composer->getRootPackage() + ); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/composer.json b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/composer.json new file mode 100644 index 000000000..c21401af7 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/composer.json @@ -0,0 +1,21 @@ +{ + "name": "magento/module2-functional-test", + "type": "magento2-functional-test-module", + "description": "MFTF tests for magento", + "version": "1.0.0", + "require": { + "magento/magento2-functional-testing-framework": "^2.5.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.5.0 || ~7.0.0" + }, + "suggest": { + "magento/module-one": "name: Magento_ModuleY, version: ~100.0.0", + "magento/module-module-x": " type: magento2-module ,name: Magento_ModuleX, version: ~100.0.0", + "magento/module-two": "*", + "magento/module-module-y": "type: magento2-module, name:Magento_ModuleY,version:~100.0.0", + "magento/module-module-z": " type:magento2-module, name: Magento_ModuleZ , version: ~100.0.0", + "magento/module-three": "type: magento2-module, ~100.0.0", + "magento/module-four": "some suggestions" + } +} \ No newline at end of file diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/composer.lock b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/composer.lock new file mode 100644 index 000000000..4493b5615 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/composer.lock @@ -0,0 +1,149 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "f40a2fa7e19322bd961f212ad270b0d7", + "packages": [ + { + "name": "magento/module-authorization", + "version": "100.3.2", + "dist": { + "type": "zip", + "url": "https://repo.magento.com/archives/magento/module-authorization/magento-module-authorization-100.3.2.0.zip", + "shasum": "c17ed45c3bffca3bf704d2f4031069ed36b70273" + }, + "require": { + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "php": "~7.1.3||~7.2.0" + }, + "type": "magento2-module", + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\Authorization\\": "" + } + }, + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "description": "Authorization module provides access to Magento ACL functionality." + }, + { + "name": "composer/composer", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/composer/composer.git", + "reference": "314aa57fdcfc942065996f59fb73a8b3f74f3fa5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/composer/zipball/314aa57fdcfc942065996f59fb73a8b3f74f3fa5", + "reference": "314aa57fdcfc942065996f59fb73a8b3f74f3fa5", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", + "composer/semver": "^1.0", + "composer/spdx-licenses": "^1.2", + "composer/xdebug-handler": "^1.1", + "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0", + "php": "^5.3.2 || ^7.0", + "psr/log": "^1.0", + "seld/jsonlint": "^1.4", + "seld/phar-utils": "^1.0", + "symfony/console": "^2.7 || ^3.0 || ^4.0", + "symfony/filesystem": "^2.7 || ^3.0 || ^4.0", + "symfony/finder": "^2.7 || ^3.0 || ^4.0", + "symfony/process": "^2.7 || ^3.0 || ^4.0" + }, + "conflict": { + "symfony/console": "2.8.38" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7", + "phpunit/phpunit-mock-objects": "^2.3 || ^3.0" + }, + "suggest": { + "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", + "ext-zip": "Enabling the zip extension allows you to unzip archives", + "ext-zlib": "Allow gzip compression of HTTP requests" + }, + "bin": [ + "bin/composer" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\": "src/Composer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", + "homepage": "https://getcomposer.org/", + "keywords": [ + "autoload", + "dependency", + "package" + ], + "time": "2019-08-02T18:55:33+00:00" + }, + { + "name": "magento/module2-functional-test", + "require": { + "composer/composer": "*" + }, + "type": "magento2-functional-test-module", + "version": "1.0.0", + "suggest": { + "magento/module-one": "name: Magento_ModuleY, version: ~100.0.0", + "magento/module-module-x": " type: magento2-module ,name: Magento_ModuleX, version: ~100.0.0", + "magento/module-two": "*", + "magento/module-module-y": "type: magento2-module, name:Magento_ModuleY,version:~100.0.0", + "magento/module-module-z": " type:magento2-module, name: Magento_ModuleZ , version: ~100.0.0", + "magento/module-three": "type: magento2-module, ~100.0.0", + "magento/module-four": "some suggestions" + }, + "description": "magento module2-functional-test", + "keywords": [ + "mftf", + "test" + ], + "time": "2019-03-19T17:25:45+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir31/composer.json b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir31/composer.json new file mode 100644 index 000000000..49e952ee9 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir31/composer.json @@ -0,0 +1,10 @@ +{ + "name": "magento/module-31-functional-test", + "type": "magento2-functional-test-module", + "require": { + "magento/magento2-functional-testing-framework": "*" + }, + "suggest": { + "magento/module-module-a": "type: magento2-module, name: Magento_ModuleA, version: ~100.0.0" + } +} \ No newline at end of file diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir31/dir41/composer.json b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir31/dir41/composer.json new file mode 100644 index 000000000..97737fca6 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir31/dir41/composer.json @@ -0,0 +1,11 @@ +{ + "name": "magento/module-3141-functional-test", + "type": "magento2-functional-test-module", + "require": { + "magento/magento2-functional-testing-framework": "*" + }, + "suggest": { + "magento/module-module-e": "type: magento2-module, name: Magento_ModuleE, version: ~100.0.0", + "magento/module-module-f": "type: magento2-module, name: Magento_ModuleF, version: ~100.0.0" + } +} \ No newline at end of file diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/composer.json b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/composer.json new file mode 100644 index 000000000..dffbb3bee --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/composer.json @@ -0,0 +1,11 @@ +{ + "name": "magento/module-32-functional-test", + "type": "magento2-functional-test-module", + "require": { + "magento/magento2-functional-testing-framework": "*" + }, + "suggest": { + "magento/module-module-b": "type: magento2-module, name: Magento_ModuleB, version: ~100.0.0", + "magento/module-module-c": "type: magento2-module, name: Magento_ModuleC, version: ~100.0.0" + } +} \ No newline at end of file diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/dir41/composer.json b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/dir41/composer.json new file mode 100644 index 000000000..f766c226c --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/dir41/composer.json @@ -0,0 +1,10 @@ +{ + "name": "magento/module-3241-functional-test", + "type": "magento2-functional-test-module", + "require": { + "magento/magento2-functional-testing-framework": "*" + }, + "suggest": { + "magento/module-module-g": "type: magento2-module, name: Magento_ModuleG, version: ~100.0.0" + } +} \ No newline at end of file diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/dir42/composer.json b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/dir42/composer.json new file mode 100644 index 000000000..e51f36515 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/_files/dir1/dir2/dir32/dir42/composer.json @@ -0,0 +1,10 @@ +{ + "name": "magento/module-3242-functional-test", + "type": "magento2-functional-test-module", + "require": { + "magento/magento2-functional-testing-framework": "*" + }, + "suggest": { + "magento/module-module-h": "type: magento2-module, name: Magento_ModuleH, version: ~100.0.0" + } +} \ No newline at end of file diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ComposerModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ComposerModuleResolverTest.php new file mode 100644 index 000000000..3173730b3 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ComposerModuleResolverTest.php @@ -0,0 +1,162 @@ +getComposerInstalledTestModules($composerJson); + $this->assertCount(1, $output); + $this->assertEquals($expected, array_pop($output)); + } + + /** + * Test getTestModulesFromPaths() + */ + public function testGetTestModulesFromPaths() + { + $baseDir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Composer' . DIRECTORY_SEPARATOR . '_files' + . DIRECTORY_SEPARATOR . 'dir1' . DIRECTORY_SEPARATOR . 'dir2'; + $expected = [ + $baseDir . DIRECTORY_SEPARATOR . 'dir31' . DIRECTORY_SEPARATOR . 'dir41' => [ + 'Magento_ModuleE', + 'Magento_ModuleF' + ], + $baseDir . DIRECTORY_SEPARATOR . 'dir32' . DIRECTORY_SEPARATOR . 'dir41' => [ + 'Magento_ModuleG' + ], + $baseDir . DIRECTORY_SEPARATOR . 'dir32' . DIRECTORY_SEPARATOR . 'dir42' => [ + 'Magento_ModuleH' + ], + ]; + + $composer = new ComposerModuleResolver(); + $output = $composer->getTestModulesFromPaths([$baseDir]); + $this->assertEquals($expected, $output); + } + + /** + * Test findComposerJsonFilesAtDepth() + * + * @dataProvider findComposerJsonFilesAtDepthDataProvider + * @param string $dir + * @param integer $depth + * @param array $expected + * @throws \ReflectionException + */ + public function testFindComposerJsonFilesAtDepth($dir, $depth, $expected) + { + $composer = new ComposerModuleResolver(); + $class = new ReflectionClass($composer); + $method = $class->getMethod('findComposerJsonFilesAtDepth'); + $method->setAccessible(true); + $output = $method->invoke($composer, $dir, $depth); + $this->assertEquals($expected, $output); + } + + /** + * Test findAllComposerJsonFiles() + * + * @dataProvider findAllComposerJsonFilesDataProvider + * @param string $dir + * @param array $expected + * @throws \ReflectionException + */ + public function testFindAllComposerJsonFiles($dir, $expected) + { + $composer = new ComposerModuleResolver(); + $class = new ReflectionClass($composer); + $method = $class->getMethod('findAllComposerJsonFiles'); + $method->setAccessible(true); + $output = $method->invoke($composer, $dir); + $this->assertEquals($expected, $output); + } + + /** + * Data provider for testFindComposerJsonFilesAtDepth() + * + * @return array + */ + public function findComposerJsonFilesAtDepthDataProvider() + { + $baseDir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Composer' . DIRECTORY_SEPARATOR . '_files' + . DIRECTORY_SEPARATOR . 'dir1' . DIRECTORY_SEPARATOR . 'dir2'; + return [ + [ + $baseDir, + 0, + [ + $baseDir . DIRECTORY_SEPARATOR . 'composer.json' + ] + ], + [ + $baseDir, + 1, + [ + $baseDir . DIRECTORY_SEPARATOR . 'dir31' . DIRECTORY_SEPARATOR . 'composer.json', + $baseDir . DIRECTORY_SEPARATOR . 'dir32' . DIRECTORY_SEPARATOR . 'composer.json', + ] + ], + [ + $baseDir, + 2, + [ + $baseDir . DIRECTORY_SEPARATOR . 'dir31' . DIRECTORY_SEPARATOR . 'dir41' . DIRECTORY_SEPARATOR + . 'composer.json', + $baseDir . DIRECTORY_SEPARATOR . 'dir32' . DIRECTORY_SEPARATOR . 'dir41' . DIRECTORY_SEPARATOR + . 'composer.json', + $baseDir . DIRECTORY_SEPARATOR . 'dir32' . DIRECTORY_SEPARATOR . 'dir42' . DIRECTORY_SEPARATOR + . 'composer.json', + ] + ] + ]; + } + + /** + * Data provider for testFindAllComposerJsonFiles() + * + * @return array + */ + public function findAllComposerJsonFilesDataProvider() + { + $baseDir = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Composer' . DIRECTORY_SEPARATOR . '_files' + . DIRECTORY_SEPARATOR . 'dir1' . DIRECTORY_SEPARATOR . 'dir2'; + return [ + [ + $baseDir, + [ + $baseDir . DIRECTORY_SEPARATOR . 'dir31' . DIRECTORY_SEPARATOR . 'dir41' . DIRECTORY_SEPARATOR + . 'composer.json', + $baseDir . DIRECTORY_SEPARATOR . 'dir31' . DIRECTORY_SEPARATOR . 'composer.json', + $baseDir . DIRECTORY_SEPARATOR . 'dir32' . DIRECTORY_SEPARATOR . 'dir41' . DIRECTORY_SEPARATOR + . 'composer.json', + $baseDir . DIRECTORY_SEPARATOR . 'dir32' . DIRECTORY_SEPARATOR . 'dir42' . DIRECTORY_SEPARATOR + . 'composer.json', + $baseDir . DIRECTORY_SEPARATOR . 'dir32' . DIRECTORY_SEPARATOR . 'composer.json', + $baseDir . DIRECTORY_SEPARATOR . 'composer.json', + ] + ] + ]; + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index 1d4b77740..e9fb46488 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -16,6 +16,7 @@ use Magento\FunctionalTestingFramework\Util\Logger\LoggingUtil; use Magento\FunctionalTestingFramework\Util\ModuleResolver; use Magento\FunctionalTestingFramework\Util\MagentoTestCase; +use PHPUnit\Runner\Exception; use tests\unit\Util\TestLoggingUtil; class ModuleResolverTest extends MagentoTestCase @@ -71,7 +72,11 @@ public function testGetModulePathsAggregate() [ 'Magento_example' => 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', 'Magento_sample' => 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample', - ] + ], + null, + null, + [], + [] ); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, [0 => 'Magento_example', 1 => 'Magento_sample']); @@ -104,8 +109,8 @@ public function testGetModulePathsLocations() [], [], [], - [], - [], + null, + null, [], [], null, @@ -157,11 +162,326 @@ function ($arg) { ); } + /** + * Validate aggregateTestModulePathsFromComposerJson + * + * @throws \Exception + */ + public function testAggregateTestModulePathsFromComposerJson() + { + $this->mockForceGenerate(false); + $this->setMockResolverClass( + false, + null, // getEnabledModules + null, // applyCustomMethods + null, // globRelevantWrapper + [], // relevantPath + null, // getCustomModulePaths + null, // getRegisteredModuleList + null, // aggregateTestModulePathsFromComposerJson + [], // aggregateTestModulePathsFromComposerInstaller + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA', + 'Magento_ModuleB' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleB', + 'Magento_ModuleC' + ], + ], // getComposerJsonTestModulePaths + [] // getComposerInstalledTestModulePaths + ); + + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, [0 => 'Magento_ModuleB', 1 => 'Magento_ModuleC']); + $this->assertEquals( + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' + ], + $resolver->getModulesPath() + ); + } + + /** + * Validate getComposerJsonTestModulePaths with paths invocation + * + * @throws \Exception + */ + public function testGetComposerJsonTestModulePathsForPathInvocation() + { + $this->mockForceGenerate(false); + $mockResolver = $this->setMockResolverClass( + false, + [], + null, + null, + [], + null, + null, + null, + null, + [], + [] + ); + + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, null); + $this->assertEquals( + [], + $resolver->getModulesPath() + ); + + // Expected dev tests path + $expectedSearchPaths[] = MAGENTO_BP + . DIRECTORY_SEPARATOR + . 'dev' + . DIRECTORY_SEPARATOR + . 'tests' + . DIRECTORY_SEPARATOR + . 'acceptance' + . DIRECTORY_SEPARATOR + . 'tests' + . DIRECTORY_SEPARATOR + . 'functional'; + + // Expected test module path + $testModulePath = defined('TESTS_MODULE_PATH') ? TESTS_MODULE_PATH : TESTS_BP; + + if (array_search($testModulePath, $expectedSearchPaths) === false) { + $expectedSearchPaths[] = $testModulePath; + } + + $mockResolver->verifyInvoked('getComposerJsonTestModulePaths', [$expectedSearchPaths]); + } + + /** + * Validate aggregateTestModulePathsFromComposerInstaller + * + * @throws \Exception + */ + public function testAggregateTestModulePathsFromComposerInstaller() + { + $this->mockForceGenerate(false); + $this->setMockResolverClass( + false, + null, + null, + null, + [], + null, + null, + null, + null, + [], + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA', + 'Magento_ModuleB' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleB', + 'Magento_ModuleC' + ], + ] + ); + + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties( + $resolver, + null, + [0 => 'Magento_ModuleA', 1 => 'Magento_ModuleB', 2 => 'Magento_ModuleC'] + ); + $this->assertEquals( + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA', + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' + ], + $resolver->getModulesPath() + ); + } + + /** + * Validate getComposerInstalledTestModulePaths with paths invocation + * + * @throws \Exception + */ + public function testGetComposerInstalledTestModulePathsForPathInvocation() + { + $this->mockForceGenerate(false); + $mockResolver = $this->setMockResolverClass( + false, + [], + null, + null, + [], + null, + null, + null, + null, + [], + [] + ); + + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties($resolver, null, null); + $this->assertEquals( + [], + $resolver->getModulesPath() + ); + + // Expected file path + $expectedSearchPath = MAGENTO_BP . DIRECTORY_SEPARATOR . 'composer.json'; + + $mockResolver->verifyInvoked('getComposerInstalledTestModulePaths', [$expectedSearchPath]); + } + + /** + * Validate mergeModulePaths() and flipAndFilterModulePathsArray() + * + * @throws \Exception + */ + public function testMergeFlipAndFilterModulePaths() + { + $this->mockForceGenerate(false); + $this->setMockResolverClass( + false, + null, + null, + null, + null, + null, + null, + null, + null, + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleB', + 'Magento_ModuleC', + ], + ], + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleC', + 'Magento_ModuleD' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleD' + ], + ], + [ + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_example'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_sample'], + ] + ); + + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties( + $resolver, + null, + [ + 0 => 'Magento_ModuleB', + 1 => 'Magento_ModuleC', + 2 => 'Magento_ModuleD', + 3 => 'Magento_example', + 4 => 'Magento_otherexample' + ] + ); + $this->assertEquals( + [ + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB', + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA', + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' + ], + $resolver->getModulesPath() + ); + } + + /** + * Validate logging warning in flipAndFilterModulePathsArray() + * + * @throws \Exception + */ + public function testMergeFlipAndFilterModulePathsWithLogging() + { + $this->mockForceGenerate(false); + $this->setMockResolverClass( + false, + null, + null, + null, + [], + null, + null, + null, + null, + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleB' + ], + ], + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleC' + ], + ] + ); + + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties( + $resolver, + null, + [ + 0 => 'Magento_ModuleA', + 1 => 'Magento_ModuleB', + 2 => 'Magento_ModuleC' + ] + ); + $this->assertEquals( + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA', + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB', + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' + ], + $resolver->getModulesPath() + ); + $warnMsg = 'Path: composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR; + $warnMsg .= 'pathA is ignored by ModuleResolver. ' . PHP_EOL . 'Path: composer' . DIRECTORY_SEPARATOR; + $warnMsg .= 'json' . DIRECTORY_SEPARATOR . 'pathA is set for Module: Magento_ModuleA' . PHP_EOL; + TestLoggingUtil::getInstance()->validateMockLogStatement( + 'warning', + $warnMsg, + [] + ); + } + /** * Validate custom modules are added * @throws \Exception */ - public function testGetCustomModulePath() + public function testApplyCustomModuleMethods() { $this->setMockResolverClass( false, @@ -169,7 +489,12 @@ public function testGetCustomModulePath() null, null, [], - ['Magento_Module' => 'otherPath'] + [ 'Magento_Module' => 'otherPath'], + null, + null, + null, + [], + [] ); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, null, null); @@ -177,7 +502,7 @@ public function testGetCustomModulePath() TestLoggingUtil::getInstance()->validateMockLogStatement( 'info', 'including custom module', - ['Magento_Module' => 'otherPath'] + [ 'Magento_Module' => 'otherPath'] ); } @@ -193,17 +518,17 @@ public function testGetModulePathsBlacklist() null, null, [], - [], - [], - [], - [], + null, + null, + null, + null, [], [], [ - "vendor" => "vendor", - "appCode" => "appCode", - "devTests" => "devTests", - "thisPath" => "thisPath" + 'vendor' => ['vendor'], + 'appCode' => ['appCode'], + 'devTests' => ['devTests'], + 'thisPath' => ['thisPath'] ], function ($arg) { return $arg; @@ -213,9 +538,9 @@ function ($arg) { } ); $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null, ["devTests" => "devTests"]); + $this->setMockResolverProperties($resolver, null, null, ['devTests']); $this->assertEquals( - ["vendor", "appCode", "thisPath"], + ['vendor', 'appCode', 'thisPath'], $resolver->getModulesPath() ); TestLoggingUtil::getInstance()->validateMockLogStatement( @@ -235,7 +560,19 @@ public function testGetModulePathsNoAdminToken() $this->mockForceGenerate(false); // Mock ModuleResolver and $enabledModulesPath - $this->setMockResolverClass(false, null, ["example" . DIRECTORY_SEPARATOR . "paths"], []); + $this->setMockResolverClass( + false, + null, + ["example" . DIRECTORY_SEPARATOR . "paths"], + [], + null, + null, + null, + null, + null, + [], + [] + ); $resolver = ModuleResolver::getInstance(); $this->setMockResolverProperties($resolver, null, null); @@ -304,11 +641,11 @@ public function testGetAdminTokenWithBadResponse() * Function used to set mock for parser return and force init method to run between tests. * * @param string $mockToken - * @param array $mockGetModules - * @param string[] $mockCustomMethods - * @param string[] $mockGlob - * @param string[] $mockRelativePaths - * @param string[] $mockCustomModules + * @param array $mockGetEnabledModules + * @param string[] $mockApplyCustomMethods + * @param string[] $mockGlobRelevantWrapper + * @param string[] $mockRelevantPaths + * @param string[] $mockGetCustomModulePaths * @param string[] $mockGetRegisteredModuleList * @param string[] $mockAggregateTestModulePathsFromComposerJson * @param string[] $mockAggregateTestModulePathsFromComposerInstaller @@ -322,16 +659,16 @@ public function testGetAdminTokenWithBadResponse() */ private function setMockResolverClass( $mockToken = null, - $mockGetModules = null, - $mockCustomMethods = null, - $mockGlob = null, - $mockRelativePaths = null, - $mockCustomModules = null, + $mockGetEnabledModules = null, + $mockApplyCustomMethods = null, + $mockGlobRelevantWrapper = null, + $mockRelevantPaths = null, + $mockGetCustomModulePaths = null, $mockGetRegisteredModuleList = null, - $mockAggregateTestModulePathsFromComposerJson = [], - $mockAggregateTestModulePathsFromComposerInstaller = [], - $mockGetComposerJsonTestModulePaths = [], - $mockGetComposerInstalledTestModulePaths = [], + $mockAggregateTestModulePathsFromComposerJson = null, + $mockAggregateTestModulePathsFromComposerInstaller = null, + $mockGetComposerJsonTestModulePaths = null, + $mockGetComposerInstalledTestModulePaths = null, $mockAggregateTestModulePaths = null, $mockNormalizeModuleNames = null, $mockFlipAndFilterModulePathsArray = null @@ -344,29 +681,37 @@ private function setMockResolverClass( if (isset($mockToken)) { $mockMethods['getAdminToken'] = $mockToken; } - if (isset($mockGetModules)) { - $mockMethods['getEnabledModules'] = $mockGetModules; + if (isset($mockGetEnabledModules)) { + $mockMethods['getEnabledModules'] = $mockGetEnabledModules; } - if (isset($mockCustomMethods)) { - $mockMethods['applyCustomModuleMethods'] = $mockCustomMethods; + if (isset($mockApplyCustomMethods)) { + $mockMethods['applyCustomModuleMethods'] = $mockApplyCustomMethods; } - if (isset($mockGlob)) { - $mockMethods['globRelevantWrapper'] = $mockGlob; + if (isset($mockGlobRelevantWrapper)) { + $mockMethods['globRelevantWrapper'] = $mockGlobRelevantWrapper; } - if (isset($mockRelativePaths)) { - $mockMethods['globRelevantPaths'] = $mockRelativePaths; + if (isset($mockRelevantPaths)) { + $mockMethods['globRelevantPaths'] = $mockRelevantPaths; } - if (isset($mockCustomModules)) { - $mockMethods['getCustomModulePaths'] = $mockCustomModules; + if (isset($mockGetCustomModulePaths)) { + $mockMethods['getCustomModulePaths'] = $mockGetCustomModulePaths; } if (isset($mockGetRegisteredModuleList)) { $mockMethods['getRegisteredModuleList'] = $mockGetRegisteredModuleList; } - $mockMethods['aggregateTestModulePathsFromComposerJson'] = $mockAggregateTestModulePathsFromComposerJson ?? []; - $mockMethods['aggregateTestModulePathsFromComposerInstaller'] = - $mockAggregateTestModulePathsFromComposerInstaller ?? []; - $mockMethods['getComposerJsonTestModulePaths'] = $mockGetComposerJsonTestModulePaths ?? []; - $mockMethods['getComposerInstalledTestModulePaths'] = $mockGetComposerInstalledTestModulePaths ?? []; + if (isset($mockAggregateTestModulePathsFromComposerJson)) { + $mockMethods['aggregateTestModulePathsFromComposerJson'] = $mockAggregateTestModulePathsFromComposerJson; + } + if (isset($mockAggregateTestModulePathsFromComposerInstaller)) { + $mockMethods['aggregateTestModulePathsFromComposerInstaller'] = + $mockAggregateTestModulePathsFromComposerInstaller; + } + if (isset($mockGetComposerJsonTestModulePaths)) { + $mockMethods['getComposerJsonTestModulePaths'] = $mockGetComposerJsonTestModulePaths; + } + if (isset($mockGetComposerInstalledTestModulePaths)) { + $mockMethods['getComposerInstalledTestModulePaths'] = $mockGetComposerInstalledTestModulePaths; + } if (isset($mockAggregateTestModulePaths)) { $mockMethods['aggregateTestModulePaths'] = $mockAggregateTestModulePaths; } diff --git a/src/Magento/FunctionalTestingFramework/Util/ComposerModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ComposerModuleResolver.php index 5152989e7..210c10fdd 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ComposerModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ComposerModuleResolver.php @@ -135,16 +135,16 @@ private function findAllComposerJsonFiles($directory) $jsonPattern = DIRECTORY_SEPARATOR . "composer.json"; $subDirectoryPattern = DIRECTORY_SEPARATOR . "*"; - $jsonFileList = glob($directory . $jsonPattern); - if ($jsonFileList !== false && !empty($jsonFileList)) { - return $jsonFileList; - } else { - $jsonFileList = []; - foreach (glob($directory . $subDirectoryPattern, GLOB_ONLYDIR) as $dir) { - $jsonFileList = array_merge_recursive($jsonFileList, self::findAllComposerJsonFiles($dir)); - } - return $jsonFileList; + $jsonFileList = []; + foreach (glob($directory . $subDirectoryPattern, GLOB_ONLYDIR) as $dir) { + $jsonFileList = array_merge_recursive($jsonFileList, self::findAllComposerJsonFiles($dir)); } + + $curJsonFiles = glob($directory . $jsonPattern); + if ($curJsonFiles !== false && !empty($curJsonFiles)) { + $jsonFileList = array_merge_recursive($jsonFileList, $curJsonFiles); + } + return $jsonFileList; } /** diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index c27496dd5..2bf93242a 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -511,12 +511,16 @@ private function flipAndFilterModulePathsArray($objectArray, $filterArray = null if (strpos($modules[0], '_') === false) { $modules[0] = $this->findVendorNameFromPath($path) . '_' . $modules[0]; } - $flippedArray[$modules[0]] = $path; + $flippedArray = $this->setArrayValueWithLogging($flippedArray, $modules[0], $path); } } else { // One path maps to multiple modules if (!is_array($filterArray)) { - $flippedArray[$this->findVendorAndModuleNameFromPath($path)] = $path; + $flippedArray = $this->setArrayValueWithLogging( + $flippedArray, + $this->findVendorAndModuleNameFromPath($path), + $path + ); } else { $skip = false; foreach ($modules as $module) { @@ -526,7 +530,11 @@ private function flipAndFilterModulePathsArray($objectArray, $filterArray = null } } if (!$skip) { - $flippedArray[$this->findVendorAndModuleNameFromPath($path)] = $path; + // The one path to many module names use case is designed to be strictly used when it's + // impossible to write tests in dedicated modules. Due to performance consideration and there + // is no real usage of this currently, we will use the first module name for the path. + // TODO: consider saving all module names if this information is needed in the future. + $flippedArray = $this->setArrayValueWithLogging($flippedArray, $modules[0], $path); } } } @@ -534,6 +542,28 @@ private function flipAndFilterModulePathsArray($objectArray, $filterArray = null return $flippedArray; } + /** + * Set array value at index only if array value at index is not yet set, skip otherwise and log warning message + * + * @param array $inArray + * @param string $index + * @param string $value + * + * @return array + */ + private function setArrayValueWithLogging($inArray, $index, $value) + { + $outArray = $inArray; + if (!isset($inArray[$index])) { + $outArray[$index] = $value; + } else { + $warnMsg = 'Path: ' . $value . ' is ignored by ModuleResolver. ' . PHP_EOL . 'Path: '; + $warnMsg .= $inArray[$index] . ' is set for Module: ' . $index . PHP_EOL; + LoggingUtil::getInstance()->getLogger(ModuleResolver::class)->warn($warnMsg); + } + return $outArray; + } + /** * Merge code paths * From 7c3bd33569ea32f0f8cbda002c8eef144664dd2d Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 8 Oct 2019 13:57:54 -0500 Subject: [PATCH 2/4] MQE-1750: unit tests and some code refactor. --- .../Util/ModuleResolverTest.php | 121 +++++++++++++++--- .../Util/ModuleResolver.php | 104 ++++++++++----- 2 files changed, 177 insertions(+), 48 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index e9fb46488..b7c154e34 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -345,9 +345,92 @@ public function testGetComposerInstalledTestModulePathsForPathInvocation() * * @throws \Exception */ - public function testMergeFlipAndFilterModulePaths() + public function testMergeFlipAndFilterModulePathsNoForceGenerate() { $this->mockForceGenerate(false); + $this->setMockResolverClass( + false, + null, + null, + null, + null, + null, + null, + null, + null, + [ + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA' => + [ + 'Magento_ModuleA' + ], + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB' => + [ + 'Magento_ModuleB' + ], + ], + [ + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathD' => + [ + 'Magento_ModuleD' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathE' => + [ + 'Magento_ModuleE' + ], + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathC' => + [ + 'Magento_ModuleC', + 'Magento_ModuleB', + ], + ], + [ + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_Example'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_Sample'], + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path1' => ['Magento_Path1'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path2' => ['Magento_Path2'], + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path3' => ['Magento_Path3'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path4' => ['Magento_Path4'], + ] + ); + + $resolver = ModuleResolver::getInstance(); + $this->setMockResolverProperties( + $resolver, + null, + [ + 0 => 'Magento_Path1', + 1 => 'Magento_Path2', + 2 => 'Magento_Path4', + 3 => 'Magento_Example', + 4 => 'Magento_ModuleB', + 5 => 'Magento_ModuleD', + 6 => 'Magento_Otherexample', + 7 => 'Magento_ModuleC', + ] + ); + $this->assertEquals( + [ + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path1', + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path2', + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'path4', + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB', + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathD', + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathC', + + ], + $resolver->getModulesPath() + ); + } + + /** + * Validate mergeModulePaths() and flipAndFilterModulePathsArray() + * + * @throws \Exception + */ + public function testMergeFlipAndFilterModulePathsForceGenerate() + { + $this->mockForceGenerate(true); $this->setMockResolverClass( false, null, @@ -381,8 +464,8 @@ public function testMergeFlipAndFilterModulePaths() ], ], [ - 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_example'], - 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_sample'], + 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example' => ['Magento_Example'], + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' => ['Magento_Sample'], ] ); @@ -394,16 +477,18 @@ public function testMergeFlipAndFilterModulePaths() 0 => 'Magento_ModuleB', 1 => 'Magento_ModuleC', 2 => 'Magento_ModuleD', - 3 => 'Magento_example', - 4 => 'Magento_otherexample' + 3 => 'Magento_Example', + 4 => 'Magento_Otherexample' ] ); $this->assertEquals( [ 'some' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'example', + 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathA', 'composer' . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'pathB', 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathA', - 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB' + 'composer' . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'pathB', + 'other' . DIRECTORY_SEPARATOR . 'path' . DIRECTORY_SEPARATOR . 'sample' ], $resolver->getModulesPath() ); @@ -508,6 +593,8 @@ public function testApplyCustomModuleMethods() /** * Validate blacklisted modules are removed + * Module paths are sorted according to module name in alphabetically ascending order + * * @throws \Exception */ public function testGetModulePathsBlacklist() @@ -525,10 +612,10 @@ public function testGetModulePathsBlacklist() [], [], [ - 'vendor' => ['vendor'], - 'appCode' => ['appCode'], - 'devTests' => ['devTests'], - 'thisPath' => ['thisPath'] + 'thisPath/some/path4' => ['Some_Module4'], + 'devTests/Magento/path3' => ['Magento_Module3'], + 'appCode/Magento/path2' => ['Magento_Module2'], + 'vendor/amazon/path1' => ['Amazon_Module1'], ], function ($arg) { return $arg; @@ -538,15 +625,15 @@ function ($arg) { } ); $resolver = ModuleResolver::getInstance(); - $this->setMockResolverProperties($resolver, null, null, ['devTests']); + $this->setMockResolverProperties($resolver, null, null, ['Magento_Module3']); $this->assertEquals( - ['vendor', 'appCode', 'thisPath'], + ['vendor/amazon/path1', 'appCode/Magento/path2', 'thisPath/some/path4'], $resolver->getModulesPath() ); TestLoggingUtil::getInstance()->validateMockLogStatement( 'info', 'excluding module', - ['module' => 'devTests'] + ['module' => 'Magento_Module3'] ); } @@ -654,6 +741,7 @@ public function testGetAdminTokenWithBadResponse() * @param string[] $mockAggregateTestModulePaths * @param string[] $mockNormalizeModuleNames * @param string[] $mockFlipAndFilterModulePathsArray + * @param string[] $mockFlipAndSortModulePathsArray * @throws \Exception * @return Verifier ModuleResolver double */ @@ -671,7 +759,8 @@ private function setMockResolverClass( $mockGetComposerInstalledTestModulePaths = null, $mockAggregateTestModulePaths = null, $mockNormalizeModuleNames = null, - $mockFlipAndFilterModulePathsArray = null + $mockFlipAndFilterModulePathsArray = null, + $mockFlipAndSortModulePathsArray = null ) { $property = new \ReflectionProperty(ModuleResolver::class, 'instance'); $property->setAccessible(true); @@ -721,7 +810,9 @@ private function setMockResolverClass( if (isset($mockFlipAndFilterModulePathsArray)) { $mockMethods['flipAndFilterModulePathsArray'] = $mockFlipAndFilterModulePathsArray; } - + if (isset($mockFlipAndSortModulePathsArray)) { + $mockMethods['flipAndSortModulePathsArray'] = $mockFlipAndSortModulePathsArray; + } $mockResolver = AspectMock::double( ModuleResolver::class, $mockMethods diff --git a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php index 2bf93242a..447516075 100644 --- a/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php +++ b/src/Magento/FunctionalTestingFramework/Util/ModuleResolver.php @@ -16,6 +16,7 @@ * * @api * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ class ModuleResolver { @@ -263,7 +264,7 @@ public function getModulesPath($verbosePath = false) $allModulePaths = $this->normalizeModuleNames($allModulePaths); if (MftfApplicationConfig::getConfig()->forceGenerateEnabled()) { - $allModulePaths = $this->flipAndFilterModulePathsArray($allModulePaths); + $allModulePaths = $this->flipAndSortModulePathsArray($allModulePaths, true); $this->enabledModulePaths = $this->applyCustomModuleMethods($allModulePaths); return $this->enabledModulePaths; } @@ -497,48 +498,85 @@ private function getComposerInstalledTestModulePaths($composerFile) * @param array $objectArray * @param array $filterArray * @return array - * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - private function flipAndFilterModulePathsArray($objectArray, $filterArray = null) + private function flipAndFilterModulePathsArray($objectArray, $filterArray) { + $oneToOneArray = []; + $oneToManyArray = []; + // Filter array by enabled modules + foreach ($objectArray as $path => $modules) { + if (!array_diff($modules, $filterArray) + || (count($modules) == 1 && isset($this->knownDirectories[$modules[0]]))) { + if (count($modules) == 1) { + $oneToOneArray[$path] = $modules[0]; + } else { + $oneToManyArray[$path] = $modules; + } + } + } + $flippedArray = []; + // Set flipped array for "one path => one module" case first to maintain module sequencing + foreach ($filterArray as $moduleName) { + $path = array_search($moduleName, $oneToOneArray); + if ($path !== false) { + if (strpos($moduleName, '_') === false) { + $moduleName = $this->findVendorNameFromPath($path) . '_' . $moduleName; + } + $flippedArray = $this->setArrayValueWithLogging($flippedArray, $moduleName, $path); + unset($oneToOneArray[$path]); + } + } + + // Set flipped array for everything else + return $this->flipAndSortModulePathsArray( + array_merge($oneToOneArray, $oneToManyArray), + false, + $flippedArray + ); + } + + /** + * Flip module code paths and optionally sort in alphabetical order + * + * @param array $objectArray + * @param boolean $sort + * @param array $inFlippedArray + * @return array + */ + private function flipAndSortModulePathsArray($objectArray, $sort, $inFlippedArray = []) + { + $flippedArray = $inFlippedArray; + + // Set flipped array from object array foreach ($objectArray as $path => $modules) { - // One path maps to one module - if (count($modules) == 1) { - if (!is_array($filterArray) - || (is_array($filterArray) && in_array($modules[0], $filterArray)) - || isset($this->knownDirectories[$modules[0]])) { - if (strpos($modules[0], '_') === false) { - $modules[0] = $this->findVendorNameFromPath($path) . '_' . $modules[0]; - } - $flippedArray = $this->setArrayValueWithLogging($flippedArray, $modules[0], $path); + if (is_array($modules) && count($modules) > 1) { + // The "one path => many module names" case is designed to be strictly used when it's + // impossible to write tests in dedicated modules. Due to performance consideration and there + // is no real usage of this currently, we will use the first module name for the path. + // TODO: consider saving all module names if this information is needed in the future. + $module = $modules[0]; + } elseif (is_array($modules)) { + if (strpos($modules[0], '_') === false) { + $module = $this->findVendorNameFromPath($path) . '_' . $modules[0]; + } else { + $module = $modules[0]; } } else { - // One path maps to multiple modules - if (!is_array($filterArray)) { - $flippedArray = $this->setArrayValueWithLogging( - $flippedArray, - $this->findVendorAndModuleNameFromPath($path), - $path - ); + if (strpos($modules, '_') === false) { + $module = $this->findVendorNameFromPath($path) . '_' . $modules; } else { - $skip = false; - foreach ($modules as $module) { - if (!in_array($module, $filterArray)) { - $skip = true; - break; - } - } - if (!$skip) { - // The one path to many module names use case is designed to be strictly used when it's - // impossible to write tests in dedicated modules. Due to performance consideration and there - // is no real usage of this currently, we will use the first module name for the path. - // TODO: consider saving all module names if this information is needed in the future. - $flippedArray = $this->setArrayValueWithLogging($flippedArray, $modules[0], $path); - } + $module = $modules; } } + $flippedArray = $this->setArrayValueWithLogging($flippedArray, $module, $path); } + + // Sort array in alphabetical order + if ($sort) { + ksort($flippedArray); + } + return $flippedArray; } From c7d990090f2015e1bcfa457c0c696d72ce9e4f47 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 8 Oct 2019 14:07:19 -0500 Subject: [PATCH 3/4] MQE-1750: unit tests and some code refactor. --- .../Composer/ComposerInstallTest.php | 18 ++++------- .../Composer/ComposerPackageTest.php | 32 +++++++++---------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php index 4eb047457..e4977184f 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerInstallTest.php @@ -16,16 +16,14 @@ class ComposerInstallTest extends MagentoTestCase * * @var ComposerInstall */ - private static $composer; + private $composer; - public static function setUpBeforeClass() + public function setUp() { - parent::setUpBeforeClass(); - $composerJson = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Composer' . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'dir1' . DIRECTORY_SEPARATOR . 'dir2' . DIRECTORY_SEPARATOR . 'composer.json'; - self::$composer = new ComposerInstall($composerJson); + $this->composer = new ComposerInstall($composerJson); } /** @@ -33,7 +31,7 @@ public static function setUpBeforeClass() */ public function testIsMftfTestPackage() { - $this->assertTrue(self::$composer->isMftfTestPackage('magento/module2-functional-test')); + $this->assertTrue($this->composer->isMftfTestPackage('magento/module2-functional-test')); } /** @@ -41,7 +39,7 @@ public function testIsMftfTestPackage() */ public function testIsMagentoPackage() { - $this->assertTrue(self::$composer->isMagentoPackage('magento/module-authorization')); + $this->assertTrue($this->composer->isMagentoPackage('magento/module-authorization')); } /** @@ -49,9 +47,7 @@ public function testIsMagentoPackage() */ public function testIsInstalledPackageOfType() { - $this->assertTrue( - self::$composer->isInstalledPackageOfType('composer/composer', 'library') - ); + $this->assertTrue($this->composer->isInstalledPackageOfType('composer/composer', 'library')); } /** @@ -59,7 +55,7 @@ public function testIsInstalledPackageOfType() */ public function testGetInstalledTestPackages() { - $output = self::$composer->getInstalledTestPackages(); + $output = $this->composer->getInstalledTestPackages(); $this->assertCount(1, $output); $this->assertArrayHasKey('magento/module2-functional-test', $output); } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php index 04ace7b19..4802f0c33 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Composer/ComposerPackageTest.php @@ -17,16 +17,14 @@ class ComposerPackageTest extends MagentoTestCase * * @var ComposerPackage */ - private static $composer; + private $composer; - public static function setUpBeforeClass() + public function setUp() { - parent::setUpBeforeClass(); - $composerJson = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Composer' . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'dir1' . DIRECTORY_SEPARATOR . 'dir2' . DIRECTORY_SEPARATOR . 'composer.json'; - self::$composer = new ComposerPackage($composerJson); + $this->composer = new ComposerPackage($composerJson); } /** @@ -35,7 +33,7 @@ public static function setUpBeforeClass() public function testGetName() { $expected = 'magento/module2-functional-test'; - $this->assertEquals($expected, self::$composer->getName()); + $this->assertEquals($expected, $this->composer->getName()); } /** @@ -44,7 +42,7 @@ public function testGetName() public function testGetType() { $expected = 'magento2-functional-test-module'; - $this->assertEquals($expected, self::$composer->getType()); + $this->assertEquals($expected, $this->composer->getType()); } /** @@ -53,7 +51,7 @@ public function testGetType() public function testGetVersion() { $expected = '1.0.0'; - $this->assertEquals($expected, self::$composer->getVersion()); + $this->assertEquals($expected, $this->composer->getVersion()); } /** @@ -62,7 +60,7 @@ public function testGetVersion() public function testGetDescription() { $expected = 'MFTF tests for magento'; - $this->assertEquals($expected, self::$composer->getDescription()); + $this->assertEquals($expected, $this->composer->getDescription()); } /** @@ -71,7 +69,7 @@ public function testGetDescription() public function testGetRequires() { $expected = 'magento/magento2-functional-testing-framework'; - $output = self::$composer->getRequires(); + $output = $this->composer->getRequires(); $this->assertCount(1, $output); $this->assertArrayHasKey($expected, $output); } @@ -82,7 +80,7 @@ public function testGetRequires() public function testGetDevRequires() { $expected = ['phpunit/phpunit']; - $this->assertEquals($expected, array_keys(self::$composer->getDevRequires())); + $this->assertEquals($expected, array_keys($this->composer->getDevRequires())); } /** @@ -99,7 +97,7 @@ public function testGetSuggests() 'magento/module-three', 'magento/module-four' ]; - $this->assertEquals($expected, array_keys(self::$composer->getSuggests())); + $this->assertEquals($expected, array_keys($this->composer->getSuggests())); } /** @@ -112,7 +110,7 @@ public function testGetSuggestedMagentoModules() 'Magento_ModuleY', 'Magento_ModuleZ' ]; - $this->assertEquals($expected, self::$composer->getSuggestedMagentoModules()); + $this->assertEquals($expected, $this->composer->getSuggestedMagentoModules()); } /** @@ -120,7 +118,7 @@ public function testGetSuggestedMagentoModules() */ public function testIsMftfTestPackage() { - $this->assertTrue(self::$composer->isMftfTestPackage()); + $this->assertTrue($this->composer->isMftfTestPackage()); } /** @@ -145,7 +143,7 @@ public function testGetRequiresForPackage() ]; $this->assertEquals( $expected, - array_keys(self::$composer->getRequiresForPackage('magento/magento2-functional-testing-framework', '2.5.0')) + array_keys($this->composer->getRequiresForPackage('magento/magento2-functional-testing-framework', '2.5.0')) ); } @@ -155,7 +153,7 @@ public function testGetRequiresForPackage() public function testIsPackageRequiredInComposerJson() { $this->assertTrue( - self::$composer->isPackageRequiredInComposerJson('magento/magento2-functional-testing-framework') + $this->composer->isPackageRequiredInComposerJson('magento/magento2-functional-testing-framework') ); } @@ -166,7 +164,7 @@ public function testGetRootPackage() { $this->assertInstanceOf( RootPackage::class, - self::$composer->getRootPackage() + $this->composer->getRootPackage() ); } } From 5cfd7cd4ede0d42607fff2f2be50f3c51099ee02 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 8 Oct 2019 15:29:51 -0500 Subject: [PATCH 4/4] MQE-1750: unit tests and some code refactor. --- .../FunctionalTestFramework/Util/ModuleResolverTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php index b7c154e34..07e1ee7fa 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Util/ModuleResolverTest.php @@ -424,11 +424,11 @@ public function testMergeFlipAndFilterModulePathsNoForceGenerate() } /** - * Validate mergeModulePaths() and flipAndFilterModulePathsArray() + * Validate mergeModulePaths() and flipAndSortModulePathsArray() * * @throws \Exception */ - public function testMergeFlipAndFilterModulePathsForceGenerate() + public function testMergeFlipAndSortModulePathsForceGenerate() { $this->mockForceGenerate(true); $this->setMockResolverClass(