LogTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. <?php
  2. /**
  3. * CakePHP(tm) <http://book.cakephp.org/2.0/en/development/testing.html>
  4. * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * Redistributions of files must retain the above copyright notice
  8. *
  9. * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
  11. * @since 1.2.0
  12. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  13. */
  14. namespace Cake\Test\TestCase\Log;
  15. use Cake\Core\App;
  16. use Cake\Core\Configure;
  17. use Cake\Core\Plugin;
  18. use Cake\Log\Engine\FileLog;
  19. use Cake\Log\Log;
  20. use Cake\TestSuite\TestCase;
  21. /**
  22. * LogTest class
  23. *
  24. */
  25. class LogTest extends TestCase {
  26. public function tearDown() {
  27. parent::tearDown();
  28. Log::reset();
  29. }
  30. /**
  31. * test importing loggers from app/libs and plugins.
  32. *
  33. * @return void
  34. */
  35. public function testImportingLoggers() {
  36. Configure::write('App.namespace', 'TestApp');
  37. Plugin::load('TestPlugin');
  38. Log::config('libtest', [
  39. 'engine' => 'TestApp'
  40. ]);
  41. Log::config('plugintest', [
  42. 'engine' => 'TestPlugin.TestPlugin'
  43. ]);
  44. $result = Log::engine('libtest');
  45. $this->assertInstanceOf('TestApp\Log\Engine\TestAppLog', $result);
  46. $this->assertContains('libtest', Log::configured());
  47. $result = Log::engine('plugintest');
  48. $this->assertInstanceOf('TestPlugin\Log\Engine\TestPluginLog', $result);
  49. $this->assertContains('libtest', Log::configured());
  50. $this->assertContains('plugintest', Log::configured());
  51. Log::write(LOG_INFO, 'TestPluginLog is not a BaseLog descendant');
  52. Plugin::unload();
  53. }
  54. /**
  55. * test all the errors from failed logger imports
  56. *
  57. * @expectedException \Cake\Error\Exception
  58. * @return void
  59. */
  60. public function testImportingLoggerFailure() {
  61. Log::config('fail', []);
  62. Log::engine('fail');
  63. }
  64. /**
  65. * test config() with valid key name
  66. *
  67. * @return void
  68. */
  69. public function testValidKeyName() {
  70. Log::config('valid', array('engine' => 'File'));
  71. $stream = Log::engine('valid');
  72. $this->assertInstanceOf('Cake\Log\Engine\FileLog', $stream);
  73. }
  74. /**
  75. * test that loggers have to implement the correct interface.
  76. *
  77. * @expectedException \Cake\Error\Exception
  78. * @return void
  79. */
  80. public function testNotImplementingInterface() {
  81. Log::config('fail', array('engine' => '\stdClass'));
  82. Log::engine('fail');
  83. }
  84. /**
  85. * explicit tests for drop()
  86. *
  87. * @return void
  88. **/
  89. public function testDrop() {
  90. Log::config('file', array(
  91. 'engine' => 'File',
  92. 'path' => LOGS
  93. ));
  94. $result = Log::configured();
  95. $this->assertContains('file', $result);
  96. $this->assertTrue(Log::drop('file'), 'Should be dropped');
  97. $this->assertFalse(Log::drop('file'), 'Already gone');
  98. $result = Log::configured();
  99. $this->assertNotContains('file', $result);
  100. }
  101. /**
  102. * test config() with valid key name
  103. *
  104. * @expectedException \Cake\Error\Exception
  105. * @return void
  106. */
  107. public function testInvalidLevel() {
  108. Log::config('myengine', array('engine' => 'File'));
  109. Log::write('invalid', 'This will not be logged');
  110. }
  111. /**
  112. * Provider for config() tests.
  113. *
  114. * @return array
  115. */
  116. public static function configProvider() {
  117. return [
  118. 'Array of data using engine key.' => [[
  119. 'engine' => 'File',
  120. 'path' => TMP . 'tests',
  121. ]],
  122. 'Array of data using classname key.' => [[
  123. 'className' => 'File',
  124. 'path' => TMP . 'tests',
  125. ]],
  126. 'Direct instance' => [new FileLog()],
  127. ];
  128. }
  129. /**
  130. * Test the various config call signatures.
  131. *
  132. * @dataProvider configProvider
  133. * @return void
  134. */
  135. public function testConfigVariants($settings) {
  136. Log::config('test', $settings);
  137. $this->assertContains('test', Log::configured());
  138. $this->assertInstanceOf('Cake\Log\Engine\FileLog', Log::engine('test'));
  139. Log::drop('test');
  140. }
  141. /**
  142. * Test that config() throws an exception when adding an
  143. * adapter with the wrong type.
  144. *
  145. * @expectedException \Cake\Error\Exception
  146. * @return void
  147. */
  148. public function testConfigInjectErrorOnWrongType() {
  149. Log::config('test', new \StdClass);
  150. Log::info('testing');
  151. }
  152. /**
  153. * Test that config() can read data back
  154. *
  155. * @return void
  156. */
  157. public function testConfigRead() {
  158. $config = [
  159. 'engine' => 'File',
  160. 'path' => LOGS
  161. ];
  162. Log::config('tests', $config);
  163. $expected = $config;
  164. $expected['className'] = $config['engine'];
  165. unset($expected['engine']);
  166. $this->assertSame($expected, Log::config('tests'));
  167. }
  168. /**
  169. * Ensure you cannot reconfigure a log adapter.
  170. *
  171. * @expectedException \Cake\Error\Exception
  172. * @return void
  173. */
  174. public function testConfigErrorOnReconfigure() {
  175. Log::config('tests', ['engine' => 'File', 'path' => TMP]);
  176. Log::config('tests', ['engine' => 'Apc']);
  177. }
  178. /**
  179. * testLogFileWriting method
  180. *
  181. * @return void
  182. */
  183. public function testLogFileWriting() {
  184. $this->_resetLogConfig();
  185. if (file_exists(LOGS . 'error.log')) {
  186. unlink(LOGS . 'error.log');
  187. }
  188. $result = Log::write(LOG_WARNING, 'Test warning');
  189. $this->assertTrue($result);
  190. $this->assertTrue(file_exists(LOGS . 'error.log'));
  191. unlink(LOGS . 'error.log');
  192. Log::write(LOG_WARNING, 'Test warning 1');
  193. Log::write(LOG_WARNING, 'Test warning 2');
  194. $result = file_get_contents(LOGS . 'error.log');
  195. $this->assertRegExp('/^2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Warning: Test warning 1/', $result);
  196. $this->assertRegExp('/2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Warning: Test warning 2$/', $result);
  197. unlink(LOGS . 'error.log');
  198. }
  199. /**
  200. * test selective logging by level/type
  201. *
  202. * @return void
  203. */
  204. public function testSelectiveLoggingByLevel() {
  205. if (file_exists(LOGS . 'spam.log')) {
  206. unlink(LOGS . 'spam.log');
  207. }
  208. if (file_exists(LOGS . 'eggs.log')) {
  209. unlink(LOGS . 'eggs.log');
  210. }
  211. Log::config('spam', array(
  212. 'engine' => 'File',
  213. 'types' => 'debug',
  214. 'file' => 'spam',
  215. ));
  216. Log::config('eggs', array(
  217. 'engine' => 'File',
  218. 'types' => array('eggs', 'debug', 'error', 'warning'),
  219. 'file' => 'eggs',
  220. ));
  221. $testMessage = 'selective logging';
  222. Log::write(LOG_WARNING, $testMessage);
  223. $this->assertTrue(file_exists(LOGS . 'eggs.log'));
  224. $this->assertFalse(file_exists(LOGS . 'spam.log'));
  225. Log::write(LOG_DEBUG, $testMessage);
  226. $this->assertTrue(file_exists(LOGS . 'spam.log'));
  227. $contents = file_get_contents(LOGS . 'spam.log');
  228. $this->assertContains('Debug: ' . $testMessage, $contents);
  229. $contents = file_get_contents(LOGS . 'eggs.log');
  230. $this->assertContains('Debug: ' . $testMessage, $contents);
  231. if (file_exists(LOGS . 'spam.log')) {
  232. unlink(LOGS . 'spam.log');
  233. }
  234. if (file_exists(LOGS . 'eggs.log')) {
  235. unlink(LOGS . 'eggs.log');
  236. }
  237. }
  238. protected function _resetLogConfig() {
  239. Log::config('debug', array(
  240. 'engine' => 'File',
  241. 'types' => array('notice', 'info', 'debug'),
  242. 'file' => 'debug',
  243. ));
  244. Log::config('error', array(
  245. 'engine' => 'File',
  246. 'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
  247. 'file' => 'error',
  248. ));
  249. }
  250. protected function _deleteLogs() {
  251. if (file_exists(LOGS . 'shops.log')) {
  252. unlink(LOGS . 'shops.log');
  253. }
  254. if (file_exists(LOGS . 'error.log')) {
  255. unlink(LOGS . 'error.log');
  256. }
  257. if (file_exists(LOGS . 'debug.log')) {
  258. unlink(LOGS . 'debug.log');
  259. }
  260. if (file_exists(LOGS . 'bogus.log')) {
  261. unlink(LOGS . 'bogus.log');
  262. }
  263. if (file_exists(LOGS . 'spam.log')) {
  264. unlink(LOGS . 'spam.log');
  265. }
  266. if (file_exists(LOGS . 'eggs.log')) {
  267. unlink(LOGS . 'eggs.log');
  268. }
  269. }
  270. /**
  271. * test scoped logging
  272. *
  273. * @return void
  274. */
  275. public function testScopedLogging() {
  276. $this->_deleteLogs();
  277. $this->_resetLogConfig();
  278. Log::config('shops', array(
  279. 'engine' => 'File',
  280. 'types' => array('info', 'notice', 'warning'),
  281. 'scopes' => array('transactions', 'orders'),
  282. 'file' => 'shops',
  283. ));
  284. Log::write('info', 'info message', 'transactions');
  285. $this->assertFalse(file_exists(LOGS . 'error.log'));
  286. $this->assertTrue(file_exists(LOGS . 'shops.log'));
  287. $this->assertTrue(file_exists(LOGS . 'debug.log'));
  288. $this->_deleteLogs();
  289. Log::write('warning', 'warning message', 'orders');
  290. $this->assertTrue(file_exists(LOGS . 'error.log'));
  291. $this->assertTrue(file_exists(LOGS . 'shops.log'));
  292. $this->assertFalse(file_exists(LOGS . 'debug.log'));
  293. $this->_deleteLogs();
  294. Log::write('error', 'error message', 'orders');
  295. $this->assertTrue(file_exists(LOGS . 'error.log'));
  296. $this->assertFalse(file_exists(LOGS . 'debug.log'));
  297. $this->assertFalse(file_exists(LOGS . 'shops.log'));
  298. $this->_deleteLogs();
  299. Log::drop('shops');
  300. }
  301. /**
  302. * test scoped logging with convenience methods
  303. */
  304. public function testConvenienceScopedLogging() {
  305. if (file_exists(LOGS . 'shops.log')) {
  306. unlink(LOGS . 'shops.log');
  307. }
  308. if (file_exists(LOGS . 'error.log')) {
  309. unlink(LOGS . 'error.log');
  310. }
  311. if (file_exists(LOGS . 'debug.log')) {
  312. unlink(LOGS . 'debug.log');
  313. }
  314. $this->_resetLogConfig();
  315. Log::config('shops', array(
  316. 'engine' => 'File',
  317. 'types' => array('info', 'debug', 'notice', 'warning'),
  318. 'scopes' => array('transactions', 'orders'),
  319. 'file' => 'shops',
  320. ));
  321. Log::info('info message', 'transactions');
  322. $this->assertFalse(file_exists(LOGS . 'error.log'));
  323. $this->assertTrue(file_exists(LOGS . 'shops.log'));
  324. $this->assertTrue(file_exists(LOGS . 'debug.log'));
  325. $this->_deleteLogs();
  326. Log::error('error message', 'orders');
  327. $this->assertTrue(file_exists(LOGS . 'error.log'));
  328. $this->assertFalse(file_exists(LOGS . 'debug.log'));
  329. $this->assertFalse(file_exists(LOGS . 'shops.log'));
  330. $this->_deleteLogs();
  331. Log::warning('warning message', 'orders');
  332. $this->assertTrue(file_exists(LOGS . 'error.log'));
  333. $this->assertTrue(file_exists(LOGS . 'shops.log'));
  334. $this->assertFalse(file_exists(LOGS . 'debug.log'));
  335. $this->_deleteLogs();
  336. Log::drop('shops');
  337. }
  338. /**
  339. * Test that scopes are exclusive and don't bleed.
  340. *
  341. * @return void
  342. */
  343. public function testScopedLoggingExclusive() {
  344. $this->_deleteLogs();
  345. Log::config('shops', array(
  346. 'engine' => 'File',
  347. 'types' => array('info', 'notice', 'warning'),
  348. 'scopes' => array('transactions', 'orders'),
  349. 'file' => 'shops.log',
  350. ));
  351. Log::config('eggs', array(
  352. 'engine' => 'File',
  353. 'types' => array('info', 'notice', 'warning'),
  354. 'scopes' => array('eggs'),
  355. 'file' => 'eggs.log',
  356. ));
  357. Log::write('info', 'transactions message', 'transactions');
  358. $this->assertFalse(file_exists(LOGS . 'eggs.log'));
  359. $this->assertTrue(file_exists(LOGS . 'shops.log'));
  360. $this->_deleteLogs();
  361. Log::write('info', 'eggs message', 'eggs');
  362. $this->assertTrue(file_exists(LOGS . 'eggs.log'));
  363. $this->assertFalse(file_exists(LOGS . 'shops.log'));
  364. }
  365. /**
  366. * testPassingScopeToEngine method
  367. */
  368. public function testPassingScopeToEngine() {
  369. Configure::write('App.namespace', 'TestApp');
  370. Log::reset();
  371. Log::config('scope_test', [
  372. 'engine' => 'TestApp',
  373. 'types' => array('notice', 'info', 'debug'),
  374. 'scopes' => array('foo', 'bar'),
  375. ]);
  376. $engine = Log::engine('scope_test');
  377. $this->assertNull($engine->passedScope);
  378. Log::write('debug', 'test message', 'foo');
  379. $this->assertEquals('foo', $engine->passedScope);
  380. Log::write('debug', 'test message', ['foo', 'bar']);
  381. $this->assertEquals(['foo', 'bar'], $engine->passedScope);
  382. $result = Log::write('debug', 'test message');
  383. $this->assertFalse($result);
  384. }
  385. /**
  386. * test convenience methods
  387. */
  388. public function testConvenienceMethods() {
  389. $this->_deleteLogs();
  390. Log::config('debug', array(
  391. 'engine' => 'File',
  392. 'types' => array('notice', 'info', 'debug'),
  393. 'file' => 'debug',
  394. ));
  395. Log::config('error', array(
  396. 'engine' => 'File',
  397. 'types' => array('emergency', 'alert', 'critical', 'error', 'warning'),
  398. 'file' => 'error',
  399. ));
  400. $testMessage = 'emergency message';
  401. Log::emergency($testMessage);
  402. $contents = file_get_contents(LOGS . 'error.log');
  403. $this->assertRegExp('/(Emergency|Critical): ' . $testMessage . '/', $contents);
  404. $this->assertFalse(file_exists(LOGS . 'debug.log'));
  405. $this->_deleteLogs();
  406. $testMessage = 'alert message';
  407. Log::alert($testMessage);
  408. $contents = file_get_contents(LOGS . 'error.log');
  409. $this->assertRegExp('/(Alert|Critical): ' . $testMessage . '/', $contents);
  410. $this->assertFalse(file_exists(LOGS . 'debug.log'));
  411. $this->_deleteLogs();
  412. $testMessage = 'critical message';
  413. Log::critical($testMessage);
  414. $contents = file_get_contents(LOGS . 'error.log');
  415. $this->assertContains('Critical: ' . $testMessage, $contents);
  416. $this->assertFalse(file_exists(LOGS . 'debug.log'));
  417. $this->_deleteLogs();
  418. $testMessage = 'error message';
  419. Log::error($testMessage);
  420. $contents = file_get_contents(LOGS . 'error.log');
  421. $this->assertContains('Error: ' . $testMessage, $contents);
  422. $this->assertFalse(file_exists(LOGS . 'debug.log'));
  423. $this->_deleteLogs();
  424. $testMessage = 'warning message';
  425. Log::warning($testMessage);
  426. $contents = file_get_contents(LOGS . 'error.log');
  427. $this->assertContains('Warning: ' . $testMessage, $contents);
  428. $this->assertFalse(file_exists(LOGS . 'debug.log'));
  429. $this->_deleteLogs();
  430. $testMessage = 'notice message';
  431. Log::notice($testMessage);
  432. $contents = file_get_contents(LOGS . 'debug.log');
  433. $this->assertRegExp('/(Notice|Debug): ' . $testMessage . '/', $contents);
  434. $this->assertFalse(file_exists(LOGS . 'error.log'));
  435. $this->_deleteLogs();
  436. $testMessage = 'info message';
  437. Log::info($testMessage);
  438. $contents = file_get_contents(LOGS . 'debug.log');
  439. $this->assertRegExp('/(Info|Debug): ' . $testMessage . '/', $contents);
  440. $this->assertFalse(file_exists(LOGS . 'error.log'));
  441. $this->_deleteLogs();
  442. $testMessage = 'debug message';
  443. Log::debug($testMessage);
  444. $contents = file_get_contents(LOGS . 'debug.log');
  445. $this->assertContains('Debug: ' . $testMessage, $contents);
  446. $this->assertFalse(file_exists(LOGS . 'error.log'));
  447. $this->_deleteLogs();
  448. }
  449. /**
  450. * Test that write() returns false on an unhandled message.
  451. *
  452. * @return false
  453. */
  454. public function testWriteUnhandled() {
  455. Log::drop('error');
  456. Log::drop('debug');
  457. $result = Log::write('error', 'Bad stuff', 'unpossible');
  458. $this->assertFalse($result);
  459. }
  460. }