Skip to content

Commit 3ef39ba

Browse files
committed
Merge branch 'develop' of github.com:magento/magento2-functional-testing-framework into CD-develop
# Conflicts: # src/Magento/FunctionalTestingFramework/Util/TestGenerator.php
2 parents 9fff8f2 + b35c503 commit 3ef39ba

File tree

9 files changed

+213
-77
lines changed

9 files changed

+213
-77
lines changed

RoboFile.php

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,28 @@ function buildProject()
4141
/**
4242
* Generate all Tests in PHP.
4343
*
44+
* @param array $tests
4445
* @param array $opts
4546
* @return void
4647
*/
47-
function generateTests($opts = ['config' => null, 'force' => true, 'nodes' => null, 'debug' => false])
48+
function generateTests(array $tests, $opts = ['config' => null, 'force' => true, 'nodes' => null, 'debug' => false])
4849
{
50+
require 'dev' . DIRECTORY_SEPARATOR . 'tests'. DIRECTORY_SEPARATOR . 'functional' . DIRECTORY_SEPARATOR . '_bootstrap.php';
4951
$GLOBALS['GENERATE_TESTS'] = true;
50-
51-
if ($opts['force'])
52-
{
53-
$GLOBALS['FORCE_PHP_GENERATE'] = true;
54-
}
55-
56-
require 'dev' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'functional' . DIRECTORY_SEPARATOR . '_bootstrap.php';
57-
5852
if (!$this->isProjectBuilt()) {
59-
throw new Exception('Please run vendor/bin/robo build:project and configure your environment (.env) first.');
53+
$this->say("<info>Please run bin/mftf build:project and configure your environment (.env) first.</info>");
54+
exit(\Robo\Result::EXITCODE_ERROR);
6055
}
61-
62-
\Magento\FunctionalTestingFramework\Util\TestGenerator::getInstance()
63-
->createAllTestFiles($opts['config'], $opts['nodes'], $opts['debug']);
64-
$this->say("Generate Tests Command Run");
56+
$testsObjects = [];
57+
foreach ($tests as $test) {
58+
$testsObjects[] = Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler::getInstance()->getObject($test);
59+
}
60+
if ($opts['force']) {
61+
$GLOBALS['FORCE_PHP_GENERATE'] = true;
62+
}
63+
$testsReferencedInSuites = \Magento\FunctionalTestingFramework\Suite\SuiteGenerator::getInstance()->generateAllSuites($opts['config']);
64+
\Magento\FunctionalTestingFramework\Util\TestGenerator::getInstance(null, $testsObjects, $opts['debug'])->createAllTestFiles($opts['config'], $opts['nodes'], $testsReferencedInSuites);
65+
$this->say("<comment>Generate Tests Command Run</comment>");
6566
}
6667

6768
/**
@@ -72,12 +73,12 @@ private function isProjectBuilt()
7273
{
7374
$actorFile = __DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'Magento' . DIRECTORY_SEPARATOR . 'FunctionalTestingFramework' . DIRECTORY_SEPARATOR . '_generated' . DIRECTORY_SEPARATOR . 'AcceptanceTesterActions.php';
7475

75-
$login = getenv('MAGENTO_ADMIN_USERNAME');
76-
$password = getenv('MAGENTO_ADMIN_PASSWORD');
77-
$baseUrl = getenv('MAGENTO_BASE_URL');
78-
$backendName = getenv('MAGENTO_BACKEND_NAME');
79-
80-
return (file_exists($actorFile) && $login && $password && $baseUrl && $backendName);
76+
$login = !empty(getenv('MAGENTO_ADMIN_USERNAME'));
77+
$password = !empty(getenv('MAGENTO_ADMIN_PASSWORD'));
78+
$baseUrl = !empty(getenv('MAGENTO_BASE_URL'));
79+
$backendName = !empty(getenv('MAGENTO_BACKEND_NAME'));
80+
$test = (file_exists($actorFile) && $login && $password && $baseUrl && $backendName);
81+
return $test;
8182
}
8283

8384
/**

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,6 @@
5151
"hooks": {
5252
"pre-push": "bin/all-checks"
5353
}
54-
}
54+
},
55+
"bin": ["bin/mftf"]
5556
}

dev/tests/verification/Tests/SuiteGenerationTest.php

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,6 @@ class SuiteGenerationTest extends MftfTestCase
1717
const RESOURCES_DIR = TESTS_BP . DIRECTORY_SEPARATOR . 'verification' . DIRECTORY_SEPARATOR . 'Resources';
1818
const CONFIG_YML_FILE = FW_BP . DIRECTORY_SEPARATOR . SuiteGenerator::YAML_CODECEPTION_CONFIG_FILENAME;
1919

20-
const MANIFEST_RESULTS = [
21-
'IncludeTest2Cest.php',
22-
'additionalTestCest.php',
23-
'IncludeTestCest.php',
24-
'additionalIncludeTest2Cest.php'
25-
];
26-
2720
/**
2821
* Flag to track existence of config.yml file
2922
*
@@ -48,6 +41,11 @@ public static function setUpBeforeClass()
4841
return;
4942
}
5043

44+
// destroy manifest file if it exists
45+
if (file_exists(self::getManifestFilePath())) {
46+
unlink(self::getManifestFilePath());
47+
}
48+
5149
$configYml = fopen(self::CONFIG_YML_FILE, "w");
5250
fclose($configYml);
5351
}
@@ -59,6 +57,13 @@ public function testSuiteGeneration1()
5957
{
6058
$groupName = 'functionalSuite1';
6159

60+
$expectedContents = [
61+
'additionalTestCest.php',
62+
'additionalIncludeTest2Cest.php',
63+
'IncludeTest2Cest.php',
64+
'IncludeTestCest.php'
65+
];
66+
6267
// Generate the Suite
6368
SuiteGenerator::getInstance()->generateSuite($groupName);
6469

@@ -79,23 +84,10 @@ public function testSuiteGeneration1()
7984
$groupName .
8085
DIRECTORY_SEPARATOR;
8186

82-
// Validate test manifest contents
83-
$actualManifest = dirname($suiteResultBaseDir). DIRECTORY_SEPARATOR . 'testManifest.txt';
84-
$actualTestReferences = explode(PHP_EOL, file_get_contents($actualManifest));
85-
86-
for ($i = 0; $i < count($actualTestReferences); $i++) {
87-
if (empty($actualTestReferences[$i])) {
88-
continue;
89-
}
90-
91-
$this->assertStringEndsWith(self::MANIFEST_RESULTS[$i], $actualTestReferences[$i]);
92-
$this->assertNotFalse(strpos($actualTestReferences[$i], $groupName));
93-
}
94-
95-
// Validate expected php files exist
96-
foreach (self::MANIFEST_RESULTS as $expectedTestReference) {
97-
$cestName = explode(":", $expectedTestReference, 2);
98-
$this->assertFileExists($suiteResultBaseDir . $cestName[0]);
87+
// Validate tests have been generated
88+
$dirContents = array_diff(scandir($suiteResultBaseDir), ['..', '.']);
89+
foreach ($expectedContents as $expectedFile) {
90+
$this->assertTrue(in_array($expectedFile, $dirContents));
9991
}
10092
}
10193

@@ -117,4 +109,20 @@ public static function tearDownAfterClass()
117109

118110
unlink(self::CONFIG_YML_FILE);
119111
}
112+
113+
/**
114+
* Getter for manifest file path
115+
*
116+
* @return string
117+
*/
118+
private static function getManifestFilePath()
119+
{
120+
return TESTS_BP .
121+
DIRECTORY_SEPARATOR .
122+
"verification" .
123+
DIRECTORY_SEPARATOR .
124+
"_generated" .
125+
DIRECTORY_SEPARATOR .
126+
'testManifest.txt';
127+
}
120128
}

src/Magento/FunctionalTestingFramework/Suite/SuiteGenerator.php

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ class SuiteGenerator
3232
*/
3333
private static $SUITE_GENERATOR_INSTANCE;
3434

35+
/**
36+
* Boolean to track whether we have already cleared the yaml file.
37+
*
38+
* @var bool
39+
*/
40+
private $ymlFileCleared = false;
41+
3542
/**
3643
* Group Class Generator initialized in constructor.
3744
*
@@ -61,14 +68,35 @@ public static function getInstance()
6168
return self::$SUITE_GENERATOR_INSTANCE;
6269
}
6370

71+
/**
72+
* Function which takes all suite configurations and generates to appropriate directory, updating yml configuration
73+
* as needed. Returns an array of all tests generated keyed by test name.
74+
*
75+
* @param string $config
76+
* @return array
77+
*/
78+
public function generateAllSuites($config)
79+
{
80+
$testsReferencedInSuites = [];
81+
$suites = SuiteObjectHandler::getInstance()->getAllObjects();
82+
foreach ($suites as $suite) {
83+
/** @var SuiteObject $suite */
84+
$testsReferencedInSuites = array_merge($testsReferencedInSuites, $suite->getTests());
85+
$this->generateSuite($suite->getName(), $config);
86+
}
87+
88+
return $testsReferencedInSuites;
89+
}
90+
6491
/**
6592
* Function which takes a suite name and generates corresponding dir, test files, group class, and updates
6693
* yml configuration for group run.
6794
*
6895
* @param string $suiteName
96+
* @param string $config
6997
* @return void
7098
*/
71-
public function generateSuite($suiteName)
99+
public function generateSuite($suiteName, $config = null)
72100
{
73101
/**@var SuiteObject $suite **/
74102
$suite = SuiteObjectHandler::getInstance()->getObject($suiteName);
@@ -77,7 +105,7 @@ public function generateSuite($suiteName)
77105
$groupNamespace = null;
78106

79107
DirSetupUtil::createGroupDir($fullPath);
80-
$this->generateRelevantGroupTests($suiteName, $suite->getTests());
108+
$this->generateRelevantGroupTests($suiteName, $suite->getTests(), $config);
81109

82110
if ($suite->requiresGroupFile()) {
83111
// if the suite requires a group file, generate it and set the namespace
@@ -117,29 +145,69 @@ private function appendEntriesToConfig($suiteName, $suitePath, $groupNamespace)
117145
$ymlArray[self::YAML_GROUPS_TAG]= [];
118146
}
119147

120-
$ymlArray[self::YAML_GROUPS_TAG][$suiteName] = [$relativeSuitePath];
148+
$ymlArray = $this->clearPreviousSessionConfigEntries($ymlArray);
121149

122-
if ($groupNamespace &&
123-
!in_array($groupNamespace, $ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG])) {
150+
if ($groupNamespace) {
124151
$ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][] = $groupNamespace;
125152
}
153+
$ymlArray[self::YAML_GROUPS_TAG][$suiteName] = [$relativeSuitePath];
126154

127155
$ymlText = self::YAML_COPYRIGHT_TEXT . Yaml::dump($ymlArray, 10);
128156
file_put_contents($configYmlFile, $ymlText);
129157
}
130158

159+
/**
160+
* Function which takes the current config.yml array and clears any previous configuration for suite group object
161+
* files.
162+
*
163+
* @param array $ymlArray
164+
* @return array
165+
*/
166+
private function clearPreviousSessionConfigEntries($ymlArray)
167+
{
168+
if ($this->ymlFileCleared) {
169+
return $ymlArray;
170+
}
171+
172+
$newYmlArray = $ymlArray;
173+
// if the yaml entries haven't already been cleared
174+
175+
if (array_key_exists(self::YAML_EXTENSIONS_TAG, $ymlArray)) {
176+
foreach ($ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG] as $key => $entry) {
177+
if (preg_match('/(Group\\\\.*)/', $entry)) {
178+
unset($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][$key]);
179+
}
180+
181+
}
182+
183+
// needed for proper yml file generation based on indices
184+
$newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG] =
185+
array_values($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG]);
186+
187+
}
188+
189+
if (array_key_exists(self::YAML_GROUPS_TAG, $newYmlArray)) {
190+
unset($newYmlArray[self::YAML_GROUPS_TAG]);
191+
}
192+
193+
$this->ymlFileCleared = true;
194+
195+
return $newYmlArray;
196+
}
197+
131198
/**
132199
* Function which takes a string which is the desired output directory (under _generated) and an array of tests
133200
* relevant to the suite to be generated. The function takes this information and creates a new instance of the test
134201
* generator which is then called to create all the test files for the suite.
135202
*
136203
* @param string $path
137204
* @param array $tests
205+
* @param string $config
138206
* @return void
139207
*/
140-
private function generateRelevantGroupTests($path, $tests)
208+
private function generateRelevantGroupTests($path, $tests, $config)
141209
{
142210
$testGenerator = TestGenerator::getInstance($path, $tests);
143-
$testGenerator->createAllTestFiles();
211+
$testGenerator->createAllTestFiles($config);
144212
}
145213
}

src/Magento/FunctionalTestingFramework/Suite/Util/SuiteObjectExtractor.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ public function parseSuiteDataIntoObjects($parsedSuiteData)
4444
{
4545
$suiteObjects = [];
4646
$testHookObjectExtractor = new TestHookObjectExtractor();
47+
48+
// make sure there are suites defined before trying to parse as objects.
49+
if (!array_key_exists(self::SUITE_ROOT_TAG, $parsedSuiteData)) {
50+
return $suiteObjects;
51+
}
52+
4753
foreach ($parsedSuiteData[self::SUITE_ROOT_TAG] as $parsedSuite) {
4854
if (!is_array($parsedSuite)) {
4955
// skip non array items parsed from suite (suite objects will always be arrays)

src/Magento/FunctionalTestingFramework/Util/Filesystem/DirSetupUtil.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111

1212
class DirSetupUtil
1313
{
14+
/**
15+
* Array which will track any previously cleared directories, to prevent any unintended removal.
16+
*
17+
* @var array
18+
*/
19+
private static $DIR_CONTEXT = [];
20+
1421
/**
1522
* Method used to clean export dir if needed and create new empty export dir.
1623
*
@@ -19,11 +26,17 @@ class DirSetupUtil
1926
*/
2027
public static function createGroupDir($fullPath)
2128
{
29+
// make sure we haven't already cleaned up this directory at any point before deletion
30+
if (in_array($fullPath, self::$DIR_CONTEXT)) {
31+
return;
32+
}
33+
2234
if (file_exists($fullPath)) {
2335
self::rmDirRecursive($fullPath);
2436
}
2537

2638
mkdir($fullPath, 0777, true);
39+
self::$DIR_CONTEXT[] = $fullPath;
2740
}
2841

2942
/**

src/Magento/FunctionalTestingFramework/Util/Manifest/DefaultTestManifest.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Magento\FunctionalTestingFramework\Util\Manifest;
88

99
use Magento\FunctionalTestingFramework\Test\Objects\TestObject;
10+
use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil;
1011

1112
class DefaultTestManifest extends BaseTestManifest
1213
{
@@ -19,6 +20,13 @@ class DefaultTestManifest extends BaseTestManifest
1920
*/
2021
protected $manifestPath;
2122

23+
/**
24+
* A static array to track which test manifests have been cleared to prevent overwriting during generation.
25+
*
26+
* @var array
27+
*/
28+
private static $CLEARED_MANIFESTS = [];
29+
2230
/**
2331
* An array containing all test names for output.
2432
*
@@ -34,8 +42,9 @@ class DefaultTestManifest extends BaseTestManifest
3442
public function __construct($manifestPath, $testPath)
3543
{
3644
$this->manifestPath = $manifestPath . DIRECTORY_SEPARATOR . 'testManifest.txt';
45+
$this->cleanManifest($this->manifestPath);
3746
parent::__construct($testPath, self::DEFAULT_CONFIG);
38-
$fileResource = fopen($this->manifestPath, 'w');
47+
$fileResource = fopen($this->manifestPath, 'a');
3948
fclose($fileResource);
4049
}
4150

@@ -67,4 +76,26 @@ public function generate($nodes = null)
6776

6877
fclose($fileResource);
6978
}
79+
80+
/**
81+
* Function which checks the path for an existing test manifest and clears if the file has not already been cleared
82+
* during current runtime.
83+
*
84+
* @param string $path
85+
* @return void
86+
*/
87+
private function cleanManifest($path)
88+
{
89+
// if we have already cleared the file then simply return
90+
if (in_array($path, self::$CLEARED_MANIFESTS)) {
91+
return;
92+
}
93+
94+
// if the file exists remove
95+
if (file_exists($path)) {
96+
unlink($path);
97+
}
98+
99+
self::$CLEARED_MANIFESTS[] = $path;
100+
}
70101
}

0 commit comments

Comments
 (0)