Skip to content

Commit 2383c4c

Browse files
authored
Merge pull request #128 from magento-arcticfoxes/B2B-1671
B2B-1671: Detect Missing Primary Key in Table Schema Test
2 parents cd857f9 + b43c4aa commit 2383c4c

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Test\Integrity\DBSchema;
10+
11+
use Magento\Framework\App\Utility\Files;
12+
use Magento\Framework\Exception\LocalizedException;
13+
use Magento\Framework\Setup\Declaration\Schema\Config\Converter;
14+
use PHPUnit\Framework\TestCase;
15+
16+
/**
17+
* Test for finding database tables missing primary key
18+
*/
19+
class PrimaryKeyTest extends TestCase
20+
{
21+
/**
22+
* Check missing database tables' primary key
23+
*
24+
* @throws LocalizedException
25+
*/
26+
public function testMissingPrimaryKey()
27+
{
28+
$exemptionList = $this->getExemptionList();
29+
$tablesSchemaDeclaration = $this->getDbSchemaDeclarations()['table'];
30+
$exemptionList = array_intersect(array_keys($tablesSchemaDeclaration), $exemptionList);
31+
foreach ($exemptionList as $exemptionTableName) {
32+
unset($tablesSchemaDeclaration[$exemptionTableName]);
33+
}
34+
$errorMessage = '';
35+
$failedTableCtr = 0;
36+
foreach ($tablesSchemaDeclaration as $tableName => $tableSchemaDeclaration) {
37+
if (!$this->hasPrimaryKey($tableSchemaDeclaration)) {
38+
$message = '';
39+
if (!empty($tableSchemaDeclaration['modules'])) {
40+
$message = "It is declared in the following modules: \n" . implode(
41+
"\t\n",
42+
$tableSchemaDeclaration['modules']
43+
);
44+
}
45+
$errorMessage .= 'Table ' . $tableName . ' does not have primary key. ' . $message . "\n";
46+
$failedTableCtr ++;
47+
}
48+
}
49+
if (!empty($errorMessage)) {
50+
$errorMessage .= "\n\nTotal " . $failedTableCtr . " tables failed";
51+
$this->fail($errorMessage);
52+
}
53+
}
54+
55+
/**
56+
* Check table schema and verify if the table has primary key defined.
57+
*
58+
* @param array $tableSchemaDeclaration
59+
* @return bool
60+
*/
61+
private function hasPrimaryKey(array $tableSchemaDeclaration): bool
62+
{
63+
if (isset($tableSchemaDeclaration['constraint'])) {
64+
foreach ($tableSchemaDeclaration['constraint'] as $constraint) {
65+
if ($constraint['type'] == 'primary') {
66+
return true;
67+
}
68+
}
69+
}
70+
return false;
71+
}
72+
73+
/**
74+
* Get database schema declarations from file.
75+
*
76+
* @param string $filePath
77+
* @return array
78+
*/
79+
private function getDbSchemaDeclarationByFile(string $filePath): array
80+
{
81+
$dom = new \DOMDocument();
82+
$dom->loadXML(file_get_contents($filePath));
83+
return (new Converter())->convert($dom);
84+
}
85+
86+
/**
87+
* Get database schema declarations for whole application
88+
*
89+
* @return array
90+
* @throws LocalizedException
91+
*/
92+
private function getDbSchemaDeclarations(): array
93+
{
94+
$declarations = [];
95+
foreach (Files::init()->getDbSchemaFiles() as $filePath) {
96+
$filePath = reset($filePath);
97+
preg_match('#/(\w+/\w+)/etc/db_schema.xml#', $filePath, $result);
98+
$moduleName = str_replace('/', '_', $result[1]);
99+
$moduleDeclaration = $this->getDbSchemaDeclarationByFile($filePath);
100+
101+
foreach ($moduleDeclaration['table'] as $tableName => $tableDeclaration) {
102+
if (!isset($tableDeclaration['modules'])) {
103+
$tableDeclaration['modules'] = [];
104+
}
105+
array_push($tableDeclaration['modules'], $moduleName);
106+
$moduleDeclaration = array_replace_recursive(
107+
$moduleDeclaration,
108+
[
109+
'table' => [
110+
$tableName => $tableDeclaration,
111+
]
112+
]
113+
);
114+
}
115+
$declarations = array_merge_recursive($declarations, $moduleDeclaration);
116+
}
117+
return $declarations;
118+
}
119+
120+
/**
121+
* Return primary key exemption tables list
122+
*
123+
* @return string[]
124+
*/
125+
private function getExemptionList(): array
126+
{
127+
$exemptionListFiles = str_replace(
128+
'\\',
129+
'/',
130+
realpath(__DIR__) . '/_files/primary_key_exemption_list*.txt'
131+
);
132+
$exemptionList = [];
133+
foreach (glob($exemptionListFiles) as $fileName) {
134+
$exemptionList[] = file($fileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
135+
}
136+
return array_merge([], ...$exemptionList);
137+
}
138+
}

dev/tests/static/testsuite/Magento/Test/Integrity/DBSchema/_files/primary_key_exemption_list.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)