<?php /* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** 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 Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ require_once dirname(__FILE__).'/../../include/CWebTest.php'; require_once dirname(__FILE__).'/../behaviors/CMessageBehavior.php'; require_once dirname(__FILE__).'/../behaviors/CTableBehavior.php'; require_once dirname(__FILE__).'/../common/testWidgets.php'; /** * @backup dashboard * * @onBefore prepareData * * @dataSource AllItemValueTypes */ class testDashboardItemHistoryWidget extends testWidgets { /** * Attach MessageBehavior and TableBehavior to the test. * * @return array */ public function getBehaviors() { return [ CMessageBehavior::class, CTableBehavior::class ]; } const DEFAULT_WIDGET = 'Default Item history Widget'; const DELETE_WIDGET = 'Widget for delete'; const DATA_WIDGET = 'Widget for data check'; protected static $dashboardid; protected static $dashboard_create; protected static $dashboard_data; protected static $update_widget = 'Update Item history Widget'; public static function prepareData() { // Create host for widget header and data tests. CDataHelper::createHosts([ [ 'host' => 'Simple host with item for Item history widget', 'interfaces' => [ [ 'type' => INTERFACE_TYPE_AGENT, 'main' => INTERFACE_PRIMARY, 'useip' => INTERFACE_USE_IP, 'ip' => '127.0.9.1', 'dns' => '', 'port' => '10077' ] ], 'groups' => [ 'groupid' => '4' ], 'items' => [ [ 'name' => 'Test Item history', 'key_' => 'plain_text', 'type' => ITEM_TYPE_ZABBIX, 'value_type' => ITEM_VALUE_TYPE_FLOAT, 'delay' => '30' ] ] ] ]); $itemids = CDataHelper::getIds('name'); $response = CDataHelper::call('dashboard.create', [ [ 'name' => 'Dashboard for Item history Widget test', 'pages' => [ [ 'name' => 'Page with default widgets', 'widgets' => [ [ 'type' => 'itemhistory', 'name' => self::DEFAULT_WIDGET, 'x' => 0, 'y' => 0, 'width' => 12, 'height' => 5, 'fields' => [ [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'columns.0.name', 'value' => 'Column_1' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_ITEM, 'name' => 'columns.0.itemid', 'value' => '42227' // item name in widget 'ЗАББИКС Сервер: Linux: Host name of Zabbix agent running'. ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'override_hostid._reference', 'value' => 'DASHBOARD._hostid' ] ] ], [ 'type' => 'itemhistory', 'name' => self::DELETE_WIDGET, 'x' => 0, 'y' => 5, 'width' => 12, 'height' => 5, 'fields' => [ [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'columns.0.name', 'value' => 'Column_1' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_ITEM, 'name' => 'columns.0.itemid', 'value' => '42227' // item name in widget 'ЗАББИКС Сервер: Linux: Host name of Zabbix agent running'. ] ] ] ] ] ] ], [ 'name' => 'Dashboard for Item history Widget create/update test', 'pages' => [ [ 'name' => 'Page with created/updated widgets', 'widgets' => [ [ 'type' => 'itemhistory', 'name' => self::$update_widget, 'x' => 0, 'y' => 0, 'width' => 12, 'height' => 5, 'fields' => [ [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'columns.0.name', 'value' => 'Update column 1' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_ITEM, 'name' => 'columns.0.itemid', 'value' => '42243' // item name in widget 'ЗАББИКС Сервер: Available memory'. ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'reference', 'value' => 'EDCBA' ] ] ], [ 'type' => 'graph', 'name' => 'Classic graph for time period reference', 'x' => 12, 'y' => 0, 'width' => 24, 'height' => 5, 'fields' => [ [ 'type' => ZBX_WIDGET_FIELD_TYPE_INT32, 'name' => 'source_type', 'value' => 1 ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_ITEM, 'name' => 'itemid.0', 'value' => $itemids['Test Item history'] ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'reference', 'value' => 'FEDCB' ] ] ] ] ] ] ], [ 'name' => 'Dashboard for checking data', 'pages' => [ [ 'name' => 'Page with Item history widget', 'widgets' => [ [ 'type' => 'itemhistory', 'name' => self::DATA_WIDGET, 'x' => 0, 'y' => 0, 'width' => 60, 'height' => 6, 'fields' => [ [ 'type' => ZBX_WIDGET_FIELD_TYPE_INT32, 'name' => 'show_timestamp', 'value' => 1 ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'time_period.from', 'value' => 'now-1y' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'time_period.to', 'value' => 'now/d' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'columns.0.name', 'value' => 'Host name' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_ITEM, 'name' => 'columns.0.itemid', 'value' => '42227' // item name in widget 'ЗАББИКС Сервер: Linux: Host name of Zabbix agent running'. ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'columns.1.name', 'value' => 'Available memory' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_INT32, 'name' => 'columns.1.history', 'value' => 1 ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_ITEM, 'name' => 'columns.1.itemid', 'value' => '42243' // item name in widget 'ЗАББИКС Сервер: Linux: Available memory'. ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'columns.2.name', 'value' => 'Available memory in %' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_INT32, 'name' => 'columns.2.history', 'value' => 1 ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_ITEM, 'name' => 'columns.2.itemid', 'value' => '42244' // item name in widget 'ЗАББИКС Сервер: Linux: Available memory in %'. ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'columns.3.name', 'value' => 'Test Item history' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_ITEM, 'name' => 'columns.3.itemid', 'value' => $itemids['Test Item history'] // item name in widget 'Simple host with item for Item history widget: Test Item history'. ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_INT32, 'name' => 'columns.3.history', 'value' => 1 ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'columns.4.name', 'value' => 'Master item' ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_INT32, 'name' => 'columns.4.history', 'value' => 1 ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_ITEM, 'name' => 'columns.4.itemid', 'value' => '99142' // item name in widget 'Test item host: Master item'. ], [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, 'name' => 'override_hostid._reference', 'value' => 'DASHBOARD._hostid' ] ] ] ] ] ] ] ]); self::$dashboardid = $response['dashboardids'][0]; self::$dashboard_create = $response['dashboardids'][1]; self::$dashboard_data = $response['dashboardids'][2]; } public function testDashboardItemHistoryWidget_Layout() { $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid)->waitUntilReady(); $dashboard = CDashboardElement::find()->one(); $dialog = $dashboard->edit()->addWidget(); $this->assertEquals('Add widget', $dialog->getTitle()); $form = $dialog->asForm(); $form->fill(['Type' => CFormElement::RELOADABLE_FILL('Item history')]); // Check default state. $default_state = [ 'Type' => 'Item history', 'Name' => '', 'Show header' => true, 'Refresh interval' => 'Default (1 minute)', 'Columns' => [], 'Show lines' => '25', 'Override host' => '', 'New values' => 'Top', 'Show timestamp' => false, 'Show column header' => 'Vertical', 'Time period' => 'Dashboard', 'Widget' => '', 'id:time_period_from' => 'now-1h', 'id:time_period_to' => 'now' ]; $form->checkValue($default_state); // Check required fields. $this->assertEquals(['Columns', 'Show lines'], $form->getRequiredLabels()); // Check attributes of input elements. $inputs = [ 'Name' => [ 'maxlength' => '255', 'placeholder' => 'default' ], 'Show lines' => [ 'maxlength' => '4' ], 'id:override_hostid_ms' => [ 'placeholder' => 'type here to search' ], 'id:time_period_from' => [ 'maxlength' => '255', 'placeholder' => 'YYYY-MM-DD hh:mm:ss' ], 'id:time_period_to' => [ 'maxlength' => '255', 'placeholder' => 'YYYY-MM-DD hh:mm:ss' ] ]; foreach ($inputs as $field => $attributes) { $this->assertTrue($form->getField($field)->isAttributePresent($attributes)); } // Check radio buttons. $radiobuttons = [ 'Layout' => ['Horizontal', 'Vertical'], 'New values' => ['Top', 'Bottom'], 'Show column header' => ['Off', 'Horizontal', 'Vertical'], 'Time period' => ['Dashboard', 'Widget', 'Custom'] ]; foreach ($radiobuttons as $field => $labels) { $this->assertEquals($labels, $form->getField($field)->getLabels()->asText()); } $refresh_interval = ['Default (1 minute)', 'No refresh', '10 seconds', '30 seconds', '1 minute', '2 minutes', '10 minutes', '15 minutes' ]; $this->assertEquals($refresh_interval, $form->getField('Refresh interval')->getOptions()->asText()); // Check Column popup. $form->getFieldContainer('Columns')->query('button:Add')->waitUntilClickable()->one()->click(); $column_overlay = COverlayDialogElement::find()->all()->last()->waitUntilReady(); $this->assertEquals('New column', $column_overlay->getTitle()); $column_form = $column_overlay->asForm(); $this->assertEquals(['Name', 'Item', 'Base colour', 'Highlights', 'Display', 'Min', 'Max', 'Thresholds', 'History data', 'Use monospace font', 'Display log time', 'Show thumbnail'], $column_form->getLabels()->asText() ); $this->assertEquals(['Name', 'Item'], $column_form->getRequiredLabels()); $defaults = [ 'Name' => ['value' => '', 'maxlength' => 255], 'Item' => ['value' => ''], 'xpath://input[@id="base_color"]/..' => ['value' => ''], 'Display' => ['value' => 'As is', 'lables' => ['As is', 'HTML', 'Single line']], 'Min' => ['value' => '', 'placeholder' => 'calculated', 'maxlength' => 255], 'Max' => ['value' => '', 'placeholder' => 'calculated', 'maxlength' => 255], 'History data' => ['value' => 'Auto', 'lables' => ['Auto', 'History', 'Trends']], 'id:max_length' => ['value' => 100, 'maxlength' => 3], 'Use monospace font' => ['value' => false], 'Display log time' => ['value' => false], 'Show thumbnail' => ['value' => false] ]; foreach ($defaults as $label => $attributes) { $field = $column_form->getField($label); $this->assertEquals($attributes['value'], $field->getValue()); foreach (['maxlength', 'placeholder'] as $attribute) { if (array_key_exists($attribute, $attributes)) { $this->assertEquals($attributes[$attribute], $field->getAttribute($attribute)); } } if (array_key_exists('labels', $attributes)) { $this->assertEquals($attributes['labels'], $field->asSegmentedRadio()->getLabels()->asText()); } } // Check buttons in column dialog. $this->assertEquals(['Add', 'Cancel'], $column_overlay->getFooter()->query('button')->all() ->filter(CElementFilter::CLICKABLE)->asText() ); // Check initial visible fields. foreach (['Name', 'Item', 'Base colour'] as $label) { $field = $column_form->getField($label); $this->assertTrue($field->isEnabled()); $this->assertTrue($field->isVisible()); } // Check fields for binary item. $column_form->fill(['Item' => 'Binary item']); // Check that name is filled automatically. $this->assertEquals('Host for all item value types: Binary item', $column_form->getField('Name')->getValue()); $this->assertEquals(['Name', 'Item', 'Base colour', 'Show thumbnail'], array_values($column_form->getLabels()->filter(CElementFilter::VISIBLE)->asText()) ); // Check fields for character, text and log items. foreach (['Character item', 'Text item', 'Log item'] as $i => $item) { $column_form->fill(['Item' => $item]); $this->assertEquals('Host for all item value types: '.$item, $column_form->getField('Name')->getValue()); $labels = ($item === 'Log item') ? ['Name', 'Item', 'Base colour', 'Highlights', 'Display', 'Use monospace font', 'Display log time'] : ['Name', 'Item', 'Base colour', 'Highlights', 'Display', 'Use monospace font']; $this->assertEquals($labels, array_values($column_form->getLabels()->filter(CElementFilter::VISIBLE)->asText())); $this->checkThresholdsHighlights($column_form, 'Highlights', $i, '_pattern'); $this->checkHint($column_form, 'Display', 'Single line - result will be displayed in a single line and truncated to specified length.' ); $display_maxlength_dependencies = [ 'As is' => false, 'HTML' => false, 'Single line' => true ]; foreach ($display_maxlength_dependencies as $label => $status) { $column_form->fill(['Display' => $label]); $max_length = $column_form->getField('id:max_length'); $this->assertTrue($max_length->isEnabled($status)); $this->assertTrue($max_length->isVisible($status)); } if ($item === 'Log item') { $this->checkHint($column_form, 'Display log time', 'This setting will display log time'. ' instead of item\'s timestamp. "Show timestamp" must also be checked in the advanced'. ' configuration.' ); } } // Check fields for float and unsigned item. foreach (['Float item', 'Unsigned item'] as $j => $item) { $column_form->fill(['Item' => $item]); $this->assertEquals(['Name', 'Item', 'Base colour', 'Display', 'Thresholds', 'History data'], array_values($column_form->getLabels()->filter(CElementFilter::VISIBLE)->asText()) ); $display_fields = [ 'Bar' => true, 'Indicators' => true, 'As is' => false ]; foreach ($display_fields as $label => $status) { $column_form->fill(['Display' => $label]); foreach (['Min', 'Max'] as $display_input) { $input = $column_form->getField($display_input); $this->assertTrue($input->isEnabled($status)); $this->assertTrue($input->isVisible($status)); } } $this->checkThresholdsHighlights($column_form, 'Thresholds', $j, '_threshold'); } $column_overlay->close(); // Check if buttons present and clickable. $this->assertEquals(['Add', 'Cancel'], $dialog->getFooter()->query('button')->all() ->filter(CElementFilter::CLICKABLE)->asText() ); $visible_labels = ['Type', 'Show header', 'Name', 'Refresh interval', 'Layout', 'Columns', 'Show lines', 'Override host', 'Advanced configuration' ]; $hidden_labels = ['New values', 'Show timestamp', 'Show column header', 'Time period', 'Widget', 'From', 'To']; $this->assertEquals($visible_labels, array_values($form->getLabels()->filter(CElementFilter::VISIBLE)->asText())); $this->assertEquals($hidden_labels, array_values($form->getLabels()->filter(CElementFilter::NOT_VISIBLE)->asText())); $expanded_labels = ['New values', 'Show timestamp', 'Show column header', 'Time period']; $form->fill(['Advanced configuration' => true]); $this->assertEquals(array_merge($visible_labels, $expanded_labels), array_values($form->getLabels()->filter(CElementFilter::VISIBLE)->asText()) ); $time_period_fields = [ 'Dashboard' => ['Widget' => false, 'From' => false, 'To' => false], 'Widget' => ['Widget' => true, 'From' => false, 'To' => false], 'Custom' => ['Widget' => false, 'From' => true, 'To' => true] ]; foreach ($time_period_fields as $label => $visibility) { $form->fill(['Time period' => $label]); foreach ($visibility as $field => $status) { $this->assertTrue($form->getField($field)->isEnabled($status)); } // Check Widget multiselect's placeholder. if ($label === 'Widget') { $this->assertTrue($form->getField('id:time_period_reference_ms') ->isAttributePresent(['placeholder' => 'type here to search']) ); } // Check calendar buttons. if ($label === 'Custom') { foreach (['time_period_from_calendar', 'time_period_to_calendar'] as $button) { $this->assertTrue($form->query('id', $button)->one()->isClickable()); } } } $dialog->close(); $dashboard->save(); // Check parameter 'Override host' true/false state. $host_selector = $dashboard->getControls()->query('class:multiselect-control')->asMultiselect()->one(); $this->assertTrue($host_selector->isVisible()); $dashboard->getWidget(self::DEFAULT_WIDGET)->edit(); $this->assertEquals('Edit widget', $dialog->getTitle()); $form->fill(['Override host' => ''])->submit(); $dashboard->save(); $this->assertFalse($host_selector->isVisible()); } public static function getWidgetData() { return [ // #0. [ [ 'expected' => TEST_BAD, 'error' => 'Invalid parameter "Columns": cannot be empty.' ] ], // #1. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Show lines' => '' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory in %', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ], 'error' => ['Invalid parameter "Show lines": value must be one of 1-1000.'] ] ], // #2. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Show lines' => '0' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory in %', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ], 'error' => 'Invalid parameter "Show lines": value must be one of 1-1000.' ] ], // #3. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Show lines' => '1001' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory in %', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ], 'error' => 'Invalid parameter "Show lines": value must be one of 1-1000.' ] ], // #4. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Show lines' => ' ' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory in %', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ], 'error' => 'Invalid parameter "Show lines": value must be one of 1-1000.' ] ], // #5. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Show lines' => '' ], 'error' => [ 'Invalid parameter "Columns": cannot be empty.', 'Invalid parameter "Show lines": value must be one of 1-1000.' ] ] ], // #6. [ [ 'expected' => TEST_GOOD, 'same_host' => 'ЗАББИКС Сервер', 'fields' => [ 'Name' => '2 columns from one host' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory in %', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ], [ 'fields' => [ 'Name' => 'Column2', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #7 Test case with items from two different hosts. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => '' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory in %', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ], [ 'fields' => [ 'Name' => 'Column2', 'Item' => [ 'values' => 'Test Item history', 'context' => ['values' => 'Simple host with item for Item history widget'] ] ] ] ] ] ], // #8 Test case with items from the same host and with custom name. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Test custom name' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory in %', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ], [ 'fields' => [ 'Name' => 'Column2', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #9 Test case with items from two different hosts and with custom name. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Test custom name2' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory in %', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ], [ 'fields' => [ 'Name' => 'Column2', 'Item' => [ 'values' => 'Test Item history', 'context' => ['values' => 'Simple host with item for Item history widget'] ] ] ] ] ] ], // #10. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Custom refresh', 'Refresh interval' => 'Default (1 minute)' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Test Item history', 'context' => ['values' => 'Simple host with item for Item history widget'] ] ] ] ] ] ], // #11. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Header is hidden', 'Show header' => false, 'Refresh interval' => 'No refresh', 'Layout' => 'Vertical', 'Advanced configuration' => true, 'New values' => 'Bottom', 'Show timestamp' => true, 'Show column header' => 'Horizontal' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #12. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Header appears', 'Show header' => true, 'Refresh interval' => '10 seconds', 'Advanced configuration' => true, 'Show column header' => 'Off' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #13. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Refresh interval' => '30 seconds' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #14. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Refresh interval' => '1 minute' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #15. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Show lines' => '1', 'Refresh interval' => '2 minutes' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #16. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Show lines' => '100', 'Refresh interval' => '10 minutes' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #17. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Refresh interval' => '15 minutes' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #18. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Refresh interval' => '10 minutes' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #19. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Override host' => 'Dashboard', 'Refresh interval' => '2 minutes' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #20. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Override host' => 'Dashboard', 'Refresh interval' => '1 minute' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #21. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => ' Widget with trimmed trailing and leading spaces ', 'Refresh interval' => '30 seconds', 'Show lines' => ' 5 ' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Test Item history', 'context' => ['values' => 'Simple host with item for Item history widget'] ] ] ] ], 'trim' => ['Name', 'Show lines'] ] ], // #22. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Show header' => true, 'Name' => 'Widget with updated fields', 'Refresh interval' => '1 minute', 'Show lines' => '50', 'Override host' => 'Dashboard' ], 'Columns' => [ [ 'fields' => [ 'Name' => 'Column1', 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ] ] ] ] ] ], // #23. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Empty name in column' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Available memory', 'context' => ['values' => 'ЗАББИКС Сервер'] ], 'Name' => '' ] ] ], 'column_error' => 'Invalid parameter "/1/name": cannot be empty.' ] ], // #24. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Binary column with color' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Binary item', 'context' => ['values' => 'Host for all item value types'] ] ], 'xpath://input[@id="base_color"]/..' => '90CAF9', 'Show thumbnail' => true ] ] ] ], // #25. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Character column with color and highlights' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Character item', 'context' => ['values' => 'Host for all item value types'] ], 'xpath://input[@id="base_color"]/..' => 'AFB42B', 'Display' => 'HTML', 'Use monospace font' => true ], 'Highlights' => [ [ 'xpath://input[@id="highlights_0_color"]/..' => '00ACC1', 'id:highlights_0_pattern' => 'pattern_1' ], [ 'xpath://input[@id="highlights_1_color"]/..' => '00ACC1', 'id:highlights_1_pattern' => 12345 ] ] ] ] ] ], // #26. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Duplicated highlights' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Character item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'HTML' ], 'Highlights' => [ [ 'xpath://input[@id="highlights_0_color"]/..' => '00ACC1', 'id:highlights_0_pattern' => 'pattern_1' ], [ 'xpath://input[@id="highlights_1_color"]/..' => '0288D1', 'id:highlights_1_pattern' => 'pattern_1' ] ] ] ], 'column_error' => 'Invalid parameter "/1/highlights/2": value (pattern)=(pattern_1) already exists.' ] ], // #27. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Character column with empty Highlight' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Character item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'HTML', 'Use monospace font' => true ], 'Highlights' => [ [ 'xpath://input[@id="highlights_0_color"]/..' => '00ACC1' ] ] ] ], 'column_error' => 'Invalid parameter "/1/highlights/1/pattern": cannot be empty.' ] ], // #28. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Character column with 0 max length' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Character item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Single line', 'Use monospace font' => true, 'id:max_length' => 0 ] ] ], 'column_error' => 'Invalid parameter "/1/max_length": value must be one of 1-500.' ] ], // #29. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Character column with text in max length' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Character item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Single line', 'Use monospace font' => true, 'id:max_length' => 'text' ] ] ], 'column_error' => 'Invalid parameter "/1/max_length": value must be one of 1-500.' ] ], // #30. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Character column with too large max length' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Character item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Single line', 'id:max_length' => 599 ] ] ], 'column_error' => 'Invalid parameter "/1/max_length": value must be one of 1-500.' ] ], // #31. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Float column with text in min' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Bar', 'id:min' => 'min' ] ] ], 'column_error' => 'Invalid parameter "/1/min": a number is expected.' ] ], // #32. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Float column with text in max' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Bar', 'id:max' => 'max' ] ] ], 'column_error' => 'Invalid parameter "/1/max": a number is expected.' ] ], // #33. [ [ 'fields' => [ 'Name' => 'Float column with Bar display and calculated min/max' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Bar' ] ] ] ] ], // #34. [ [ 'fields' => [ 'Name' => 'Float column with Bar display and negative min/max' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Bar', 'id:min' => -9999, 'id:max' => -20 ] ] ] ] ], // #35. [ [ 'fields' => [ 'Name' => 'Float column with Bar display and float min/max' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Bar', 'id:min' => -1.5000009, 'id:max' => -30 ] ] ] ] ], // #36. [ [ 'fields' => [ 'Name' => 'Unsigned column with Indicators display and float min/max' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Indicators', 'id:min' => -1.5000009, 'id:max' => -500.999 ] ] ] ] ], // #37. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Float column with Indicators display and text in min' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Indicators', 'id:min' => 'minimal' ] ] ], 'column_error' => 'Invalid parameter "/1/min": a number is expected.' ] ], // #38. [ [ 'fields' => [ 'Name' => 'Unsigned column with Indicators display and calculated min/max' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Unsigned item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Indicators' ] ] ] ] ], // #39. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Duplicated Thresholds' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ] ], 'Thresholds' => [ [ 'id:thresholds_0_threshold' => 12 ], [ 'id:thresholds_1_threshold' => 12 ] ] ] ], 'column_error' => 'Invalid parameter "/1/thresholds/2": value (threshold)=(12) already exists.' ] ], // #40. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Text in Thresholds' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ] ], 'Thresholds' => [ [ 'id:thresholds_0_threshold' => 'text' ] ] ] ], 'column_error' => 'Invalid parameter "/1/thresholds/1/threshold": a number is expected.' ] ], // #41. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Float with negative Thresholds' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Bar', 'id:min' => 0, 'id:max' => 0, 'History data' => 'History' ], 'Thresholds' => [ [ 'xpath://input[@id="thresholds_0_color"]/..' => '039BE5', 'id:thresholds_0_threshold' => -12 ], [ 'xpath://input[@id="thresholds_1_color"]/..' => '039BE5', 'id:thresholds_1_threshold' => -500.99 ], [ 'xpath://input[@id="thresholds_2_color"]/..' => '00ACC1', 'id:thresholds_2_threshold' => 20.0099 ] ] ] ] ] ], // #42. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Float with different colors Thresholds' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ], 'Display' => 'Indicators', 'id:min' => 9999999, 'id:max' => 9999999999999, 'History data' => 'Trends' ], 'Thresholds' => [ [ 'xpath://input[@id="thresholds_0_color"]/..' => 'E91E63', 'id:thresholds_0_threshold' => 158 ], [ 'xpath://input[@id="thresholds_1_color"]/..' => '039BE5', 'id:thresholds_1_threshold' => 19.20 ] ] ] ] ] ], // #43. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Float with empty Threshold' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Float item', 'context' => ['values' => 'Host for all item value types'] ] ], 'Thresholds' => [ [ 'xpath://input[@id="thresholds_0_color"]/..' => 'E91E63' ] ] ] ] ] ], // #44. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Log item column' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Log item', 'context' => ['values' => 'Host for all item value types'] ], 'Use monospace font' => true, 'Display log time' => true ] ] ] ] ], // #45. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Text item column' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ], 'Use monospace font' => true ] ] ] ] ], // #46. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Time period = empty widget', 'Advanced configuration' => true, 'Time period' => 'Widget' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ], 'error' => 'Invalid parameter "Time period/Widget": cannot be empty.' ] ], // #47. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Time period = Custom, empty from/to', 'Advanced configuration' => true, 'Time period' => 'Custom', 'From' => '', 'To' => '' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ], 'error' => [ 'Invalid parameter "Time period/From": cannot be empty.', 'Invalid parameter "Time period/To": cannot be empty.' ] ] ], // #48. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Time period = Custom, wrong from/to', 'Advanced configuration' => true, 'Time period' => 'Custom', 'From' => 'test_1', 'To' => 'test_2' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ], 'error' => [ 'Invalid parameter "Time period/From": a time is expected.', 'Invalid parameter "Time period/To": a time is expected.' ] ] ], // #49. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Time period = Custom, Default from/to', 'Advanced configuration' => true, 'Time period' => 'Custom' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ] ] ], // #50. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Time period = Custom', 'Advanced configuration' => true, 'Time period' => 'Custom', 'From' => 'now-1y', 'To' => 'now-1M' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ], 'check_time' => 'now-1y – now-1M' ] ], // #51. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Time period = Custom, To in future', 'Advanced configuration' => true, 'Time period' => 'Custom' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ], 'time_shift' => true, 'check_time' => 'future' ] ], // #52. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Time period = Custom, human readable in the past', 'Advanced configuration' => true, 'Time period' => 'Custom' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ], 'time_shift' => true, 'check_time' => 'past' ] ], // #53. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Time period = Custom, To < From', 'Advanced configuration' => true, 'Time period' => 'Custom', 'From' => 'now-1M', 'To' => 'now-2M' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ], 'error' => 'Minimum time period to display is 1 minute.' ] ], // #54. [ [ 'expected' => TEST_BAD, 'fields' => [ 'Name' => 'Time period = Custom, period 30s', 'Advanced configuration' => true, 'Time period' => 'Custom' ], 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ], 'time_shift' => true, 'check_time' => 'custom', 'error' => 'Minimum time period to display is 1 minute.' ] ], // #55. [ [ 'expected' => TEST_GOOD, 'fields' => [ 'Name' => 'Time period = widget', 'Advanced configuration' => true, 'Time period' => 'Widget', 'Widget' => 'Classic graph for time period reference' ], 'clear_custom' => true, 'Columns' => [ [ 'fields' => [ 'Item' => [ 'values' => 'Text item', 'context' => ['values' => 'Host for all item value types'] ] ] ] ] ] ] ]; } /** * @dataProvider getWidgetData */ public function testDashboardItemHistoryWidget_Create($data) { $this->checkWidgetForm($data); } public function testDashboardItemHistoryWidget_SimpleUpdate() { $old_hash = CDBHelper::getHash(self::SQL); $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboard_create)->waitUntilReady(); $dashboard = CDashboardElement::find()->one(); $dashboard->getWidget(self::$update_widget)->edit()->submit(); $dashboard->save(); $this->page->waitUntilReady(); $this->assertMessage(TEST_GOOD, 'Dashboard updated'); $this->assertEquals($old_hash, CDBHelper::getHash(self::SQL)); } /** * @dataProvider getWidgetData */ public function testDashboardItemHistoryWidget_Update($data) { $this->checkWidgetForm($data, true); } /** * Perform Item history widget creation or update and verify the result. * * @param array $data data provider * @param boolean $update updating is performed */ protected function checkWidgetForm($data, $update = false) { $expected = CTestArrayHelper::get($data, 'expected', TEST_GOOD); if ($expected === TEST_BAD) { $old_hash = CDBHelper::getHash(self::SQL); } $data['fields']['Name'] = CTestArrayHelper::get($data, 'fields.Name', 'Item history widget '.microtime()); $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboard_create)->waitUntilReady(); $dashboard = CDashboardElement::find()->one(); $old_widget_count = $dashboard->getWidgets()->count(); $form = $update ? $dashboard->getWidget(self::$update_widget)->edit()->asForm() : $dashboard->edit()->addWidget()->asForm(); $form->fill(['Type' => CFormElement::RELOADABLE_FILL('Item history')]); if ($update) { $button_remove = $form->query('id:list_columns')->asTable()->one()->query('button:Remove'); $remove_count = $button_remove->count(); for ($i = 0; $i < $remove_count; $i++) { $button_remove->waitUntilClickable()->one()->click(); $form->waitUntilReloaded(); } } // Reset custom period fields to defaults, because they are saved from previous cases. if ($update && CTestArrayHelper::get($data, 'clear_custom')) { $form->fill([ 'Advanced configuration' => true, 'Time period' => 'Custom', 'From' => 'now-1h', 'To' => 'now' ]); } $form->fill($data['fields']); // Fill time period with data From: now, To: now +/- time shift in human-readable format. if (CTestArrayHelper::get($data, 'time_shift', false)) { $time = time(); switch ($data['check_time']) { case 'future': $period = [ 'From' => date('Y-m-d H:i:s', $time), // Now. 'To' => date('Y-m-d H:i:s', ($time + 31536000)) // Now + 1 year. ]; break; case 'past': $period = [ 'From' => date('Y-m-d H:i:s', $time - 31536000), // Now - 1 Year. 'To' => date('Y-m-d H:i:s', ($time)) // Now. ]; break; case 'custom': $period = [ 'From' => date('Y-m-d H:i:s', $time - 30), // Now - 30 seconds. 'To' => date('Y-m-d H:i:s', ($time)) // Now. ]; break; } $form->fill($period); $data['check_time'] = $period['From'].' – '.$period['To']; } $values = $form->getValues(); // Fill Columns field. if (array_key_exists('Columns', $data)) { foreach ($data['Columns'] as $column) { $form->getFieldContainer('Columns')->query('button:Add')->one()->waitUntilClickable()->click(); $column_overlay = COverlayDialogElement::find()->all()->last()->waitUntilReady(); $column_overlay_form = $column_overlay->asForm(); $column_overlay_form->fill($column['fields']); foreach (['Highlights', 'Thresholds'] as $table_field) { if (array_key_exists($table_field, $column)) { foreach ($column[$table_field] as $highlight) { $column_overlay_form->getFieldContainer($table_field)->query('button:Add')->one() ->waitUntilClickable()->click(); $column_overlay_form->fill($highlight); } } } $column_overlay->getFooter()->query('button:Add')->waitUntilClickable()->one()->click(); if (array_key_exists('column_error', $data)) { break; } $column_overlay->waitUntilNotVisible(); $form->waitUntilReloaded(); } } if (!array_key_exists('column_error', $data)) { $form->submit(); } // Trim leading and trailing spaces from expected results if necessary. if (array_key_exists('trim', $data)) { foreach ($data['trim'] as $field) { $data['fields'][$field] = trim($data['fields'][$field]); $values[$field] = trim($data['fields'][$field]); } } if ($expected === TEST_BAD) { if (array_key_exists('column_error', $data)) { $data['error'] = $data['column_error']; } $this->assertMessage($data['expected'], null, $data['error']); $this->assertEquals($old_hash, CDBHelper::getHash(self::SQL)); // Check that after error and cancellation of the widget, the widget is not available on dashboard. $dialogs = COverlayDialogElement::find()->all(); $dialog_count = $dialogs->count(); for ($i = $dialog_count - 1; $i >= 0; $i--) { $dialogs->get($i)->close(true); } $dashboard->save()->waitUntilReady(); $this->assertMessage(TEST_GOOD, 'Dashboard updated'); $this->assertFalse($dashboard->getWidget($data['fields']['Name'], false)->isValid()); } else { if (array_key_exists('Name', $data['fields'])) { $header = ($data['fields']['Name'] === '') ? 'Item history' : $data['fields']['Name']; } else { $header = $update ? self::$update_widget : 'Item history'; } COverlayDialogElement::ensureNotPresent(); $widget = $dashboard->getWidget($header); // Save Dashboard to ensure that widget is correctly saved. $dashboard->save()->waitUntilReady(); $this->assertMessage(TEST_GOOD, 'Dashboard updated'); if ($update) { self::$update_widget = $header; } // Check widgets count. $this->assertEquals($old_widget_count + ($update ? 0 : 1), $dashboard->getWidgets()->count()); if (array_key_exists('check_time', $data)) { $this->assertEquals($data['check_time'], $widget->getTimeInterval()); } // Check new widget update interval. $refresh = (CTestArrayHelper::get($data['fields'], 'Refresh interval', 'Default (1 minute)') === 'Default (1 minute)') ? '1 minute' : $data['fields']['Refresh interval']; $this->assertEquals($refresh, $widget->getRefreshInterval()); // Check new widget form fields and values in frontend. $saved_form = $widget->edit(); // 'Advanced configuration' is always collapsed after save. $values['Advanced configuration'] = false; $data['fields']['Advanced configuration'] = false; $this->assertEquals($values, $saved_form->getValues()); $table = $saved_form->query('id:list_columns')->asTable()->one(); // Count is minus one row because of Add button row. $columns_count = $table->getRows()->count() - 1; $this->assertEquals(count($data['Columns']), $columns_count); foreach ($data['Columns'] as $i => $column) { $row = $table->getRow($i); $column_name = (array_key_exists('Name', $column['fields'])) ? $column['fields']['Name'] : $column['fields']['Item']['context']['values'].': '.$column['fields']['Item']['values']; $this->assertEquals($column_name, $row->getColumn('Name')->getText()); $this->assertEquals($column['fields']['Item']['context']['values'].': '.$column['fields']['Item']['values'], $row->getColumn('Data')->getText() ); } $saved_form->checkValue($data['fields']); // Close widget window and cancel editing the dashboard. COverlayDialogElement::find()->one()->close(); $dashboard->cancelEditing(); } } public static function getCancelData() { return [ // Cancel update widget. [ [ 'update' => true, 'save_widget' => true, 'save_dashboard' => false ] ], [ [ 'update' => true, 'save_widget' => false, 'save_dashboard' => true ] ], // Cancel create widget. [ [ 'save_widget' => true, 'save_dashboard' => false ] ], [ [ 'save_widget' => false, 'save_dashboard' => true ] ] ]; } /** * @dataProvider getCancelData */ public function testDashboardItemHistoryWidget_Cancel($data) { $old_hash = CDBHelper::getHash(self::SQL); $new_name = 'Widget to be cancelled'; $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid)->waitUntilReady(); $dashboard = CDashboardElement::find()->one()->edit(); $old_widget_count = $dashboard->getWidgets()->count(); // Start updating or creating a widget. if (CTestArrayHelper::get($data, 'update', false)) { $form = $dashboard->getWidget(self::DEFAULT_WIDGET)->edit(); } else { $form = $dashboard->addWidget()->asForm(); $form->fill(['Type' => CFormElement::RELOADABLE_FILL('Item history')]); } $form->fill([ 'Name' => $new_name, 'Refresh interval' => '15 minutes' ]); $form->getFieldContainer('Columns')->query('button:Add')->waitUntilClickable()->one()->click(); $column_overlay = COverlayDialogElement::find()->all()->last()->waitUntilReady(); $column_overlay->asForm()->fill([ 'Item' => [ 'values' => 'Test Item history', 'context' => ['values' => 'Simple host with item for Item history widget'] ] ]); $column_overlay->getFooter()->query('button:Add')->waitUntilClickable()->one()->click(); $column_overlay->waitUntilNotVisible(); $form->waitUntilReloaded(); // Save or cancel widget. if (CTestArrayHelper::get($data, 'save_widget', false)) { $form->submit(); // Check that changes took place on the unsaved dashboard. $this->assertTrue($dashboard->getWidget($new_name)->isVisible()); } else { $dialog = COverlayDialogElement::find()->one(); $dialog->query('button:Cancel')->one()->click(); $dialog->ensureNotPresent(); if (CTestArrayHelper::get($data, 'update', false)) { foreach ([self::DEFAULT_WIDGET => true, $new_name => false] as $name => $valid) { $dashboard->getWidget($name, false)->isValid($valid); } } $this->assertEquals($old_widget_count, $dashboard->getWidgets()->count()); } // Save or cancel dashboard update. if (CTestArrayHelper::get($data, 'save_dashboard', false)) { $dashboard->save(); } else { $dashboard->cancelEditing(); } // Check that no changes were made to the widget. $this->assertEquals($old_hash, CDBHelper::getHash(self::SQL)); } public function testDashboardItemHistoryWidget_Delete() { $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid)->waitUntilReady(); $dashboard = CDashboardElement::find()->one()->edit(); $widget = $dashboard->getWidget(self::DELETE_WIDGET); $dashboard->deleteWidget(self::DELETE_WIDGET); $widget->waitUntilNotPresent(); $dashboard->save(); $this->assertMessage(TEST_GOOD, 'Dashboard updated'); // Check that widget is not present on dashboard. $this->assertFalse($dashboard->getWidget(self::DELETE_WIDGET, false)->isValid()); $widget_sql = 'SELECT NULL FROM widget_field wf LEFT JOIN widget w ON w.widgetid=wf.widgetid'. ' WHERE w.name='.zbx_dbstr(self::DELETE_WIDGET); $this->assertEquals(0, CDBHelper::getCount($widget_sql)); } public static function getTableData() { return [ // #0 Simple test case with one item and one data entry. [ [ 'initial_data' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Host name', 'Value' => 'Zabbix Item history' ] ], 'item_data' => [ ['itemid' => '42227', 'values' => 'Zabbix Item history', 'time' => strtotime('Now')] ] ] ], // #1 Simple test case with one item and several data entries. [ [ 'initial_data' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Host name', 'Value' => 'Zabbix Item history' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-1 minute')), 'Name' => 'Host name', 'Value' => 'Zabbix Item history2' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-2 minutes')), 'Name' => 'Host name', 'Value' => 'Zabbix plain ⓣⓔⓧⓣ' ] ], 'item_data' => [ ['itemid' => '42227', 'values' => 'Zabbix Item history', 'time' => strtotime('now')], ['itemid' => '42227', 'values' => 'Zabbix Item history2', 'time' => strtotime('-1 minute')], ['itemid' => '42227', 'values' => 'Zabbix plain ⓣⓔⓧⓣ', 'time' => strtotime('-2 minutes')] ] ] ], // #2 Test case with two items and several data entries. [ [ 'initial_data' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Available memory', 'Value' => '9.37 GB' // value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-30 seconds')), 'Name' => 'Available memory in %', 'Value' => '82.0618 %' // value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-1 minute')), 'Name' => 'Available memory in %', 'Value' => '72.0618 %' // value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-1 hour')), 'Name' => 'Available memory', 'Value' => '8.44 GB' // value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-2 hours')), 'Name' => 'Available memory', 'Value' => '7.51 GB' // value rounding is expected. ] ], 'item_data' => [ ['itemid' => '42243', 'values' => '8061078528', 'time' => strtotime('-2 hours')], ['itemid' => '42243', 'values' => '9061078528', 'time' => strtotime('-1 hour')], ['itemid' => '42243', 'values' => '10061078528', 'time' => strtotime('now')], ['itemid' => '42244', 'values' => '72.061797', 'time' => strtotime('-1 minute')], ['itemid' => '42244', 'values' => '82.061797', 'time' => strtotime('-30 seconds')] ] ] ], // #3 Test case with limited lines to show. [ [ 'fields' => [ 'Show lines' => '1' ], 'initial_data' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('today + 9 hours')), 'Name' => 'Available memory', 'Value' => '9.37 GB' // Value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('yesterday')), 'Name' => 'Available memory', 'Value' => '8.44 GB' // Value rounding is expected. ] ], 'result' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('today + 9 hours')), 'Name' => 'Available memory', 'Value' => '9.37 GB' // Value rounding is expected. ] ], 'item_data' => [ ['itemid' => '42243', 'values' => '10061078528', 'time' => strtotime('today + 9 hours')], ['itemid' => '42243', 'values' => '9061078528', 'time' => strtotime('yesterday')] ] ] ], // #4 Test case for 'Items location' and 'Show text as HTML' options check. [ [ 'fields' => ['Layout' => 'Vertical'], 'edit_columns' => [ 'Host name' => ['Display' => 'HTML'] ], 'initial_data' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Master item', 'Value' => '1' // Value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-15 hours')), 'Name' => 'Host name', 'Value' => '<b>'.STRING_128.'</b>' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-16 hours')), 'Name' => 'Host name', 'Value' => '<span style="text-transform:uppercase;">'.'test'.'</span>' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-25 hours')), 'Name' => 'Host name', 'Value' => STRING_255 ] ], 'result' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Master item' => '1' // Value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-15 hours')), 'Host name' => STRING_128 ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-16 hours')), 'Host name' => 'TEST' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-25 hours')), 'Host name' => STRING_255 ] ], 'item_data' => [ ['itemid' => '99142', 'values' => '1.00001', 'time' => strtotime('now')], ['itemid' => '42227', 'values' => '<b>'.STRING_128.'</b>', 'time' => strtotime('-15 hours')], ['itemid' => '42227', 'values' => '<span style="text-transform:uppercase;">'.'test'.'</span>', 'time' => strtotime('-16 hours') ], ['itemid' => '42227', 'values' => STRING_255, 'time' => strtotime('-25 hours')] ] ] ], // #5 Test case for 'Items location' and 'Show text as Single line' options check. [ [ 'fields' => [ 'Advanced configuration' => true, 'New values' => 'Bottom', 'Show timestamp' => false ], 'edit_columns' => [ 'Host name' => ['Display' => 'Single line', 'id:max_length' => 3] ], 'initial_data' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Master item', 'Value' => '1' // Value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-15 hours')), 'Name' => 'Host name', 'Value' => '<b>'.STRING_128.'</b>' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-16 hours')), 'Name' => 'Host name', 'Value' => '<span style="text-transform:uppercase;">'.'test'.'</span>' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-25 hours')), 'Name' => 'Host name', 'Value' => STRING_255 ] ], 'result' => [ [ 'Name' => 'Host name', 'Value' => 'lon…' ], [ 'Name' => 'Host name', 'Value' => '<sp…' ], [ 'Name' => 'Host name', 'Value' => '<b>…' ], [ 'Name' => 'Master item', 'Value' => '1' // Value rounding is expected. ] ], 'item_data' => [ ['itemid' => '99142', 'values' => '1.00001', 'time' => strtotime('now')], ['itemid' => '42227', 'values' => '<b>'.STRING_128.'</b>', 'time' => strtotime('-15 hours')], ['itemid' => '42227', 'values' => '<span style="text-transform:uppercase;">'.'test'.'</span>', 'time' => strtotime('-16 hours') ], ['itemid' => '42227', 'values' => STRING_255, 'time' => strtotime('-25 hours')] ] ] ], // #6 Test case for host selection check. [ [ 'host_select' => [ 'without_data' => 'Simple host with item for Item history widget', 'with_data' => 'ЗАББИКС Сервер' ], 'initial_data' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Host name', 'Value' => 'Zabbix Item history' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-80 seconds')), 'Name' => 'Master item', 'Value' => '7.7778' // Value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-1 week')), 'Name' => 'Host name', 'Value' => STRING_255 ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-1 month')), 'Name' => 'Available memory in %', 'Value' => '82.0618 %' // Value rounding is expected. ] ], 'result' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Host name', 'Value' => 'Zabbix Item history' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-1 week')), 'Name' => 'Host name', 'Value' => STRING_255 ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-1 month')), 'Name' => 'Available memory in %', 'Value' => '82.0618 %' // Value rounding is expected. ] ], 'item_data' => [ ['itemid' => '42227', 'values' => 'Zabbix Item history', 'time' => strtotime('now')], ['itemid' => '99142', 'values' => '7.777777', 'time' => strtotime('-80 seconds')], ['itemid' => '42227', 'values' => STRING_255, 'time' => strtotime('-1 week')], ['itemid' => '42244', 'values' => '82.061797', 'time' => strtotime('-1 month')] ] ] ], // #7 Test case for Auto/History options check. [ [ 'fields' => [ 'Advanced configuration' => true, 'Time period' => 'Custom' ], 'edit_columns' => [ 'Master item' => ['History data' => 'Auto'] ], 'initial_data' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Master item', 'Value' => '1' // Value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-15 hours')), 'Name' => 'Host name', 'Value' => '<b>'.STRING_128.'</b>' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-16 hours')), 'Name' => 'Host name', 'Value' => '<span style="text-transform:uppercase;">'.'test'.'</span>' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-25 hours')), 'Name' => 'Host name', 'Value' => STRING_255 ] ], 'result' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-15 hours')), 'Name' => 'Host name', 'Value' => '<b>'.STRING_128.'</b>' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-16 hours')), 'Name' => 'Host name', 'Value' => '<span style="text-transform:uppercase;">'.'test'.'</span>' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-25 hours')), 'Name' => 'Host name', 'Value' => STRING_255 ] ], 'item_data' => [ ['itemid' => '99142', 'values' => '1.00001', 'time' => strtotime('now')], ['itemid' => '42227', 'values' => '<b>'.STRING_128.'</b>', 'time' => strtotime('-15 hours')], ['itemid' => '42227', 'values' => '<span style="text-transform:uppercase;">'.'test'.'</span>', 'time' => strtotime('-16 hours') ], ['itemid' => '42227', 'values' => STRING_255, 'time' => strtotime('-25 hours')] ] ] ], // #8 Test case for Time period check. [ [ 'fields' => [ 'Advanced configuration' => true, 'Time period' => 'Custom', 'From' => date('Y-m-d H:i:s', strtotime('-5 days')), 'To' => date('Y-m-d H:i:s', strtotime('now')) ], 'initial_data' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('+1 hours')), 'Name' => 'Available memory in %', 'Value' => '82.0618 %' // Value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Host name', 'Value' => 'Zabbix Item history' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-80 seconds')), 'Name' => 'Master item', 'Value' => '7.7778' // Value rounding is expected. ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-1 week')), 'Name' => 'Host name', 'Value' => STRING_255 ] ], 'result' => [ [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('now')), 'Name' => 'Host name', 'Value' => 'Zabbix Item history' ], [ 'Timestamp' => date('Y-m-d H:i:s', strtotime('-80 seconds')), 'Name' => 'Master item', 'Value' => '7.7778' // Value rounding is expected. ] ], 'item_data' => [ ['itemid' => '42227', 'values' => 'Zabbix Item history', 'time' => strtotime('now')], ['itemid' => '99142', 'values' => '7.777777', 'time' => strtotime('-80 seconds')], ['itemid' => '42227', 'values' => STRING_255, 'time' => strtotime('-1 week')], ['itemid' => '42244', 'values' => '82.061797', 'time' => strtotime('+1 hours')] ] ] ] ]; } /** * @backup !history, !history_uint, !history_str * * @dataProvider getTableData */ public function testDashboardItemHistoryWidget_TableData($data) { foreach ($data['item_data'] as $params) { CDataHelper::addItemData($params['itemid'], $params['values'], $params['time']); } $this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboard_data)->waitUntilReady(); $dashboard = CDashboardElement::find()->one(); $dashboard->waitUntilReady(); $this->assertTableData($data['initial_data']); $default_values = [ 'fields' => [ 'Layout' => 'Horizontal', 'Show lines' => '25', 'Advanced configuration' => true, 'New values' => 'Top', 'Show timestamp' => true, 'Time period' => 'Custom', 'From' => 'now-1y', 'To' => 'now/d' ], 'columns' => [ 'Host name' => ['id:display' => 'As is'], 'Master item' => ['History data' => 'History'] ] ]; if (array_key_exists('fields', $data)) { $this->widgetConfigurationChange($data['fields'], $dashboard, CTestArrayHelper::get($data, 'edit_columns', []) ); $this->assertTableData($data['result']); $this->widgetConfigurationChange($default_values['fields'], $dashboard, $default_values['columns']); } if (array_key_exists('host_select', $data)) { $multiselect_field = $dashboard->getControls()->query('class:multiselect-control')->asMultiselect()->one(); $multiselect_field->fill($data['host_select']['without_data']); $dashboard->waitUntilReady(); $this->assertTableData(); $multiselect_field->fill($data['host_select']['with_data']); $dashboard->waitUntilReady(); $this->assertTableData($data['result']); $multiselect_field->clear(); $dashboard->waitUntilReady(); } if (array_key_exists('result', $data)) { $this->assertTableData($data['initial_data']); } } /** * Test function for assuring that all items are available in Item History widget. */ public function testDashboardItemHistoryWidget_CheckAvailableItems() { $this->checkAvailableItems('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid, 'Item history' ); } /** * Change Item history widget configuration. * * @param CDashboardElement $dashboard dashboard element * @param array $configuration widget parameter(s) * @param array $edit_columns array of columns to be changed in test */ protected function widgetConfigurationChange($configuration, $dashboard, $edit_columns = []) { $form = $dashboard->getWidget(self::DATA_WIDGET)->edit(); $form->fill($configuration); if ($edit_columns !== []) { foreach ($edit_columns as $name => $settings) { $form->getFieldContainer('Columns')->asTable()->findRow('Name', $name) ->query('button:Edit')->one()->click(); $column_overlay = COverlayDialogElement::find()->all()->last()->waitUntilReady(); $column_overlay->asForm()->fill($settings); $column_overlay->getFooter()->query('button:Update')->waitUntilClickable()->one()->click(); $column_overlay->waitUntilNotVisible(); $form->waitUntilReloaded(); } } $form->submit(); $dashboard->getWidget(self::DATA_WIDGET); $dashboard->save(); $dashboard->waitUntilReady(); } /** * Check field's hint text. * * @param CFormElement $form given form * @param string $label checked field's label * @param string $hint_text text of the hint */ protected function checkHint($form, $label, $hint_text) { $form->getLabel($label)->query('xpath:./button[@data-hintbox]')->one()->click(); $hint = $this->query('xpath://div[@data-hintboxid]')->waitUntilVisible(); $this->assertEquals($hint_text, $hint->one()->getText()); $hint->one()->query('xpath:.//button[@class="btn-overlay-close"]')->one()->click(); $hint->waitUntilNotPresent(); } /** * Check Thresholds or Highlights field inputs and color-pickers. * * @param CFormElement $form given form * @param string $label checked field's label * @param int $i input counter * @param string $selector selector of tested input */ protected function checkThresholdsHighlights($form, $label, $i, $selector) { $container = $form->getFieldContainer($label); $container->query('button:Add')->one()->click(); $input = $form->query('xpath:.//input[contains(@id, '.CXPathHelper::escapeQuotes($i.$selector).')]')->one(); $this->assertTrue($input->isVisible()); $this->assertEquals('FF465C', $container->query('xpath:.//div[@class="color-picker"]') ->asColorPicker()->one()->getValue() ); $container->query('xpath:.//button[contains(@id, '.CXPathHelper::escapeQuotes($i.'_remove').')]') ->one()->click(); $this->assertFalse($input->isVisible()); } }