You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1116 lines
34 KiB

<?php
/*
** Zabbix
** Copyright (C) 2001-2023 Zabbix SIA
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
require_once dirname(__FILE__).'/../../include/CWebTest.php';
require_once dirname(__FILE__).'/../behaviors/CMessageBehavior.php';
require_once dirname(__FILE__).'/../traits/TableTrait.php';
require_once dirname(__FILE__).'/../../include/helpers/CDataHelper.php';
/**
* Base class for Value mappings function tests.
*/
class testFormValueMappings extends CWebTest {
use TableTrait;
/**
* Attach MessageBehavior to the test.
*
* @return array
*/
public function getBehaviors() {
return [CMessageBehavior::class];
}
const HOSTID = 99134; // ID of the host for valuemap update.
const TEMPLATEID = 40000; // ID of the template for valuemap update.
const UPDATE_VALUEMAP1 = 'Valuemap for update 1';
const UPDATE_VALUEMAP2 = 'Valuemap for update 2';
const DELETE_VALUEMAP = 'Valuemap for delete';
const EXISTING_VALUEMAPS = [
[
'Name' => 'Valuemap for delete',
'Value' => "=1010101010101010101010101010101\n\ndefault value1010101010101010101010101010101".
"\n424242424242424242424242424242424242424242424242\n\nAnswer to the Ultimate Question of Life, ".
"Universe and Everything\n123458945-987653341\n\nfrom 123458945 to 987653341\n",
'Action' => 'Remove'
],
[
'Name' => 'Valuemap for update 1',
'Value' => "=\n\nreference newvalue",
'Action' => 'Remove'
],
[
'Name' => 'Valuemap for update 2',
'Value' => "=\n\nno data\n=1\n\none\n=2\n\ntwo\n",
'Action' => 'Remove'
]
];
private static $previous_valuemap_name = self::UPDATE_VALUEMAP1;
private static $previous_class = null;
/**
* Function that checks the layout of the Value mappings tab in Host or Template configuration forms.
*
* @param string $source Entity (host or template) for which the scenario is executed.
*/
public function checkLayout($source) {
// Open value mapping tab.
$this->openValueMappingTab($source);
// Check value mapping table headers and content.
$table = $this->query('id', ($source === 'template' ? 'template-' : '').'valuemap-table')->asTable()->one();
$this->assertEquals(['Name', 'Value', 'Action'], $table->getHeadersText());
$this->assertTableData(self::EXISTING_VALUEMAPS, 'id:valuemap-formlist');
// Check value mapping configuration form layout.
$this->query('name:valuemap_add')->one()->click();
$dialog = COverlayDialogElement::find()->waitUntilReady()->all()->last();
$this->assertEquals('Value mapping', $dialog->getTitle());
$mapping_form = $dialog->getContent()->asForm();
$labels = $mapping_form->query('xpath:.//label')->all()->asText();
$this->assertEquals(['Name', 'Mappings'], $labels);
$this->assertEquals('64', $mapping_form->query('id:name')->one()->getAttribute('maxlength'));
// Check mappings table layout.
$mappings_table = $mapping_form->query('id:mappings_table')->asTable()->one();
$this->assertEquals(['', 'Type', 'Value', '', 'Mapped to', 'Action', ''], $mappings_table->getHeadersText());
$row = $mappings_table->getRow(0);
foreach (['Value', 'Mapped to'] as $mapping_column) {
$mapping_field = $row->getColumn($mapping_column)->query('xpath:.//input')->one();
$this->assertEquals('64', $mapping_field->getAttribute('maxlength'));
}
$this->assertEquals(1, $row->query('xpath:.//td[text()="⇒"]')->all()->count());
$this->assertTrue($row->query('button:Remove')->one()->isClickable());
// Check types.
$value_column = $row->getColumn('Value')->query('xpath:.//input')->one();
$dropdown = $row->query('name:mappings[1][type]')->asDropdown()->one();
$types = ['equals', 'is greater than or equals', 'is less than or equals', 'in range', 'regexp', 'default'];
$this->assertEquals($types, $dropdown->getOptions()->asText());
foreach ($types as $type) {
$dropdown->select($type);
if ($type === 'default') {
$this->assertEquals('visibility-hidden', $value_column->getAttribute('class'));
}
else {
$placeholder = ($type === 'regexp') ? 'regexp' : 'value';
$this->assertEquals($placeholder, $value_column->getAttribute('placeholder'));
}
}
// Check that both overlay control buttons are clickable.
$this->assertEquals(2, $dialog->getFooter()->query('button', ['Add', 'Cancel'])->all()
->filter(new CElementFilter(CElementFilter::CLICKABLE))->count());
}
/**
* Creates a clone of a host/template and verifies that value mappings were copied.
*
* @param string $source Entity (host or template) for which the scenario is executed.
*/
public function checkClone($source) {
// Create a clone of an existing host/template with value mappings.
$this->openValueMappingTab($source, true, false);
$this->query('button', 'Clone')->one()->click();
$form = COverlayDialogElement::find()->asForm()->waitUntilReady()->one();
$form->getField(ucfirst($source).' name')->fill('Clone Valuemap Test');
$form->submit();
$this->page->waitUntilReady();
$this->assertMessage(TEST_GOOD);
$this->page->open('zabbix.php?action='.$source.'.list&filter_name=Clone Valuemap Test&filter_set=1')->waitUntilReady();
$this->query('link', 'Clone Valuemap Test')->one()->click();
COverlayDialogElement::find()->asForm()->one()->waitUntilVisible()->selectTab('Value mapping');
$this->assertTableData(self::EXISTING_VALUEMAPS, 'id:valuemap-formlist');
COverlayDialogElement::find()->one()->close();
}
public function getValuemapData() {
return [
// Mapping type - default.
[
[
'name' => 'default',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'default',
'newvalue' => 'default value'
]
]
]
],
// Successful creation/update of value mapping with multiple mappings and type equals.
[
[
'name' => 'ABC!@#$%^&*()_+=[].абвгдеёжзāīōēūšķļ€‡Œ™£¥©µ¾ÆÖÕæƩƴƵɷʁΔβφψϾֆ۝ܫज',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'equals',
'value' => ' ',
'newvalue' => 'jaunā vērtība'
],
[
'type' => 'equals',
'value' => ' 2 два ',
'newvalue' => 'один + один'
],
[
'type' => 'equals',
'value' => 'duplicate newvalue',
'newvalue' => 'один + один'
],
[
'type' => 'equals',
'value' => '1_WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW',
'newvalue' => 'WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW'
],
[
'type' => 'equals',
'value' => 'mapping not shown',
'newvalue' => ' not shown on screenshot '
]
],
'trim' => true
]
],
// Successful creation/update of value mapping with all available types.
[
[
'name' => 'all types together',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'equals',
'value' => '10',
'newvalue' => 'default value'
],
[
'type' => 'is greater than or equals',
'value' => '11',
'newvalue' => 'greater or equals 11'
],
[
'type' => 'is less than or equals',
'value' => '12',
'newvalue' => 'less or equals 12'
],
[
'type' => 'in range',
'value' => '13-16',
'newvalue' => 'from 13 to 16'
],
[
'type' => 'regexp',
'value' => '42',
'newvalue' => 'Answer to the Ultimate Question of Life, Universe and Everything'
],
[
'type' => 'default',
'newvalue' => 'default value'
]
],
'screenshot_id' => 'ValuemapScreenshot1'
]
],
// Successful creation/update of value mapping with empty value field.
[
[
'name' => 'Equals without value',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'equals',
'value' => '',
'newvalue' => 'no value'
]
]
]
],
// Successful creation/update of value mapping with type - is greater than or equals.
[
[
'name' => 'greater than or equals',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'is greater than or equals',
'value' => '10',
'newvalue' => 'greater or equals 10'
],
[
'type' => 'is greater than or equals',
'value' => '25.25',
'newvalue' => 'greater or equals 25.25'
],
[
'type' => 'is greater than or equals',
'value' => '.55',
'newvalue' => 'greater or equals .55'
],
[
'type' => 'is greater than or equals',
'value' => '0',
'newvalue' => 'greater or equals 0'
],
[
'type' => 'is greater than or equals',
'value' => '-25',
'newvalue' => 'greater or equals -25'
],
[
'type' => 'is greater than or equals',
'value' => '-30.30',
'newvalue' => 'greater or equals -30.30'
]
]
]
],
// Successful creation/update of value mapping with type - is less than or equals.
[
[
'name' => 'less than or equals',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'is less than or equals',
'value' => '10',
'newvalue' => 'less or equals 10'
],
[
'type' => 'is less than or equals',
'value' => '25.25',
'newvalue' => 'less or equals 25.25'
],
[
'type' => 'is less than or equals',
'value' => '.55',
'newvalue' => 'less or equals .55'
],
[
'type' => 'is less than or equals',
'value' => '0',
'newvalue' => 'less or equals 0'
],
[
'type' => 'is less than or equals',
'value' => '-25',
'newvalue' => 'less or equals -25'
],
[
'type' => 'is less than or equals',
'value' => '-30.30',
'newvalue' => 'less or equals -30.30'
]
]
]
],
// Successful creation/update of value mapping with type - in range.
[
[
'name' => 'in range',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'in range',
'value' => '1-10',
'newvalue' => 'from 1 to 10'
],
[
'type' => 'in range',
'value' => '-10-10',
'newvalue' => 'from -10 to 10'
],
[
'type' => 'in range',
'value' => '-20--10',
'newvalue' => 'from -20 to -10'
],
[
'type' => 'in range',
'value' => '20-20',
'newvalue' => 'from 20 to 20'
],
[
'type' => 'in range',
'value' => '123.456-789.1011',
'newvalue' => 'from 123.456 to 789.1011'
],
[
'type' => 'in range',
'value' => '-789.1011--123.456',
'newvalue' => 'from -789.1011 to -123.456'
],
[
'type' => 'in range',
'value' => '.00001-.00002',
'newvalue' => 'from .00001 to .00002'
]
]
]
],
// Successful creation/update of value mapping with type - regex.
[
[
'name' => 'regex',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'regexp',
'value' => '^&^%&%&%^',
'newvalue' => 'symbols'
],
[
'type' => 'regexp',
'value' => '^\d+(\.\d+)?',
'newvalue' => 'true regex'
],
[
'type' => 'regexp',
'value' => '42',
'newvalue' => 'Answer to the Ultimate Question of Life, Universe and Everything'
]
]
]
],
// Successful creation/update for value mapping with same value and types - in range, equals.
[
[
'name' => 'equals and inrange',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'in range',
'value' => '1-10',
'newvalue' => 'same mapping'
],
[
'type' => 'equals',
'value' => '1-10',
'newvalue' => 'same mapping'
]
]
]
],
// Value mapping with duplicate name.
[
[
'expected' => TEST_BAD,
'name' => ' Valuemap for delete ',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'value' => 'one',
'newvalue' => '1'
],
[
'value' => 'two',
'newvalue' => '2'
],
[
'value' => 'three',
'newvalue' => '3'
]
],
'error_details' => 'Incorrect value for field "Name": value (Valuemap for delete) already exists.'
]
],
// Empty name.
[
[
'expected' => TEST_BAD,
'name' => '',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'value' => 'one',
'newvalue' => '1'
]
],
'error_details' => 'Incorrect value for field "Name": cannot be empty.'
]
],
// No mappings.
[
[
'expected' => TEST_BAD,
'name' => 'Valuemap without mappings',
'remove_all' => true,
'error_details' => 'Incorrect value for field "Mappings": cannot be empty.'
]
],
// Empty Mapped to field.
[
[
'expected' => TEST_BAD,
'name' => 'Empty mapped to',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'value' => 'one',
'newvalue' => '1'
],
[
'value' => 'two',
'newvalue' => '2'
],
[
'value' => 'three',
'newvalue' => ''
]
],
'error_details' => 'Incorrect value for field "Mapped to": cannot be empty.'
]
],
// Space in Name field.
[
[
'expected' => TEST_BAD,
'name' => ' ',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'value' => 'one',
'newvalue' => '1'
]
],
'error_details' => 'Incorrect value for field "Name": cannot be empty.'
]
],
// Space in mapped to field.
[
[
'expected' => TEST_BAD,
'name' => 'Empty mapped to',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'value' => 'one',
'newvalue' => '1'
],
[
'value' => 'two',
'newvalue' => '2'
],
[
'value' => 'three',
'newvalue' => ' '
]
],
'error_details' => 'Incorrect value for field "Mapped to": cannot be empty.'
]
],
// Duplicate value field values within the same value mapping.
[
[
'expected' => TEST_BAD,
'name' => 'Valuemap with duplicate values',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'value' => 'one',
'newvalue' => '1'
],
[
'value' => 'two',
'newvalue' => '2'
],
[
'value' => ' one ',
'newvalue' => '1 again'
]
],
'error_details' => 'Incorrect value for field "Value": value (one) already exists.'
]
],
// Text in value field with type - is greater than or equals.
[
[
'expected' => TEST_BAD,
'name' => 'error message for greater than or equals',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'is greater than or equals',
'value' => 'text here',
'newvalue' => 'this is text'
]
],
'error_details' => 'Incorrect value for field "Value": a floating point value is expected.'
]
],
// Text in value field with type - is less than or equals.
[
[
'expected' => TEST_BAD,
'name' => 'error message for less than or equals',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'is less than or equals',
'value' => 'text here',
'newvalue' => 'this is text'
]
],
'error_details' => 'Incorrect value for field "Value": a floating point value is expected.'
]
],
// Incorrect value for - in range.
[
[
'expected' => TEST_BAD,
'name' => 'error message for incorrect in range',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'in range',
'value' => '5---10',
'newvalue' => 'several symbols'
]
],
'error_details' => 'Incorrect value for field "Value": invalid range expression.'
]
],
// Empty value for - regexp.
[
[
'expected' => TEST_BAD,
'name' => 'error message empty regexp value field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'regexp',
'value' => '',
'newvalue' => 'empty value'
]
],
'error_details' => 'Incorrect value for field "Value": cannot be empty.'
]
],
// Empty value for - is greater or equals.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty value field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'is greater than or equals',
'value' => '',
'newvalue' => 'empty value'
]
],
'error_details' => 'Incorrect value for field "Value": a floating point value is expected.'
]
],
// Empty value for - is less than or equals.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty value field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'is less than or equals',
'value' => '',
'newvalue' => 'empty value'
]
],
'error_details' => 'Incorrect value for field "Value": a floating point value is expected.'
]
],
// Empty value for - in range.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty value field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'in range',
'value' => '',
'newvalue' => 'empty value'
]
],
'error_details' => 'Incorrect value for field "Value": cannot be empty.'
]
],
// 2 empty values for - equals.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty value field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'equals',
'value' => ' ',
'newvalue' => 'empty value1'
],
[
'type' => 'equals',
'value' => '',
'newvalue' => 'empty value2'
]
],
'error_details' => 'Incorrect value for field "Value": value () already exists.'
]
],
// Empty "Mapped to" field for type - in range.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty mapping field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'in range',
'value' => '1-10',
'newvalue' => ''
]
],
'error_details' => 'Incorrect value for field "Mapped to": cannot be empty.'
]
],
// Empty "Mapped to" field for type - less.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty mapping field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'is less than or equals',
'value' => '11',
'newvalue' => ''
]
],
'error_details' => 'Incorrect value for field "Mapped to": cannot be empty.'
]
],
// Empty "Mapped to" field for type - greater.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty mapping field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'is greater than or equals',
'value' => '12',
'newvalue' => ''
]
],
'error_details' => 'Incorrect value for field "Mapped to": cannot be empty.'
]
],
// Empty "Mapped to" field for type - regex.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty mapping field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'regexp',
'value' => 'regexp',
'newvalue' => ''
]
],
'error_details' => 'Incorrect value for field "Mapped to": cannot be empty.'
]
],
// Empty "Mapped to" field for type - equals.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty mapping field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'equals',
'value' => 'equals',
'newvalue' => ''
]
],
'error_details' => 'Incorrect value for field "Mapped to": cannot be empty.'
]
],
// Empty "Mapped to" field for type - default.
[
[
'expected' => TEST_BAD,
'name' => 'error message for empty mapping field',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'type' => 'default',
'newvalue' => ''
]
],
'error_details' => 'Incorrect value for field "Mapped to": cannot be empty.'
]
]
];
}
/**
* Function that checks the layout of the value mappings tab in Host or Template configuration forms.
*
* @param array $data Data provider
* @param string $source Entity (host or template) for which the scenario is executed.
* @param string $action Action to be performed with value mappings.
*/
public function checkAction($data, $source, $action) {
if (self::$previous_class !== get_called_class()) {
self::$previous_class = get_called_class();
self::$previous_valuemap_name = static::UPDATE_VALUEMAP1;
}
$expected = CTestArrayHelper::get($data, 'expected', TEST_GOOD);
if ($expected === TEST_BAD) {
$sql = 'SELECT * FROM valuemap v INNER JOIN valuemap_mapping vm ON vm.valuemapid = v.valuemapid';
$old_hash = CDBHelper::getHash($sql);
}
$this->openValueMappingTab($source);
// Add a new value mapping or open the value mapping to be updated.
$this->query(($action === 'create')
? 'name:valuemap_add'
: 'link:'.($expected === TEST_GOOD ? self::$previous_valuemap_name : self::UPDATE_VALUEMAP2
))->one()->click();
// Fill in the name of the valuemap and the parameters of its mappings.
$dialog = COverlayDialogElement::find()->asForm()->waitUntilVisible()->all()->last();
$dialog->query('xpath:.//input[@id="name"]')->one()->fill($data['name']);
$mapping_table = $dialog->query('id:mappings_table')->asMultifieldTable()->one();
if (CTestArrayHelper::get($data, 'remove_all')) {
$mapping_table->clear();
}
else {
if ($action === 'update' && CTestArrayHelper::get($data, 'expected') !== TEST_BAD) {
$mapping_table->clear();
$mapping_table->query('button:Add')->one()->click();
}
$mapping_table->fill($data['mappings']);
}
$dialog->submit();
if ($expected === TEST_BAD) {
$this->assertMessage(TEST_BAD, null, $data['error_details']);
$this->assertEquals($old_hash, CDBHelper::getHash($sql));
}
else {
// Save the configuration of the host with created/updated value mappings.
$dialog->waitUntilNotVisible();
$this->query('button:Update')->waitUntilClickable()->one()->click();
$this->assertMessage(TEST_GOOD, ucfirst($source).' updated');
// Write valuemap name to variable to use it in next Update test case.
if ($action === 'update') {
self::$previous_valuemap_name = $data['name'];
}
// Check all mappings that belong to the created value mapping.
$this->openValueMappingTab($source, false);
$this->query('link', $data['name'])->one()->click();
$this->checkMappings($data);
// Check the value mapping screenshots after form submit.
if (CTestArrayHelper::get($data, 'screenshot_id')) {
// Viewport update needed because of an unexpected viewport shift.
$this->page->removeFocus();
$this->page->updateViewport();
// Take a screenshot to test draggable object position in overlay dialog.
if ($action === 'create') {
$dialog = COverlayDialogElement::find()->waitUntilReady()->all()->last();
$this->assertScreenshot($dialog->query('id:mappings_table')->asMultifieldTable()->one(),
'Value mappings popup'.$data['screenshot_id']);
}
// Check the screenshot of the whole value mappings tab.
$this->openValueMappingTab($source, false);
$this->assertScreenshot($this->query('id', ($source === 'template' ? 'template-' : '').'valuemap-table')->one(),
$action.$source.$data['screenshot_id']);
COverlayDialogElement::find()->one()->close();
}
}
}
/**
* Function that checks configuration of the created/updated value mapping.
*
* @param array $data Data provider
*/
private function checkMappings($data) {
$dialog = COverlayDialogElement::find()->asForm()->waitUntilVisible()->all()->last();
$mappings_table = $this->query('id:mappings_table')->asMultifieldTable()->one();
// Check value mapping name.
$this->assertEquals($data['name'], $dialog->query('xpath:.//input[@id="name"]')->one()->getValue());
// Remove unnecessary mapping parameters from the reference array and trim trailing and leading spaces.
$mappings = $data['mappings'];
foreach($mappings as &$mapping) {
unset($mapping['action'], $mapping['index']);
if (CTestArrayHelper::get($data, 'trim', false)) {
$mapping = array_map('trim', $mapping);
}
}
unset($mapping);
$mappings_table->checkValue($mappings);
}
/**
* Function that opens the configuration form of a host/template and switches to the value mapping tab.
*
* @param string $source Entity (host or template) configuration of which should be opened.
* @param boolean $login Flag that determines if a login is required.
* @param boolean $open_tab Flag that determines if opening the value mapping tab is required.
*
* @return CFormElement|CFluidFormElemt $form
*/
private function openValueMappingTab($source, $login = true, $open_tab = true) {
$sourceid = ($source === 'host') ? self::HOSTID : self::TEMPLATEID;
if ($login) {
$this->page->login();
}
// Get name of host or template for the filter and link.
$name = CDBHelper::getValue('SELECT host FROM hosts WHERE hostid='.zbx_dbstr($sourceid));
$this->page->open('zabbix.php?action='.$source.'.list&filter_name='.$name.'&filter_set=1')->waitUntilReady();
$this->query('link', $name)->one()->click();
$form = COverlayDialogElement::find()->asForm()->one()->waitUntilVisible();
if ($open_tab) {
$form->selectTab('Value mapping');
}
return $form;
}
/**
* Function that checks that no database changes occurred if nothing was actually changed during update.
*
* @param string $source Entity (host or template) for which the scenario is executed.
*/
public function checkSimpleUpdate($source) {
$sql = 'SELECT * FROM valuemap v INNER JOIN valuemap_mapping vm ON vm.valuemapid=v.valuemapid'.
' ORDER BY v.name, v.valuemapid, vm.sortorder';
$old_hash = CDBHelper::getHash($sql);
// Open configuration of a value mapping and save it without making any changes.
$this->openValueMappingTab($source);
$this->query('link', self::UPDATE_VALUEMAP1)->one()->click();
$dialog = COverlayDialogElement::find()->asForm()->waitUntilVisible()->all()->last();
$dialog->submit()->waitUntilNotVisible();
$this->query('button:Update')->one()->click();
// Check that no changes occurred in the database.
$this->assertEquals($old_hash, CDBHelper::getHash($sql));
}
/**
* Function that checks that no changes in the database are made in case if value mapping update is cancelled.
*
* @param string $source Entity (host or template) for which the scenario is executed.
*/
public function checkCancel($source) {
// New values of value mapping fields.
$fields = [
'name' => 'Updated valuemap name',
'mappings' => [
[
'action' => USER_ACTION_UPDATE,
'index' => 0,
'value' => 'new value',
'newvalue' => 'new newvalue'
],
[
'action' => USER_ACTION_REMOVE,
'index' => 2
],
[
'value' => 'new mapping value',
'newvalue' => 'new mapping newvalue'
]
]
];
$sql = 'SELECT * FROM valuemap v INNER JOIN valuemap_mapping vm ON vm.valuemapid=v.valuemapid'.
' ORDER BY v.name, v.valuemapid, vm.sortorder';
$old_hash = CDBHelper::getHash($sql);
// Open value mapping configuration and update its fields.
$this->openValueMappingTab($source);
$this->query('link', self::UPDATE_VALUEMAP2)->one()->click();
$dialog = COverlayDialogElement::find()->asForm()->waitUntilVisible()->all()->last();
$dialog->query('xpath:.//input[@id="name"]')->one()->fill($fields['name']);
$dialog->query('id:mappings_table')->asMultifieldTable()->one()->fill($fields['mappings']);
// Submit the value mapping configuration dialog, but Cancel the update of the host/template.
$dialog->submit()->waitUntilNotVisible();
$this->query('button:Cancel')->one()->click();
// Check that no changes occurred in the database.
$this->assertEquals($old_hash, CDBHelper::getHash($sql));
}
/**
* Function that checks value mapping deletion.
*
* @param string $source Entity (host or template) for which the scenario is executed.
*/
public function checkDelete($source) {
// Get the Database records that correspond to the value mapping to be deleted and its mappings.
$valuemap_sql = 'SELECT valuemapid FROM valuemap WHERE name=';
$mappings_sql = 'SELECT valuemap_mappingid FROM valuemap_mapping WHERE valuemapid=';
$valuemap_id = CDBHelper::getValue($valuemap_sql.zbx_dbstr(self::DELETE_VALUEMAP));
// Delete the value mapping.
$form = $this->openValueMappingTab($source);
$table = $this->query('id', ($source === 'template' ? 'template-' : '').'valuemap-table')->asTable()->one();
$table->findRow('Name', self::DELETE_VALUEMAP)->query('button:Remove')->one()->click();
$form->submit();
$this->page->waitUntilReady();
$this->assertMessage(TEST_GOOD);
// Check that the deleted value mapping and its mappings are not present in the DB.
$this->assertEquals(0, CDBHelper::getCount($valuemap_sql.zbx_dbstr(self::DELETE_VALUEMAP)));
$this->assertEquals(0, CDBHelper::getCount($mappings_sql.$valuemap_id));
}
/**
* Function that checks that valuemap data is not lost if there is an error when saving the host/template.
*
* @param string $source Entity (host or template) for which the scenario is executed.
*/
public function checkSavingError($source) {
// Value mapping data to be entered.
$valuemap = [
'name' => 'Updated valuemap name',
'mappings' => [
'action' => USER_ACTION_UPDATE,
'index' => 0,
'value' => 'received value',
'newvalue' => 'new newvalue'
]
];
// Value mapping data to be visible in the value mapping tab.
$reference_valuemaps = [
[
'Name' => $valuemap['name'],
'Value' => "=".$valuemap['mappings']['value']."\n\n".$valuemap['mappings']['newvalue'],
'Action' => 'Remove'
]
];
// Create a new host/template, populate the hosthgroup but leave the name empty.
$this->page->login()->open('zabbix.php?action='.$source.'.list')->waitUntilReady();
$this->query('button:Create '.$source)->one()->click();
$form = COverlayDialogElement::find()->asForm()->one()->waitUntilVisible();
$form->getField(ucfirst($source).' groups')->fill(($source === 'host') ? 'Discovered hosts' : 'Templates');
// Open value mappings tab and add a value mapping.
$form->selectTab('Value mapping');
$this->query('name:valuemap_add')->one()->click();
$dialog = COverlayDialogElement::find()->asForm()->waitUntilVisible()->all()->last();
$dialog->query('xpath:.//input[@id="name"]')->one()->fill($valuemap['name']);
$dialog->query('id:mappings_table')->asMultifieldTable()->one()->fill($valuemap['mappings']);
$dialog->submit()->waitUntilNotVisible();
// Submit host/template configuration and wait for the error message to appear.
$form->submit();
$this->page->waitUntilReady();
$this->assertMessage(TEST_BAD);
// Check that the value mapping data is still populated.
$this->assertTableData($reference_valuemaps, 'id:valuemap-formlist');
}
/**
* Function that checks a screenshot of draggable element in hosts/templates value mapping while mass updating.
*
* @param string $source Entity (hosts or templates) for which the scenario is executed.
*/
public function checkMassValuemappingScreenshot($source) {
$this->page->login()->open(($source === 'hosts') ? 'zabbix.php?action=host.list' : 'zabbix.php?action=template.list')->waitUntilReady();
$this->selectTableRows();
$this->query('button:Mass update')->one()->click();
$update_form = COverlayDialogElement::find()->asForm()->one()->waitUntilReady();
$update_form->selectTab('Value mapping');
$update_form->query('id:visible_valuemaps')->asCheckbox()->one()->check();
$update_form->query('id:valuemap_add')->one()->click();
$mapping_form = COverlayDialogElement::find()->asForm()->all()->last()->waitUntilReady();
// Take a screenshot to test draggable object position of value mapping field.
$this->page->removeFocus();
// It is necessary because of unexpected viewport shift.
$this->page->updateViewport();
$this->assertScreenshot($mapping_form->query('id:mappings_table')->waitUntilVisible()->one(), 'Value mapping mass update');
}
}