Skip to content

Commit 37683bb

Browse files
committed
Merge branch 'MQE-2669' of github.com:magento-gl/magento2-functional-testing-framework into MQE-2669
2 parents c565c45 + ba201f1 commit 37683bb

File tree

4 files changed

+188
-100
lines changed

4 files changed

+188
-100
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@ dev/tests/docs/*
2020
dev/tests/_output
2121
dev/tests/functional.suite.yml
2222
/v2/
23+
dev/.credentials.example
24+
dev/tests/.phpunit.result.cache
25+
dev/tests/verification/TestModule/Test/testFile.xml

src/Magento/FunctionalTestingFramework/Console/CommandList.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public function __construct(array $commands = [])
3636
'generate:tests' => new GenerateTestsCommand(),
3737
'generate:urn-catalog' => new GenerateDevUrnCommand(),
3838
'reset' => new CleanProjectCommand(),
39+
'generate:failed' => new GenerateTestFailedCommand(),
3940
'run:failed' => new RunTestFailedCommand(),
4041
'run:group' => new RunTestGroupCommand(),
4142
'run:manifest' => new RunManifestCommand(),
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types = 1);
7+
8+
namespace Magento\FunctionalTestingFramework\Console;
9+
10+
use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig;
11+
use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter;
12+
use Symfony\Component\Console\Input\ArrayInput;
13+
use Symfony\Component\Console\Input\InputInterface;
14+
use Symfony\Component\Console\Output\OutputInterface;
15+
use Symfony\Component\Process\Process;
16+
use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException;
17+
use Symfony\Component\Console\Input\InputOption;
18+
19+
class GenerateTestFailedCommand extends BaseGenerateCommand
20+
{
21+
/**
22+
* Default Test group to signify not in suite
23+
*/
24+
const DEFAULT_TEST_GROUP = 'default';
25+
26+
/**
27+
* @var string
28+
*/
29+
private $testsReRunFile;
30+
31+
/**
32+
* Configures the current command.
33+
*
34+
* @return void
35+
*/
36+
protected function configure()
37+
{
38+
$this->setName('generate:failed')
39+
->setDescription('Generate a set of tests failed');
40+
41+
parent::configure();
42+
}
43+
44+
/**
45+
* Executes the current command.
46+
*
47+
* @param InputInterface $input
48+
* @param OutputInterface $output
49+
* @return integer
50+
* @throws \Exception
51+
*
52+
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
53+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
54+
*/
55+
protected function execute(InputInterface $input, OutputInterface $output): int
56+
{
57+
$this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE;
58+
$this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests";
59+
60+
$force = $input->getOption('force');
61+
$debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility
62+
$allowSkipped = $input->getOption('allow-skipped');
63+
$verbose = $output->isVerbose();
64+
65+
// Create Mftf Configuration
66+
MftfApplicationConfig::create(
67+
$force,
68+
MftfApplicationConfig::EXECUTION_PHASE,
69+
$verbose,
70+
$debug,
71+
$allowSkipped
72+
);
73+
74+
$testConfiguration = $this->getFailedTestList();
75+
76+
if ($testConfiguration === null) {
77+
// no failed tests found, run is a success
78+
return 0;
79+
}
80+
81+
$command = $this->getApplication()->find('generate:tests');
82+
$args = [
83+
'--tests' => $testConfiguration,
84+
'--force' => $force,
85+
'--remove' => true,
86+
'--debug' => $debug,
87+
'--allow-skipped' => $allowSkipped,
88+
'-v' => $verbose
89+
];
90+
$command->run(new ArrayInput($args), $output);
91+
$output->writeln("Test Failed Generated, now run:failed command");
92+
return 1;
93+
}
94+
95+
/**
96+
* Returns a json string of tests that failed on the last run
97+
*
98+
* @return string
99+
*/
100+
private function getFailedTestList()
101+
{
102+
$failedTestDetails = ['tests' => [], 'suites' => []];
103+
104+
if (realpath($this->testsFailedFile)) {
105+
$testList = $this->readFailedTestFile($this->testsFailedFile);
106+
107+
foreach ($testList as $test) {
108+
if (!empty($test)) {
109+
$this->writeFailedTestToFile($test, $this->testsReRunFile);
110+
$testInfo = explode(DIRECTORY_SEPARATOR, $test);
111+
$testName = explode(":", $testInfo[count($testInfo) - 1])[1];
112+
$suiteName = $testInfo[count($testInfo) - 2];
113+
114+
if ($suiteName === self::DEFAULT_TEST_GROUP) {
115+
array_push($failedTestDetails['tests'], $testName);
116+
} else {
117+
$suiteName = $this->sanitizeSuiteName($suiteName);
118+
$failedTestDetails['suites'] = array_merge_recursive(
119+
$failedTestDetails['suites'],
120+
[$suiteName => [$testName]]
121+
);
122+
}
123+
}
124+
}
125+
}
126+
if (empty($failedTestDetails['tests']) & empty($failedTestDetails['suites'])) {
127+
return null;
128+
}
129+
if (empty($failedTestDetails['tests'])) {
130+
$failedTestDetails['tests'] = null;
131+
}
132+
if (empty($failedTestDetails['suites'])) {
133+
$failedTestDetails['suites'] = null;
134+
}
135+
$testConfigurationJson = json_encode($failedTestDetails);
136+
return $testConfigurationJson;
137+
}
138+
139+
/**
140+
* Trim potential suite_parallel_0_G to suite_parallel
141+
*
142+
* @param string $suiteName
143+
* @return string
144+
*/
145+
private function sanitizeSuiteName($suiteName)
146+
{
147+
$suiteNameArray = explode("_", $suiteName);
148+
if (array_pop($suiteNameArray) === 'G') {
149+
if (is_numeric(array_pop($suiteNameArray))) {
150+
$suiteName = implode("_", $suiteNameArray);
151+
}
152+
}
153+
return $suiteName;
154+
}
155+
156+
/**
157+
* Returns an array of tests read from the failed test file in _output
158+
*
159+
* @param string $filePath
160+
* @return array|boolean
161+
*/
162+
private function readFailedTestFile($filePath)
163+
{
164+
return file($filePath, FILE_IGNORE_NEW_LINES);
165+
}
166+
167+
/**
168+
* Writes the test name to a file if it does not already exist
169+
*
170+
* @param string $test
171+
* @param string $filePath
172+
* @return void
173+
*/
174+
private function writeFailedTestToFile($test, $filePath)
175+
{
176+
if (file_exists($filePath)) {
177+
if (strpos(file_get_contents($filePath), $test) === false) {
178+
file_put_contents($filePath, "\n" . $test, FILE_APPEND);
179+
}
180+
} else {
181+
file_put_contents($filePath, $test . "\n");
182+
}
183+
}
184+
}

src/Magento/FunctionalTestingFramework/Console/RunTestFailedCommand.php

Lines changed: 0 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ class RunTestFailedCommand extends BaseGenerateCommand
2323
*/
2424
const DEFAULT_TEST_GROUP = 'default';
2525

26-
/**
27-
* @var string
28-
*/
29-
private $testsReRunFile;
30-
3126
/**
3227
* @var string
3328
*/
@@ -64,45 +59,11 @@ protected function configure()
6459
*/
6560
protected function execute(InputInterface $input, OutputInterface $output): int
6661
{
67-
$this->testsFailedFile = $this->getTestsOutputDir() . self::FAILED_FILE;
68-
$this->testsReRunFile = $this->getTestsOutputDir() . "rerun_tests";
6962
$this->testsManifestFile= FilePathFormatter::format(TESTS_MODULE_PATH) .
7063
"_generated" .
7164
DIRECTORY_SEPARATOR .
7265
"testManifest.txt";
7366

74-
$force = $input->getOption('force');
75-
$debug = $input->getOption('debug') ?? MftfApplicationConfig::LEVEL_DEVELOPER; // for backward compatibility
76-
$allowSkipped = $input->getOption('allow-skipped');
77-
$verbose = $output->isVerbose();
78-
79-
// Create Mftf Configuration
80-
MftfApplicationConfig::create(
81-
$force,
82-
MftfApplicationConfig::EXECUTION_PHASE,
83-
$verbose,
84-
$debug,
85-
$allowSkipped
86-
);
87-
88-
$testConfiguration = $this->getFailedTestList();
89-
90-
if ($testConfiguration === null) {
91-
// no failed tests found, run is a success
92-
return 0;
93-
}
94-
95-
$command = $this->getApplication()->find('generate:tests');
96-
$args = [
97-
'--tests' => $testConfiguration,
98-
'--force' => $force,
99-
'--remove' => true,
100-
'--debug' => $debug,
101-
'--allow-skipped' => $allowSkipped,
102-
'-v' => $verbose
103-
];
104-
$command->run(new ArrayInput($args), $output);
105-
10667
$testManifestList = $this->readTestManifestFile();
10768
$returnCode = 0;
10869
for ($i = 0; $i < count($testManifestList); $i++) {
@@ -142,67 +103,6 @@ function ($type, $buffer) use ($output) {
142103
return $returnCode;
143104
}
144105

145-
/**
146-
* Returns a json string of tests that failed on the last run
147-
*
148-
* @return string
149-
*/
150-
private function getFailedTestList()
151-
{
152-
$failedTestDetails = ['tests' => [], 'suites' => []];
153-
154-
if (realpath($this->testsFailedFile)) {
155-
$testList = $this->readFailedTestFile($this->testsFailedFile);
156-
157-
foreach ($testList as $test) {
158-
if (!empty($test)) {
159-
$this->writeFailedTestToFile($test, $this->testsReRunFile);
160-
$testInfo = explode(DIRECTORY_SEPARATOR, $test);
161-
$testName = explode(":", $testInfo[count($testInfo) - 1])[1];
162-
$suiteName = $testInfo[count($testInfo) - 2];
163-
164-
if ($suiteName === self::DEFAULT_TEST_GROUP) {
165-
array_push($failedTestDetails['tests'], $testName);
166-
} else {
167-
$suiteName = $this->sanitizeSuiteName($suiteName);
168-
$failedTestDetails['suites'] = array_merge_recursive(
169-
$failedTestDetails['suites'],
170-
[$suiteName => [$testName]]
171-
);
172-
}
173-
}
174-
}
175-
}
176-
if (empty($failedTestDetails['tests']) & empty($failedTestDetails['suites'])) {
177-
return null;
178-
}
179-
if (empty($failedTestDetails['tests'])) {
180-
$failedTestDetails['tests'] = null;
181-
}
182-
if (empty($failedTestDetails['suites'])) {
183-
$failedTestDetails['suites'] = null;
184-
}
185-
$testConfigurationJson = json_encode($failedTestDetails);
186-
return $testConfigurationJson;
187-
}
188-
189-
/**
190-
* Trim potential suite_parallel_0_G to suite_parallel
191-
*
192-
* @param string $suiteName
193-
* @return string
194-
*/
195-
private function sanitizeSuiteName($suiteName)
196-
{
197-
$suiteNameArray = explode("_", $suiteName);
198-
if (array_pop($suiteNameArray) === 'G') {
199-
if (is_numeric(array_pop($suiteNameArray))) {
200-
$suiteName = implode("_", $suiteNameArray);
201-
}
202-
}
203-
return $suiteName;
204-
}
205-
206106
/**
207107
* Returns an array of run commands read from the manifest file created post generation
208108
*

0 commit comments

Comments
 (0)