You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1000 lines
33 KiB

<?php
/*
** Zabbix
** Copyright (C) 2001-2023 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
require_once dirname(__FILE__).'/../../include/CWebTest.php';
require_once dirname(__FILE__).'/../../include/helpers/CDataHelper.php';
/**
* @backup hosts
*
* @onBefore prepareProblemsData
*/
class testFormUpdateProblem extends CWebTest {
/**
* Id of the host with problems.
*
* @var integer
*/
protected static $hostid;
/**
* Ids of the triggers for problems.
*
* @var array
*/
protected static $triggerids;
/**
* Time when acknowledge was created.
*
* @var string
*/
protected static $acktime;
/**
* Attach MessageBehavior to the test.
*
* @return array
*/
public function getBehaviors() {
return [CMessageBehavior::class];
}
/**
* Get all events related tables hash values.
*/
public static function getHash() {
return CDBHelper::getHash('SELECT * FROM events').
CDBHelper::getHash('SELECT * FROM problem').
CDBHelper::getHash('SELECT * FROM triggers').
CDBHelper::getHash('SELECT * FROM acknowledges').
CDBHelper::getHash('SELECT * FROM event_suppress');
}
public function prepareProblemsData() {
// Create hostgroup for hosts with items triggers.
$hostgroups = CDataHelper::call('hostgroup.create', [['name' => 'Group for Problems Update']]);
$this->assertArrayHasKey('groupids', $hostgroups);
$groupid = $hostgroups['groupids'][0];
// Create host for items and triggers.
$hosts = CDataHelper::call('host.create', [
'host' => 'Host for Problems Update',
'groups' => [['groupid' => $groupid]]
]);
$this->assertArrayHasKey('hostids', $hosts);
self::$hostid = $hosts['hostids'][0];
// Create items on previously created host.
$item_names = ['float', 'char', 'log', 'unsigned', 'text'];
$items_data = [];
foreach ($item_names as $i => $item) {
$items_data[] = [
'hostid' => self::$hostid,
'name' => $item,
'key_' => $item,
'type' => 2,
'value_type' => $i
];
}
$items = CDataHelper::call('item.create', $items_data);
$this->assertArrayHasKey('itemids', $items);
// Create triggers based on items.
$triggers = CDataHelper::call('trigger.create', [
[
'description' => 'Trigger for float',
'expression' => 'last(/Host for Problems Update/float)=0',
'priority' => 0
],
[
'description' => 'Trigger for char',
'expression' => 'last(/Host for Problems Update/char)=0',
'priority' => 1,
'manual_close' => 1
],
[
'description' => 'Trigger for log',
'expression' => 'last(/Host for Problems Update/log)=0',
'priority' => 2
],
[
'description' => 'Trigger for unsigned',
'expression' => 'last(/Host for Problems Update/unsigned)=0',
'priority' => 3
],
[
'description' => 'Trigger for text',
'expression' => 'last(/Host for Problems Update/text)=0',
'priority' => 4
],
[
'description' => 'Trigger for icon test',
'expression' => 'last(/Host for Problems Update/log)=0',
'priority' => 3
]
]);
$this->assertArrayHasKey('triggerids', $triggers);
self::$triggerids = CDataHelper::getIds('description');
// Create events.
$time = time();
$i=0;
foreach (self::$triggerids as $name => $id) {
DBexecute('INSERT INTO events (eventid, source, object, objectid, clock, ns, value, name, severity) VALUES ('.(100550 + $i).', 0, 0, '.
zbx_dbstr($id).', '.$time.', 0, 1, '.zbx_dbstr($name).', '.zbx_dbstr($i).')'
);
$i++;
}
// Create problems.
$j=0;
foreach (self::$triggerids as $name => $id) {
DBexecute('INSERT INTO problem (eventid, source, object, objectid, clock, ns, name, severity) VALUES ('.(100550 + $j).', 0, 0, '.
zbx_dbstr($id).', '.$time.', 0, '.zbx_dbstr($name).', '.zbx_dbstr($j).')'
);
$j++;
}
// Change triggers' state to Problem. Manual close is true for the problem: Trigger for char'.
DBexecute('UPDATE triggers SET value = 1 WHERE description IN ('.zbx_dbstr('Trigger for float').', '.
zbx_dbstr('Trigger for log').', '.zbx_dbstr('Trigger for unsigned').', '.zbx_dbstr('Trigger for text').', '.
zbx_dbstr('Trigger for icon test').')'
);
DBexecute('UPDATE triggers SET value = 1, manual_close = 1 WHERE description = '.zbx_dbstr('Trigger for char'));
// Suppress the problem: 'Trigger for text'.
DBexecute('INSERT INTO event_suppress (event_suppressid, eventid, maintenanceid, suppress_until) VALUES (10050, 100554, NULL, 0)');
// Acknowledge the problem: 'Trigger for unsigned' and get acknowledge time.
CDataHelper::call('event.acknowledge', [
'eventids' => 100553,
'action' => 6,
'message' => 'Acknowledged event'
]);
$event = CDataHelper::call('event.get', [
'eventids' => 100553,
'selectAcknowledges' => ['clock']
]);
self::$acktime = CTestArrayHelper::get($event, '0.acknowledges.0.clock');
}
public function getLayoutData() {
return [
[
[
'problems' => ['Trigger for float'],
'hintboxes' => [
'Suppress' => 'Manual problem suppression. Date-time input accepts relative and absolute time format.',
'Unsuppress' => 'Deactivates manual suppression.',
'Acknowledge' => 'Confirms the problem is noticed (acknowledging user will be recorded). '.
'Status change triggers action update operation.'
],
'history' => [],
'Acknowledge' => true,
'check_suppress' => true
]
],
[
[
'problems' => ['Trigger for char'],
'close_enabled' => true,
'history' => [],
'Acknowledge' => true
]
],
[
[
'problems' => ['Trigger for text'],
'unsuppress_enabled' => true,
'history' => [],
'Acknowledge' => true
]
],
[
[
'problems' => ['Trigger for unsigned'],
// If problem is Aknowledged - label is changed to Unacknowledge.
'labels' => ['Problem', 'Message', 'History', 'Scope', 'Change severity', 'Suppress',
'Unsuppress', 'Unacknowledge', 'Convert to cause', 'Close problem', ''
],
'message' => 'Acknowledged event',
'Unacknowledge' => true,
'history' => [" Admin (Zabbix Administrator)".
"\nAcknowledged event"
],
'hintboxes' => [
'Suppress' => 'Manual problem suppression. Date-time input accepts relative and absolute time format.',
'Unsuppress' => 'Deactivates manual suppression.',
'Unacknowledge' => 'Undo problem acknowledgement.'
]
]
],
[
[
'problems' => ['Trigger for log'],
'history' => [],
'Acknowledge' => true
]
],
// Two problems.
[
[
'problems' => ['Trigger for float', 'Trigger for char'],
// If more than one problems selected - History label is absent.
'labels' => ['Problem', 'Message', 'Scope', 'Change severity', 'Suppress', 'Unsuppress',
'Acknowledge', 'Convert to cause', 'Close problem', ''
],
'close_enabled' => true,
'Acknowledge' => true,
'hintboxes' => [
'Suppress' => 'Manual problem suppression. Date-time input accepts relative and absolute time format.',
'Unsuppress' => 'Deactivates manual suppression.',
'Acknowledge' => 'Confirms the problem is noticed (acknowledging user will be recorded). '.
'Status change triggers action update operation.'
]
]
],
// Five problems.
[
[
'problems' => ['Trigger for float', 'Trigger for char', 'Trigger for log', 'Trigger for unsigned', 'Trigger for text'],
// If more than one problem selected - History label is absent.
'labels' => ['Problem', 'Message', 'Scope', 'Change severity', 'Suppress', 'Unsuppress',
'Acknowledge', 'Unacknowledge', 'Convert to cause', 'Close problem', ''
],
'hintboxes' => [
'Suppress' => 'Manual problem suppression. Date-time input accepts relative and absolute time format.',
'Unsuppress' => 'Deactivates manual suppression.',
'Acknowledge' => 'Confirms the problem is noticed (acknowledging user will be recorded). '.
'Status change triggers action update operation.',
'Unacknowledge' => 'Undo problem acknowledgement.'
],
'close_enabled' => true,
'unsuppress_enabled' => true,
'Acknowledge' => true,
'Unacknowledge' => true
]
]
];
}
/**
* @dataProvider getLayoutData
*/
public function testFormUpdateProblem_Layout($data) {
// Open filtered Problems list.
$this->page->login()->open('zabbix.php?&action=problem.view&filter_set=1&show_suppressed=1&hostids%5B%5D='.self::$hostid)->waitUntilReady();
$table = $this->query('class:list-table')->asTable()->one();
$table->findRows('Problem', $data['problems'])->select();
$this->query('button:Mass update')->waitUntilClickable()->one()->click();
$dialog = COverlayDialogElement::find()->one()->waitUntilReady();
$this->assertEquals('Update problem', $dialog->getTitle());
$form = $dialog->query('id:acknowledge_form')->asForm()->one();
// Check form labels.
$count = count($data['problems']);
$default_labels = ['Problem', 'Message', 'History', 'Scope', 'Change severity', 'Suppress', 'Unsuppress',
'Acknowledge', 'Convert to cause', 'Close problem', ''];
$this->assertEquals(CTestArrayHelper::get($data, 'labels', $default_labels), $form->getLabels()->asText());
// Check "Problem" field value.
$problem = $count > 1 ? $count.' problems selected.' : $data['problems'][0];
$this->assertTrue($form->query('xpath:.//div[@class="wordbreak" and text()='.
CXPathHelper::escapeQuotes($problem).']')->exists()
);
// Check first label in Scope field.
$scope_field = $form->getField('Scope');
$scope_label_query = $count > 1
? 'xpath:.//label[text()="Only selected problems"]/sup[text()='.CXPathHelper::escapeQuotes($count.' events').']'
: 'xpath:.//label[text()="Only selected problem"]';
$this->assertTrue($scope_field->query($scope_label_query)->exists());
// Check second label in Scope field.
$this->assertTrue($scope_field->query("xpath:.//label[text()=".
"\"Selected and all other problems of related triggers\"]/sup[text()=".
CXPathHelper::escapeQuotes($count > 1 ? $count.' events' : '1 event')."]")->exists()
);
// Check Hintboxes.
if (CTestArrayHelper::get($data, 'hintboxes')) {
foreach ($data['hintboxes'] as $field => $text) {
$form->getLabel($field)->query('xpath:./button[@data-hintbox]')->one()->click();
$hint = $this->query('xpath://div[@class="overlay-dialogue"]')->waitUntilPresent()->one();
$this->assertEquals($text, $hint->getText());
$hint->query('class:btn-overlay-close')->waitUntilClickable()->one()->click();
}
}
// Check History field.
if (array_key_exists('history', $data)) {
$history = ($data['history'] === []) ? $data['history'] : [date('Y-m-d H:i:s', self::$acktime).$data['history'][0]];
$history_table = $form->getField('History')->asTable();
$this->assertEquals(['Time', 'User', 'User action', 'Message'], $history_table->getHeadersText());
$this->assertEquals($history, $history_table->getRows()->asText());
if ($data['problems'] === ['Trigger for unsigned']) {
foreach (['Acknowledged', 'Message'] as $icon) {
$this->assertTrue($history_table->query("xpath:.//span[@class=".CXPathHelper::fromClass('icon-action').
" and @title=".CXPathHelper::escapeQuotes($icon)."]")->exists()
);
}
}
}
// Check fields' default values and attributes.
$fields = [
'id:message' => ['value' => '', 'maxlength' => 2048, 'enabled' => true],
'id:scope_0' => ['value' => true, 'enabled' => true], // Only selected problem.
'id:scope_1' => ['value' => false, 'enabled' => true], // Selected and all other problems of related triggers.
'id:change_severity' => ['value' => false, 'enabled' => true],
'id:severity' => ['value' => 'Not classified', 'enabled' => false],
'id:suppress_problem' => ['value' => false, 'enabled' => true],
'id:suppress_time_option' => ['value' => 'Until', 'enabled' => false],
'id:suppress_until_problem' => ['maxlength' => 19, 'value' => 'now+1d', 'enabled' => false, 'placeholder' => 'now+1d'],
'id:unsuppress_problem' => ['value' => false, 'enabled' => CTestArrayHelper::get($data, 'unsuppress_enabled', false)],
'Close problem' => ['value' => false, 'enabled' => CTestArrayHelper::get($data, 'close_enabled', false)]
];
foreach ($fields as $field => $attributes) {
$this->assertEquals($attributes['value'], $form->getField($field)->getValue());
$this->assertTrue($form->getField($field)->isEnabled($attributes['enabled']));
if (array_key_exists('maxlength', $attributes)) {
$this->assertEquals($attributes['maxlength'], $form->getField($field)->getAttribute('maxlength'));
}
if (array_key_exists('placeholder', $attributes)) {
$this->assertEquals($attributes['placeholder'], $form->getField($field)->getAttribute('placeholder'));
}
}
// Check default values for 'Acknowledge' and 'Unacknowledge' fields.
foreach (['Acknowledge', 'Unacknowledge'] as $label) {
if (array_key_exists($label, $data)) {
$field = $form->getField($label);
$this->assertEquals(false, $field->getValue());
$this->assertTrue($field->isEnabled());
}
}
// Check Suppress and Unsuppress checkboxes dependency.
if (CTestArrayHelper::get($data, 'unsuppress_enabled')) {
$suppress_combinations = [
['id:suppress_problem', 'id:unsuppress_problem'],
['id:unsuppress_problem', 'id:suppress_problem']
];
foreach ($suppress_combinations as $checkboxes) {
foreach ([true, false] as $state) {
$form->fill([$checkboxes[0] => $state]);
$this->assertTrue($form->getField($checkboxes[1])->isEnabled(!$state));
}
}
}
// Check other buttons in overlay.
$button_queries = [
// Button ? (help) is covered in testDocumentationLinks.
'xpath:.//button[@title="Close"]' => true,
'xpath:.//button[@id="suppress_until_problem_calendar"]' => false,
'button:Update' => true,
'button:Cancel' => true
];
foreach ($button_queries as $query => $clickable) {
$this->assertEquals($clickable, $dialog->query($query)->one()->isClickable());
}
// Check Suppress field.
if (CTestArrayHelper::get($data, 'check_suppress')) {
$form->fill(['id:suppress_problem' => true]);
// Check Until field is enabled.
$this->assertTrue($form->getField('id:suppress_time_option')->isEnabled());
$this->assertTrue($form->getField('id:suppress_until_problem')->isEnabled());
// Check calendar.
$calendar = $form->query('xpath:.//button[@id="suppress_until_problem_calendar"]')->one();
$calendar->waitUntilClickable()->click();
$calendar_overlay = $this->query('xpath://div[@aria-label="Calendar"]');
$this->assertTrue($calendar_overlay->exists());
$calendar->click();
$this->assertFalse($calendar_overlay->exists());
// Check Until field is disabled.
$form->fill(['id:suppress_time_option' => 'Indefinitely']);
$this->assertFalse($form->getField('id:suppress_until_problem')->isEnabled());
$this->assertEquals(false, $calendar->isClickable());
}
// Check Suppress/Unsuppress fields depending on Close problem checkbox.
if (CTestArrayHelper::get($data, 'close_enabled') && CTestArrayHelper::get($data, 'unsuppress_enabled')) {
foreach ([true, false] as $state) {
$form->fill(['id:close_problem' => $state]);
$this->assertFalse($form->getField('id:suppress_problem')->isEnabled($state));
$this->assertFalse($form->getField('id:unsuppress_problem')->isEnabled($state));
}
}
// Check asterisk text.
$this->assertTrue($form->query('xpath:.//label[@class="form-label-asterisk" and '.
'text()="At least one update operation or message must exist."]')->exists()
);
$dialog->close();
}
public function getFormData() {
return [
[
[
'expected' => TEST_BAD,
'problems' => ['Trigger for float'],
'fields' => [
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => '2020-08-01 00:00:00'
],
'error' => 'Incorrect value for field "Suppress": invalid time.'
]
],
[
[
'expected' => TEST_BAD,
'problems' => ['Trigger for float', 'Trigger for log'],
'fields' => [
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => '2040-08-01'
],
'error' => 'Incorrect value for field "Suppress": invalid time.'
]
],
[
[
'expected' => TEST_BAD,
'problems' => ['Trigger for text', 'Trigger for log'],
'fields' => [
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => '2040-08-01 00:00:00'
],
'error' => 'Incorrect value for field "Suppress": invalid time.'
]
],
[
[
'expected' => TEST_BAD,
'problems' => ['Trigger for text'],
'fields' => [
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => '00:00:00'
],
'error' => 'Incorrect value for field "suppress_until_problem": a time is expected.'
]
],
[
[
'expected' => TEST_BAD,
'problems' => ['Trigger for text'],
'fields' => [
'id:message' => 'not showing message 😾',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now+16y'
],
'error' => 'Incorrect value for field "Suppress": invalid time.'
]
],
[
[
'expected' => TEST_BAD,
'problems' => ['Trigger for text'],
'fields' => [
'id:message' => 'not showing message',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now-1d'
],
'error' => 'Incorrect value for field "Suppress": invalid time.'
]
],
[
[
'expected' => TEST_BAD,
'problems' => ['Trigger for text'],
'fields' => [
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => '-3d'
],
'error' => 'Incorrect value for field "suppress_until_problem": a time is expected.'
]
],
[
[
'expected' => TEST_BAD,
'problems' => ['Trigger for char'],
'fields' => [
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'text'
],
'error' => 'Incorrect value for field "suppress_until_problem": a time is expected.'
]
],
[
[
'problems' => ['Trigger for log', 'Trigger for char', 'Trigger for float'],
'fields' => [
'id:scope_1' => true,
'id:change_severity' => true,
'id:severity' => 'Information',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now+2h'
],
'db_check' => [
[
'name' => 'Trigger for log',
'db_fields' => ['message' => '', 'action' => 40, 'new_severity' => 1, 'suppress_until' => true]
],
[
'name' => 'Trigger for char',
'db_fields' => ['message' => '', 'action' => 32, 'new_severity' => 0, 'suppress_until' => true]
],
[
'name' => 'Trigger for float',
'db_fields' => ['message' => '', 'action' => 40, 'new_severity' => 1, 'suppress_until' => true]
]
]
]
],
[
[
'problems' => ['Trigger for float'],
'fields' => [
'id:message' => 'test message text',
'id:change_severity' => true,
'id:severity' => 'Warning',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Indefinitely',
'Acknowledge' => true
],
'db_check' => [
[
'name' => 'Trigger for float',
'db_fields' => ['message' => 'test message text', 'action' => 46, 'new_severity' => 2, 'suppress_until' => 0]
]
]
]
],
[
[
'problems' => ['Trigger for text', 'Trigger for log'],
'fields' => [
'id:change_severity' => true,
'id:severity' => 'Not classified',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now+30s'
],
'db_check' => [
[
'name' => 'Trigger for text',
'db_fields' => ['message' => '', 'action' => 40, 'new_severity' => 0, 'suppress_until' => true]
],
[
'name' => 'Trigger for text',
'db_fields' => ['message' => '', 'action' => 40, 'new_severity' => 0, 'suppress_until' => true]
]
]
]
],
[
[
'problems' => ['Trigger for char'],
'fields' => [
'id:change_severity' => true,
'id:severity' => 'Average',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now+3d'
],
'db_check' => [
[
'name' => 'Trigger for char',
'db_fields' => ['message' => '', 'action' => 40, 'new_severity' => 3, 'suppress_until' => true]
]
]
]
],
[
[
'problems' => ['Trigger for unsigned'],
'fields' => [
'id:message' => '😻 😻 😻',
'id:change_severity' => true,
'id:severity' => 'High',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now+14y'
],
'db_check' => [
[
'name' => 'Trigger for unsigned',
'db_fields' => ['message' => '😻 😻 😻', 'action' => 44, 'new_severity' => 4, 'suppress_until' => true]
]
]
]
],
[
[
'problems' => ['Trigger for log'],
'fields' => [
'id:change_severity' => true,
'id:severity' => 'Disaster',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now+18w'
],
'db_check' => [
[
'name' => 'Trigger for log',
'db_fields' => ['message' => '', 'action' => 40, 'new_severity' => 5, 'suppress_until' => true]
]
]
]
],
[
[
'problems' => ['Trigger for text', 'Trigger for log'],
'fields' => [
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now+9M'
],
'db_check' => [
[
'name' => 'Trigger for text',
'db_fields' => ['message' => '', 'action' => 32, 'new_severity' => 0, 'suppress_until' => true]
],
[
'name' => 'Trigger for log',
'db_fields' => ['message' => '', 'action' => 32, 'new_severity' => 0, 'suppress_until' => true]
]
]
]
],
[
[
'problems' => ['Trigger for log', 'Trigger for char', 'Trigger for float', 'Trigger for text', 'Trigger for unsigned'],
'fields' => [
'id:message' => 'Update all 5 problems',
'id:change_severity' => true,
'id:severity' => 'High',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now+2h'
],
'db_check' => [
[
'name' => 'Trigger for log',
'db_fields' => ['message' => 'Update all 5 problems', 'action' => 44, 'new_severity' => 4, 'suppress_until' => true]
],
[
'name' => 'Trigger for char',
'db_fields' => ['message' => 'Update all 5 problems', 'action' => 44, 'new_severity' => 4, 'suppress_until' => true]
],
[
'name' => 'Trigger for float',
'db_fields' => ['message' => 'Update all 5 problems', 'action' => 44, 'new_severity' => 4, 'suppress_until' => true]
],
[
'name' => 'Trigger for text',
'db_fields' => ['message' => 'Update all 5 problems', 'action' => 44, 'new_severity' => 4, 'suppress_until' => true]
],
[
'name' => 'Trigger for unsigned',
'db_fields' => ['message' => 'Update all 5 problems', 'action' => 36, 'new_severity' => 0, 'suppress_until' => true]
]
]
]
],
[
[
'problems' => ['Trigger for text'],
'fields' => [
'id:unsuppress_problem' => true
],
'db_check' => [
[
'name' => 'Trigger for text',
'db_fields' => ['message' => '', 'action' => 64, 'new_severity' => 0, 'suppress_until' => 0]
]
]
]
],
[
[
'problems' => ['Trigger for unsigned'],
'fields' => [
'Unacknowledge' => true
],
'db_check' => [
[
'name' => 'Trigger for unsigned',
'db_fields' => ['message' => '', 'action' => 16, 'new_severity' => 0, 'suppress_until' => 0]
]
]
]
],
[
[
'problems' => ['Trigger for char'],
'fields' => [
'Close problem' => true
],
'db_check' => [
[
'name' => 'Trigger for char',
'db_fields' => ['message' => '', 'action' => 1, 'new_severity' => 0, 'suppress_until' => 0]
]
]
]
]
];
}
/**
* @dataProvider getFormData
*/
public function testFormUpdateProblem_Form($data) {
if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
$old_hash = $this->getHash();
}
// Open filtered Problems list.
$this->page->login()->open('zabbix.php?&action=problem.view&show_suppressed=1&hostids%5B%5D='.self::$hostid)->waitUntilReady();
$table = $this->query('class:list-table')->asTable()->one();
$count = count($data['problems']);
$table->findRows('Problem', $data['problems']);
if ($count > 1) {
$table->findRows('Problem', $data['problems'])->select();
$this->query('button:Mass update')->waitUntilClickable()->one()->click();
}
else {
$table->findRow('Problem', $data['problems'][0])->getColumn('Update')->query('tag:a')->waitUntilClickable()->one()->click();
}
$dialog = COverlayDialogElement::find()->one()->waitUntilReady();
$form = $dialog->query('id:acknowledge_form')->asForm()->one();
$form->fill($data['fields']);
$form->submit();
if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
$this->assertTrue($dialog->isVisible());
$this->assertMessage(TEST_BAD, null, $data['error']);
$this->assertEquals($old_hash, $this->getHash());
$dialog->close();
}
else {
$dialog->ensureNotPresent();
$this->page->waitUntilReady();
$this->page->assertHeader('Problems');
$message = ($count > 1) ? 'Events updated' : 'Event updated';
$this->assertMessage(TEST_GOOD, $message);
// Check db change.
foreach ($data['db_check'] as $event) {
$sql = CDBHelper::getRow('SELECT message, action, new_severity, suppress_until'.
' FROM acknowledges'.
' WHERE eventid=('.
'SELECT eventid'.
' FROM events'.
' WHERE name='.zbx_dbstr($event['name']).
') ORDER BY acknowledgeid DESC'
);
// Suppress time is always different, so we check only that it is > 0.
if ($sql['suppress_until'] > 0) {
$sql['suppress_until'] = true;
}
$this->assertEquals($event['db_fields'], $sql);
}
}
}
public function getCancelData() {
return [
[
[
'case' => 'Cancel'
]
],
[
[
'case' => 'Close'
]
]
];
}
/**
* @dataProvider getCancelData
*/
public function testFormUpdateProblem_Cancel($data) {
$old_hash = $this->getHash();
// Open filtered Problems list.
$this->page->login()->open('zabbix.php?&action=problem.view&show_suppressed=1&hostids%5B%5D='.self::$hostid)->waitUntilReady();
$this->query('class:list-table')->asTable()->one()->findRow('Problem', 'Trigger for log')->getColumn('Update')
->query('tag:a')->waitUntilClickable()->one()->click();
$dialog = COverlayDialogElement::find()->one()->waitUntilReady();
$dialog->query('id:acknowledge_form')->asForm()->one()->fill([
'id:scope_1' => true,
'id:change_severity' => true,
'id:severity' => 'Disaster',
'id:suppress_problem' => true,
'id:suppress_time_option' => 'Until',
'id:suppress_until_problem' => 'now+2h',
'Acknowledge' => true
]);
$dialog->query(($data['case'] === 'Close') ? 'xpath:.//button[@title="Close"]' : 'button:Cancel')->one()
->waitUntilClickable()->click();
$dialog->ensureNotPresent();
$this->page->assertHeader('Problems');
$this->assertEquals($old_hash, $this->getHash());
}
public function testFormUpdateProblem_CheckSuppressIcon() {
$this->page->login()->open('zabbix.php?&action=problem.view&show_suppressed=1&hostids%5B%5D='.self::$hostid)->waitUntilReady();
$table = $this->query('class:list-table')->asTable()->one();
$row = $table->findRow('Problem', 'Trigger for icon test');
$row->getColumn('Update')->query('tag:a')->waitUntilClickable()->one()->click();
$dialog = COverlayDialogElement::find()->one()->waitUntilReady();
$form = $dialog->query('id:acknowledge_form')->asForm()->one();
$form->fill(['id:suppress_problem' => true, 'id:suppress_time_option' => 'Indefinitely']);
$form->submit();
$dialog->ensureNotPresent();
$this->page->waitUntilReady();
$table->waitUntilReloaded();
// Check suppressed icon and hint.
$this->checkIconAndHint($row, 'zi-eye-off', "Suppressed till: Indefinitely".
"\nManually by: Admin (Zabbix Administrator)"
);
// Suppress the problem in DB: 'Trigger for icon test'.
DBexecute('INSERT INTO event_suppress (event_suppressid, eventid, maintenanceid, suppress_until) VALUES (10051, 100555, NULL, 0)');
// Assert that eye icon stopped blinking.
$this->page->refresh();
$this->assertTrue($row->getColumn('Info')->query('xpath:.//button[not(contains(@class, "js-blink"))]')->exists());
// Unsuppress problem.
$row->getColumn('Update')->query('tag:a')->waitUntilClickable()->one()->click();
$form->fill(['id:unsuppress_problem' => true]);
$form->submit();
$dialog->ensureNotPresent();
$this->page->waitUntilReady();
$table->waitUntilReloaded();
// Check unsuppressed icon and hint.
$this->checkIconAndHint($row, 'zi-eye', 'Unsuppressed by: Admin (Zabbix Administrator)');
// Unsuppress the problem in DB: 'Trigger for icon test'.
DBexecute('DELETE FROM event_suppress WHERE event_suppressid=10051');
$this->page->refresh();
// Check that eye icon disappeared.
$this->assertFalse($row->getColumn('Info')->query("xpath:.//button[@class=".
CXPathHelper::fromClass('zi-eye')."]")->exists()
);
// Check Suppress/Unsuppress icon in History table.
$row->getColumn('Update')->query('tag:a')->waitUntilClickable()->one()->click();
$dialog->waitUntilReady();
$form->invalidate();
$this->checkHistoryTable($form->getField('History')->asTable(), 'User', 'User action');
$dialog->close();
$this->page->waitUntilReady();
// Check Actions hint in Problem row.
$row->invalidate();
$unsuppress_button = 'xpath:.//button['.CXPathHelper::fromClass('zi-eye').']';
$row->getColumn('Actions')->query($unsuppress_button)->waitUntilClickable()->one()->click();
$hint = $this->query('xpath://div[@data-hintboxid and @class="overlay-dialogue"]')->asOverlayDialog()
->one()->waitUntilReady();
$this->checkHistoryTable($hint->query('class:list-table')->asTable()->one(), 'User', 'Action');
$hint->close();
// Check Event details page.
$row->getColumn('Time')->query('tag:a')->waitUntilClickable()->one()->click();
$this->page->assertHeader('Event details');
$this->checkHistoryTable($this->query("xpath://section[@id=\"hat_eventactions\"]//table")->asTable()->one(),
'User/Recipient', 'Action'
);
// Check Actions hint in Event list.
$event_list_table = $this->query('xpath://section[@id="hat_eventlist"]//table')->asTable()->one();
$event_list_table->getRow(0)->getColumn('Actions')->query($unsuppress_button)->waitUntilClickable()->one()->click();
$hint->invalidate();
$this->checkHistoryTable($hint->query('class:list-table')->asTable()->one(), 'User', 'Action');
$hint->close();
}
/**
* Function for testing Suppressed/Unsuppressed icon or button in history tables.
*
* @param CTableElement $table problem/event history table
* @param string $user user table header
* @param string $action action table header
*/
private function checkHistoryTable($table, $user, $action) {
// Check last two rows.
foreach ([0, 1] as $i) {
$action_row = $table->getRow($i);
$this->assertEquals('Admin (Zabbix Administrator)', $action_row->getColumn($user)->getText());
$query = ($i === 0)
? 'xpath:.//span[@title="Unsuppressed"]'
: 'xpath:.//*['.CXPathHelper::fromClass('zi-eye-off').']';
$this->assertTrue($action_row->getColumn($action)->query($query)->exists());
}
}
/**
*
* @param CTableRowElement $row table row where necessary problem is found
* @param string $class suppressed or unsuppressed icon class
* @param string $text text of suppression/unsuppression info-hint
*/
private function checkIconAndHint($row, $class, $text) {
// Assert blinking icon in Info column.
$icon = $row->getColumn('Info')->query('class', [$class, 'js-blink'])->waitUntilVisible();
$this->assertTrue($icon->exists());
// Check icon hintbox.
$icon->one()->waitUntilClickable()->click(true);
$hint = $this->query('xpath://div[@data-hintboxid]')->one();
$this->assertTrue($hint->isVisible());
$this->assertEquals($text, $hint->getText());
$hint->asOverlayDialog()->close();
// Assert non-blinking icon in Actions column.
$this->assertTrue($row->getColumn('Actions')->query('xpath:.//button['.CXPathHelper::fromClass($class).']')->exists());
}
}