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.

668 lines
17 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__).'/../behaviors/CMessageBehavior.php';
require_once dirname(__FILE__).'/../traits/TableTrait.php';
/**
* @backup scripts
*
* @dataSource HostTemplateGroups
*
* @onBefore prepareScriptData
*/
class testPageAlertsScripts extends CWebTest {
use TableTrait;
/**
* Attach MessageBehavior to the test.
*
* @return array
*/
public function getBehaviors() {
return [
'class' => CMessageBehavior::class
];
}
/**
* Script created in dataSource HostTemplateGroups.
*/
const HOST_GROUP_SCRIPT = 'Script for host group testing';
private static $script_sql = 'SELECT * FROM scripts ORDER BY scriptid';
private static $custom_script = 'Custom script with linked action';
private static $script_for_filter = 'Script для фильтра - $¢Řĩ₱₮';
private static $script_scope_event = 'Manual event action for filter check';
private static $custom_action = 'Trigger action for Scripts page testing';
public function prepareScriptData() {
CDataHelper::call('script.create', [
[
'name' => self::$script_scope_event,
'type' => ZBX_SCRIPT_TYPE_CUSTOM_SCRIPT,
'scope' => ZBX_SCRIPT_SCOPE_EVENT,
'command' => 'test'
],
[
'name' => self::$script_for_filter,
'type' => ZBX_SCRIPT_TYPE_CUSTOM_SCRIPT,
'scope' => ZBX_SCRIPT_SCOPE_EVENT,
'command' => '/sbin/run'
],
[
'name' => self::$custom_script,
'type' => ZBX_SCRIPT_TYPE_CUSTOM_SCRIPT,
'scope' => ZBX_SCRIPT_SCOPE_ACTION,
'command' => '/sbin/zabbix_server --runtime-control config_cache_reload',
'groupid' => '4',
'description' => 'This command reload cache.'
]
]);
$scriptids = CDataHelper::getIds('name');
// Create trigger action
CDataHelper::call('action.create', [
'esc_period' => '1m',
'eventsource' => EVENT_SOURCE_TRIGGERS,
'status' => ACTION_STATUS_ENABLED,
'name' => self::$custom_action,
'operations' => [
[
'esc_period' => '0',
'esc_step_from' => '1',
'esc_step_to' => '1',
'operationtype' => OPERATION_TYPE_COMMAND,
'opcommand' => [
'scriptid' => $scriptids[self::$custom_script]
],
'opcommand_hst' => [
[
'hostid'=> '0'
]
]
]
]
]);
}
public function getScriptsData() {
return [
[
[
[
'Name' => self::$custom_script,
'Scope' => 'Action operation',
'Used in actions' => self::$custom_action,
'Type' => 'Script',
'Execute on' => 'Server (proxy)',
'Commands' => '/sbin/zabbix_server --runtime-control config_cache_reload',
'User group' => 'All',
'Host group' => 'Zabbix servers',
'Host access' => 'Read'
],
[
'Name' => 'Detect operating system',
'Scope' => 'Manual host action',
'Used in actions' => '',
'Type' => 'Script',
'Execute on' => 'Server (proxy)',
'Commands' => 'sudo /usr/bin/nmap -O {HOST.CONN}',
'User group' => 'Zabbix administrators',
'Host group' => 'All',
'Host access' => 'Read'
],
[
'Name' => self::$script_scope_event,
'Scope' => 'Manual event action',
'Used in actions' => '',
'Type' => 'Script',
'Execute on' => 'Server (proxy)',
'Commands' => 'test',
'User group' => 'All',
'Host group' => 'All',
'Host access' => 'Read'
],
[
'Name' => 'Ping',
'Scope' => 'Manual host action',
'Used in actions' => '',
'Type' => 'Script',
'Execute on' => 'Server (proxy)',
'Commands' => 'ping -c 3 {HOST.CONN}; case $? in [01]) true;; *) false;; esac',
'User group' => 'All',
'Host group' => 'All',
'Host access' => 'Read'
],
[
'Name' => 'Reboot',
'Scope' => 'Action operation',
'Used in actions' => 'Autoregistration action 1, Autoregistration action 2, Trigger action 4',
'Type' => 'Script',
'Execute on' => 'Server (proxy)',
'Commands' => '/sbin/shutdown -r',
'User group' => 'Zabbix administrators',
'Host group' => 'Zabbix servers',
'Host access' => 'Write'
],
[
'Name' => self::HOST_GROUP_SCRIPT,
'Scope' => 'Action operation',
'Used in actions' => '',
'Type' => 'Webhook',
'Execute on' => '',
'Commands' => '',
'User group' => 'All',
'Host group' => 'Group for Script',
'Host access' => 'Read'
],
[
'Name' => self::$script_for_filter,
'Scope' => 'Manual event action',
'Used in actions' => '',
'Type' => 'Script',
'Execute on' => 'Server (proxy)',
'Commands' => '/sbin/run',
'User group' => 'All',
'Host group' => 'All',
'Host access' => 'Read'
],
[
'Name' => 'Selenium script',
'Scope' => 'Action operation',
'Used in actions' => '',
'Type' => 'Script',
'Execute on' => 'Server (proxy)',
'Commands' => 'test',
'User group' => 'Selenium user group in scripts',
'Host group' => 'All',
'Host access' => 'Read'
],
[
'Name' => 'Traceroute',
'Scope' => 'Manual host action',
'Used in actions' => '',
'Type' => 'Script',
'Execute on' => 'Server (proxy)',
'Commands' => '/usr/bin/traceroute {HOST.CONN}',
'User group' => 'All',
'Host group' => 'All',
'Host access' => 'Read'
]
]
]
];
}
/**
* @dataProvider getScriptsData
*/
public function testPageAlertsScripts_Layout($data) {
$scripts_count = count($data);
$this->page->login()->open('zabbix.php?action=script.list');
$this->page->assertTitle('Configuration of scripts');
$this->page->assertHeader('Scripts');
// Check buttons on the Script page.
$this->assertEquals(3, $this->query('button', ['Create script', 'Apply', 'Reset'])
->all()->filter(CElementFilter::CLICKABLE)->count()
);
$this->assertFalse($this->query('button:Delete')->one()->isClickable());
// Check displaying and hiding the filter.
$filter_form = $this->query('name:zbx_filter')->asForm()->one();
$filter_tab = $this->query('link:Filter')->one();
$filter = $filter_form->query('id:tab_0')->one();
$this->assertTrue($filter->isDisplayed());
$filter_tab->click();
$this->assertFalse($filter->isDisplayed());
$filter_tab->click();
$this->assertTrue($filter->isDisplayed());
// Check filter labels and default values.
$this->assertEquals(['Name', 'Scope'], $filter_form->getLabels()->asText());
$filter_form->checkValue(['Name' => '', 'Scope' => 'Any']);
$this->assertEquals('255', $filter_form->getField('Name')->getAttribute('maxlength'));
// Check the count of returned Scripts and the count of selected Scripts.
$this->assertTableStats($scripts_count);
$this->assertSelectedCount(0);
$all_scripts = $this->query('id:all_scripts')->asCheckbox()->one();
$all_scripts->check();
$this->assertSelectedCount($scripts_count);
// Check that button became enabled.
$this->assertTrue($this->query('button:Delete')->one()->isClickable());
$all_scripts->uncheck();
$this->assertSelectedCount(0);
// Check table headers.
$table = $this->query('class:list-table')->asTable()->one();
$this->assertEquals(['', 'Name', 'Scope', 'Used in actions', 'Type', 'Execute on', 'Commands', 'User group',
'Host group', 'Host access'], $table->getHeadersText()
);
// Check sortable headers.
$this->assertEquals(['Name', 'Commands'], $table->getHeaders()->query('tag:a')->asText());
// Check Script table content.
$this->assertTableHasData($data);
}
public function getFilterData() {
return [
// Name with special symbols.
[
[
'filter' => [
'Name' => '$¢Řĩ₱₮'
],
'expected' => [
self::$script_for_filter
]
]
],
// Exact match for field Name.
[
[
'filter' => [
'Name' => 'Traceroute'
],
'expected' => [
'Traceroute'
]
]
],
// Partial match for field Name.
[
[
'filter' => [
'Name' => 'Detect'
],
'expected' => [
'Detect operating system'
]
]
],
// Space in search field Name.
[
[
'filter' => [
'Name' => ' '
],
'expected' => [
self::$custom_script,
'Detect operating system',
self::$script_scope_event,
self::HOST_GROUP_SCRIPT,
self::$script_for_filter,
'Selenium script'
]
]
],
// Partial name match with space between.
[
[
'filter' => [
'Name' => 'm s'
],
'expected' => [
self::$custom_script,
'Selenium script'
]
]
],
// Partial name match with spaces on the sides.
[
[
'filter' => [
'Name' => ' operating '
],
'expected' => [
'Detect operating system'
]
]
],
// Search should not be case sensitive.
[
[
'filter' => [
'Name' => 'Selenium SCRIPT'
],
'expected' => [
'Selenium script'
]
]
],
// Wrong name in filter field "Name".
[
[
'filter' => [
'Name' => 'No data should be returned'
]
]
],
// Search by Action operation.
[
[
'filter' => [
'Scope' => 'Action operation'
],
'expected' => [
self::$custom_script,
'Reboot',
self::HOST_GROUP_SCRIPT,
'Selenium script'
]
]
],
// Search by Action operation and Name.
[
[
'filter' => [
'Name' => 'Reboot',
'Scope' => 'Action operation'
],
'expected' => [
'Reboot'
]
]
],
// Search by Manual host action.
[
[
'filter' => [
'Scope' => 'Manual host action'
],
'expected' => [
'Detect operating system',
'Ping',
'Traceroute'
]
]
],
// Search by Manual host action and Partial name match.
[
[
'filter' => [
'Name' => 'ing',
'Scope' => 'Manual host action'
],
'expected' => [
'Detect operating system',
'Ping'
]
]
],
// Search by Manual event action.
[
[
'filter' => [
'Scope' => 'Manual event action'
],
'expected' => [
self::$script_scope_event,
self::$script_for_filter
]
]
],
// Search by Manual event action and Partial name match.
[
[
'filter' => [
'Name' => 'Manual event',
'Scope' => 'Manual event action'
],
'expected' => [
self::$script_scope_event
]
]
],
// Search Any scripts.
[
[
'filter' => [
'Scope' => 'Any'
],
'expected' => [
self::$custom_script,
'Detect operating system',
self::$script_scope_event,
'Ping',
'Reboot',
self::HOST_GROUP_SCRIPT,
self::$script_for_filter,
'Selenium script',
'Traceroute'
]
]
]
];
}
/**
* @dataProvider getFilterData
*/
public function testPageAlertsScripts_Filter($data) {
$this->page->login()->open('zabbix.php?action=script.list');
$form = $this->query('name:zbx_filter')->asForm()->waitUntilVisible()->one();
// Fill filter fields if such present in data provider.
$form->fill(CTestArrayHelper::get($data, 'filter'));
$form->submit();
$this->page->waitUntilReady();
// Check that expected Scripts are returned in the list.
$this->assertTableDataColumn(CTestArrayHelper::get($data, 'expected', []));
// Reset filter due to not influence further tests.
$this->query('button:Reset')->one()->click();
}
public function getSortData() {
return [
[
[
'sort_field' => 'Name',
'expected' => [
'Traceroute',
'Selenium script',
self::$script_for_filter,
self::HOST_GROUP_SCRIPT,
'Reboot',
'Ping',
self::$script_scope_event,
'Detect operating system',
self::$custom_script
]
]
],
[
[
'sort_field' => 'Commands',
'expected' => [
'/sbin/run',
'/sbin/shutdown -r',
'/sbin/zabbix_server --runtime-control config_cache_reload',
'/usr/bin/traceroute {HOST.CONN}',
'ping -c 3 {HOST.CONN}; case $? in [01]) true;; *) false;; esac',
// TODO: fix order after fix ZBX-22329
'',
'sudo /usr/bin/nmap -O {HOST.CONN}',
'test',
'test'
]
]
]
];
}
/**
* @dataProvider getSortData
*/
public function testPageAlertsScripts_Sort($data) {
$this->page->login()->open('zabbix.php?action=script.list');
$table = $this->query('class:list-table')->asTable()->one();
$header = $table->query('link', $data['sort_field'])->one();
foreach(['desc', 'asc'] as $sorting) {
$expected = ($sorting === 'desc') ? $data['expected'] : array_reverse($data['expected']);
$header->click();
$this->assertTableDataColumn($expected, $data['sort_field']);
}
}
public function getDeleteData() {
return [
[
[
'expected' => TEST_BAD,
'error' => 'Cannot delete scripts. Script "Reboot" is used in action operation "Trigger action 4".'
]
],
[
[
'expected' => TEST_BAD,
'name' => [
self::$custom_script
],
'error' => 'Cannot delete scripts. Script "'.self::$custom_script.
'" is used in action operation "'.self::$custom_action.'".'
]
],
[
[
'expected' => TEST_BAD,
'name' => [
self::$custom_script,
self::$script_for_filter
],
'error' => 'Cannot delete scripts. Script "'.self::$custom_script.
'" is used in action operation "'.self::$custom_action.'".'
]
],
[
[
'expected' => TEST_GOOD,
'name' => [
self::$script_scope_event
]
]
],
[
[
'expected' => TEST_GOOD,
'name' => [
self::$script_for_filter,
'Ping'
]
]
]
];
}
/**
* @dataProvider getDeleteData
*/
public function testPageAlertsScripts_Delete($data) {
if ($data['expected'] === TEST_BAD) {
$old_hash = CDBHelper::getHash(self::$script_sql);
}
$this->page->login()->open('zabbix.php?action=script.list');
// Scripts count that will be selected before delete action.
$scripts_count = (array_key_exists('name', $data))
? count($data['name'])
: CDBHelper::getCount(self::$script_sql);
$this->selectTableRows(CTestArrayHelper::get($data, 'name'));
$this->query('button:Delete')->one()->waitUntilClickable()->click();
$this->page->acceptAlert();
$this->page->waitUntilReady();
// Verify that there is no possibility to delete selected script(s) if at least one of them contains linked action.
if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
$this->assertMessage(TEST_BAD, 'Cannot delete script'.(($scripts_count > 1) ? 's' : ''), $data['error']);
$this->assertSelectedCount($scripts_count);
$this->assertEquals($old_hash, CDBHelper::getHash(self::$script_sql));
// Uncheck selected scripts due to not influence further tests.
$this->query('button:Reset')->one()->click();
}
else {
$this->assertMessage(TEST_GOOD, ($scripts_count > 1) ? 'Scripts deleted' : 'Script deleted');
$this->assertSelectedCount(0);
$this->assertEquals(0, CDBHelper::getCount('SELECT NULL FROM scripts WHERE name IN ('.
CDBHelper::escape($data['name']).')')
);
}
}
public function testPageAlertsScripts_CancelDelete() {
$this->cancelDelete([self::$custom_script]);
}
public function testPageAlertsScripts_CancelMassDelete() {
$this->cancelDelete();
}
/**
* Function for checking cancelling of Delete action.
*
* @param array $scripts script names, if empty delete will perform for all scripts
*/
private function cancelDelete($scripts = []) {
$old_hash = CDBHelper::getHash(self::$script_sql);
$this->page->login()->open('zabbix.php?action=script.list');
$this->selectTableRows($scripts);
// Scripts count that will be selected before delete action.
$scripts_count = ($scripts === []) ? CDBHelper::getCount(self::$script_sql) : count($scripts);
$this->query('button:Delete')->one()->waitUntilClickable()->click();
$this->assertEquals(($scripts_count > 1) ? 'Delete selected scripts?' : 'Delete selected script?', $this->page->getAlertText());
$this->page->dismissAlert();
$this->page->waitUntilReady();
$this->assertSelectedCount($scripts_count);
$this->assertEquals($old_hash, CDBHelper::getHash(self::$script_sql));
}
/**
* Verify that there is possibility to open 'action' modal popup via link located in 'Used in actions' tab.
*/
public function testPageAlertsScripts_ActionLinks() {
$this->page->login()->open('zabbix.php?action=script.list');
$this->query('link', self::$custom_action)->one()->waitUntilClickable()->click();
$dialog = COverlayDialogElement::find()->waitUntilReady()->asForm()->one();
$dialog->checkValue(['Name' => self::$custom_action]);
$dialog->submit();
COverlayDialogElement::ensureNotPresent();
$this->page->assertHeader('Scripts');
$this->assertMessage(TEST_GOOD, 'Action updated');
}
}