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