PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/web/core/tests/Drupal/KernelTests/Core/Database/LoggingTest.php

https://gitlab.com/mohamed_hussein/prodt
PHP | 332 lines | 222 code | 41 blank | 69 comment | 0 complexity | c581dd4ef0d876c30d6865808dc33794 MD5 | raw file
  1. <?php
  2. namespace Drupal\KernelTests\Core\Database;
  3. use Drupal\Core\Database\Log;
  4. use Drupal\Core\Database\Database;
  5. /**
  6. * Tests the query logging facility.
  7. *
  8. * @coversDefaultClass \Drupal\Core\Database\Log
  9. *
  10. * @group Database
  11. */
  12. class LoggingTest extends DatabaseTestBase {
  13. /**
  14. * Tests that we can log the existence of a query.
  15. */
  16. public function testEnableLogging() {
  17. Database::startLog('testing');
  18. $start = microtime(TRUE);
  19. $this->connection->query('SELECT [name] FROM {test} WHERE [age] > :age', [':age' => 25])->fetchCol();
  20. $this->connection->query('SELECT [age] FROM {test} WHERE [name] = :name', [':name' => 'Ringo'])->fetchCol();
  21. // Trigger a call that does not have file in the backtrace.
  22. call_user_func_array([Database::getConnection(), 'query'], ['SELECT [age] FROM {test} WHERE [name] = :name', [':name' => 'Ringo']])->fetchCol();
  23. $queries = Database::getLog('testing', 'default');
  24. $this->assertCount(3, $queries, 'Correct number of queries recorded.');
  25. foreach ($queries as $query) {
  26. $this->assertEquals(__FUNCTION__, $query['caller']['function'], 'Correct function in query log.');
  27. $this->assertIsFloat($query['start']);
  28. $this->assertGreaterThanOrEqual($start, $query['start']);
  29. }
  30. }
  31. /**
  32. * Tests that we can run two logs in parallel.
  33. */
  34. public function testEnableMultiLogging() {
  35. Database::startLog('testing1');
  36. $this->connection->query('SELECT [name] FROM {test} WHERE [age] > :age', [':age' => 25])->fetchCol();
  37. Database::startLog('testing2');
  38. $this->connection->query('SELECT [age] FROM {test} WHERE [name] = :name', [':name' => 'Ringo'])->fetchCol();
  39. $queries1 = Database::getLog('testing1');
  40. $queries2 = Database::getLog('testing2');
  41. $this->assertCount(2, $queries1, 'Correct number of queries recorded for log 1.');
  42. $this->assertCount(1, $queries2, 'Correct number of queries recorded for log 2.');
  43. }
  44. /**
  45. * Tests logging queries against multiple targets on the same connection.
  46. */
  47. public function testEnableTargetLogging() {
  48. // Clone the primary credentials to a replica connection and to another fake
  49. // connection.
  50. $connection_info = Database::getConnectionInfo('default');
  51. Database::addConnectionInfo('default', 'replica', $connection_info['default']);
  52. Database::startLog('testing1');
  53. $this->connection->query('SELECT [name] FROM {test} WHERE [age] > :age', [':age' => 25])->fetchCol();
  54. Database::getConnection('replica')->query('SELECT [age] FROM {test} WHERE [name] = :name', [':name' => 'Ringo'])->fetchCol();
  55. $queries1 = Database::getLog('testing1');
  56. $this->assertCount(2, $queries1, 'Recorded queries from all targets.');
  57. $this->assertEquals('default', $queries1[0]['target'], 'First query used default target.');
  58. $this->assertEquals('replica', $queries1[1]['target'], 'Second query used replica target.');
  59. }
  60. /**
  61. * Tests that logs to separate targets use the same connection properly.
  62. *
  63. * This test is identical to the one above, except that it doesn't create
  64. * a fake target so the query should fall back to running on the default
  65. * target.
  66. */
  67. public function testEnableTargetLoggingNoTarget() {
  68. Database::startLog('testing1');
  69. $this->connection->query('SELECT [name] FROM {test} WHERE [age] > :age', [':age' => 25])->fetchCol();
  70. // We use "fake" here as a target because any non-existent target will do.
  71. // However, because all of the tests in this class share a single page
  72. // request there is likely to be a target of "replica" from one of the other
  73. // unit tests, so we use a target here that we know with absolute certainty
  74. // does not exist.
  75. Database::getConnection('fake')->query('SELECT [age] FROM {test} WHERE [name] = :name', [':name' => 'Ringo'])->fetchCol();
  76. $queries1 = Database::getLog('testing1');
  77. $this->assertCount(2, $queries1, 'Recorded queries from all targets.');
  78. $this->assertEquals('default', $queries1[0]['target'], 'First query used default target.');
  79. $this->assertEquals('default', $queries1[1]['target'], 'Second query used default target as fallback.');
  80. }
  81. /**
  82. * Tests that we can log queries separately on different connections.
  83. */
  84. public function testEnableMultiConnectionLogging() {
  85. // Clone the primary credentials to a fake connection.
  86. // That both connections point to the same physical database is irrelevant.
  87. $connection_info = Database::getConnectionInfo('default');
  88. Database::addConnectionInfo('test2', 'default', $connection_info['default']);
  89. Database::startLog('testing1');
  90. Database::startLog('testing1', 'test2');
  91. $this->connection->query('SELECT [name] FROM {test} WHERE [age] > :age', [':age' => 25])->fetchCol();
  92. $old_key = Database::setActiveConnection('test2');
  93. Database::getConnection('replica')->query('SELECT [age] FROM {test} WHERE [name] = :name', [':name' => 'Ringo'])->fetchCol();
  94. Database::setActiveConnection($old_key);
  95. $queries1 = Database::getLog('testing1');
  96. $queries2 = Database::getLog('testing1', 'test2');
  97. $this->assertCount(1, $queries1, 'Correct number of queries recorded for first connection.');
  98. $this->assertCount(1, $queries2, 'Correct number of queries recorded for second connection.');
  99. }
  100. /**
  101. * Tests that getLog with a wrong key return an empty array.
  102. */
  103. public function testGetLoggingWrongKey() {
  104. $result = Database::getLog('wrong');
  105. $this->assertEquals([], $result, 'The function getLog with a wrong key returns an empty array.');
  106. }
  107. /**
  108. * Tests that a log called by a custom database driver returns proper caller.
  109. *
  110. * @param string $driver_namespace
  111. * The driver namespace to be tested.
  112. * @param string $stack
  113. * A test debug_backtrace stack.
  114. * @param array $expected_entry
  115. * The expected stack entry.
  116. *
  117. * @covers ::findCaller
  118. *
  119. * @dataProvider providerContribDriverLog
  120. */
  121. public function testContribDriverLog($driver_namespace, $stack, array $expected_entry) {
  122. $mock_builder = $this->getMockBuilder(Log::class);
  123. $log = $mock_builder
  124. ->onlyMethods(['getDebugBacktrace'])
  125. ->setConstructorArgs(['test'])
  126. ->getMock();
  127. $log->expects($this->once())
  128. ->method('getDebugBacktrace')
  129. ->will($this->returnValue($stack));
  130. Database::addConnectionInfo('test', 'default', ['driver' => 'mysql', 'namespace' => $driver_namespace]);
  131. $result = $log->findCaller($stack);
  132. $this->assertEquals($expected_entry, $result);
  133. }
  134. /**
  135. * Provides data for the testContribDriverLog test.
  136. *
  137. * @return array[]
  138. * A associative array of simple arrays, each having the following elements:
  139. * - the contrib driver PHP namespace
  140. * - a test debug_backtrace stack
  141. * - the stack entry expected to be returned.
  142. *
  143. * @see ::testContribDriverLog()
  144. */
  145. public function providerContribDriverLog() {
  146. $stack = [
  147. [
  148. 'file' => '/var/www/core/lib/Drupal/Core/Database/Log.php',
  149. 'line' => 125,
  150. 'function' => 'findCaller',
  151. 'class' => 'Drupal\\Core\\Database\\Log',
  152. 'object' => 'test',
  153. 'type' => '->',
  154. 'args' => [
  155. 0 => 'test',
  156. ],
  157. ],
  158. [
  159. 'file' => '/var/www/libraries/drudbal/lib/Statement.php',
  160. 'line' => 264,
  161. 'function' => 'log',
  162. 'class' => 'Drupal\\Core\\Database\\Log',
  163. 'object' => 'test',
  164. 'type' => '->',
  165. 'args' => [
  166. 0 => 'test',
  167. ],
  168. ],
  169. [
  170. 'file' => '/var/www/libraries/drudbal/lib/Connection.php',
  171. 'line' => 213,
  172. 'function' => 'execute',
  173. 'class' => 'Drupal\\Driver\\Database\\dbal\\Statement',
  174. 'object' => 'test',
  175. 'type' => '->',
  176. 'args' => [
  177. 0 => 'test',
  178. ],
  179. ],
  180. [
  181. 'file' => '/var/www/core/tests/Drupal/KernelTests/Core/Database/LoggingTest.php',
  182. 'line' => 23,
  183. 'function' => 'query',
  184. 'class' => 'Drupal\\Driver\\Database\\dbal\\Connection',
  185. 'object' => 'test',
  186. 'type' => '->',
  187. 'args' => [
  188. 0 => 'test',
  189. ],
  190. ],
  191. [
  192. 'file' => '/var/www/vendor/phpunit/phpunit/src/Framework/TestCase.php',
  193. 'line' => 1154,
  194. 'function' => 'testEnableLogging',
  195. 'class' => 'Drupal\\KernelTests\\Core\\Database\\LoggingTest',
  196. 'object' => 'test',
  197. 'type' => '->',
  198. 'args' => [
  199. 0 => 'test',
  200. ],
  201. ],
  202. [
  203. 'file' => '/var/www/vendor/phpunit/phpunit/src/Framework/TestCase.php',
  204. 'line' => 842,
  205. 'function' => 'runTest',
  206. 'class' => 'PHPUnit\\Framework\\TestCase',
  207. 'object' => 'test',
  208. 'type' => '->',
  209. 'args' => [
  210. 0 => 'test',
  211. ],
  212. ],
  213. [
  214. 'file' => '/var/www/vendor/phpunit/phpunit/src/Framework/TestResult.php',
  215. 'line' => 693,
  216. 'function' => 'runBare',
  217. 'class' => 'PHPUnit\\Framework\\TestCase',
  218. 'object' => 'test',
  219. 'type' => '->',
  220. 'args' => [
  221. 0 => 'test',
  222. ],
  223. ],
  224. [
  225. 'file' => '/var/www/vendor/phpunit/phpunit/src/Framework/TestCase.php',
  226. 'line' => 796,
  227. 'function' => 'run',
  228. 'class' => 'PHPUnit\\Framework\\TestResult',
  229. 'object' => 'test',
  230. 'type' => '->',
  231. 'args' => [
  232. 0 => 'test',
  233. ],
  234. ],
  235. [
  236. 'file' => 'Standard input code',
  237. 'line' => 57,
  238. 'function' => 'run',
  239. 'class' => 'PHPUnit\\Framework\\TestCase',
  240. 'object' => 'test',
  241. 'type' => '->',
  242. 'args' => [
  243. 0 => 'test',
  244. ],
  245. ],
  246. [
  247. 'file' => 'Standard input code',
  248. 'line' => 111,
  249. 'function' => '__phpunit_run_isolated_test',
  250. 'args' => [
  251. 0 => 'test',
  252. ],
  253. ],
  254. ];
  255. return [
  256. // Test that if the driver namespace is in the stack trace, the first
  257. // non-database entry is returned.
  258. 'contrib driver namespace' => [
  259. 'Drupal\\Driver\\Database\\dbal',
  260. $stack,
  261. [
  262. 'class' => 'Drupal\\KernelTests\\Core\\Database\\LoggingTest',
  263. 'function' => 'testEnableLogging',
  264. 'file' => '/var/www/core/tests/Drupal/KernelTests/Core/Database/LoggingTest.php',
  265. 'line' => 23,
  266. 'type' => '->',
  267. 'args' => [
  268. 0 => 'test',
  269. ],
  270. ],
  271. ],
  272. // Extreme case, should not happen at normal runtime - if the driver
  273. // namespace is not in the stack trace, the first entry to a method
  274. // in core database namespace is returned.
  275. 'missing driver namespace' => [
  276. 'Drupal\\Driver\\Database\\fake',
  277. $stack,
  278. [
  279. 'class' => 'Drupal\\Driver\\Database\\dbal\\Statement',
  280. 'function' => 'execute',
  281. 'file' => '/var/www/libraries/drudbal/lib/Statement.php',
  282. 'line' => 264,
  283. 'type' => '->',
  284. 'args' => [
  285. 0 => 'test',
  286. ],
  287. ],
  288. ],
  289. ];
  290. }
  291. }