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.

1354 lines
38 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';
/**
* @backup dashboard
*
* @onBefore prepareDashboardData
*
* @dataSource WebScenarios
*/
class testDashboardItemValueWidget extends CWebTest {
/**
* Attach MessageBehavior to the test.
*
* @return array
*/
public function getBehaviors() {
return [
'class' => CMessageBehavior::class
];
}
protected static $dashboardid;
protected static $old_name = 'New widget';
protected static $threshold_widget = 'Widget with thresholds';
private $sql = 'SELECT wf.widgetid, wf.type, wf.name, wf.value_int, wf.value_str, wf.value_groupid, wf.value_hostid,'.
' wf.value_itemid, wf.value_graphid, wf.value_sysmapid, w.widgetid, w.dashboard_pageid, w.type, w.name, w.x, w.y,'.
' w.width, w.height'.
' FROM widget_field wf'.
' INNER JOIN widget w'.
' ON w.widgetid=wf.widgetid ORDER BY wf.widgetid, wf.name, wf.value_int, wf.value_str, wf.value_groupid,'.
' wf.value_itemid, wf.value_graphid';
/**
* Get threshold table element with mapping set.
*
* @return CMultifieldTable
*/
protected function getThresholdTable() {
return $this->query('id:thresholds-table')->asMultifieldTable([
'mapping' => [
'' => [
'name' => 'color',
'selector' => 'class:color-picker',
'class' => 'CColorPickerElement'
],
'Threshold' => [
'name' => 'threshold',
'selector' => 'xpath:./input',
'class' => 'CElement'
]
]
])->waitUntilVisible()->one();
}
public static function prepareDashboardData() {
$response = CDataHelper::call('dashboard.create', [
[
'name' => 'Dashboard for Single Item Widget test',
'private' => 0,
'pages' => [
[
'name' => 'Page with widgets',
'widgets' => [
[
'type' => 'item',
'name' => self::$old_name,
'x' => 0,
'y' => 0,
'width' => 12,
'height' => 4,
'fields' => [
[
'type' => 4,
'name' => 'itemid',
'value' => 42230
],
[
'type' => 0,
'name' => 'adv_conf',
'value' => 1
],
[
'type' => 1,
'name' => 'description',
'value' => 'Some description here. Описание.'
],
[
'type' => 0,
'name' => 'desc_h_pos',
'value' => 0
],
[
'type' => 0,
'name' => 'desc_v_pos',
'value' => 0
],
[
'type' => 0,
'name' => 'time_h_pos',
'value' => 2
],
[
'type' => 0,
'name' => 'time_v_pos',
'value' => 2
],
[
'type' => 0,
'name' => 'desc_size',
'value' => 17
],
[
'type' => 0,
'name' => 'decimal_size',
'value' => 41
],
[
'type' => 0,
'name' => 'value_size',
'value' => 56
],
[
'type' => 0,
'name' => 'time_size',
'value' => 14
]
]
],
[
'type' => 'item',
'name' => 'Widget with thresholds',
'x' => 0,
'y' => 6,
'width' => 10,
'height' => 3,
'fields' => [
[
'type' => 4,
'name' => 'itemid',
'value' => 42230
],
[
'type' => '1',
'name' => 'thresholds.color.0',
'value' => 'BF00FF'
],
[
'type' => '1',
'name' => 'thresholds.threshold.0',
'value' => '0'
],
[
'type' => '1',
'name' => 'thresholds.color.1',
'value' => 'FF0080'
],
[
'type' => '1',
'name' => 'thresholds.threshold.1',
'value' => '0.01'
]
]
],
[
'type' => 'item',
'name' => 'Widget to delete',
'x' => 13,
'y' => 0,
'width' => 4,
'height' => 4,
'fields' => [
[
'type' => 4,
'name' => 'itemid',
'value' => 42230
]
]
]
]
]
]
]
]);
self::$dashboardid = $response['dashboardids'][0];
}
/**
* Test to check Item Value Widget.
* Check authentication form fields layout.
*/
public function testDashboardItemValueWidget_FormLayout() {
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid)->waitUntilReady();
$dashboard = CDashboardElement::find()->waitUntilReady()->one();
$form = $dashboard->edit()->addWidget()->waitUntilReady()->asForm();
if ($form->getField('Type') !== 'Item value') {
$form->fill(['Type' => CFormElement::RELOADABLE_FILL('Item value')]);
}
// Check default values with default Advanced configuration (false).
$default_values = [
'Name' => '',
'Refresh interval' => 'Default (1 minute)',
'id:show_header' => true,
'id:show_1' => true,
'id:show_2' => true,
'id:show_3' => true,
'id:show_4' => true,
'Advanced configuration' => false,
'id:dynamic' => false
];
foreach ($default_values as $field => $value) {
$this->assertEquals($value, $form->getField($field)->getValue());
}
// Check checkboxes dependency on Advanced configuration checkbox.
$description = [
'id:description',
'id:desc_h_pos',
'id:desc_v_pos',
'id:desc_size',
'id:desc_bold',
'xpath://input[@id="desc_color"]/..'
];
$values = [
'id:decimal_places',
'id:decimal_size',
'id:value_h_pos',
'id:value_size',
'id:value_v_pos',
'id:value_bold',
'xpath://input[@id="value_color"]/..'
];
$units = [
'id:units',
'id:units_pos',
'id:units_size',
'id:units_bold',
'xpath://input[@id="units_color"]/..'
];
$time = [
'id:time_h_pos',
'id:time_v_pos',
'id:time_size',
'id:time_bold',
'xpath://input[@id="time_color"]/..'
];
$indicator_colors = [
'xpath://input[@id="up_color"]/..',
'xpath://input[@id="down_color"]/..',
'xpath://input[@id="updown_color"]/..'
];
// Merge all Advanced fields into one array.
$fields = array_merge($description, $values, $units, $time, $indicator_colors, ['Background color']);
foreach ([false, true] as $advanced_config) {
$form->fill(['Advanced configuration' => $advanced_config]);
// Check that dynamic item checkbox is not depending on Advanced configuration checkbox state.
$dynamic_field = $form->getField('Enable host selection');
$this->assertTrue($dynamic_field->isVisible());
$this->assertTrue($dynamic_field->isEnabled());
// Check fields visibility depending on Advanced configuration checkbox state.
foreach ($fields as $field) {
$this->assertTrue($form->getField($field)->isVisible($advanced_config));
}
// Check advanced fields when Advanced configuration is true.
if ($advanced_config){
// Check hintbox.
$form->getLabel('Description')->query('class:zi-help-filled-small')->one()->click();
$hint = $this->query('xpath:.//div[@data-hintboxid]')->waitUntilPresent();
// Assert text.
$this->assertEquals("Supported macros:".
"\n{HOST.*}".
"\n{ITEM.*}".
"\n{INVENTORY.*}".
"\nUser macros", $hint->one()->getText());
// Close the hint-box.
$hint->one()->query('xpath:.//button[@class="btn-overlay-close"]')->one()->click();
$hint->waitUntilNotPresent();
// Check default values with Advanced configuration = true.
$default_values_advanced = [
'id:description' => '{ITEM.NAME}',
'id:desc_h_pos' => 'Center',
'id:desc_v_pos' => 'Bottom',
'id:desc_size' => 15,
'id:desc_bold' => false,
'id:decimal_places' => 2,
'id:decimal_size' => 35,
'id:value_h_pos' => 'Center',
'id:value_v_pos' => 'Middle',
'id:value_size' => 45,
'id:value_bold' => true,
'id:units' => '',
'id:units_pos' => 'After value',
'id:units_size' => 35,
'id:units_bold' => true
];
foreach ($default_values_advanced as $field => $value) {
$this->assertEquals($value, $form->getField($field)->getValue());
}
// Check fields' lengths.
$field_lenghts = [
'Name' => 255,
'id:description' => 2048,
'id:desc_size' => 3,
'id:decimal_places' => 2,
'id:decimal_size' => 3,
'id:value_size' => 3,
'id:units' => 255,
'id:units_size' => 3
];
foreach ($field_lenghts as $field => $length) {
$this->assertEquals($length, $form->getField($field)->getAttribute('maxlength'));
}
// Check fields editability depending on "Show" checkboxes.
$config_editability = [
'id:show_1' => $description,
'id:show_2' => $values,
'id:units_show' => $units,
'id:show_3' => $time,
'id:show_4' => $indicator_colors
];
foreach ($config_editability as $config => $elements) {
foreach ([false, true] as $state) {
$form->fill([$config => $state]);
foreach ($elements as $element) {
$this->assertTrue($form->getField($element)->isEnabled($state));
}
}
}
}
}
}
public static function getWidgetData() {
return [
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Refresh interval' => '30 seconds',
'Item' => [
'values' => '',
'context' => [
'values' => '',
'context' => ''
]
]
],
'error' => ['Invalid parameter "Item": cannot be empty.']
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true,
// Description size in % relative to the size of the widget.
'id:desc_size' => '0',
// Value decimal part's size relative in %.
'id:decimal_size' => '0',
// Value size in % relative to the size of the widget.
'id:value_size' => '0',
// Value units size in % relative to the size of the widget.
'id:units_size' => '0',
// Time size in % relative to the size of the widget.
'id:time_size' => '0'
],
'error' => [
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true,
// Description size in % relative to the size of the widget.
'id:desc_size' => '101',
// Value decimal part's size relative in %.
'id:decimal_size' => '102',
// Value size in % relative to the size of the widget.
'id:value_size' => '103',
// Value units size in % relative to the size of the widget.
'id:units_size' => '104',
// Time size in % relative to the size of the widget.
'id:time_size' => '105'
],
'error' => [
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true,
// Description size in % relative to the size of the widget.
'id:desc_size' => '-1',
// Value decimal part's size relative in %.
'id:decimal_size' => '-2',
// Value size in % relative to the size of the widget.
'id:value_size' => '-3',
// Value units size in % relative to the size of the widget.
'id:units_size' => '-4',
// Time size in % relative to the size of the widget.
'id:time_size' => '-5'
],
'error' => [
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true,
// Description size in % relative to the size of the widget.
'id:desc_size' => 'aqua',
// Value decimal part's size relative in %.
'id:decimal_size' => 'один',
// Value size in % relative to the size of the widget.
'id:value_size' => 'some',
// Value units size in % relative to the size of the widget.
'id:units_size' => '@6$',
// Time size in % relative to the size of the widget.
'id:time_size' => '_+(*'
],
'error' => [
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.',
'Invalid parameter "Size": value must be one of 1-100.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true,
'id:decimal_places' => '-1'
],
'error' => [
'Invalid parameter "Decimal places": value must be one of 0-10.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true,
'id:decimal_places' => '99'
],
'error' => [
'Invalid parameter "Decimal places": value must be one of 0-10.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true,
'id:description' => ''
],
'error' => [
'Invalid parameter "Description": cannot be empty.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => '-']
],
'error' => [
'Invalid parameter "Thresholds/1/threshold": a number is expected.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => 'a']
],
'error' => [
'Invalid parameter "Thresholds/1/threshold": a number is expected.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => '1a%?']
],
'error' => [
'Invalid parameter "Thresholds/1/threshold": a number is expected.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => '1.79E+400']
],
'error' => [
'Invalid parameter "Thresholds/1/threshold": a number is too large.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => '1'],
['threshold' => 'a']
],
'error' => [
'Invalid parameter "Thresholds/2/threshold": a number is expected.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => '1'],
['threshold' => '1']
],
'error' => [
'Invalid parameter "Thresholds/2": value (threshold)=(1) already exists.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => '1', 'color' => '']
],
'error' => [
'Invalid parameter "Thresholds/1/color": cannot be empty.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => '1', 'color' => 'AABBCC'],
['threshold' => '2', 'color' => '']
],
'error' => [
'Invalid parameter "Thresholds/2/color": cannot be empty.'
]
]
],
[
[
'expected' => TEST_BAD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => 'a', 'color' => 'AABBCC']
],
'error' => [
'Invalid parameter "Thresholds/1/threshold": a number is expected.'
]
]
],
[
[
'expected' => TEST_GOOD,
'fields' => [
'Type' => 'Item value',
'Item' => [
'values' => 'Linux: Available memory',
'context' => [
'values' => 'ЗАББИКС Сервер',
'context' => 'Zabbix servers'
]
]
]
]
],
[
[
'expected' => TEST_GOOD,
'fields' => [
'Type' => 'Item value',
'Name' => 'Any name',
'Refresh interval' => 'No refresh',
'Item' => 'Available memory in %'
]
]
],
[
[
'expected' => TEST_GOOD,
'fields' => [
'Type' => 'Item value',
'Name' => 'Имя виджета',
'Refresh interval' => '10 seconds',
'Item' => [
'values' => 'Master item',
'context' => [
'values' => 'Test item host',
'context' => 'Zabbix servers'
]
],
// Description checkbox.
'id:show_1' => true,
// Value checkbox.
'id:show_2' => false,
// Time checkbox.
'id:show_3' => true,
// Change indicator checkbox.
'id:show_4' => false,
'Advanced configuration' => true,
'id:description' => 'Несколько слов. Dāži vārdi.',
// Description horizontal position.
'id:desc_h_pos' => 'Right',
// Description vertical position.
'id:desc_v_pos' => 'Bottom',
// Description size in % relative to the size of the widget.
'id:desc_size' => '1',
// Time horizontal position.
'id:time_h_pos' => 'Right',
// Time vertical position.
'id:time_v_pos' => 'Middle',
// Time size in % relative to the size of the widget.
'id:time_size' => '21'
]
]
],
[
[
'expected' => TEST_GOOD,
'fields' => [
'Type' => 'Item value',
'id:show_header' => false,
'Name' => '#$%^&*()!@{}[]<>,.|',
'Refresh interval' => '10 minutes',
'Item' => 'Response code for step "step 1 of scenario 1" of scenario "Scenario for Update".',
// Description checkbox.
'id:show_1' => false,
// Value checkbox.
'id:show_2' => true,
// Time checkbox.
'id:show_3' => false,
// Change indicator checkbox.
'id:show_4' => true,
'Advanced configuration' => true,
// Value units type.
'id:units' => 'Some Units',
// Value units position.
'id:units_pos' => 'Below value',
// Value units size in % relative to the size of the widget.
'id:units_size' => '100',
'id:units_bold' => true
]
]
],
[
[
'expected' => TEST_GOOD,
'fields' => [
'Type' => 'Item value',
'Name' => 'New Single Item Widget',
'Refresh interval' => '2 minutes',
'Item' => 'Http agent item form',
// Description checkbox.
'id:show_1' => true,
// Value checkbox.
'id:show_2' => true,
// Time checkbox.
'id:show_3' => true,
// Change indicator checkbox.
'id:show_4' => true,
'Advanced configuration' => true,
'id:description' => 'Some description here.',
// Description horizontal position.
'id:desc_h_pos' => 'Left',
// Description vertical position.
'id:desc_v_pos' => 'Top',
// Description size in % relative to the size of the widget.
'id:desc_size' => '11',
// Description bold font checkbox.
'id:desc_bold' => true,
// Value decimal places count.
'id:decimal_places' => '3',
// Value horizontal position.
'id:value_h_pos' => 'Right',
// Value vertical position.
'id:value_v_pos' => 'Bottom',
// Value decimal part's size relative in %.
'id:decimal_size' => '32',
// Value size in % relative to the size of the widget.
'id:value_size' => '46',
'id:value_bold' => true,
'id:units' => 's',
// Value units position.
'id:units_pos' => 'Before value',
// Value units size in % relative to the size of the widget.
'id:units_size' => '36',
'id:units_bold' => true,
// Time horizontal position.
'id:time_h_pos' => 'Left',
// Time vertical position.
'id:time_v_pos' => 'Bottom',
// Time size in % relative to the size of the widget.
'id:time_size' => '13',
'id:time_bold' => true,
'Enable host selection' => true
]
]
],
[
[
'expected' => TEST_GOOD,
'fields' => [
'Type' => 'Item value',
'id:show_header' => false,
'Name' => 'Color pick',
'Refresh interval' => '10 minutes',
'Item' => 'Response code for step "step 1 of scenario 1" of scenario "Template_Web_scenario".',
// Description checkbox.
'id:show_1' => true,
// Value checkbox.
'id:show_2' => true,
// Time checkbox.
'id:show_3' => true,
// Change indicator checkbox.
'id:show_4' => true,
'Advanced configuration' => true,
'id:units' => 'B',
// Value units position.
'id:units_pos' => 'Below value',
// Value units size in % relative to the size of the widget.
'id:units_size' => '99',
'id:units_bold' => true,
'Background color' => 'FFAAAA',
'xpath://button[@id="lbl_desc_color"]/..' => 'AABBCC',
'xpath://button[@id="lbl_value_color"]/..' => 'CC11CC',
'xpath://button[@id="lbl_units_color"]/..' => 'BBCC55',
'xpath://button[@id="lbl_time_color"]/..' => '11AA00',
'xpath://button[@id="lbl_up_color"]/..' => '00FF00',
'xpath://button[@id="lbl_down_color"]/..' => 'FF0000',
'xpath://button[@id="lbl_updown_color"]/..' => '0000FF'
]
]
],
[
[
'expected' => TEST_GOOD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Name' => 'Item Widget with threshold',
'Refresh interval' => '1 minute',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => '0.01']
]
]
],
[
[
'expected' => TEST_GOOD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Name' => 'One threshold with color',
'Refresh interval' => '2 minutes',
'Advanced configuration' => true
],
'thresholds' => [
['color' => 'EF6C00', 'threshold' => '0.02']
]
]
],
[
[
'expected' => TEST_GOOD,
'fields' => [
'Type' => 'Item value',
'Item' => 'Available memory in %',
'Name' => 'Thresholds',
'Refresh interval' => '2 minutes',
'Advanced configuration' => true
],
'thresholds' => [
['threshold' => '0.9999'],
['color' => 'AABBCC', 'threshold' => '1'],
['threshold' => '5K'],
['color' => 'FFEB3B', 'threshold' => '1G'],
['threshold' => '999999999999999']
]
]
]
];
}
/**
* @backupOnce dashboard
* @dataProvider getWidgetData
*/
public function testDashboardItemValueWidget_Create($data) {
$this->checkWidgetForm($data);
}
public static function getWidgetUpdateData() {
return [
[
[
'expected' => TEST_GOOD,
'threshold_widget' => true,
'fields' => [
'Item' => 'Available memory in %',
'Name' => 'Widget with thresholds - update',
'Refresh interval' => '10 minutes',
'Advanced configuration' => true
],
'thresholds' => [
['action' => USER_ACTION_UPDATE, 'index' => 0, 'color' => 'AABBCC', 'threshold' => '1'],
['action' => USER_ACTION_UPDATE, 'index' => 1, 'threshold' => '999999999999999']
]
]
],
[
[
'expected' => TEST_GOOD,
'threshold_widget' => true,
'fields' => [
'Item' => 'Available memory in %',
'Name' => 'Widget with thresholds - remove',
'Refresh interval' => '10 minutes',
'Advanced configuration' => true
],
'thresholds' => [
['action' => USER_ACTION_REMOVE, 'index' => 0],
['action' => USER_ACTION_REMOVE, 'index' => 0]
]
]
]
];
}
/**
* @dataProvider getWidgetData
* @dataProvider getWidgetUpdateData
*/
public function testDashboardItemValueWidget_Update($data) {
$this->checkWidgetForm($data, true);
}
/**
* Function for check the changes.
*
* @param boolean $update updating is performed
*/
public function checkWidgetForm($data, $update = false) {
if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
$old_hash = CDBHelper::getHash('SELECT * FROM widget ORDER BY widgetid');
}
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one();
$old_widget_count = $dashboard->getWidgets()->count();
$name = ($update && array_key_exists('threshold_widget', $data)) ? self::$threshold_widget : self::$old_name;
$form = ($update)
? $dashboard->getWidget($name)->edit()->asForm()
: $dashboard->edit()->addWidget()->asForm();
COverlayDialogElement::find()->one()->waitUntilReady();
$form->fill($data['fields']);
if ($update && !CTestArrayHelper::get($data['fields'], 'Name')) {
$form->fill(['Name' => '']);
}
if (array_key_exists('thresholds', $data)) {
$this->getThresholdTable()->fill($data['thresholds']);
}
$values = $form->getFields()->filter(new CElementFilter(CElementFilter::VISIBLE))->asValues();
$form->submit();
$this->page->waitUntilReady();
if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
$this->assertMessage($data['expected'], null, $data['error']);
$this->assertEquals($old_hash, CDBHelper::getHash('SELECT * FROM widget ORDER BY widgetid'));
}
else {
COverlayDialogElement::ensureNotPresent();
$header = CTestArrayHelper::get($data['fields'], 'Name')
? $data['fields']['Name']
: $data['fields']['Item']['context']['values'].': '.$data['fields']['Item']['values'];
$dashboard->getWidget($header)->waitUntilReady();
// Save Dashboard to ensure that widget is correctly saved.
$dashboard->save();
$this->assertMessage(TEST_GOOD, 'Dashboard updated');
// Check widget count.
$this->assertEquals($old_widget_count + ($update ? 0 : 1), $dashboard->getWidgets()->count());
// Check new widget form fields and values in frontend.
$saved_form = $dashboard->getWidget($header)->edit();
// Open "Advanced configuration" block if it was filled with data.
if (CTestArrayHelper::get($data, 'fields.Advanced configuration', false)) {
// After form submit "Advanced configuration" is closed.
$saved_form->checkValue(['Advanced configuration' => false]);
$saved_form->fill(['Advanced configuration' => true]);
}
$this->assertEquals($values, $saved_form->getFields()->filter(new CElementFilter(CElementFilter::VISIBLE))->asValues());
// As form is quite complex, show_header field should be checked separately.
if (array_key_exists('show_header', $data['fields'])) {
$saved_form->checkValue(['id:show_header' => $data['fields']['show_header']]);
}
// Check that widget is saved in DB for correct dashboard and correct dashboard page.
$this->assertEquals(1,
CDBHelper::getCount('SELECT * FROM widget w'.
' WHERE EXISTS ('.
'SELECT NULL'.
' FROM dashboard_page dp'.
' WHERE w.dashboard_pageid=dp.dashboard_pageid'.
' AND dp.dashboardid='.self::$dashboardid.
' AND w.name ='.zbx_dbstr(CTestArrayHelper::get($data['fields'], 'Name', '')).')'
));
// Check that original widget was not left in DB.
if ($update) {
$this->assertEquals(0, CDBHelper::getCount('SELECT NULL FROM widget WHERE name='.zbx_dbstr($name)));
}
// Close widget popup and check update interval.
$saved_form->submit();
COverlayDialogElement::ensureNotPresent();
$dashboard->save();
$this->assertMessage(TEST_GOOD, 'Dashboard updated');
// Check new widget update interval.
$refresh = (CTestArrayHelper::get($data['fields'], 'Refresh interval') === 'Default (1 minute)')
? '15 minutes'
: (CTestArrayHelper::get($data['fields'], 'Refresh interval', '1 minute'));
$this->assertEquals($refresh, CDashboardElement::find()->one()->getWidget($header)->getRefreshInterval());
// Write new name to update widget for update scenario.
if ($update) {
if (array_key_exists('threshold_widget', $data)) {
self::$threshold_widget = $header;
}
else {
self::$old_name = $header;
}
}
}
}
public function testDashboardItemValueWidget_SimpleUpdate() {
$this->checkNoChanges();
}
public static function getCancelData() {
return [
// Cancel creating widget with saving the dashboard.
[
[
'cancel_form' => true,
'create_widget' => true,
'save_dashboard' => true
]
],
// Cancel updating widget with saving the dashboard.
[
[
'cancel_form' => true,
'create_widget' => false,
'save_dashboard' => true
]
],
// Create widget without saving the dashboard.
[
[
'cancel_form' => false,
'create_widget' => true,
'save_dashboard' => false
]
],
// Update widget without saving the dashboard.
[
[
'cancel_form' => false,
'create_widget' => false,
'save_dashboard' => false
]
]
];
}
/**
* @dataProvider getCancelData
*/
public function testDashboardItemValueWidget_Cancel($data) {
$this->checkNoChanges($data['cancel_form'], $data['create_widget'], $data['save_dashboard']);
}
/**
* Function for checking canceling form or submitting without any changes.
*
* @param boolean $cancel true if cancel scenario, false if form is submitted
* @param boolean $create true if create scenario, false if update
* @param boolean $save_dashboard true if dashboard will be saved, false if not
*/
private function checkNoChanges($cancel = false, $create = false, $save_dashboard = true) {
$old_hash = CDBHelper::getHash($this->sql);
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one();
$old_widget_count = $dashboard->getWidgets()->count();
$form = $create
? $dashboard->edit()->addWidget()->asForm()
: $dashboard->getWidget(self::$old_name)->edit();
$dialog = COverlayDialogElement::find()->one()->waitUntilReady();
if (!$create) {
$values = $form->getFields()->asValues();
}
else {
$form->fill(['Type' => 'Item value']);
}
if ($cancel || !$save_dashboard) {
$form->fill([
'Name' => 'Widget to cancel',
'Item' => 'Available memory in %'
]);
}
if ($cancel) {
$dialog->query('button:Cancel')->one()->click();
}
else {
$form->submit();
}
COverlayDialogElement::ensureNotPresent();
if (!$cancel) {
$dashboard->waitUntilReady()->getWidget(!$save_dashboard ? 'Widget to cancel' : self::$old_name)->waitUntilReady();
}
if ($save_dashboard) {
$dashboard->save();
$this->assertMessage(TEST_GOOD, 'Dashboard updated');
}
else {
$dashboard->cancelEditing();
}
$this->assertEquals($old_widget_count, $dashboard->getWidgets()->count());
// Check that updating widget form values did not change in frontend.
if (!$create && !$save_dashboard) {
$this->assertEquals($values, $dashboard->getWidget(self::$old_name)->edit()->getFields()->asValues());
}
// Check that DB hash is not changed.
$this->assertEquals($old_hash, CDBHelper::getHash($this->sql));
}
public function testDashboardItemValueWidget_Delete() {
$name = 'Widget to delete';
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one()->edit();
$old_widget_count = $dashboard->getWidgets()->count();
$this->assertEquals(true, $dashboard->getWidget($name)->isEditable());
$dashboard->deleteWidget($name);
$dashboard->save();
$this->assertMessage(TEST_GOOD, 'Dashboard updated');
$this->assertEquals($old_widget_count - 1, $dashboard->getWidgets()->count());
$this->assertEquals('', CDBHelper::getRow('SELECT * from widget WHERE name = '.zbx_dbstr('Widget to delete')));
}
public static function getWarningMessageData() {
return [
[
[
'fields' => [
'Item' => 'System description',
'Name' => 'Item Widget with type of information - characters',
'Advanced configuration' => true
]
]
],
[
[
'fields' => [
'Item' => 'Get filesystems',
'Name' => 'Item Widget with type of information - text',
'Advanced configuration' => true
]
]
],
[
[
'fields' => [
'Item' => 'item_testPageHistory_CheckLayout_Log',
'Name' => 'Item Widget with type of information - log',
'Advanced configuration' => true
]
]
],
[
[
'numeric' => true,
'fields' => [
'Item' => 'Free swap space',
'Name' => 'Item Widget with type of information - Numeric (unsigned)',
'Advanced configuration' => true
]
]
],
[
[
'numeric' => true,
'fields' => [
'Item' => 'Interrupts per second',
'Name' => 'Item Widget with type of information - Numeric (float)',
'Advanced configuration' => true
]
]
]
];
}
/**
* Check warning message for threshold, when item type is not numeric.
*
* @dataProvider getWarningMessageData
*/
public function testDashboardItemValueWidget_ThresholdWarningMessage($data) {
$warning = 'id:item-value-thresholds-warning';
$info = 'class:zi-i-warning';
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one();
$form = $dashboard->edit()->addWidget()->asForm();
if ($form->getField('Type')->getValue() !== 'Item value') {
$form->fill(['Type' => CFormElement::RELOADABLE_FILL('Item value')]);
}
$form->fill($data['fields']);
if (!array_key_exists('numeric', $data)) {
// Check that warning item is displayed.
$this->assertTrue($form->query($warning)->one()->isVisible());
// Check that info icon is displayed.
$this->assertTrue($form->getLabel('Thresholds')->query($info)->one()->isVisible());
// Check hint-box.
$form->query($warning)->one()->click();
$hint = $form->query('xpath://div[@class="overlay-dialogue"]')->one()->waitUntilVisible();
$this->assertEquals('This setting applies only to numeric data.', $hint->getText());
// Close the hint-box.
$hint->query('xpath:.//button[@class="btn-overlay-close"]')->one()->click()->waitUntilNotVisible();
}
else {
// Check that warning item is not displayed.
$this->assertFalse($form->query($warning)->one()->isVisible());
// Check that info icon is not displayed.
$this->assertFalse($form->getLabel('Thresholds')->query($info)->one()->isVisible());
}
}
public function testDashboardItemValueWidget_ThresholdColor() {
$data = [
'fields' => [
'Item' => 'Available memory in %',
'Name' => 'Item Widget with threshold',
'Advanced configuration' => true
],
'thresholds' => [
['color' => 'AABBCC', 'threshold' => '1'],
['color' => 'CCDDAA', 'threshold' => '2']
]
];
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one();
$form = $dashboard->edit()->addWidget()->asForm();
if ($form->getField('Type')->getValue() !== 'Item value') {
$form->fill(['Type' => CFormElement::RELOADABLE_FILL('Item value')]);
}
$form->fill($data['fields']);
$this->getThresholdTable()->fill($data['thresholds']);
$form->submit();
COverlayDialogElement::ensureNotPresent();
$this->page->waitUntilReady();
$dashboard->save();
$this->assertMessage('Dashboard updated');
// Value for threshold trigger.
$index = 1;
foreach ($data['thresholds'] as $threshold) {
// Insert item data.
CDataHelper::addItemData(42244, $index, time() + $index);
$this->page->refresh()->waitUntilReady();
$rgb = implode(', ', sscanf($threshold['color'], "%02x%02x%02x"));
$this->assertEquals('rgba('.$rgb.', 1)', $dashboard->getWidget($data['fields']['Name'])
->query('xpath:.//div[contains(@class, "dashboard-widget-item")]/div/div')->one()->getCSSValue('background-color')
);
$index++;
}
}
}