View source
<?php
namespace Drupal\system\Tests\System;
use Drupal\simpletest\WebTestBase;
class UncaughtExceptionTest extends WebTestBase {
protected $expectedExceptionMessage;
public static $modules = array(
'error_service_test',
);
protected function setUp() {
parent::setUp();
$settings_filename = $this->siteDirectory . '/settings.php';
chmod($settings_filename, 0777);
$settings_php = file_get_contents($settings_filename);
$settings_php .= "\ninclude_once 'core/modules/system/src/Tests/Bootstrap/ErrorContainer.php';\n";
$settings_php .= "\ninclude_once 'core/modules/system/src/Tests/Bootstrap/ExceptionContainer.php';\n";
file_put_contents($settings_filename, $settings_php);
$settings = [];
$settings['config']['system.logging']['error_level'] = (object) [
'value' => ERROR_REPORTING_DISPLAY_VERBOSE,
'required' => TRUE,
];
$this
->writeSettings($settings);
}
public function testUncaughtException() {
$this->expectedExceptionMessage = 'Oh oh, bananas in the instruments.';
\Drupal::state()
->set('error_service_test.break_bare_html_renderer', TRUE);
$this
->config('system.logging')
->set('error_level', ERROR_REPORTING_HIDE)
->save();
$settings = [];
$settings['config']['system.logging']['error_level'] = (object) [
'value' => ERROR_REPORTING_HIDE,
'required' => TRUE,
];
$this
->writeSettings($settings);
$this
->drupalGet('');
$this
->assertResponse(500);
$this
->assertText('The website encountered an unexpected error. Please try again later.');
$this
->assertNoText($this->expectedExceptionMessage);
$this
->config('system.logging')
->set('error_level', ERROR_REPORTING_DISPLAY_ALL)
->save();
$settings = [];
$settings['config']['system.logging']['error_level'] = (object) [
'value' => ERROR_REPORTING_DISPLAY_ALL,
'required' => TRUE,
];
$this
->writeSettings($settings);
$this
->drupalGet('');
$this
->assertResponse(500);
$this
->assertText('The website encountered an unexpected error. Please try again later.');
$this
->assertText($this->expectedExceptionMessage);
$this
->assertErrorLogged($this->expectedExceptionMessage);
}
public function testUncaughtExceptionCustomExceptionHandler() {
$settings_filename = $this->siteDirectory . '/settings.php';
chmod($settings_filename, 0777);
$settings_php = file_get_contents($settings_filename);
$settings_php .= "\n";
$settings_php .= "set_exception_handler(function() {\n";
$settings_php .= " header('HTTP/1.1 418 I\\'m a teapot');\n";
$settings_php .= " print('Oh oh, flying teapots');\n";
$settings_php .= "});\n";
file_put_contents($settings_filename, $settings_php);
\Drupal::state()
->set('error_service_test.break_bare_html_renderer', TRUE);
$this
->drupalGet('');
$this
->assertResponse(418);
$this
->assertNoText('The website encountered an unexpected error. Please try again later.');
$this
->assertNoText('Oh oh, bananas in the instruments');
$this
->assertText('Oh oh, flying teapots');
}
public function testMissingDependency() {
$this->expectedExceptionMessage = 'Argument 1 passed to Drupal\\error_service_test\\LonelyMonkeyClass::__construct() must be an instance of Drupal\\Core\\Database\\Connection, non';
$this
->drupalGet('broken-service-class');
$this
->assertResponse(500);
$this
->assertRaw('The website encountered an unexpected error.');
$this
->assertRaw($this->expectedExceptionMessage);
$this
->assertErrorLogged($this->expectedExceptionMessage);
}
public function testMissingDependencyCustomErrorHandler() {
$settings_filename = $this->siteDirectory . '/settings.php';
chmod($settings_filename, 0777);
$settings_php = file_get_contents($settings_filename);
$settings_php .= "\n";
$settings_php .= "set_error_handler(function() {\n";
$settings_php .= " header('HTTP/1.1 418 I\\'m a teapot');\n";
$settings_php .= " print('Oh oh, flying teapots');\n";
$settings_php .= " exit();\n";
$settings_php .= "});\n";
$settings_php .= "\$settings['teapots'] = TRUE;\n";
file_put_contents($settings_filename, $settings_php);
$this
->drupalGet('broken-service-class');
$this
->assertResponse(418);
$this
->assertRaw('Oh oh, flying teapots');
$message = 'Argument 1 passed to Drupal\\error_service_test\\LonelyMonkeyClass::__construct() must be an instance of Drupal\\Core\\Database\\Connection, non';
$this
->assertNoRaw('The website encountered an unexpected error.');
$this
->assertNoRaw($message);
$found_exception = FALSE;
foreach ($this->assertions as &$assertion) {
if (strpos($assertion['message'], $message) !== FALSE) {
$found_exception = TRUE;
$this
->deleteAssert($assertion['message_id']);
unset($assertion);
}
}
$this
->assertTrue($found_exception, 'Ensure that the exception of a missing constructor argument was triggered.');
}
public function testErrorContainer() {
$settings = [];
$settings['settings']['container_base_class'] = (object) [
'value' => '\\Drupal\\system\\Tests\\Bootstrap\\ErrorContainer',
'required' => TRUE,
];
$this
->writeSettings($settings);
\Drupal::service('kernel')
->invalidateContainer();
$this->expectedExceptionMessage = 'Argument 1 passed to Drupal\\system\\Tests\\Bootstrap\\ErrorContainer::Drupal\\system\\Tests\\Bootstrap\\{closur';
$this
->drupalGet('');
$this
->assertResponse(500);
$this
->assertRaw($this->expectedExceptionMessage);
$this
->assertErrorLogged($this->expectedExceptionMessage);
}
public function testExceptionContainer() {
$settings = [];
$settings['settings']['container_base_class'] = (object) [
'value' => '\\Drupal\\system\\Tests\\Bootstrap\\ExceptionContainer',
'required' => TRUE,
];
$this
->writeSettings($settings);
\Drupal::service('kernel')
->invalidateContainer();
$this->expectedExceptionMessage = 'Thrown exception during Container::get';
$this
->drupalGet('');
$this
->assertResponse(500);
$this
->assertRaw('The website encountered an unexpected error');
$this
->assertRaw($this->expectedExceptionMessage);
$this
->assertErrorLogged($this->expectedExceptionMessage);
}
public function testLostDatabaseConnection() {
$incorrect_username = $this
->randomMachineName(16);
switch ($this->container
->get('database')
->driver()) {
case 'pgsql':
case 'mysql':
$this->expectedExceptionMessage = $incorrect_username;
break;
default:
$this
->pass('Unable to run \\Drupal\\system\\Tests\\System\\UncaughtExceptionTest::testLostDatabaseConnection for this database type.');
return;
}
$settings['databases']['default']['default']['username'] = (object) array(
'value' => $incorrect_username,
'required' => TRUE,
);
$settings['databases']['default']['default']['passowrd'] = (object) array(
'value' => $this
->randomMachineName(16),
'required' => TRUE,
);
$this
->writeSettings($settings);
$this
->drupalGet('');
$this
->assertResponse(500);
$this
->assertRaw('PDOException');
$this
->assertErrorLogged($this->expectedExceptionMessage);
}
public function testLoggerException() {
$this
->assertNoErrorsLogged();
$this->expectedExceptionMessage = 'Deforestation';
\Drupal::state()
->set('error_service_test.break_logger', TRUE);
$this
->drupalGet('');
$this
->assertResponse(500);
$this
->assertText('The website encountered an unexpected error. Please try again later.');
$this
->assertRaw($this->expectedExceptionMessage);
$errors = file(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
$this
->assertIdentical(count($errors), 2, 'The error + the error that the logging service is broken has been written to the error log.');
$this
->assertTrue(strpos($errors[0], 'Failed to log error') !== FALSE, 'The error handling logs when an error could not be logged to the logger.');
$expected_path = \Drupal::root() . '/core/modules/system/tests/modules/error_service_test/src/MonkeysInTheControlRoom.php';
$expected_line = 63;
$expected_entry = "Failed to log error: Exception: Deforestation in Drupal\\error_service_test\\MonkeysInTheControlRoom->handle() (line {$expected_line} of {$expected_path})";
$this
->assert(strpos($errors[0], $expected_entry) !== FALSE, 'Original error logged to the PHP error log when an exception is thrown by a logger');
unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
}
protected function error($message = '', $group = 'Other', array $caller = NULL) {
if (!empty($this->expectedExceptionMessage) && strpos($message, $this->expectedExceptionMessage) !== FALSE) {
return FALSE;
}
return parent::error($message, $group, $caller);
}
}