Skip to content

Commit c24ad1e

Browse files
authored
Merge pull request magento#2498 from magento-borg/DEVOPS-2174-2.2
Fixed issues: - DEVOPS-232 Static Testing in Jenkins - MAGETWO-89342 Backport fixes for broken L3 builds on B2B
2 parents ffac6ee + dbcf31f commit c24ad1e

File tree

10 files changed

+189
-45
lines changed

10 files changed

+189
-45
lines changed

dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixture.php

+9-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
*/
1010
namespace Magento\TestFramework\Annotation;
1111

12+
use PHPUnit\Framework\Exception;
13+
1214
class DataFixture
1315
{
1416
/**
@@ -171,8 +173,13 @@ protected function _applyOneFixture($fixture)
171173
require $fixture;
172174
}
173175
} catch (\Exception $e) {
174-
throw new \Exception(
175-
sprintf("Error in fixture: %s.\n %s", json_encode($fixture), $e->getMessage()),
176+
throw new Exception(
177+
sprintf(
178+
"Error in fixture: %s.\n %s\n %s",
179+
json_encode($fixture),
180+
$e->getMessage(),
181+
$e->getTraceAsString()
182+
),
176183
500,
177184
$e
178185
);

dev/tests/integration/framework/Magento/TestFramework/Annotation/DataFixtureBeforeTransaction.php

+11-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
*/
1010
namespace Magento\TestFramework\Annotation;
1111

12+
use PHPUnit\Framework\Exception;
13+
1214
class DataFixtureBeforeTransaction
1315
{
1416
/**
@@ -138,8 +140,15 @@ protected function _applyOneFixture($fixture)
138140
require $fixture;
139141
}
140142
} catch (\Exception $e) {
141-
throw new \Exception(
142-
sprintf("Error in fixture: %s.\n %s", json_encode($fixture), (string)$e)
143+
throw new Exception(
144+
sprintf(
145+
"Error in fixture: %s.\n %s\n %s",
146+
json_encode($fixture),
147+
$e->getMessage(),
148+
$e->getTraceAsString()
149+
),
150+
500,
151+
$e
143152
);
144153
}
145154
}

dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php

+81-27
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ class ComposerTest extends \PHPUnit\Framework\TestCase
4141
*/
4242
private static $objectManager;
4343

44+
/**
45+
* @var string[]
46+
*/
47+
private static $rootComposerModuleBlacklist = [];
48+
49+
/**
50+
* @var string[]
51+
*/
52+
private static $moduleNameBlacklist;
53+
4454
public static function setUpBeforeClass()
4555
{
4656
self::$root = BP;
@@ -52,6 +62,26 @@ public static function setUpBeforeClass()
5262
}
5363
self::$dependencies = [];
5464
self::$objectManager = Bootstrap::create(BP, $_SERVER)->getObjectManager();
65+
// A block can be whitelisted and thus not be required to be public
66+
self::$rootComposerModuleBlacklist = self::getBlacklist(
67+
__DIR__ . '/_files/blacklist/composer_root_modules*.txt'
68+
);
69+
self::$moduleNameBlacklist = self::getBlacklist(__DIR__ . '/_files/blacklist/composer_module_names*.txt');
70+
}
71+
72+
/**
73+
* Return aggregated blacklist
74+
*
75+
* @param string $pattern
76+
* @return string[]
77+
*/
78+
public static function getBlacklist(string $pattern)
79+
{
80+
$blacklist = [];
81+
foreach (glob($pattern) as $list) {
82+
$blacklist = array_merge($blacklist, file($list, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
83+
}
84+
return $blacklist;
5585
}
5686

5787
public function testValidComposerJson()
@@ -248,12 +278,15 @@ private function assertNoMap(\StdClass $json)
248278
*/
249279
private function assertConsistentModuleName(\SimpleXMLElement $xml, $packageName)
250280
{
251-
$moduleName = (string)$xml->module->attributes()->name;
252-
$this->assertEquals(
253-
$packageName,
254-
$this->convertModuleToPackageName($moduleName),
255-
"For the module '{$moduleName}', the expected package name is '{$packageName}'"
256-
);
281+
if (!in_array($packageName, self::$moduleNameBlacklist)) {
282+
$moduleName = (string)$xml->module->attributes()->name;
283+
$expectedPackageName = $this->convertModuleToPackageName($moduleName);
284+
$this->assertEquals(
285+
$expectedPackageName,
286+
$packageName,
287+
"For the module '{$moduleName}', the expected package name is '{$expectedPackageName}'"
288+
);
289+
}
257290
}
258291

259292
/**
@@ -314,36 +347,49 @@ private function assertPhpVersionInSync($name, $phpVersion)
314347
* Make sure requirements of components are reflected in root composer.json
315348
*
316349
* @param \StdClass $json
350+
* @return void
317351
*/
318352
private function assertRequireInSync(\StdClass $json)
319353
{
320-
$name = $json->name;
321354
if (preg_match('/magento\/project-*/', self::$rootJson['name']) == 1) {
322355
return;
323356
}
324-
if (isset($json->require)) {
325-
$errors = [];
326-
foreach (array_keys((array)$json->require) as $depName) {
327-
if ($depName == 'magento/magento-composer-installer') {
328-
// Magento Composer Installer is not needed for already existing components
329-
continue;
330-
}
331-
if (!isset(self::$mainComposerModules[$depName])) {
332-
$errors[] = "'$name' depends on '$depName'";
333-
}
357+
if (!in_array($json->name, self::$rootComposerModuleBlacklist) && isset($json->require)) {
358+
$this->checkPackageInRootComposer($json);
359+
}
360+
}
361+
362+
/**
363+
* Check if package is reflected in root composer.json
364+
*
365+
* @param \StdClass $json
366+
* @return void
367+
*/
368+
private function checkPackageInRootComposer(\StdClass $json)
369+
{
370+
$name = $json->name;
371+
$errors = [];
372+
foreach (array_keys((array)$json->require) as $depName) {
373+
if ($depName == 'magento/magento-composer-installer') {
374+
// Magento Composer Installer is not needed for already existing components
375+
continue;
334376
}
335377

336-
if (!empty($errors)) {
337-
$this->fail(
338-
"The following dependencies are missing in root 'composer.json',"
339-
. " while declared in child components.\n"
340-
. "Consider adding them to 'require-dev' section (if needed for child components only),"
341-
. " to 'replace' section (if they are present in the project),"
342-
. " to 'require' section (if needed for the skeleton).\n"
343-
. join("\n", $errors)
344-
);
378+
if (!isset(self::$rootJson['require-dev'][$depName]) && !isset(self::$rootJson['require'][$depName])
379+
&& !isset(self::$rootJson['replace'][$depName])) {
380+
$errors[] = "'$name' depends on '$depName'";
345381
}
346382
}
383+
if (!empty($errors)) {
384+
$this->fail(
385+
"The following dependencies are missing in root 'composer.json',"
386+
. " while declared in child components.\n"
387+
. "Consider adding them to 'require-dev' section (if needed for child components only),"
388+
. " to 'replace' section (if they are present in the project),"
389+
. " to 'require' section (if needed for the skeleton).\n"
390+
. join("\n", $errors)
391+
);
392+
}
347393
}
348394

349395
/**
@@ -386,6 +432,10 @@ private function assertPackageVersions(\StdClass $json)
386432
*/
387433
private function checkDiscrepancy($componentConfig, $packageName)
388434
{
435+
if (in_array($packageName, self::$rootComposerModuleBlacklist)) {
436+
return false;
437+
}
438+
389439
$rootConstraint = (new VersionParser())->parseConstraints(self::$mainComposerModules[$packageName]);
390440
$componentConstraint = (new VersionParser())->parseConstraints($componentConfig->require->$packageName);
391441

@@ -484,7 +534,11 @@ private function checkProject()
484534
}
485535
}
486536
sort($dependenciesListed);
487-
$nonDeclaredDependencies = array_diff(self::$dependencies, $dependenciesListed);
537+
$nonDeclaredDependencies = array_diff(
538+
self::$dependencies,
539+
$dependenciesListed,
540+
self::$rootComposerModuleBlacklist
541+
);
488542
$nonexistentDependencies = array_diff($dependenciesListed, self::$dependencies);
489543
$this->assertEmpty(
490544
$nonDeclaredDependencies,

dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php

+35-2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ class CompilerTest extends \PHPUnit\Framework\TestCase
6262
*/
6363
protected $pluginValidator;
6464

65+
/**
66+
* @var string[]|null
67+
*/
68+
private $pluginBlacklist;
69+
6570
protected function setUp()
6671
{
6772
$this->_shell = new \Magento\Framework\Shell(new \Magento\Framework\Shell\CommandRenderer());
@@ -107,6 +112,31 @@ protected function setUp()
107112
$this->pluginValidator = new PluginValidator(new InterfaceValidator());
108113
}
109114

115+
/**
116+
* Return plugin blacklist class names
117+
*
118+
* @return string[]
119+
*/
120+
private function getPluginBlacklist(): array
121+
{
122+
if ($this->pluginBlacklist === null) {
123+
$blacklistFiles = str_replace(
124+
'\\',
125+
'/',
126+
realpath(__DIR__) . '/../_files/blacklist/compiler_plugins*.txt'
127+
);
128+
$blacklistItems = [];
129+
foreach (glob($blacklistFiles) as $fileName) {
130+
$blacklistItems = array_merge(
131+
$blacklistItems,
132+
file($fileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
133+
);
134+
}
135+
$this->pluginBlacklist = $blacklistItems;
136+
}
137+
return $this->pluginBlacklist;
138+
}
139+
110140
/**
111141
* Validate DI config file
112142
*
@@ -360,6 +390,7 @@ protected function validatePlugins($plugin, $type)
360390
* Get application plugins
361391
*
362392
* @return array
393+
* @throws \Exception
363394
*/
364395
protected function pluginDataProvider()
365396
{
@@ -376,8 +407,10 @@ protected function pluginDataProvider()
376407
$type = \Magento\Framework\App\Utility\Classes::resolveVirtualType($type);
377408
if ($node->attributes->getNamedItem('type')) {
378409
$plugin = $node->attributes->getNamedItem('type')->nodeValue;
379-
$plugin = \Magento\Framework\App\Utility\Classes::resolveVirtualType($plugin);
380-
$plugins[] = ['plugin' => $plugin, 'intercepted type' => $type];
410+
if (!in_array($plugin, $this->getPluginBlacklist())) {
411+
$plugin = \Magento\Framework\App\Utility\Classes::resolveVirtualType($plugin);
412+
$plugins[] = ['plugin' => $plugin, 'intercepted type' => $type];
413+
}
381414
}
382415
}
383416
}

dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/ControllerAclTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,10 @@ private function getAclResources()
148148
if ($this->aclResources !== null) {
149149
return $this->aclResources;
150150
}
151-
$aclFiles = array_keys(Files::init()->getConfigFiles('acl.xml', []));
151+
$aclFiles = Files::init()->getConfigFiles('acl.xml', []);
152152
$xmlResources = [];
153153
array_map(function ($file) use (&$xmlResources) {
154-
$config = simplexml_load_file($file);
154+
$config = simplexml_load_file($file[0]);
155155
$nodes = $config->xpath('.//resource/@id') ?: [];
156156
foreach ($nodes as $node) {
157157
$xmlResources[(string)$node] = $node;

dev/tests/static/testsuite/Magento/Test/Integrity/PublicCodeTest.php

+40-5
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,42 @@ class PublicCodeTest extends \PHPUnit\Framework\TestCase
2222
'$this', 'void', 'string', 'int', 'bool', 'boolean', 'integer', 'null'
2323
];
2424

25+
/**
26+
* @var string[]|null
27+
*/
28+
private $blockWhitelist;
29+
30+
/**
31+
* Return whitelist class names
32+
*
33+
* @return string[]
34+
*/
35+
private function getWhitelist(): array
36+
{
37+
if ($this->blockWhitelist === null) {
38+
$whiteListFiles = str_replace(
39+
'\\',
40+
'/',
41+
realpath(__DIR__) . '/_files/whitelist/public_code*.txt'
42+
);
43+
$whiteListItems = [];
44+
foreach (glob($whiteListFiles) as $fileName) {
45+
$whiteListItems = array_merge(
46+
$whiteListItems,
47+
file($fileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
48+
);
49+
}
50+
$this->blockWhitelist = $whiteListItems;
51+
}
52+
return $this->blockWhitelist;
53+
}
54+
2555
/**
2656
* Since blocks can be referenced from templates, they should be stable not to break theme customizations.
2757
* So all blocks should be @api annotated. This test checks that all blocks declared in layout files are public
2858
*
2959
* @param $layoutFile
60+
* @throws \ReflectionException
3061
* @dataProvider layoutFilesDataProvider
3162
*/
3263
public function testAllBlocksReferencedInLayoutArePublic($layoutFile)
@@ -37,7 +68,7 @@ public function testAllBlocksReferencedInLayoutArePublic($layoutFile)
3768
/** @var $node \SimpleXMLElement */
3869
foreach ($elements as $node) {
3970
$class = (string) $node['class'];
40-
if ($class && \class_exists($class)) {
71+
if ($class && \class_exists($class) && !in_array($class, $this->getWhitelist())) {
4172
$reflection = (new \ReflectionClass($class));
4273
if (strpos($reflection->getDocComment(), '@api') === false) {
4374
$nonPublishedBlocks[] = $class;
@@ -47,7 +78,7 @@ public function testAllBlocksReferencedInLayoutArePublic($layoutFile)
4778
if (count($nonPublishedBlocks)) {
4879
$this->fail(
4980
"Layout file '$layoutFile' uses following blocks that are not marked with @api annotation:\n"
50-
. implode(",\n", $nonPublishedBlocks)
81+
. implode(",\n", array_unique($nonPublishedBlocks))
5182
);
5283
}
5384
}
@@ -56,6 +87,7 @@ public function testAllBlocksReferencedInLayoutArePublic($layoutFile)
5687
* Find all layout update files in magento modules and themes.
5788
*
5889
* @return array
90+
* @throws \Exception
5991
*/
6092
public function layoutFilesDataProvider()
6193
{
@@ -68,8 +100,8 @@ public function layoutFilesDataProvider()
68100
* This test walks through all public PHP types and makes sure that all their method arguments
69101
* and return values are public types.
70102
*
71-
*
72103
* @param string $class
104+
* @throws \ReflectionException
73105
* @dataProvider publicPHPTypesDataProvider
74106
*/
75107
public function testAllPHPClassesReferencedFromPublicClassesArePublic($class)
@@ -102,14 +134,15 @@ public function testAllPHPClassesReferencedFromPublicClassesArePublic($class)
102134
if (count($nonPublishedClasses)) {
103135
$this->fail(
104136
"Public type '" . $class . "' references following non-public types:\n"
105-
. implode("\n", $nonPublishedClasses)
137+
. implode("\n", array_unique($nonPublishedClasses))
106138
);
107139
}
108140
}
109141

110142
/**
111143
* Retrieve list of all interfaces and classes in Magento codebase that are marked with @api annotation.
112144
* @return array
145+
* @throws \Exception
113146
*/
114147
public function publicPHPTypesDataProvider()
115148
{
@@ -119,7 +152,9 @@ public function publicPHPTypesDataProvider()
119152
$fileContents = \file_get_contents($file);
120153
if (strpos($fileContents, '@api') !== false) {
121154
foreach ($this->getDeclaredClassesAndInterfaces($file) as $class) {
122-
if (class_exists($class->getName()) || interface_exists($class->getName())) {
155+
if (!in_array($class->getName(), $this->getWhitelist())
156+
&& (class_exists($class->getName()) || interface_exists($class->getName()))
157+
) {
123158
$result[$class->getName()] = [$class->getName()];
124159
}
125160
}

0 commit comments

Comments
 (0)