monitoring-8.x-1.x-dev/tests/src/Kernel/MonitoringCoreKernelTest.php
tests/src/Kernel/MonitoringCoreKernelTest.php
<?php
namespace Drupal\Tests\monitoring\Kernel;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\monitoring\Entity\SensorConfig;
use Drupal\monitoring\Result\SensorResultInterface;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
/**
* Kernel tests for the core pieces of monitoring.
*
* @group monitoring
*/
class MonitoringCoreKernelTest extends MonitoringUnitTestBase {
protected static $modules = [
'dblog',
'image',
'file',
'node',
'taxonomy',
'automated_cron',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installSchema('dblog', ['watchdog']);
$this->installConfig(array('system'));
\Drupal::moduleHandler()->invoke('monitoring', 'modules_installed', [['monitoring'], FALSE]);
}
/**
* Tests monitoring_cron.
*/
public function testCronRunAllEnabledSensors() {
// Per default cron_run_sensors is false, this should not run any sensors.
\Drupal::cache('default')->deleteAll();
monitoring_cron();
$cid = 'monitoring_sensor_result:test_sensor';
$cache = \Drupal::cache('default')->get($cid);
// Checks that the cache is empty when cron is disabled.
$this->assertTrue(!is_object($cache));
$sensorConfig = SensorConfig::load('test_sensor');
$result = \Drupal::service('monitoring.sensor_runner')->runSensors([$sensorConfig]);
// Since after a sensor ran its result is cached, check if it is not cached.
$this->assertTrue(!$result[0]->isCached());
// Allow running all enabled sensors.
\Drupal::configFactory()
->getEditable('monitoring.settings')
->set('cron_run_sensors', TRUE)
->save();
\Drupal::cache('default')->deleteAll();
monitoring_cron();
$cache = \Drupal::cache('default')->get($cid);
// Checks that the cache is not empty when cron is enabled.
$this->assertTrue(is_object($cache));
$sensorConfig = SensorConfig::load('test_sensor');
$result = \Drupal::service('monitoring.sensor_runner')->runSensors([$sensorConfig]);
// Since after a sensor ran its result is cached, check if it is cached.
$this->assertTrue($result[0]->isCached());
}
/**
* Tests cron last run age sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\CronLastRunAgeSensorPlugin
*/
public function testCronLastRunAgeSensorPlugin() {
// Fake cron run 1d+1s ago.
$time_shift = (60 * 60 * 24 + 1);
\Drupal::state()->set('system.cron_last', \Drupal::time()->getRequestTime() - $time_shift);
$result = $this->runSensor('core_cron_last_run_age');
$this->assertTrue($result->isWarning());
$this->assertEquals($time_shift, $result->getValue());
// Fake cron run from 3d+1s ago.
$time_shift = (60 * 60 * 24 * 3 + 1);
\Drupal::state()->set('system.cron_last', \Drupal::time()->getRequestTime() - $time_shift);
$result = $this->runSensor('core_cron_last_run_age');
$this->assertTrue($result->isCritical());
$this->assertEquals($time_shift, $result->getValue());
// Run cron and check sensor.
\Drupal::service('cron')->run();
$result = $this->runSensor('core_cron_last_run_age');
$this->assertTrue($result->isOk());
$this->assertEquals(0, $result->getValue());
}
/**
* Tests cron safe threshold (poormanscron) sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\ConfigValueSensorPlugin
*/
public function testConfigValueSensorPluginCronSafeThreshold() {
// Run sensor, all is OK.
$result = $this->runSensor('core_cron_safe_threshold');
$this->assertTrue($result->isOk());
// Enable cron safe threshold and run sensor.
$this->config('automated_cron.settings')->set('interval', 3600)->save();
$result = $this->runSensor('core_cron_safe_threshold');
$this->assertTrue($result->isCritical());
$this->assertEquals($result->getMessage(), 'TRUE, expected FALSE');
}
/**
* Tests maintenance mode sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\StateValueSensorPlugin
*/
public function testStateValueSensorPluginMaintenanceMode() {
// Run sensor, all is OK.
$result = $this->runSensor('core_maintenance_mode');
$this->assertTrue($result->isOk());
// Enable maintenance mode and run sensor.
\Drupal::state()->set('system.maintenance_mode', TRUE);
$result = $this->runSensor('core_maintenance_mode');
$this->assertTrue($result->isCritical());
// Switch out of maintenance mode to continue regularly.
\Drupal::state()->set('system.maintenance_mode', FALSE);
$this->assertEquals($result->getMessage(), 'TRUE, expected FALSE');
}
/**
* Tests queue size sensors.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\QueueSizeSensorPlugin
*/
public function testQueueSizeSensorPlugin() {
// Create queue sensor.
$sensor_config = SensorConfig::create(array(
'id' => 'core_queue_monitoring_test',
'plugin_id' => 'queue_size',
'value_type' => 'number',
'settings' => [
'queue' => 'monitoring_test',
],
));
$sensor_config->save();
// Create queue with some items and run sensor.
$queue = \Drupal::queue('monitoring_test');
$queue->createItem(array());
$queue->createItem(array());
$result = $this->runSensor('core_queue_monitoring_test');
$this->assertEquals($result->getValue(), 2);
}
/**
* Tests php notices watchdog sensor.
*/
public function testPhpNoticesSensor() {
// Prepare a fake PHP error.
$error = [
'%type' => 'Recoverable fatal error',
'@message' => 'Argument 1 passed to Drupal\Core\Form\ConfigFormBase::buildForm() must be of the type array, null given, called in /usr/local/var/www/d8/www/core/modules/system/src/Form/CronForm.php on line 127 and defined',
'%function' => 'Drupal\Core\Form\ConfigFormBase->buildForm()',
'%line' => '42',
'%file' => DRUPAL_ROOT . '/core/lib/Drupal/Core/Form/ConfigFormBase.php',
];
// Log it twice.
\Drupal::logger('php')->error('%type: @message in %function (Line %line of %file).', $error);
\Drupal::logger('php')->error('%type: @message in %function (Line %line of %file).', $error);
$result = $this->runSensor('dblog_php_notices');
$message = $result->getMessage();
$error['%file'] = str_replace(DRUPAL_ROOT . '/', '', $error['%file']);
// Assert the message has been set and replaced successfully.
$this->assertEquals($message, new FormattableMarkup('2 times: %type: @message in %function (Line %line of %file).', $error));
// Prepare another fake PHP notice.
$new_error = [
'%type' => 'Notice',
'@message' => 'Use of undefined constant B - assumed \'B\'',
'%function' => 'Drupal\system\Form\CronForm->buildForm()',
'%line' => '126',
'%file' => DRUPAL_ROOT . '/core/modules/system/src/Form/CronForm.php',
];
\Drupal::logger('php')->notice('%type: @message in %function (Line %line of %file).', $new_error);
$result = $this->runSensor('dblog_php_notices');
$message = $result->getMessage();
// Assert the message is still the one from above and not the new message.
$this->assertEquals($message, new FormattableMarkup('2 times: %type: @message in %function (Line %line of %file).', $error), 'The sensor message is still the old message.');
$this->assertNotEquals($message, new FormattableMarkup('%type: @message in %function (Line %line of %file).', $new_error), 'The sensor message is not the new message.');
// Log the new error twice more, check it is now the sensor message.
\Drupal::logger('php')->notice('%type: @message in %function (Line %line of %file).', $new_error);
\Drupal::logger('php')->notice('%type: @message in %function (Line %line of %file).', $new_error);
$result = $this->runSensor('dblog_php_notices');
$message = $result->getMessage();
$new_error['%file'] = str_replace(DRUPAL_ROOT . '/', '', $new_error['%file']);
// Assert the new message is returned as a message.
$this->assertEquals($message, new FormattableMarkup('3 times: %type: @message in %function (Line %line of %file).', $new_error), 'The new message is now the sensor message.');
$this->assertNotEquals($message, new FormattableMarkup('2 times: %type: @message in %function (Line %line of %file).', $error), 'The old message is not the sensor message anymore.');
}
/**
* Tests dblog 404 errors sensor.
*
* Logged through watchdog.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\Dblog404SensorPlugin
*/
public function testDblog404SensorPlugin() {
// Fake some not found errors.
\Drupal::service('logger.dblog')->log(RfcLogLevel::NOTICE, '@uri', [
'request_uri' => 'not/found',
'uid' => 0,
'channel' => 'page not found',
'link' => '',
'referer' => '',
'ip' => '127.0.0.1',
'timestamp' => \Drupal::time()->getRequestTime(),
]);
// Run sensor and test the output.
$result = $this->runSensor('dblog_404');
$this->assertTrue($result->isOk());
$this->assertEquals($result->getMessage(), '1 watchdog events in 1 day, not/found');
$this->assertEquals($result->getValue(), 1);
// Fake more 404s.
for ($i = 1; $i <= 20; $i++) {
\Drupal::service('logger.dblog')->log(RfcLogLevel::NOTICE, '@uri', [
'request_uri' => 'not/found',
'uid' => 0,
'channel' => 'page not found',
'link' => '',
'referer' => '',
'ip' => '127.0.0.1',
'timestamp' => \Drupal::time()->getRequestTime(),
]);
}
// Run sensor and check the aggregate value.
$result = $this->runSensor('dblog_404');
$this->assertEquals($result->getValue(), 21);
$this->assertTrue($result->isWarning());
// Fake more 404s.
for ($i = 0; $i <= 100; $i++) {
\Drupal::service('logger.dblog')->log(RfcLogLevel::NOTICE, '@uri', [
'request_uri' => 'not/found/another',
'uid' => 0,
'channel' => 'page not found',
'link' => '',
'referer' => '',
'ip' => '127.0.0.1',
'timestamp' => \Drupal::time()->getRequestTime(),
]);
}
// Run sensor and check the aggregate value.
$result = $this->runSensor('dblog_404');
$this->assertEquals($result->getValue(), 101);
$this->assertTrue($result->isCritical());
}
/**
* Tests dblog missing image style sensor.
*
* Logged through watchdog.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\ImageMissingStyleSensorPlugin
*/
public function testImageMissingStyleSensorPlugin() {
$this->installSchema('file', ['file_usage']);
$this->installEntitySchema('file');
$this->installConfig(['system', 'dblog']);
// Fake some image style derivative errors.
$file = \Drupal::service('file.repository')->writeData($this->randomMachineName(), 'public://');
/** @var \Drupal\file\FileUsage\FileUsageInterface $usage */
$usage = \Drupal::service('file.usage');
$usage->add($file, 'monitoring_test', 'node', 123456789);
for ($i = 1; $i <= 6; $i++) {
// We use the logger.dblog service to be able to set the referer.
\Drupal::service('logger.dblog')->notice('Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', [
'%source_image_path' => $file->getFileUri(),
'%derivative_path' => 'hash://styles/preview/1234.jpeg',
'request_uri' => '',
'uid' => 0,
'channel' => 'image',
'link' => '',
'referer' => 'http://example.com/node/123456789',
'ip' => '127.0.0.1',
'timestamp' => \Drupal::time()->getRequestTime() - $i,
]);
}
\Drupal::logger('image')->notice('Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.',
array(
'%source_image_path' => 'public://portrait-pictures/bluemouse.jpeg',
'%derivative_path' => 'hash://styles/preview/5678.jpeg',
'timestamp' => \Drupal::time()->getRequestTime(),
));
// Run sensor and test the output.
$result = $this->runSensor('dblog_image_missing_style');
$this->assertEquals(6, $result->getValue());
$this->assertTrue(strpos($result->getMessage(), $file->getFileUri()) !== FALSE);
$this->assertTrue($result->isWarning());
$verbose_output = $result->getVerboseOutput();
$this->setRawContent(\Drupal::service('renderer')->renderPlain($verbose_output));
$xpath = $this->xpath('//*[@id="unaggregated_result"]/table/tbody');
$this->assertEquals('public://portrait-pictures/bluemouse.jpeg', (string) $xpath[0]->tr[0]->td[2]);
$this->assertEquals('http://example.com/node/123456789', (string) $xpath[0]->tr[6]->td[1]);
$this->assertLink('7');
}
/**
* Tests requirements sensors.
*
* The module monitoring_test implements custom requirements injected through
* state monitoring_test.requirements.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\CoreRequirementsSensorPlugin
*/
public function testCoreRequirementsSensorPlugin() {
$result = $this->runSensor('core_requirements_monitoring_test');
$this->assertTrue($result->isOk());
$this->assertEquals($result->getMessage(), 'Requirements check OK');
// Set basic requirements saying that all is OK.
$requirements = array(
'requirement1' => array(
'title' => 'requirement1',
'description' => 'requirement1 description',
'severity' => REQUIREMENT_OK,
),
'requirement_excluded' => array(
'title' => 'excluded requirement',
'description' => 'requirement that should be excluded from monitoring by the sensor',
// Set the severity to ERROR to test if the sensor result is not
// affected by this requirement.
'severity' => REQUIREMENT_ERROR,
),
);
\Drupal::state()->set('monitoring_test.requirements', $requirements);
// Set requirements exclude keys into the sensor settings.
$sensor_config = SensorConfig::load('core_requirements_monitoring_test');
$settings = $sensor_config->getSettings();
$settings['exclude_keys'] = array('requirement_excluded');
$sensor_config->settings = $settings;
$sensor_config->save();
// We still have OK status but with different message.
$result = $this->runSensor('core_requirements_monitoring_test');
// We expect OK status as REQUIREMENT_ERROR is set by excluded requirement.
$this->assertTrue($result->isOk());
$this->assertEquals($result->getMessage(), 'requirement1, requirement1 description');
// Add warning state.
$requirements['requirement2'] = array(
'title' => 'requirement2',
'description' => 'requirement2 description',
'severity' => REQUIREMENT_WARNING,
);
\Drupal::state()->set('monitoring_test.requirements', $requirements);
// Now the sensor escalates to the requirement in warning state.
$result = $this->runSensor('core_requirements_monitoring_test');
$this->assertTrue($result->isWarning());
$this->assertEquals($result->getMessage(), 'requirement2, requirement2 description');
// Add error state.
$requirements['requirement3'] = array(
'title' => 'requirement3',
'description' => 'requirement3 description',
'severity' => REQUIREMENT_ERROR,
);
\Drupal::state()->set('monitoring_test.requirements', $requirements);
// Now the sensor escalates to the requirement in critical state.
$result = $this->runSensor('core_requirements_monitoring_test');
$this->assertTrue($result->isCritical());
$this->assertEquals($result->getMessage(), 'requirement3, requirement3 description');
// Check verbose message. All output should be part of it.
$verbose_output = $result->getVerboseOutput();
$this->setRawContent(\Drupal::service('renderer')->renderPlain($verbose_output));
$this->assertText('requirement1');
$this->assertText('requirement1 description');
$this->assertText('requirement_excluded');
$this->assertText('excluded requirement');
$this->assertText('requirement that should be excluded from monitoring by the sensor');
$this->assertText('requirement2');
$this->assertText('requirement2 description');
// Add error state.
$requirements = [
'requirement4' => [
'title' => ['#markup' => 'requirement 4'],
'description' => ['#markup' => 'Description as a render array'],
'severity' => REQUIREMENT_WARNING,
],
];
\Drupal::state()->set('monitoring_test.requirements', $requirements);
// Check verbose message. Make sure that the render array is converted to
// a string.
$result = $this->runSensor('core_requirements_monitoring_test');
$this->assertTrue($result->isWarning());
$this->assertEquals('requirement 4, Description as a render array', $result->getMessage());
$verbose_output = $result->getVerboseOutput();
$this->setRawContent(\Drupal::service('renderer')->renderPlain($verbose_output));
$this->assertText('requirement 4');
$this->assertText('Description as a render array');
}
/**
* Tests the node count per content type sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\ContentEntityAggregatorSensorPlugin
*/
public function testDefaultNodeTypeSensors() {
$this->installEntitySchema('user');
$this->installEntitySchema('node');
\Drupal::service('router.builder')->rebuild();
$type1 = NodeType::create([
'type' => $this->randomMachineName(),
'name' => $this->randomString(),
]);
$type1->save();
$sensor1 = SensorConfig::create(array(
'id' => 'node_new_' . $type1->id(),
'label' => new FormattableMarkup('New @type nodes', array('@type' => $type1->label())),
'description' => new FormattableMarkup('New nodes of type @type', array('@type' => $type1->label())),
'plugin_id' => 'entity_aggregator',
'value_label' => new FormattableMarkup('@type nodes', array('@type' => $type1->label())),
'category' => 'Content',
'status' => FALSE,
'caching_time' => 600,
'settings' => array(
'entity_type' => 'node',
'conditions' => array(
array('field' => 'type', 'value' => $type1->id()),
),
'time_interval_field' => 'created',
'time_interval_value' => 60 * 60 * 24,
),
));
$sensor1->save();
$type2 = NodeType::create([
'type' => $this->randomMachineName(),
'name' => $this->randomString(),
]);
$type2->save();
$sensor2 = SensorConfig::create(array(
'id' => 'node_new_' . $type2->id(),
'label' => new FormattableMarkup('New @type nodes', array('@type' => $type2->label())),
'description' => new FormattableMarkup('New nodes of type @type', array('@type' => $type2->label())),
'plugin_id' => 'entity_aggregator',
'value_label' => new FormattableMarkup('@type nodes', array('@type' => $type2->label())),
'category' => 'Content',
'status' => FALSE,
'caching_time' => 600,
'settings' => array(
'entity_type' => 'node',
'conditions' => array(
array('field' => 'type', 'value' => $type2->id()),
),
'time_interval_field' => 'created',
'time_interval_value' => 60 * 60 * 24,
),
));
$sensor2->save();
Node::create(array('title' => $this->randomString(), 'type' => $type1->id()))->save();
Node::create(array('title' => $this->randomString(), 'type' => $type1->id()))->save();
Node::create(array('title' => $this->randomString(), 'type' => $type2->id()))->save();
// Make sure that sensors for the new node types are available.
monitoring_sensor_manager()->resetCache();
// Run sensor for type1.
$result = $this->runSensor('node_new_' . $type1->id());
$this->assertEquals($result->getValue(), 2);
// Test for the ContentEntityAggregatorSensorPlugin custom message.
$this->assertEquals($result->getMessage(), new FormattableMarkup('@count @unit in @time_interval', array(
'@count' => $result->getValue(),
'@unit' => strtolower($result->getSensorConfig()->getValueLabel()),
'@time_interval' => \Drupal::service('date.formatter')
->formatInterval($result->getSensorConfig()
->getTimeIntervalValue()),
)));
// Run sensor for all types.
$result = $this->runSensor('node_new_all');
$this->assertEquals($result->getValue(), 3);
// Verify that hooks do not break when sensors unexpectedly do exist or
// don't exist.
$sensor = SensorConfig::create(array(
'id' => 'node_new_existing',
'label' => 'Existing sensor',
'plugin_id' => 'entity_aggregator',
'settings' => array(
'entity_type' => 'node',
),
));
$sensor->save();
$type_existing = NodeType::create(['type' => 'existing', 'label' => 'Existing']);
$type_existing->save();
// Manually delete the sensor and then the node type.
$sensor->delete();
$type_existing->delete();
// Rename type when the target sensor already exists.
$sensor = SensorConfig::create(array(
'id' => 'node_new_existing',
'label' => 'Existing sensor',
'plugin_id' => 'entity_aggregator',
'settings' => array(
'entity_type' => 'node',
),
));
$sensor->save();
$type1->set('name', 'existing');
$type1->save();
// Delete the sensor for $type2 before renaming.
$sensor = SensorConfig::load('node_new_' . $type2->id());
$sensor->delete();
$type2->set('name', 'different');
$type2->save();
}
/**
* Tests dblog watchdog sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\DatabaseAggregatorSensorPlugin
*/
public function testDatabaseAggregatorSensorPluginDblog() {
// Create watchdog entry with severity alert.
// The testbot reported random fails with an unexpected watchdog record.
// ALERT: "Missing filter plugin: %filter." with %filter = "filter_null"
// Thus we drop all ALERT messages first.
\Drupal::database()->delete('watchdog')
->condition('severity', RfcLogLevel::ALERT)
->execute();
\Drupal::logger('test')->alert('test message');
// Run sensor and test the output.
$result = $this->runSensor('dblog_event_severity_alert');
$this->assertEquals(1, $result->getValue());
}
/**
* Tests failed user logins sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\UserFailedLoginsSensorPlugin
*/
public function testUserFailedLoginsSensorPlugin() {
// Fake some login failed dblog records.
\Drupal::logger('user')->notice('Login attempt failed for %user.', array('%user' => 'user1'));
\Drupal::logger('user')->notice('Login attempt failed for %user.', array('%user' => 'user1'));
\Drupal::logger('user')->notice('Login attempt failed for %user.', array('%user' => 'user2'));
\Drupal::logger('user')->notice('Login attempt failed for %user.', array('%user' => 'user2'));
\Drupal::logger('user')->notice('Login attempt failed for %user.', array('%user' => 'user2'));
// Run sensor and test the output.
$result = $this->runSensor('user_failed_logins');
$this->assertEquals($result->getValue(), 5);
$this->assertEquals($result->getMessage(), '5 login attempts in 1 day, user2: 3, user1: 2');
}
/**
* Tests user logouts through db aggregator sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\DatabaseAggregatorSensorPlugin
*/
public function testDatabaseAggregatorSensorPluginUserLogout() {
// Fake some logout dblog records.
\Drupal::logger('user')->notice('Session closed for %name.', array('%user' => 'user1'));
\Drupal::logger('user')->notice('Session closed for %name.', array('%user' => 'user1'));
\Drupal::logger('user')->notice('Session closed for %name.', array('%user' => 'user2'));
// Run sensor and test the output.
$result = $this->runSensor('user_session_logouts');
$this->assertEquals($result->getValue(), 3);
$this->assertEquals($result->getMessage(), '3 logouts in 1 day');
}
/**
* Tests git sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\GitDirtyTreeSensorPlugin
*/
public function testGitDirtyTreeSensorPlugin() {
// Enable the sensor and set cmd to output something.
// The command creates a line for every file in unexpected state.
$sensor_config = SensorConfig::load('monitoring_git_dirty_tree');
$sensor_config->enable();
// Ensure that newlines are treated correctly, see
// http://unix.stackexchange.com/questions/48106/what-does-it-mean-to-have-a-dollarsign-prefixed-string-in-a-script.
$sensor_config->settings['status_cmd'] = 'printf "A addedfile.txt\nM sites/all/modules/monitoring/test/tests/monitoring.core.test\nD deleted file.txt"';
$sensor_config->settings['ahead_cmd'] = 'true';
$sensor_config->settings['submodules_cmd'] = 'true';
$sensor_config->save();
$result = $this->runSensor('monitoring_git_dirty_tree');
$this->assertTrue($result->isCritical());
// The verbose output should contain the cmd output.
$verbose_output = $result->getVerboseOutput();
$this->setRawContent(\Drupal::service('renderer')->renderPlain($verbose_output));
$this->assertText('A addedfile.txt');
$this->assertText('M sites/all/modules/monitoring/test/tests/monitoring.core.test');
$this->assertText('D deleted file.txt');
// Check if the sensor message has the expected value.
$this->assertEquals($result->getMessage(), '3 files in unexpected state: A addedfile.txt, M …modules/monitoring/test/tests/monitoring.core.test');
// Now echo empty string.
$sensor_config->settings['status_cmd'] = 'true';
$sensor_config->save();
$result = $this->runSensor('monitoring_git_dirty_tree');
$this->assertTrue($result->isOk());
// The message should say that it is ok.
$this->assertEquals($result->getMessage(), 'Git repository clean');
// Test 2 commits ahead of origin.
$sensor_config->settings['ahead_cmd'] = 'printf "a4ea5e3ac5b7cca0c96aee4d00447c36121bd128\n299d85344fab9befbf6a275a4b64bda7b464b493"';
$sensor_config->save();
$result = $this->runSensor('monitoring_git_dirty_tree');
$this->assertTrue($result->isWarning());
$verbose_output = $result->getVerboseOutput();
$this->setRawContent(\Drupal::service('renderer')->renderPlain($verbose_output));
$this->assertText('a4ea5e3ac5b7cca0c96aee4d00447c36121bd128');
$this->assertText('299d85344fab9befbf6a275a4b64bda7b464b493');
$this->assertEquals($result->getMessage(), 'Branch is 2 ahead of origin');
// Test not in main branch.
$sensor_config->settings['check_branch'] = TRUE;
$sensor_config->settings['ahead_cmd'] = 'true';
$sensor_config->settings['actual_branch_cmd'] = 'printf "7.0.x"';
$sensor_config->settings['expected_branch'] = '8.0.x';
$sensor_config->save();
$result = $this->runSensor('monitoring_git_dirty_tree');
$this->assertTrue($result->isWarning());
$verbose_output = $result->getVerboseOutput();
$this->setRawContent(\Drupal::service('renderer')->renderPlain($verbose_output));
$this->assertText('7.0.x');
$this->assertEquals($result->getMessage(), 'Active branch 7.0.x, expected 8.0.x');
// Test same as main branch.
$sensor_config->settings['actual_branch_cmd'] = 'printf "8.0.x"';
$sensor_config->save();
$result = $this->runSensor('monitoring_git_dirty_tree');
$this->assertTrue($result->isOk());
$this->assertEquals($result->getMessage(), 'Git repository clean');
// Test submodule not initialized.
$sensor_config->settings['submodules_cmd'] = 'printf -- "-a5066d1778b9ec7c86631234ff2795e777bdff12 test\n156fff6ee58497fa22b57c32e22e3f13377b4120 test (8.x-1.0-240-g156fff6)"';
$sensor_config->save();
$result = $this->runSensor('monitoring_git_dirty_tree');
$this->assertTrue($result->isCritical());
$verbose_output = $result->getVerboseOutput();
$this->setRawContent(\Drupal::service('renderer')->renderPlain($verbose_output));
$this->assertText('-a5066d1778b9ec7c86631234ff2795e777bdff12 test');
$this->assertEquals($result->getMessage(), '1 submodules in unexpected state: -a5066d1778b9ec7c86631234ff2795e777bdff12 test');
// Test submodule with uncommitted changes.
$sensor_config->settings['submodules_cmd'] = 'printf "a5066d1778b9ec7c86631234ff2795e777bdff12 test\n+156fff6ee58497fa22b57c32e22e3f13377b4120 test (8.x-1.0-240-g156fff6)"';
$sensor_config->save();
$result = $this->runSensor('monitoring_git_dirty_tree');
$this->assertTrue($result->isCritical());
$verbose_output = $result->getVerboseOutput();
$this->setRawContent(\Drupal::service('renderer')->renderPlain($verbose_output));
$this->assertText('+156fff6ee58497fa22b57c32e22e3f13377b4120 test (8.x-1.0-240-g156fff6)');
$this->assertEquals($result->getMessage(), '1 submodules in unexpected state: +156fff6ee58497fa22b57c32e22e3f13377b4120 test (8.x-1.0-240-g156fff6)');
// Test submodules in expected state.
$sensor_config->settings['submodules_cmd'] = 'printf "a5066d1778b9ec7c86631234ff2795e777bdff12 test\n156fff6ee58497fa22b57c32e22e3f13377b4120 test (8.x-1.0-240-g156fff6)"';
$sensor_config->save();
$result = $this->runSensor('monitoring_git_dirty_tree');
$this->assertTrue($result->isOk());
$this->assertEquals($result->getMessage(), 'Git repository clean');
}
/**
* Tests the default theme sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\ConfigValueSensorPlugin
*/
public function testConfigValueSensorPluginDefaultTheme() {
$this->config('system.theme')->set('default', 'bartik')->save();
$result = $this->runSensor('core_theme_default');
$this->assertTrue($result->isOk());
$this->assertEquals($result->getMessage(), 'Value bartik');
$this->config('system.theme')->set('default', 'garland')->save();
$result = $this->runSensor('core_theme_default');
$this->assertTrue($result->isCritical());
}
/**
* Tests the database aggregator sensor.
*
* @see \Drupal\monitoring\Plugin\monitoring\SensorPlugin\DatabaseAggregatorSensorPlugin
*/
public function testDatabaseAggregator() {
// Aggregate by watchdog type.
$sensor_config = SensorConfig::load('watchdog_aggregate_test');
$sensor_config->settings['conditions'] = array(
array('field' => 'type', 'value' => 'test_type'),
);
$sensor_config->save();
\Drupal::logger('test_type')->notice($this->randomMachineName());
\Drupal::logger('test_type')->notice($this->randomMachineName());
\Drupal::logger('other_test_type')->notice($this->randomMachineName());
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertEquals($result->getValue(), 2);
// Aggregate by watchdog message.
$sensor_config->settings['conditions'] = array(
array('field' => 'message', 'value' => 'test_message'),
);
$sensor_config->save();
\Drupal::logger($this->randomMachineName())->notice('test_message');
\Drupal::logger($this->randomMachineName())->notice('another_test_message');
\Drupal::logger($this->randomMachineName())->notice('another_test_message');
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertEquals($result->getValue(), 1);
// Aggregate by watchdog severity.
$sensor_config->settings['conditions'] = array(
array('field' => 'severity', 'value' => RfcLogLevel::CRITICAL),
);
$sensor_config->save();
\Drupal::logger($this->randomMachineName())
->critical($this->randomMachineName());
\Drupal::logger($this->randomMachineName())
->critical($this->randomMachineName());
\Drupal::logger($this->randomMachineName())
->critical($this->randomMachineName());
\Drupal::logger($this->randomMachineName())
->critical($this->randomMachineName());
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertEquals($result->getValue(), 4);
// Aggregate by watchdog location.
$sensor_config->settings['conditions'] = array(
array('field' => 'location', 'value' => 'http://some.url.dev'),
);
$sensor_config->save();
// Update the two test_type watchdog entries with a custom location.
\Drupal::database()->update('watchdog')
->fields(array('location' => 'http://some.url.dev'))
->condition('type', 'test_type')
->execute();
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertEquals($result->getValue(), 2);
// Filter for time period.
$sensor_config->settings['conditions'] = array();
$sensor_config->settings['time_interval_value'] = 10;
$sensor_config->settings['time_interval_field'] = 'timestamp';
$sensor_config->save();
// Make all system watchdog messages older than the configured time period.
\Drupal::database()->update('watchdog')
->fields(array('timestamp' => \Drupal::time()->getRequestTime() - 20))
->condition('type', 'system')
->execute();
$count_latest = \Drupal::database()->query('SELECT COUNT(*) FROM {watchdog} WHERE timestamp > :timestamp', array(':timestamp' => \Drupal::time()->getRequestTime() - 10))->fetchField();
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertEquals($result->getValue(), $count_latest);
// Test for thresholds and statuses.
$sensor_config->settings['conditions'] = array(
array('field' => 'type', 'value' => 'test_watchdog_aggregate_sensor'),
);
$sensor_config->save();
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertTrue($result->isOk());
$this->assertEquals($result->getValue(), 0);
\Drupal::logger('test_watchdog_aggregate_sensor')->notice('testing');
\Drupal::logger('test_watchdog_aggregate_sensor')->notice('testing');
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertTrue($result->isWarning());
$this->assertEquals($result->getValue(), 2);
\Drupal::logger('test_watchdog_aggregate_sensor')->notice('testing');
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertTrue($result->isCritical());
$this->assertEquals($result->getValue(), 3);
// Test database aggregator with invalid conditions.
$sensor = SensorConfig::create(array(
'id' => 'db_test',
'label' => 'Database sensor invalid',
'plugin_id' => 'database_aggregator',
'settings' => array(
'table' => 'watchdog',
),
));
$sensor->settings['conditions'] = array(
array('field' => 'invalid', 'value' => ''),
);
$sensor->settings['verbose_fields']['0'] = 'wid';
$sensor->save();
$result = $this->runSensor('db_test');
$this->assertTrue($result->isCritical());
// Test STARTS_WITH and CONTAINS operators.
$sensor_config->settings['conditions'] = array(
array('field' => 'type', 'value' => 'other', 'operator' => 'STARTS_WITH'),
);
$sensor_config->save();
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertEquals($result->getValue(), 1);
$sensor_config->settings['conditions'] = array(
array('field' => 'type', 'value' => 'test_type', 'operator' => 'CONTAINS'),
);
$sensor_config->save();
$result = $this->runSensor('watchdog_aggregate_test');
$this->assertEquals($result->getValue(), 3);
}
/**
* Tests if the previous sensor result retrieved is the expected one.
*/
public function testPreviousSensorResult() {
// Allow running all enabled sensors.
\Drupal::configFactory()
->getEditable('monitoring.settings')
->set('cron_run_sensors', TRUE)
->save();
\Drupal::cache('default')->deleteAll();
$sensor_runner = \Drupal::service('monitoring.sensor_runner');
// There should be no logged sensor result at the moment.
$sensorConfig = SensorConfig::load('test_sensor_falls');
$sensor_result_0 = monitoring_sensor_result_last($sensorConfig->id());
$this->assertNull($sensor_result_0);
// Run a sensor that is CRITICAL and check there is no previous result.
/** @var \Drupal\monitoring\Result\SensorResult $sensor_result_1 */
$sensor_result_1 = $sensor_runner->runSensors([$sensorConfig])[0];
$previous_result_1 = $sensor_result_1->getPreviousResult();
$this->assertEquals(SensorResultInterface::STATUS_CRITICAL, $sensor_result_1->getStatus());
$this->assertEquals($sensor_result_0, $previous_result_1);
$this->assertNull($previous_result_1);
// Run the same sensor and check the previous result status is
// same as $sensor_result_1.
/** @var \Drupal\monitoring\Result\SensorResult $sensor_result_2 */
$sensor_result_2 = $sensor_runner->runSensors([$sensorConfig])[0];
$previous_result_2 = $sensor_result_2->getPreviousResult();
$this->assertEquals(SensorResultInterface::STATUS_CRITICAL, $sensor_result_2->getStatus());
$this->assertEquals($sensor_result_1->getStatus(), $previous_result_2->getStatus());
$this->assertNotNull($previous_result_2);
// Change sensor threshold settings so that the sensor switches to WARNING.
$sensorConfig->thresholds['critical'] = 0;
// Run it again, a new log should be stored because the status has changed.
/** @var \Drupal\monitoring\Result\SensorResult $sensor_result_3 */
$sensor_result_3 = $sensor_runner->runSensors([$sensorConfig])[0];
$previous_result_3 = $sensor_result_3->getPreviousResult();
$this->assertEquals(SensorResultInterface::STATUS_WARNING, $sensor_result_3->getStatus());
$this->assertEquals($sensor_result_2->getStatus(), $previous_result_3->getStatus());
$this->assertNotNull($previous_result_3);
}
}
