Skip to content

Commit 2f7c598

Browse files
committed
MC-38349: Create automated test for SVC changes
- WIP on MC-38349 - Created code for parsing contents of html - Added test cases for html
1 parent 1a886fa commit 2f7c598

File tree

71 files changed

+919
-15
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+919
-15
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"wikimedia/less.php": "~1.8.0",
1717
"zendframework/zend-stdlib": "^3.2.1",
1818
"nikic/php-parser": "~4.4.0||~4.5.0||~4.6.0",
19-
"sabre/xml": "^2.1"
19+
"sabre/xml": "^2.1",
20+
"ext-dom": "*"
2021
},
2122
"require-dev": {
2223
"phpunit/phpunit": "^6.5.0",

src/Analyzer/Layout/Analyzer.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public function analyze($registryBefore, $registryAfter)
7171
$nodeAfter = $moduleNodesAfter[$uniqueKey] ?? false;
7272
if ($nodeAfter === false) {
7373
$beforeFilePath = $registryBefore->getLayoutFile($moduleName, $uniqueKey);
74-
$this->triggerNodeRemoved($moduleName, $node, $beforeFilePath);
74+
$this->triggerNodeRemoved($node, $beforeFilePath);
7575
}
7676
}
7777
}
@@ -80,11 +80,10 @@ public function analyze($registryBefore, $registryAfter)
8080
}
8181

8282
/**
83-
* @param string $moduleName
8483
* @param $node
8584
* @param string $beforeFilePath
8685
*/
87-
private function triggerNodeRemoved(string $moduleName, $node, string $beforeFilePath): void
86+
private function triggerNodeRemoved($node, string $beforeFilePath): void
8887
{
8988
if ($node instanceof Block) {
9089
$this->report->add('layout', new BlockRemoved($beforeFilePath, $node->getName()));

src/Console/Command/CompareSourceCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ protected function configure()
9797
/**
9898
* @param InputInterface $input
9999
* @param OutputInterface $cliOutput
100-
* @return void
101100
*/
102101
protected function execute(InputInterface $input, OutputInterface $cliOutput)
103102
{
@@ -221,8 +220,9 @@ protected function execute(InputInterface $input, OutputInterface $cliOutput)
221220
"It exceeds the allowed change level, which is $allowedChangeLevel " .
222221
'(' . $versionIncWord . ').'
223222
);
224-
exit(-1);
223+
return -1;
225224
}
225+
return 0;
226226
}
227227

228228
private function validateAllowedLevel($input)

src/Reporter/HtmlPackageLevelChangesRenderer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ private function getPackageChanges():array
173173
}
174174

175175
/**
176-
* Insert package into results array. Skip displaying patch-level changes
176+
* Insert package into results array. Skip inserting if change is less severe than currently stored packageChange
177177
*
178178
* @param string $pkgName
179179
* @param int $level

tests/Unit/Console/Command/CompareSourceCommandDatabaseSchemasTest.php

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,35 +64,43 @@ public function changesDataProvider()
6464
$pathToFixtures . '/drop-foreign-key/source-code-before',
6565
$pathToFixtures . '/drop-foreign-key/source-code-after',
6666
[
67-
'/Database \(MAJOR\)/',
68-
'/unit_test_table\/FL_ALLOWED_SEVERITIES\s*\|\s*Foreign key was removed\s*\|\s*M108/'
67+
'#Database \(MAJOR\)#',
68+
'#Console/Command/CompareSourceCommandTest/_files/db_schema/drop-foreign-key/source-code-before/Magento/DbSchema/etc/db_schema\.xml:0#',
69+
'#unit_test_table/FL_ALLOWED_SEVERITIES\s*\|\s*Foreign key was removed\s*\|\s*M108#',
70+
'#Console/Command/CompareSourceCommandTest/_files/db_schema/drop-foreign-key/source-code-before/Magento/DbSchema/etc/db_schema_whitelist\.json:0 \| unit_test_table/constraint#',
71+
'#unit_test_table/constraint\s*\|\s*Module db schema whitelist reduced \(unit_test_table/constraint\)#'
6972
],
7073
'Major change is detected.'
7174
],
7275
'change-foreign-key' => [
7376
$pathToFixtures . '/change-foreign-key/source-code-before',
7477
$pathToFixtures . '/change-foreign-key/source-code-after',
7578
[
76-
'/Database \(MAJOR\)/',
77-
'/unit_test_table\/FL_ALLOWED_SEVERITIES\/referenceTable\s*\|\s*Foreign key was changed\s*\|\s*M205/'
79+
'#Database \(MAJOR\)#',
80+
'#Console/Command/CompareSourceCommandTest/_files/db_schema/change-foreign-key/source-code-before/Magento/DbSchema/etc/db_schema\.xml:0#',
81+
'#unit_test_table/FL_ALLOWED_SEVERITIES/referenceTable\s*\|\s*Foreign key was changed\s*\|\s*M205#'
7882
],
7983
'Major change is detected.'
8084
],
8185
'add-foreign-key' => [
8286
$pathToFixtures . '/add-foreign-key/source-code-before',
8387
$pathToFixtures . '/add-foreign-key/source-code-after',
8488
[
85-
'/Database \(MAJOR\)/',
86-
'/unit_test_table\/FL_ALLOWED_SEVERITIES\s*\|\s*Foreign key was added\s*\|\s*M204/'
89+
'#Database \(MAJOR\)#',
90+
'#Console/Command/CompareSourceCommandTest/_files/db_schema/add-foreign-key/source-code-after/Magento/DbSchema/etc/db_schema\.xml:0#',
91+
'#unit_test_table/FL_ALLOWED_SEVERITIES\s*\|\s*Foreign key was added\s*\|\s*M204#'
8792
],
8893
'Major change is detected.'
8994
],
9095
'drop-primary-key' => [
9196
$pathToFixtures . '/drop-primary-key/source-code-before',
9297
$pathToFixtures . '/drop-primary-key/source-code-after',
9398
[
94-
'/Database \(MAJOR\)/',
95-
'/unit_test_table\/PRIMARY\s*\|\s*Primary key was removed\s*\|\s*M207/'
99+
'#Database \(MAJOR\)#',
100+
'#Console/Command/CompareSourceCommandTest/_files/db_schema/drop-primary-key/source-code-before/Magento/DbSchema/etc/db_schema\.xml:0#',
101+
'#Console/Command/CompareSourceCommandTest/_files/db_schema/drop-primary-key/source-code-before/Magento/DbSchema/etc/db_schema_whitelist.json:0#',
102+
'#unit_test_table\s*\|\s*Module db schema whitelist reduced \(unit_test_table\)\.\s*\|\s*M110#',
103+
'#unit_test_table/PRIMARY\s*\|\s*Primary key was removed\s*\|\s*M207#'
96104
],
97105
'Major change is detected.'
98106
],
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
<?php
2+
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
8+
namespace Magento\SemanticVersionChecker\Test\Unit\Console\Command\CompareSourceCommandTest;
9+
10+
use \DOMDocument;
11+
use DOMXPath;
12+
use Exception;
13+
use Magento\SemanticVersionChecker\Console\Command\CompareSourceCommand;
14+
use PHPSemVerChecker\SemanticVersioning\Level;
15+
use PHPUnit\Framework\TestCase;
16+
use Symfony\Component\Console\Tester\CommandTester;
17+
18+
/**
19+
* Defines an abstract base class for testing
20+
* {@link \Magento\SemanticVersionChecker\Console\Command\CompareSourceCommand}.
21+
*/
22+
abstract class AbstractHtmlTestCaseForHtml extends TestCase
23+
{
24+
/**
25+
* @var CompareSourceCommand
26+
*/
27+
protected $command;
28+
29+
/**
30+
* @var string
31+
*/
32+
protected $svcLogPath;
33+
34+
protected function setUp()
35+
{
36+
$this->command = new CompareSourceCommand();
37+
$this->svcLogPath = TESTS_TEMP_DIR . '/svc-' . time() . '.html';
38+
}
39+
40+
protected function tearDown()
41+
{
42+
parent::tearDown();
43+
unlink($this->svcLogPath);
44+
}
45+
46+
/**
47+
* Executes the command that shall be tested and performs assertions.
48+
*
49+
* 1. Run semantic version checker command to compare 2 source code directories
50+
* 2. Assert that SVC log contains expected entries
51+
* 3. Assert console output
52+
* 4. Assert return code
53+
*
54+
* @param string $pathToSourceCodeBefore
55+
* @param string $pathToSourceCodeAfter
56+
* @param $allowedChangeLevel
57+
* @param HtmlParseInfoContainer[] $expectedHtmlEntries
58+
* @param array $expectedPackageSection
59+
* @param string $expectedOutput
60+
* @param $expectedStatusCode
61+
* @param bool $shouldSkipTest
62+
* @throws Exception
63+
*/
64+
protected function doTestExecute(
65+
$pathToSourceCodeBefore,
66+
$pathToSourceCodeAfter,
67+
$allowedChangeLevel,
68+
$expectedHtmlEntries,
69+
$expectedPackageSection,
70+
$expectedOutput,
71+
$expectedStatusCode,
72+
$shouldSkipTest
73+
): void {
74+
try {
75+
$commandTester = $this->executeCommand($pathToSourceCodeBefore, $pathToSourceCodeAfter, $allowedChangeLevel);
76+
$svcDom = $this->getSvcReportDOM();
77+
self::assertJsonContent($expectedPackageSection, $svcDom);
78+
foreach ($expectedHtmlEntries as $expectedHtmlEntry) {
79+
$this->assertHtml($expectedHtmlEntry->xpath, $expectedHtmlEntry->pattern, $svcDom);
80+
}
81+
$this->assertContains($expectedOutput, $commandTester->getDisplay());
82+
$this->assertEquals($expectedStatusCode, $commandTester->getStatusCode());
83+
} catch (Exception $e) {
84+
if ($shouldSkipTest) {
85+
$this->markTestSkipped($e->getMessage());
86+
} else {
87+
throw $e;
88+
}
89+
}
90+
}
91+
92+
private static function assertJsonContent(array $expectedJson, DOMDocument $docDom) {
93+
if (!$expectedJson) {
94+
$xpathQuery = '/html/body/table/tbody/tr[last()]/td[2]';
95+
$pattern = '#No BIC changes found to packages#i';
96+
self::assertHtml($xpathQuery, $pattern, $docDom);
97+
} else {
98+
$docXpath = new DOMXPath($docDom);
99+
$xpathQuery = '//*[@id="packageChangesJson"]/text()';
100+
static::assertHtml($xpathQuery, null, $docDom);
101+
$jsonText = $docDom->saveHTML($docXpath->query($xpathQuery)->item(0));
102+
$encodedJson = json_decode($jsonText);
103+
//store expectedJson in same format
104+
$expectedJson = json_decode(json_encode($expectedJson));
105+
self::assertEquals(sort($expectedJson), sort($encodedJson));
106+
}
107+
}
108+
109+
/**
110+
* Assert HTML document resolves xpath, finding pattern, or finding pattern within resolving xpath
111+
* @param HtmlParseInfoContainer $container
112+
* @param DOMXPath $docXpath
113+
*/
114+
public static function assertHtml(?string $xpathQuery, ?string $pattern, DOMDocument $docDom) {
115+
$docXpath = new DOMXPath($docDom);
116+
117+
if ($xpathQuery) {
118+
$nodeList = $docXpath->query($xpathQuery);
119+
if (!$nodeList || !$nodeList->length) {
120+
$body = $docXpath->document->saveHTML();
121+
static::fail('xpath selector: ' . $xpathQuery . " was invalid. Unable to return result from document:\n" . $body); //throws exception
122+
}
123+
$body = $docDom->saveHTML($nodeList->item(-1));
124+
}
125+
else {
126+
$body = $docXpath->document->saveHTML();
127+
}
128+
if ($pattern) {
129+
static::assertRegExp($pattern, $body);
130+
}
131+
}
132+
133+
134+
/**
135+
* Executes {@link CompareSourceCommandTest::$command} via {@link CommandTester}, using the arguments as command
136+
* line parameters.
137+
*
138+
* The command line parameters are specified as follows:
139+
* <ul>
140+
* <li><kbd>source-before</kbd>: The content of the argument <var>$pathToSourceCodeBefore</var></li>
141+
* <li><kbd>source-after</kbd>: The content of the argument <var>$pathToSourceCodeAfter</var></li>
142+
* <li><kbd>--log-output-location</kbd>: The content of {@link CompareSourceCommandTest::$svcLogPath}</li>
143+
* <li><kbd>--include-patterns</kbd>: The path to the file <kbd>./_files/application_includes.txt</kbd></li>
144+
* </ul>
145+
*
146+
* @param $pathToSourceCodeBefore
147+
* @param $pathToSourceCodeAfter
148+
* @param $allowedChangeLevel
149+
* @return CommandTester
150+
*/
151+
protected function executeCommand($pathToSourceCodeBefore, $pathToSourceCodeAfter, $allowedChangeLevel): CommandTester
152+
{
153+
$commandTester = new CommandTester($this->command);
154+
$commandTester->execute(
155+
[
156+
'source-before' => $pathToSourceCodeBefore,
157+
'source-after' => $pathToSourceCodeAfter,
158+
'--log-output-location' => $this->svcLogPath,
159+
'--include-patterns' => __DIR__ . '/_files/application_includes.txt',
160+
'allowed-change-level' => $allowedChangeLevel,
161+
]
162+
);
163+
return $commandTester;
164+
}
165+
166+
/**
167+
* Returns the contents of the file specified in {@link CompareSourceCommandTest::$svcLogPath}.
168+
*
169+
* @return DOMDocument
170+
*/
171+
private function getSvcReportDOM() : ?DOMDocument
172+
{
173+
$source = file_get_contents($this->svcLogPath);
174+
if (!$source) {
175+
return null;
176+
}
177+
$doc = new DOMDocument();
178+
$doc->loadHTML($source);
179+
return $doc;
180+
}
181+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
namespace Magento\SemanticVersionChecker\Test\Unit\Console\Command\CompareSourceCommandTest;
8+
9+
class HtmlParseInfoContainer
10+
{
11+
/**
12+
* @var string|null
13+
*/
14+
public $xpath;
15+
16+
/**
17+
* @var string|null
18+
*/
19+
public $pattern;
20+
21+
const checkOnlyFirstXPathMatch = 0;
22+
const checkAllXpathMatches = 1;
23+
24+
/**
25+
* @var bool
26+
*/
27+
public $isRegex;
28+
29+
/**
30+
* @var int
31+
*/
32+
public $xpathSearchType;
33+
34+
public function __construct(?string $pattern,
35+
?string $xpath = null,
36+
bool $isRegex = false,
37+
int $xpathSearchType = self::checkOnlyFirstXPathMatch)
38+
{
39+
$this->xpath = $xpath;
40+
$this->pattern = $pattern;
41+
$this->isRegex = $isRegex;
42+
$this->xpathSearchType = $xpathSearchType;
43+
}
44+
45+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
/**
3+
*
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
namespace Test\Vcs;
8+
9+
/**
10+
* @api
11+
*/
12+
class TestClass extends TestClassBase
13+
{
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
/**
3+
*
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
namespace Test\Vcs;
8+
9+
class TestClassBase
10+
{
11+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "test/api-class",
3+
"description": "module composer package"
4+
}

0 commit comments

Comments
 (0)