1 | <?php |
||||||||
2 | |||||||||
3 | namespace Mautic\CoreBundle\Test; |
||||||||
4 | |||||||||
5 | use Exception; |
||||||||
6 | use LogicException; |
||||||||
7 | use Mautic\InstallBundle\InstallFixtures\ORM\LeadFieldData; |
||||||||
8 | use Mautic\InstallBundle\InstallFixtures\ORM\RoleData; |
||||||||
9 | use Mautic\UserBundle\DataFixtures\ORM\LoadRoleData; |
||||||||
10 | use Mautic\UserBundle\DataFixtures\ORM\LoadUserData; |
||||||||
11 | |||||||||
12 | abstract class MauticMysqlTestCase extends AbstractMauticTestCase |
||||||||
13 | { |
||||||||
14 | /** |
||||||||
15 | * @var bool |
||||||||
16 | */ |
||||||||
17 | private static $databasePrepared = false; |
||||||||
18 | |||||||||
19 | /** |
||||||||
20 | * Use transaction rollback for cleanup. Sometimes it is not possible to use it because of the following: |
||||||||
21 | * 1. A query that alters a DB schema causes an open transaction being committed immediately. |
||||||||
22 | * 2. Full-text search does not see uncommitted changes. |
||||||||
23 | * |
||||||||
24 | * @var bool |
||||||||
25 | */ |
||||||||
26 | protected $useCleanupRollback = true; |
||||||||
27 | |||||||||
28 | /** |
||||||||
29 | * @throws Exception |
||||||||
30 | */ |
||||||||
31 | protected function setUp(): void |
||||||||
32 | { |
||||||||
33 | parent::setUp(); |
||||||||
34 | |||||||||
35 | if (!self::$databasePrepared) { |
||||||||
36 | $this->prepareDatabase(); |
||||||||
37 | self::$databasePrepared = true; |
||||||||
38 | } |
||||||||
39 | |||||||||
40 | if ($this->useCleanupRollback) { |
||||||||
41 | $this->beforeBeginTransaction(); |
||||||||
42 | $this->connection->beginTransaction(); |
||||||||
43 | } |
||||||||
44 | } |
||||||||
45 | |||||||||
46 | protected function tearDown(): void |
||||||||
47 | { |
||||||||
48 | if ($this->useCleanupRollback) { |
||||||||
49 | if ($this->connection->isTransactionActive()) { |
||||||||
50 | $this->connection->rollback(); |
||||||||
51 | } |
||||||||
52 | } else { |
||||||||
53 | $this->prepareDatabase(); |
||||||||
54 | } |
||||||||
55 | |||||||||
56 | parent::tearDown(); |
||||||||
57 | } |
||||||||
58 | |||||||||
59 | /** |
||||||||
60 | * Override this method to execute some logic right before the transaction begins. |
||||||||
61 | */ |
||||||||
62 | protected function beforeBeginTransaction(): void |
||||||||
63 | { |
||||||||
64 | } |
||||||||
65 | |||||||||
66 | protected function setUpSymfony(array $defaultConfigOptions = []): void |
||||||||
67 | { |
||||||||
68 | if ($this->useCleanupRollback && $this->client) { |
||||||||
69 | throw new LogicException('You cannot re-create the client when a transaction rollback for cleanup is enabled. Turn it off using $useCleanupRollback property or avoid re-creating a client.'); |
||||||||
70 | } |
||||||||
71 | |||||||||
72 | parent::setUpSymfony($defaultConfigOptions); |
||||||||
73 | } |
||||||||
74 | |||||||||
75 | /** |
||||||||
76 | * Helper method that eases resetting auto increment values for passed $tables. |
||||||||
77 | * You should avoid using this method as relying on fixed auto-increment values makes tests more fragile. |
||||||||
78 | * For example, you should never assume that IDs of first three records are always 1, 2 and 3. |
||||||||
79 | * |
||||||||
80 | * @throws \Doctrine\DBAL\DBALException |
||||||||
81 | */ |
||||||||
82 | protected function resetAutoincrement(array $tables): void |
||||||||
83 | { |
||||||||
84 | $prefix = $this->container->getParameter('mautic.db_table_prefix'); |
||||||||
85 | $connection = $this->connection; |
||||||||
86 | |||||||||
87 | foreach ($tables as $table) { |
||||||||
88 | $connection->query(sprintf('ALTER TABLE `%s%s` AUTO_INCREMENT=1', $prefix, $table)); |
||||||||
89 | } |
||||||||
90 | } |
||||||||
91 | |||||||||
92 | /** |
||||||||
93 | * @param $file |
||||||||
94 | * |
||||||||
95 | * @throws Exception |
||||||||
96 | */ |
||||||||
97 | private function applySqlFromFile($file) |
||||||||
98 | { |
||||||||
99 | $connection = $this->connection; |
||||||||
100 | $password = ($connection->getPassword()) ? " -p{$connection->getPassword()}" : ''; |
||||||||
101 | $command = "mysql -h{$connection->getHost()} -P{$connection->getPort()} -u{$connection->getUsername()}$password {$connection->getDatabase()} < {$file} 2>&1 | grep -v \"Using a password\" || true"; |
||||||||
102 | |||||||||
103 | $lastLine = system($command, $status); |
||||||||
104 | |||||||||
105 | if (0 !== $status) { |
||||||||
106 | throw new Exception($command.' failed with status code '.$status.' and last line of "'.$lastLine.'"'); |
||||||||
107 | } |
||||||||
108 | } |
||||||||
109 | |||||||||
110 | /** |
||||||||
111 | * Reset each test using a SQL file if possible to prevent from having to run the fixtures over and over. |
||||||||
112 | * |
||||||||
113 | * @throws Exception |
||||||||
114 | */ |
||||||||
115 | private function prepareDatabase() |
||||||||
116 | { |
||||||||
117 | if (!function_exists('system')) { |
||||||||
118 | $this->installDatabase(); |
||||||||
119 | |||||||||
120 | return; |
||||||||
121 | } |
||||||||
122 | |||||||||
123 | $sqlDumpFile = $this->container->getParameter('kernel.cache_dir').'/fresh_db.sql'; |
||||||||
124 | |||||||||
125 | if (!file_exists($sqlDumpFile)) { |
||||||||
126 | $this->installDatabase(); |
||||||||
127 | $this->dumpToFile($sqlDumpFile); |
||||||||
128 | |||||||||
129 | return; |
||||||||
130 | } |
||||||||
131 | |||||||||
132 | $this->applySqlFromFile($sqlDumpFile); |
||||||||
133 | } |
||||||||
134 | |||||||||
135 | /** |
||||||||
136 | * @throws Exception |
||||||||
137 | */ |
||||||||
138 | private function installDatabase() |
||||||||
139 | { |
||||||||
140 | $this->createDatabase(); |
||||||||
141 | $this->applyMigrations(); |
||||||||
142 | $this->installDatabaseFixtures([LeadFieldData::class, RoleData::class, LoadRoleData::class, LoadUserData::class]); |
||||||||
143 | } |
||||||||
144 | |||||||||
145 | /** |
||||||||
146 | * @throws Exception |
||||||||
147 | */ |
||||||||
148 | private function createDatabase() |
||||||||
149 | { |
||||||||
150 | $this->runCommand( |
||||||||
151 | 'doctrine:database:drop', |
||||||||
152 | [ |
||||||||
153 | '--env' => 'test', |
||||||||
154 | '--force' => true, |
||||||||
155 | ] |
||||||||
156 | ); |
||||||||
157 | |||||||||
158 | $this->runCommand( |
||||||||
159 | 'doctrine:database:create', |
||||||||
160 | [ |
||||||||
161 | '--env' => 'test', |
||||||||
162 | ] |
||||||||
163 | ); |
||||||||
164 | |||||||||
165 | $this->runCommand( |
||||||||
166 | 'doctrine:schema:create', |
||||||||
167 | [ |
||||||||
168 | '--env' => 'test', |
||||||||
169 | ] |
||||||||
170 | ); |
||||||||
171 | } |
||||||||
172 | |||||||||
173 | /** |
||||||||
174 | * @throws Exception |
||||||||
175 | */ |
||||||||
176 | private function dumpToFile(string $sqlDumpFile): void |
||||||||
177 | { |
||||||||
178 | $password = ($this->connection->getPassword()) ? " -p{$this->connection->getPassword()}" : ''; |
||||||||
0 ignored issues
–
show
Deprecated Code
introduced
by
Loading history...
|
|||||||||
179 | $command = "mysqldump --add-drop-table --opt -h{$this->connection->getHost()} -P{$this->connection->getPort()} -u{$this->connection->getUsername()}$password {$this->connection->getDatabase()} > {$sqlDumpFile} 2>&1 | grep -v \"Using a password\" || true"; |
||||||||
0 ignored issues
–
show
The function
Doctrine\DBAL\Connection::getHost() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
The function
Doctrine\DBAL\Connection::getPort() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
The function
Doctrine\DBAL\Connection::getUsername() has been deprecated.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||||
180 | |||||||||
181 | $lastLine = system($command, $status); |
||||||||
182 | if (0 !== $status) { |
||||||||
183 | throw new Exception($command.' failed with status code '.$status.' and last line of "'.$lastLine.'"'); |
||||||||
184 | } |
||||||||
185 | |||||||||
186 | $f = fopen($sqlDumpFile, 'r'); |
||||||||
187 | $firstLine = fgets($f); |
||||||||
188 | if (false !== strpos($firstLine, 'Using a password')) { |
||||||||
189 | $file = file($sqlDumpFile); |
||||||||
190 | unset($file[0]); |
||||||||
191 | file_put_contents($sqlDumpFile, $file); |
||||||||
192 | } |
||||||||
193 | fclose($f); |
||||||||
194 | } |
||||||||
195 | } |
||||||||
196 |