Skip to content

Commit a313cb9

Browse files
committed
MQE-1963: Update XSD Schema to verify that file has only single entity
1 parent cdf6b84 commit a313cb9

21 files changed

+279
-171
lines changed

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"ext-curl": "*",
1414
"ext-json": "*",
1515
"ext-openssl": "*",
16+
"ext-dom": "*",
1617
"allure-framework/allure-codeception": "~1.3.0",
1718
"aws/aws-sdk-php": "^3.132",
1819
"codeception/codeception": "~2.4.5",

dev/tests/_bootstrap.php

-24
Original file line numberDiff line numberDiff line change
@@ -102,30 +102,6 @@
102102
require($unitUtilFile);
103103
}
104104

105-
106-
// Mocks suite files location getter return to get files in verification/_suite Directory
107-
// This mocks the paths of the suite files but still parses the xml files
108-
$suiteDirectory = TESTS_BP . DIRECTORY_SEPARATOR . "verification" . DIRECTORY_SEPARATOR . "_suite";
109-
110-
$paths = [
111-
$suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite' . DIRECTORY_SEPARATOR . 'functionalSuite1.xml',
112-
$suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite' . DIRECTORY_SEPARATOR . 'functionalSuite2.xml',
113-
$suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuite' . DIRECTORY_SEPARATOR . 'functionalSuiteWithComments.xml',
114-
$suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuiteHooks.xml',
115-
$suiteDirectory . DIRECTORY_SEPARATOR . 'functionalSuiteExtends.xml'
116-
];
117-
118-
// create and return the iterator for these file paths
119-
$iterator = new Magento\FunctionalTestingFramework\Util\Iterator\File($paths);
120-
try {
121-
AspectMock\Test::double(
122-
Magento\FunctionalTestingFramework\Config\FileResolver\Root::class,
123-
['get' => $iterator]
124-
)->make();
125-
} catch (Exception $e) {
126-
echo "Suite directory not mocked.";
127-
}
128-
129105
function sortInterfaces($files)
130106
{
131107
$bottom = [];

etc/di.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,12 @@
356356
<argument name="schemaPath" xsi:type="string">Magento/FunctionalTestingFramework/Suite/etc/mergedSuiteSchema.xsd</argument>
357357
</arguments>
358358
</virtualType>
359-
<virtualType name="Magento\FunctionalTestingFramework\Config\Reader\SuiteData" type="Magento\FunctionalTestingFramework\Config\Reader\Filesystem">
359+
<virtualType name="Magento\FunctionalTestingFramework\Config\Reader\SuiteData" type="Magento\FunctionalTestingFramework\Config\Reader\MftfFilesystem">
360360
<arguments>
361361
<argument name="fileResolver" xsi:type="object">Magento\FunctionalTestingFramework\Config\FileResolver\Root</argument>
362362
<argument name="converter" xsi:type="object">Magento\FunctionalTestingFramework\Config\SuiteDataConverter</argument>
363363
<argument name="schemaLocator" xsi:type="object">Magento\FunctionalTestingFramework\Config\SchemaLocator\SuiteData</argument>
364+
<argument name="domDocumentClass" xsi:type="string">Magento\FunctionalTestingFramework\Suite\Config\SuiteDom</argument>
364365
<argument name="idAttributes" xsi:type="array">
365366
<item name="/suites/suite" xsi:type="string">name</item>
366367
<item name="/suites/suite/(before|after)/remove" xsi:type="string">keyForRemoval</item>

src/Magento/FunctionalTestingFramework/Config/FileResolver/Root.php

+4-17
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,10 @@ class Root extends Mask
2727
public function get($filename, $scope)
2828
{
2929
// First pick up the root level test suite dir
30-
$paths = [];
31-
$dir = FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR;
32-
if (is_readable($dir)) {
33-
$directoryIterator = new \RecursiveIteratorIterator(
34-
new \RecursiveDirectoryIterator(
35-
$dir,
36-
\FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS
37-
)
38-
);
39-
$regexpIterator = new \RegexIterator($directoryIterator, $filename);
40-
/** @var \SplFileInfo $file */
41-
foreach ($regexpIterator as $file) {
42-
if ($file->isFile() && $file->isReadable()) {
43-
$paths[] = $file->getRealPath();
44-
}
45-
}
46-
}
30+
$paths = glob(
31+
FilePathFormatter::format(TESTS_BP) . self::ROOT_SUITE_DIR
32+
. DIRECTORY_SEPARATOR . '*.xml'
33+
);
4734

4835
// Then merge this path into the module based paths
4936
// Since we are sharing this code with Module based resolution we will unnecessarily glob against modules in the

src/Magento/FunctionalTestingFramework/Page/Config/Dom.php

+43-22
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Magento\FunctionalTestingFramework\Config\Dom\NodePathMatcher;
1313
use Magento\FunctionalTestingFramework\Util\ModulePathExtractor;
1414
use Magento\FunctionalTestingFramework\Util\Validation\DuplicateNodeValidationUtil;
15+
use Magento\FunctionalTestingFramework\Util\Validation\SingleNodePerFileValidationUtil;
1516

1617
/**
1718
* MFTF page.xml configuration XML DOM utility
@@ -36,6 +37,12 @@ class Dom extends \Magento\FunctionalTestingFramework\Config\MftfDom
3637
*/
3738
private $validationUtil;
3839

40+
/** SingleNodePerFileValidationUtil
41+
*
42+
* @var SingleNodePerFileValidationUtil
43+
*/
44+
private $singleNodePerFileValidationUtil;
45+
3946
/**
4047
* Page Dom constructor.
4148
* @param string $xml
@@ -57,6 +64,7 @@ public function __construct(
5764
) {
5865
$this->modulePathExtractor = new ModulePathExtractor();
5966
$this->validationUtil = new DuplicateNodeValidationUtil('name', $exceptionCollector);
67+
$this->singleNodePerFileValidationUtil = new SingleNodePerFileValidationUtil($exceptionCollector);
6068
parent::__construct(
6169
$xml,
6270
$filename,
@@ -79,31 +87,44 @@ public function initDom($xml, $filename = null)
7987
{
8088
$dom = parent::initDom($xml, $filename);
8189

82-
$pagesNode = $dom->getElementsByTagName('pages')->item(0);
83-
$this->validationUtil->validateChildUniqueness(
84-
$pagesNode,
85-
$filename,
86-
$pagesNode->getAttribute(self::PAGE_META_NAME_ATTRIBUTE)
87-
);
88-
$pageNodes = $dom->getElementsByTagName('page');
89-
$currentModule =
90-
$this->modulePathExtractor->getExtensionPath($filename)
91-
. '_'
92-
. $this->modulePathExtractor->extractModuleName($filename);
93-
foreach ($pageNodes as $pageNode) {
94-
$pageModule = $pageNode->getAttribute("module");
95-
$pageName = $pageNode->getAttribute("name");
96-
if ($pageModule !== $currentModule) {
97-
if (MftfApplicationConfig::getConfig()->verboseEnabled()) {
98-
print(
99-
"Page Module does not match path Module. " .
100-
"(Page, Module): ($pageName, $pageModule) - Path Module: $currentModule" .
101-
PHP_EOL
102-
);
90+
if ($dom->getElementsByTagName('pages')->length > 0) {
91+
/** @var \DOMElement $pagesNode */
92+
$pagesNode = $dom->getElementsByTagName('pages')[0];
93+
$this->validationUtil->validateChildUniqueness(
94+
$pagesNode,
95+
$filename,
96+
$pagesNode->getAttribute(self::PAGE_META_NAME_ATTRIBUTE)
97+
);
98+
99+
// Validate single page node per file
100+
$this->singleNodePerFileValidationUtil->validateSingleNodeForTag(
101+
$dom,
102+
'page',
103+
$filename
104+
);
105+
106+
if ($dom->getElementsByTagName('page')->length > 0) {
107+
/** @var \DOMElement $pageNode */
108+
$pageNode = $dom->getElementsByTagName('page')[0];
109+
$currentModule =
110+
$this->modulePathExtractor->getExtensionPath($filename)
111+
. '_'
112+
. $this->modulePathExtractor->extractModuleName($filename);
113+
$pageModule = $pageNode->getAttribute("module");
114+
$pageName = $pageNode->getAttribute("name");
115+
if ($pageModule !== $currentModule) {
116+
if (MftfApplicationConfig::getConfig()->verboseEnabled()) {
117+
print(
118+
"Page Module does not match path Module. " .
119+
"(Page, Module): ($pageName, $pageModule) - Path Module: $currentModule" .
120+
PHP_EOL
121+
);
122+
}
103123
}
124+
$pageNode->setAttribute(self::PAGE_META_FILENAME_ATTRIBUTE, $filename);
104125
}
105-
$pageNode->setAttribute(self::PAGE_META_FILENAME_ATTRIBUTE, $filename);
106126
}
127+
107128
return $dom;
108129
}
109130
}

src/Magento/FunctionalTestingFramework/Page/Config/SectionDom.php

+26-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Magento\FunctionalTestingFramework\Config\Dom\NodePathMatcher;
1313
use Magento\FunctionalTestingFramework\Util\ModulePathExtractor;
1414
use Magento\FunctionalTestingFramework\Util\Validation\DuplicateNodeValidationUtil;
15+
use Magento\FunctionalTestingFramework\Util\Validation\SingleNodePerFileValidationUtil;
1516

1617
/**
1718
* MFTF section.xml configuration XML DOM utility
@@ -28,6 +29,12 @@ class SectionDom extends \Magento\FunctionalTestingFramework\Config\MftfDom
2829
*/
2930
private $validationUtil;
3031

32+
/** SingleNodePerFileValidationUtil
33+
*
34+
* @var SingleNodePerFileValidationUtil
35+
*/
36+
private $singleNodePerFileValidationUtil;
37+
3138
/**
3239
* Entity Dom constructor.
3340
* @param string $xml
@@ -48,6 +55,7 @@ public function __construct(
4855
$errorFormat = self::ERROR_FORMAT_DEFAULT
4956
) {
5057
$this->validationUtil = new DuplicateNodeValidationUtil('name', $exceptionCollector);
58+
$this->singleNodePerFileValidationUtil = new SingleNodePerFileValidationUtil($exceptionCollector);
5159
parent::__construct(
5260
$xml,
5361
$filename,
@@ -69,15 +77,26 @@ public function __construct(
6977
public function initDom($xml, $filename = null)
7078
{
7179
$dom = parent::initDom($xml, $filename);
72-
$sectionNodes = $dom->getElementsByTagName('section');
73-
foreach ($sectionNodes as $sectionNode) {
74-
$sectionNode->setAttribute(self::SECTION_META_FILENAME_ATTRIBUTE, $filename);
75-
$this->validationUtil->validateChildUniqueness(
76-
$sectionNode,
77-
$filename,
78-
$sectionNode->getAttribute(self::SECTION_META_NAME_ATTRIBUTE)
80+
81+
if ($dom->getElementsByTagName('sections')->length > 0) {
82+
// Validate single section node per file
83+
$this->singleNodePerFileValidationUtil->validateSingleNodeForTag(
84+
$dom,
85+
'section',
86+
$filename
7987
);
88+
if ($dom->getElementsByTagName('section')->length > 0) {
89+
/** @var \DOMElement $sectionNode */
90+
$sectionNode = $dom->getElementsByTagName('section')[0];
91+
$sectionNode->setAttribute(self::SECTION_META_FILENAME_ATTRIBUTE, $filename);
92+
$this->validationUtil->validateChildUniqueness(
93+
$sectionNode,
94+
$filename,
95+
$sectionNode->getAttribute(self::SECTION_META_NAME_ATTRIBUTE)
96+
);
97+
}
8098
}
99+
81100
return $dom;
82101
}
83102
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\FunctionalTestingFramework\Suite\Config;
8+
9+
use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector;
10+
use Magento\FunctionalTestingFramework\Util\Validation\SingleNodePerFileValidationUtil;
11+
12+
/**
13+
* MFTF suite.xml configuration XML DOM utility
14+
* @package Magento\FunctionalTestingFramework\Suite\Config
15+
*/
16+
class SuiteDom extends \Magento\FunctionalTestingFramework\Config\MftfDom
17+
{
18+
const SUITE_META_FILENAME_ATTRIBUTE = "filename";
19+
20+
/** SingleNodePerFileValidationUtil
21+
*
22+
* @var SingleNodePerFileValidationUtil
23+
*/
24+
private $singleNodePerFileValidationUtil;
25+
26+
/**
27+
* Entity Dom constructor.
28+
* @param string $xml
29+
* @param string $filename
30+
* @param ExceptionCollector $exceptionCollector
31+
* @param array $idAttributes
32+
* @param string $typeAttributeName
33+
* @param string $schemaFile
34+
* @param string $errorFormat
35+
*/
36+
public function __construct(
37+
$xml,
38+
$filename,
39+
$exceptionCollector,
40+
array $idAttributes = [],
41+
$typeAttributeName = null,
42+
$schemaFile = null,
43+
$errorFormat = self::ERROR_FORMAT_DEFAULT
44+
) {
45+
$this->singleNodePerFileValidationUtil = new SingleNodePerFileValidationUtil($exceptionCollector);
46+
parent::__construct(
47+
$xml,
48+
$filename,
49+
$exceptionCollector,
50+
$idAttributes,
51+
$typeAttributeName,
52+
$schemaFile,
53+
$errorFormat
54+
);
55+
}
56+
57+
/**
58+
* Takes a dom element from xml and appends the filename based on location
59+
*
60+
* @param string $xml
61+
* @param string|null $filename
62+
* @return \DOMDocument
63+
*/
64+
public function initDom($xml, $filename = null)
65+
{
66+
$dom = parent::initDom($xml, $filename);
67+
68+
if ($dom->getElementsByTagName('suites')->length > 0) {
69+
// Validate single suite node per file
70+
$this->singleNodePerFileValidationUtil->validateSingleNodeForTag(
71+
$dom,
72+
'suite',
73+
$filename
74+
);
75+
if ($dom->getElementsByTagName('suite')->length > 0) {
76+
/** @var \DOMElement $suiteNode */
77+
$suiteNode = $dom->getElementsByTagName('suite')[0];
78+
$suiteNode->setAttribute(self::SUITE_META_FILENAME_ATTRIBUTE, $filename);
79+
}
80+
}
81+
82+
return $dom;
83+
}
84+
}

src/Magento/FunctionalTestingFramework/Suite/Objects/SuiteObject.php

+20-1
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,28 @@ class SuiteObject
4141
*/
4242
private $hooks;
4343

44+
/**
45+
* Filename of where the suite came from
46+
*
47+
* @var string
48+
*/
49+
private $filename;
50+
4451
/**
4552
* SuiteObject constructor.
4653
* @param string $name
4754
* @param TestObject[] $includeTests
4855
* @param TestObject[] $excludeTests
4956
* @param TestHookObject[] $hooks
57+
* @param string $filename
5058
*/
51-
public function __construct($name, $includeTests, $excludeTests, $hooks)
59+
public function __construct($name, $includeTests, $excludeTests, $hooks, $filename = null)
5260
{
5361
$this->name = $name;
5462
$this->includeTests = $includeTests;
5563
$this->excludeTests = $excludeTests;
5664
$this->hooks = $hooks;
65+
$this->filename = $filename;
5766
}
5867

5968
/**
@@ -146,4 +155,14 @@ public function getAfterHook()
146155
{
147156
return $this->hooks['after'] ?? null;
148157
}
158+
159+
/**
160+
* Getter for the Suite Filename
161+
*
162+
* @return string
163+
*/
164+
public function getFilename()
165+
{
166+
return $this->filename;
167+
}
149168
}

0 commit comments

Comments
 (0)