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.

1109 lines
35 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

<?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 config, widget
*
* @dataSource AllItemValueTypes
*
* @onBefore prepareDashboardData
*/
class testDashboardGaugeWidget extends CWebTest {
use TableTrait;
const HOST = 'Host for all item value types';
const DELETE_GAUGE = 'Gauge for deleting';
const GAUGE_ITEM = 'Float item';
/**
* SQL query to get widget and widget_field tables to compare hash values, but without widget_fieldid
* because it can change.
*/
const 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, wf.value_hostid';
/**
* Id of the dashboard where gauge widget is created and updated.
*
* @var integer
*/
protected static $dashboardid;
protected static $update_gauge = 'Gauge for updating';
/**
* Attach MessageBehavior to the test.
*
* @return array
*/
public function getBehaviors() {
return [CMessageBehavior::class];
}
/**
* Get Thresholds table element with mapping set.
*
* @return CMultifieldTable
*/
protected function getThresholdsTable() {
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 function prepareDashboardData() {
// Add item data to move needle on Gauge.
CDataHelper::addItemData(CDataHelper::get('AllItemValueTypes.Float item'), 50);
$dashboards = CDataHelper::call('dashboard.create', [
'name' => 'Gauge widget dashboard',
'auto_start' => 0,
'pages' => [
[
'name' => 'Gauge test page',
'widgets' => [
[
'type' => 'gauge',
'name' => self::$update_gauge,
'x' => 0,
'y' => 0,
'width' => 11,
'height' => 5,
'fields' => [
[
'type' => ZBX_WIDGET_FIELD_TYPE_ITEM,
'name' => 'itemid',
'value' => CDataHelper::get('AllItemValueTypes.Float item')
]
]
],
[
'type' => 'gauge',
'name' => self::DELETE_GAUGE,
'x' => 11,
'y' => 0,
'width' => 11,
'height' => 5,
'view_mode' => 0,
'fields' => [
[
'type' => ZBX_WIDGET_FIELD_TYPE_ITEM,
'name' => 'itemid',
'value' => CDataHelper::get('AllItemValueTypes.Float item')
]
]
]
]
],
[
'name' => 'Screenshot page'
]
]
]);
$this->assertArrayHasKey('dashboardids', $dashboards);
self::$dashboardid = $dashboards['dashboardids'][0];
}
public function testDashboardGaugeWidget_Layout() {
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dialog = CDashboardElement::find()->one()->edit()->addWidget();
$form = $dialog->asForm();
$this->assertEquals('Add widget', $dialog->getTitle());
$form->fill(['Type' => CFormElement::RELOADABLE_FILL('Gauge')]);
// Check default fields.
$fields = [
'Name' => ['value' => '', 'placeholder' => 'default', 'maxlength' => 255, 'enabled' => true, 'visible' => true],
'Refresh interval' => ['value' => 'Default (1 minute)', 'enabled' => true, 'visible' => true],
'Show header' => ['value' => true, 'enabled' => true, 'visible' => true],
'id:itemid_ms' => ['value' => '', 'placeholder' => 'type here to search', 'enabled' => true, 'visible' => true],
'Min' => ['value' => 0, 'maxlength' => 255, 'enabled' => true, 'visible' => true],
'Max' => ['value' => 100, 'maxlength' => 255, 'enabled' => true, 'visible' => true],
// Colors.
'xpath:.//input[@id="value_arc_color"]/..' => ['color' => '', 'enabled' => true, 'visible' => true],
'xpath:.//input[@id="empty_color"]/..' => ['color' => '', 'enabled' => true, 'visible' => true],
'xpath:.//input[@id="bg_color"]/..' => ['color' => '', 'enabled' => true, 'visible' => true],
'Angle' => ['value' => '180°', 'enabled' => true, 'labels' => ['180°', '270°'], 'visible' => false],
// Description.
'id:description' => ['value' => '{ITEM.NAME}', 'maxlength' => 2048, 'enabled' => true, 'visible' => false],
'id:desc_size' => ['value' => '15', 'maxlength' => 3, 'enabled' => true, 'visible' => false],
'id:desc_v_pos' => ['value' => 'Bottom', 'enabled' => true, 'labels' => ['Top', 'Bottom'], 'visible' => false],
'id:desc_bold' => ['value' => false, 'enabled' => true, 'visible' => false],
'xpath:.//input[@id="desc_color"]/..' => ['color' => '', 'enabled' => true, 'visible' => false],
// Value.
'id:decimal_places' => ['value' => 2, 'maxlength' => 2, 'enabled' => true, 'visible' => false],
'id:value_bold' => ['value' => false, 'enabled' => true, 'visible' => false],
'id:value_arc' => ['value' => true, 'enabled' => true, 'visible' => false],
'id:value_size' => ['value' => 25, 'maxlength' => 3, 'enabled' => true, 'visible' => false],
'xpath:.//input[@id="value_color"]/..' => ['color' => '', 'enabled' => true, 'visible' => false],
'id:value_arc_size' => ['value' => 20, 'maxlength' => 3, 'enabled' => true, 'visible' => false],
// Units.
'id:units_show' => ['value' => true, 'enabled' => true, 'visible' => false],
'id:units' => ['value' => '', 'maxlength' => 2048, 'enabled' => true, 'visible' => false],
'id:units_size' => ['value' => 25, 'maxlength' => 3, 'enabled' => true, 'visible' => false],
'id:units_pos' => ['value' => 'After value', 'enabled' => true, 'visible' => false],
'id:units_bold' => ['value' => false, 'enabled' => true, 'visible' => false],
'xpath:.//input[@id="units_color"]/..'=> ['color' => '', 'enabled' => true, 'visible' => false],
// Needle.
'id:needle_show' => ['value' => false, 'enabled' => true, 'visible' => false],
'xpath:.//input[@id="needle_color"]/..' => ['color' => '', 'enabled' => false, 'visible' => false],
// Scale.
'id:scale_show' => ['value' => true, 'enabled' => true, 'visible' => false],
'id:scale_size' => ['value' => 10, 'maxlength' => 3, 'enabled' => true, 'visible' => false],
'id:scale_decimal_places' => ['value' => 0, 'maxlength' => 2, 'enabled' => true, 'visible' => false],
'id:scale_show_units' => ['value' => true, 'enabled' => true, 'visible' => false],
// Tresholds.
'id:th_show_labels' => ['value' => false, 'enabled' => false, 'visible' => false],
'id:th_show_arc' => ['value' => false, 'enabled' => false, 'visible' => false],
'id:th_arc_size' => ['value' => 10, 'maxlength' => 3, 'enabled' => false, 'visible' => false],
'Enable host selection' => ['value' => false, 'enabled' => true, 'visible' => true]
];
$not_visible = [];
foreach ($fields as $label => $attributes) {
if (array_key_exists('color', $attributes)) {
$this->assertEquals($attributes['color'], $form->query($label)->asColorPicker()->one()->getValue());
}
$field = $form->getField($label);
$this->assertTrue($field->isEnabled($attributes['enabled']));
$this->assertTrue($field->isVisible($attributes['visible']));
if (array_key_exists('value', $attributes)) {
$this->assertEquals($attributes['value'], $field->getValue());
}
if (array_key_exists('maxlength', $attributes)) {
$this->assertEquals($attributes['maxlength'], $field->getAttribute('maxlength'));
}
if (array_key_exists('placeholder', $attributes)) {
$this->assertEquals($attributes['placeholder'], $field->getAttribute('placeholder'));
}
if (array_key_exists('labels', $attributes)) {
$this->assertEquals($attributes['labels'], $field->asSegmentedRadio()->getLabels()->asText());
}
if ($attributes['visible'] === false) {
$not_visible[] = $label;
}
}
// Check Advanced configuration's fields visibility.
$form->fill(['Advanced configuration' => true]);
// Check hintboxes.
$hints = [
'Description' => "Supported macros:".
"\n{HOST.*}".
"\n{ITEM.*}".
"\n{INVENTORY.*}".
"\nUser macros",
'Position' => 'Position is ignored for s, uptime and unixtime units.'
];
// Check Position dropdown options.
$this->assertEquals(['Before value', 'Above value', 'After value', 'Below value'],
$form->getField('id:units_pos')->getOptions()->asText()
);
foreach ($hints as $label => $text) {
// Force click is needed because the label might be hidden under the scrolled part of the form.
$form->getLabel($label)->query('xpath:./button[@data-hintbox]')->one()->click(true);
$hint = $this->query('xpath://div[@data-hintboxid]')->waitUntilVisible();
$this->assertEquals($text, $hint->one()->getText());
$hint->one()->query('xpath:.//button[@class="btn-overlay-close"]')->one()->click();
$hint->waitUntilNotPresent();
}
// Check visible fields.
foreach ($not_visible as $visible_field) {
$this->assertTrue($form->getField($visible_field)->isVisible());
}
// Check disabled/enabled fields.
$editable_fields = [
'id:units_show' => [
'status' => false,
'depending' => ['id:units', 'id:units_size', 'id:units_pos', 'id:units_bold', 'xpath:.//input[@id="units_color"]/..']
],
'id:needle_show' => [
'status' => true,
'depending' => ['xpath:.//input[@id="needle_color"]/..']
],
'id:scale_show' => [
'status' => false,
'depending' => ['id:scale_show_units', 'id:scale_decimal_places', 'id:scale_size']
]
];
foreach ($editable_fields as $switch => $parameters) {
$form->fill([$switch => $parameters['status']]);
foreach ($parameters['depending'] as $visible_field) {
$this->assertTrue($form->getField($visible_field)->isEnabled($parameters['status']));
}
}
// Check Threshold parameters.
$threshold_field = $form->getField('Thresholds');
$threshold_field->query('button:Add')->one()->waitUntilClickable()->click();
$threshold_input ='id:thresholds_0_threshold';
$inputs = [
'xpath:.//input[@id="thresholds_0_color"]/..',
$threshold_input,
'button:Remove'
];
foreach ($inputs as $selector) {
$this->assertTrue($threshold_field->query($selector)->one()->waitUntilVisible()->isEnabled());
}
$this->assertEquals(255, $form->getField($threshold_input)->getAttribute('maxlength'));
$form->checkValue([$threshold_input => '']);
// Fill Threshold field to enable other Threshold options.
$form->getField($threshold_input)->type('123');
foreach (['id:th_show_labels' => true, 'id:th_show_arc' => true, 'id:th_arc_size' => false] as $field => $status) {
$this->assertTrue($form->getField($field)->isEnabled($status));
}
// Enable Show arc.
$form->fill(['id:th_show_arc' => true]);
$this->assertTrue($form->getField('id:th_arc_size')->isEnabled());
// Check fields' labels and required fields.
$this->assertEquals(['Type', 'Show header', 'Name', 'Refresh interval', 'Item', 'Min', 'Max', 'Colors',
'Advanced configuration', 'Angle', 'Description', 'Value', 'Needle', 'Scale', 'Thresholds',
'Enable host selection'],
$form->getLabels()->asText()
);
$this->assertEquals(['Item', 'Min', 'Max'], $form->getRequiredLabels());
}
public static function getWidgetCommonData() {
return [
// #0 Empty item.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => ''
],
'error' => 'Invalid parameter "Item": cannot be empty.'
]
],
// #1 Both min and max equal zeros.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => self::GAUGE_ITEM,
'Min' => 0,
'Max' => 0
],
'error' => [
'Invalid parameter "Max": value must be greater than "0".'
]
]
],
// #2 All fields are zeros.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => self::GAUGE_ITEM,
'Min' => 0,
'Max' => 0,
'id:desc_size' => 0,
'id:value_size' => 0,
'id:value_arc_size' => 0,
'id:units_size' => 0,
'id:scale_size' => 0,
'id:th_show_arc' => true,
'id:th_arc_size' => 0
],
'Thresholds' => [
['threshold' => '10']
],
'error' => [
'Invalid parameter "Description size": value must be one of 1-100.',
'Invalid parameter "Value size": value must be one of 1-100.',
'Invalid parameter "Arc size": value must be one of 1-100.',
'Invalid parameter "Units size": value must be one of 1-100.',
'Invalid parameter "Scale size": value must be one of 1-100.',
'Invalid parameter "Arc size": value must be one of 1-100.'
]
]
],
// #3 Min and Max are the biggest possible.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => self::GAUGE_ITEM,
'Min' => str_repeat(9,255),
'Max' => str_repeat(9,255)
],
'error' => 'Invalid parameter "Max": value must be greater than "1.0E+255".'
]
],
// #4 Min more than Max.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => self::GAUGE_ITEM,
'Min' => 10,
'Max' => 3
],
'error' => 'Invalid parameter "Max": value must be greater than "10".'
]
],
// #5 All fields are empty.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => self::GAUGE_ITEM,
'Min' => '',
'Max' => '',
'id:desc_size' => '',
'id:decimal_places' => '',
'id:value_size' => '',
'id:value_arc_size' => '',
'id:units_size' => '',
'id:scale_size' => '',
'id:scale_decimal_places' => '',
'id:th_show_arc' => true,
'id:th_arc_size' => ''
],
'Thresholds' => [
['threshold' => '10']
],
'error' => [
'Invalid parameter "Min": cannot be empty.',
'Invalid parameter "Max": cannot be empty.',
'Invalid parameter "Description size": value must be one of 1-100.',
'Invalid parameter "Value size": value must be one of 1-100.',
'Invalid parameter "Arc size": value must be one of 1-100.',
'Invalid parameter "Units size": value must be one of 1-100.',
'Invalid parameter "Scale size": value must be one of 1-100.',
'Invalid parameter "Arc size": value must be one of 1-100.'
]
]
],
// #6 Text in numeric fields.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => self::GAUGE_ITEM,
'Min' => 'text',
'Max' => 'test',
'id:desc_size' => 'abc',
'id:decimal_places' => 'abc',
'id:value_size' => 'abc',
'id:value_arc_size' => 'abc',
'id:units_size' => 'abc',
'id:scale_size' => 'abc',
'id:scale_decimal_places' => 'abc',
'id:th_show_arc' => true,
'id:th_arc_size' => 'abc'
],
'Thresholds' => [
['threshold' => 'test']
],
'error' => [
'Invalid parameter "Min": a number is expected.',
'Invalid parameter "Max": a number is expected.',
'Invalid parameter "Description size": value must be one of 1-100.',
'Invalid parameter "Value size": value must be one of 1-100.',
'Invalid parameter "Arc size": value must be one of 1-100.',
'Invalid parameter "Units size": value must be one of 1-100.',
'Invalid parameter "Scale size": value must be one of 1-100.',
'Invalid parameter "Arc size": value must be one of 1-100.'
]
]
],
// #7 Mixed numbers and random text in numeric fields.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => self::GAUGE_ITEM,
'Min' => '2t',
'Max' => '3y',
'id:desc_size' => '1a',
'id:decimal_places' => '2b',
'id:value_size' => '1a',
'id:value_arc_size' => '1a',
'id:units_size' => '1a',
'id:scale_size' => '1a',
'id:scale_decimal_places' => '2b',
'id:th_show_arc' => true,
'id:th_arc_size' => '1a'
],
'Thresholds' => [
['threshold' => '1', 'color' => 'ERERER']
],
'error' => [
'Invalid parameter "Min": a number is expected.',
'Invalid parameter "Thresholds/1/color": a hexadecimal color code (6 symbols) is expected.'
]
]
],
// #8 2-bytes special characters.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => self::GAUGE_ITEM,
'Min' => 'そこ',
'Max' => 'ߘ',
'id:desc_size' => '۞',
'id:decimal_places' => 'Ֆ',
'id:value_size' => '©',
'id:value_arc_size' => 'ֈ',
'id:units_size' => 'æ',
'id:scale_size' => '߷',
'id:scale_decimal_places' => ' ',
'id:th_show_arc' => true,
'id:th_arc_size' => 'Ä'
],
'Thresholds' => [
['threshold' => 'ß']
],
'error' => [
'Invalid parameter "Min": a number is expected.',
'Invalid parameter "Max": a number is expected.',
'Invalid parameter "Description size": value must be one of 1-100.',
'Invalid parameter "Value size": value must be one of 1-100.',
'Invalid parameter "Arc size": value must be one of 1-100.',
'Invalid parameter "Units size": value must be one of 1-100.',
'Invalid parameter "Scale size": value must be one of 1-100.',
'Invalid parameter "Thresholds/1/threshold": a number is expected.',
'Invalid parameter "Arc size": value must be one of 1-100.'
]
]
],
// #9 4-bytes characters.
[
[
'expected' => TEST_BAD,
'fields' => [
'Name' => '𒀐',
'Item' => self::GAUGE_ITEM,
'Min' => '😁',
'Max' => '🙂',
'id:desc_size' => '😅',
'id:decimal_places' => '😘',
'id:value_size' => '😒',
'id:value_arc_size' => '😔',
'id:units_size' => '🤢',
'id:scale_size' => '😨',
'id:scale_decimal_places' => '😩',
'id:th_show_arc' => true,
'id:th_arc_size' => '😽'
],
'Thresholds' => [
['threshold' => '𒀐']
],
'error' => [
'Invalid parameter "Min": a number is expected.',
'Invalid parameter "Max": a number is expected.',
'Invalid parameter "Description size": value must be one of 1-100.',
'Invalid parameter "Value size": value must be one of 1-100.',
'Invalid parameter "Arc size": value must be one of 1-100.',
'Invalid parameter "Units size": value must be one of 1-100.',
'Invalid parameter "Scale size": value must be one of 1-100.',
'Invalid parameter "Thresholds/1/threshold": a number is expected.',
'Invalid parameter "Arc size": value must be one of 1-100.'
]
]
],
// #10 Too big numbers in decimal places.
[
[
'expected' => TEST_BAD,
'fields' => [
'Item' => self::GAUGE_ITEM,
'id:decimal_places' => '900',
'id:scale_decimal_places' => '900'
],
'error' => [
'Invalid parameter "Decimal places": value must be one of 0-10.',
'Invalid parameter "Decimal places": value must be one of 0-10.'
]
]
],
// #11 All fields successful case.
[
[
'fields' => [
'Name' => '😁🙂𒀐',
'Item' => self::GAUGE_ITEM,
'Min' => 99,
'Max' => 88888,
'xpath:.//input[@id="value_arc_color"]/..' => '64B5F6',
'xpath:.//input[@id="empty_color"]/..' => 'FFBF00',
'xpath:.//input[@id="bg_color"]/..' => 'BA68C8',
'Angle' => '270°',
'id:description' => '𒀐 New test Description 😁🙂😁🙂',
'id:desc_size' => 30,
'id:desc_bold' => true,
'id:desc_v_pos' => 'Top',
'xpath:.//input[@id="desc_color"]/..' => 'FFB300',
'id:decimal_places' => 10,
'id:value_size' => 50,
'id:value_bold' => true,
'xpath:.//input[@id="value_color"]/..' => '283593',
'id:value_arc' => true,
'id:value_arc_size' => 12,
'id:units' => 'Bytes 𒀐 😁',
'id:units_size' => 27,
'id:units_bold' => true,
'id:units_pos' => 'Above value',
'xpath:.//input[@id="units_color"]/..' => '4E342E',
'id:needle_show' => true,
'xpath:.//input[@id="needle_color"]/..' => '4DD0E1',
'id:scale_size' => 33,
'id:scale_decimal_places' => 8,
'id:th_show_arc' => true,
'id:th_arc_size' => 85,
'id:th_show_labels' => true,
'Enable host selection' => true
],
'Thresholds' => [
['threshold' => '555', 'color' => '1976D2']
]
]
],
// #12 Multiple thresholds.
[
[
'fields' => [
'Name' => 'Multiple thresholds',
'Min' => 15,
'Max' => 200,
'Refresh interval' => '30 seconds',
'Item' => self::GAUGE_ITEM,
'id:units_pos' => 'Before value'
],
'Thresholds' => [
['threshold' => '30', 'color' => '03A9F4'],
['threshold' => '50', 'color' => '283593']
]
]
],
// #13 False default checkboxes.
[
[
'fields' => [
'Name' => 'False default checkboxes',
'Item' => self::GAUGE_ITEM,
'Show header' => false,
'id:value_arc' => false,
'id:units_show' => false,
'id:scale_show' => false
]
]
]
];
}
public static function getWidgetCreateData() {
return [
// #14 Minimal required fields.
[
[
'fields' => [
'Item' => self::GAUGE_ITEM,
'Advanced configuration' => false
]
]
]
];
}
/**
*
* @backupOnce widget
*
* @dataProvider getWidgetCommonData
* @dataProvider getWidgetCreateData
*/
public function testDashboardGaugeWidget_Create($data) {
$this->checkFormGaugeWidget($data);
}
/**
* @dataProvider getWidgetCommonData
*/
public function testDashboardGaugeWidget_Update($data) {
$this->checkFormGaugeWidget($data, true);
}
/**
* Function for checking Gauge widget form.
*
* @param array $data data provider
* @param boolean $update true if update scenario, false if create
*/
public function checkFormGaugeWidget($data, $update = false) {
if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
$old_hash = CDBHelper::getHash(self::SQL);
}
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one();
$old_widget_count = $dashboard->getWidgets()->count();
$form = $update
? $dashboard->getWidget(self::$update_gauge)->edit()
: $dashboard->edit()->addWidget()->asForm();
COverlayDialogElement::find()->one();
$form->fill(['Type' => CFormElement::RELOADABLE_FILL('Gauge')]);
if ($update && CTestArrayHelper::get($data['fields'], 'Item') === '') {
$form->getField('Item')->clear();
}
$form->fill(['Advanced configuration' => true]);
if (array_key_exists('Thresholds', $data)) {
// To update Thresholds previously saved values should be removed.
if ($update) {
$this->getThresholdsTable()->clear();
}
$this->getThresholdsTable()->fill($data['Thresholds']);
}
$form->fill($data['fields']);
$form->submit();
if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
$this->assertMessage(TEST_BAD, null, $data['error']);
// Check that DB hash is not changed.
$this->assertEquals($old_hash, CDBHelper::getHash(self::SQL));
}
else {
COverlayDialogElement::ensureNotPresent();
/**
* When name is absent in create scenario it remains default: host name + item name,
* if name is absent in update scenario then previous name remains.
* If name is empty string in both scenarios it is replaced by host name + item name.
*/
if (array_key_exists('Name', $data['fields'])) {
$header = ($data['fields']['Name'] === '')
? self::HOST.': '.$data['fields']['Item']
: $data['fields']['Name'];
}
else {
$header = $update ? self::$update_gauge : self::HOST.': '.$data['fields']['Item'];
}
$dashboard->getWidget($header);
$dashboard->save();
$this->assertMessage(TEST_GOOD, 'Dashboard updated');
$this->assertEquals($old_widget_count + ($update ? 0 : 1), $dashboard->getWidgets()->count());
$saved_form = $dashboard->getWidget($header)->edit();
if (array_key_exists('Item', $data['fields'])) {
$data['fields']['Item'] = self::HOST.': '.$data['fields']['Item'];
}
// Check that Advanced configuration is false by default.
$saved_form->checkValue(['Advanced configuration' => false]);
// Open Advanced configuration if it is not defined as false in data provider.
if (CTestArrayHelper::get($data['fields'], 'Advanced configuration', true)) {
$saved_form->fill(['Advanced configuration' => true]);
}
// Check saved fields in form.
$saved_form->checkValue($data['fields']);
if (array_key_exists('Thresholds', $data)) {
$this->getThresholdsTable()->checkValue($data['Thresholds']);
}
// Check that widget is saved in DB.
$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', '')).')'
));
// Write new name to the updated widget name.
if ($update) {
self::$update_gauge = $header;
}
}
}
public function testDashboardGaugeWidget_SimpleUpdate() {
$this->checkNoChanges();
}
public static function getCancelData() {
return [
// #0 Cancel creating widget with saving the dashboard.
[
[
'cancel_form' => true,
'create_widget' => true,
'save_dashboard' => true
]
],
// #1 Cancel updating widget with saving the dashboard.
[
[
'cancel_form' => true,
'create_widget' => false,
'save_dashboard' => true
]
],
// #2 Create widget without saving the dashboard.
[
[
'cancel_form' => false,
'create_widget' => false,
'save_dashboard' => false
]
],
// #3 Update widget without saving the dashboard.
[
[
'cancel_form' => false,
'create_widget' => false,
'save_dashboard' => false
]
]
];
}
/**
* @dataProvider getCancelData
*/
public function testDashboardGaugeWidget_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
*/
protected function checkNoChanges($cancel = false, $create = false, $save_dashboard = true) {
$old_hash = CDBHelper::getHash(self::SQL);
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one();
$old_widget_count = $dashboard->getWidgets()->count();
$dashboard->edit();
$form = $create
? $dashboard->addWidget()->asForm()
: $dashboard->getWidget(self::$update_gauge)->edit();
$dialog = COverlayDialogElement::find()->one()->waitUntilReady();
if ($create) {
$form->fill(['Type' => CFormElement::RELOADABLE_FILL('Gauge')]);
}
else {
$values = $form->getValues();
}
if ($cancel || !$save_dashboard) {
$form->fill(
[
'Name' => 'new name',
'Refresh interval' => '10 minutes',
'Item' => 'testFormItem4',
'Min' => 10,
'Max' => 300
]
);
}
if ($cancel) {
$dialog->query('button:Cancel')->one()->click();
}
else {
$form->submit();
}
COverlayDialogElement::ensureNotPresent();
if (!$cancel) {
$dashboard->getWidget($save_dashboard ? self::$update_gauge : 'new 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::$update_gauge)->edit()->getValues());
}
// Check that DB hash is not changed.
$this->assertEquals($old_hash, CDBHelper::getHash(self::SQL));
}
public function testDashboardGaugeWidget_Delete() {
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one()->waitUntilReady()->edit();
$widget = $dashboard->getWidget(self::DELETE_GAUGE);
$this->assertTrue($widget->isEditable());
$dashboard->deleteWidget(self::DELETE_GAUGE);
$widget->waitUntilNotPresent();
$dashboard->save();
$this->page->waitUntilReady();
$this->assertMessage(TEST_GOOD, 'Dashboard updated');
// Check that widget is not present on dashboard and in DB.
$this->assertFalse($dashboard->getWidget(self::DELETE_GAUGE, false)->isValid());
$this->assertEquals(0, CDBHelper::getCount('SELECT * FROM widget_field wf'.
' LEFT JOIN widget w'.
' ON w.widgetid=wf.widgetid'.
' WHERE w.name='.zbx_dbstr(self::DELETE_GAUGE)
));
}
/**
* Test function for assuring that text, log, binary and char items are not available in Gauge widget.
*/
public function testDashboardGaugeWidget_CheckAvailableItems() {
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one()->waitUntilReady();
$dialog = $dashboard->edit()->addWidget()->asForm();
$dialog->fill(['Type' => CFormElement::RELOADABLE_FILL('Gauge')]);
$dialog->query('button:Select')->one()->waitUntilClickable()->click();
$host_item_dialog = COverlayDialogElement::find()->all()->last()->waitUntilReady();
$table = $host_item_dialog->query('class:list-table')->asTable()->one()->waitUntilVisible();
$host_item_dialog->query('class:multiselect-control')->asMultiselect()->one()->fill(self::HOST);
$table->waitUntilReloaded();
$this->assertTableDataColumn(['Float item', 'Unsigned item', 'Unsigned_dependent item']);
}
public static function getScreenshotsData() {
return [
// #0 Minimal settings with value.
[
[
'screenshot_id' => 'Empty gauge with data',
'fields' => [
'Item' => self::GAUGE_ITEM
]
]
],
// #1 Minimal settings No data.
[
[
'screenshot_id' => 'Empty gauge with no data',
'fields' => [
'Item' => 'Unsigned item'
]
]
],
// #2 All settings + Threshold default color.
[
[
'screenshot_id' => 'Full gauge',
'fields' => [
'Name' => 'All settings',
'Item' => self::GAUGE_ITEM,
'Min' => 20,
'Max' => 300,
'xpath:.//input[@id="value_arc_color"]/..' => 'FFCDD2',
'xpath:.//input[@id="empty_color"]/..' => '26C6DA',
'xpath:.//input[@id="bg_color"]/..' => 'FFF9C4',
'Angle' => '270°',
'id:description' => 'Screenshot Description 😁🙂😁🙂',
'id:desc_size' => 8,
'id:desc_bold' => true,
'id:desc_v_pos' => 'Top',
'xpath:.//input[@id="desc_color"]/..' => '303F9F',
'id:decimal_places' => 3,
'id:value_size' => 17,
'id:value_bold' => true,
'xpath:.//input[@id="value_color"]/..' => '00796B',
'id:value_arc' => true,
'id:value_arc_size' => 35,
'id:units' => 'Bytes 😁',
'id:units_size' => 12,
'id:units_bold' => true,
'id:units_pos' => 'Below value',
'xpath:.//input[@id="units_color"]/..' => '6D4C41',
'id:needle_show' => true,
'xpath:.//input[@id="needle_color"]/..' => 'FF0000',
'id:scale_size' => 11,
'id:scale_decimal_places' => 2,
'id:th_show_arc' => true,
'id:th_arc_size' => 40,
'id:th_show_labels' => true
],
'Thresholds' => [
['threshold' => '100']
]
]
],
// #3 Macros in description + Thresholds with color.
[
[
'screenshot_id' => 'Gauge with two thresholds',
'fields' => [
'Name' => 'All settings + treshholds',
'Item' => self::GAUGE_ITEM,
'Min' => 1,
'Max' => 300,
'id:description' => '{HOST.NAME} {ITEM.NAME}',
'id:desc_size' => 5,
'id:th_show_arc' => true,
'id:th_arc_size' => 40,
'id:th_show_labels' => true
],
'Thresholds' => [
['threshold' => '100', 'color' => '4000FF'],
['threshold' => '200', 'color' => 'E91E63']
]
]
],
// #4 More macros in description.
[
[
'screenshot_id' => 'More macros',
'fields' => [
'Name' => 'Macros',
'Item' => self::GAUGE_ITEM,
'id:description' => '{HOST.CONN} {ITEM.KEY}',
'id:desc_size' => 5
]
]
],
// #5 User macros in description.
[
[
'screenshot_id' => 'User macro',
'fields' => [
'Name' => 'User macro',
'Item' => self::GAUGE_ITEM,
'id:description' => '{$A} {INVENTORY.ALIAS}',
'id:desc_size' => 5
]
]
]
];
}
/**
* Test function for assuring that form settings affect Gauge image.
*
* @dataProvider getScreenshotsData
*/
public function testDashboardGaugeWidget_Screenshots($data) {
$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
$dashboard = CDashboardElement::find()->one()->waitUntilReady();
$dashboard->selectPage('Screenshot page');
$dashboard->invalidate();
$dialog = $dashboard->edit()->addWidget()->asForm();
$dialog->fill([
'Type' => CFormElement::RELOADABLE_FILL('Gauge'),
'Advanced configuration' => true
]);
if (array_key_exists('Thresholds', $data)) {
$this->getThresholdsTable()->fill($data['Thresholds']);
}
$dialog->fill($data['fields']);
$dialog->submit();
COverlayDialogElement::ensureNotPresent();
$header = array_key_exists('Name', $data['fields'])
? $data['fields']['Name']
: self::HOST.': '.$data['fields']['Item'];
// Wait until widget with header appears on the Dashboard.
$dashboard->save();
$widget = $dashboard->waitUntilReady()->getWidget($header)->waitUntilReady();
$this->page->removeFocus();
// Sleep waits until the gauge is animated.
sleep(1);
$this->assertScreenshot($widget->query('class:dashboard-grid-widget-container')->one(), $data['screenshot_id']);
}
}